@@ -189,3 +189,57 @@ extension RedisCommandExecutor {
189189 . mapFromRESP ( )
190190 }
191191}
192+
193+ extension RedisCommandExecutor {
194+ /// Incrementally iterates over all keys in the currently selected database.
195+ ///
196+ /// [https://redis.io/commands/scan](https://redis.io/commands/scan)
197+ /// - Parameters:
198+ /// - count: The number of elements to advance by. Redis default is 10.
199+ /// - matching: A glob-style pattern to filter values to be selected from the result set.
200+ /// - Returns: A cursor position for additional invocations with a limited collection of keys stored in the database.
201+ @inlinable
202+ public func scan(
203+ _ key: String ,
204+ atPosition pos: Int = 0 ,
205+ count: Int ? = nil ,
206+ matching match: String ? = nil ) -> EventLoopFuture < ( Int , [ String ] ) >
207+ {
208+ return _scan ( command: " SCAN " , resultType: [ String ] . self, key, pos, count, match)
209+ }
210+
211+ @inline ( __always)
212+ @usableFromInline func _scan< T: RESPValueConvertible > (
213+ command: String ,
214+ resultType: T . Type ,
215+ _ key: String ,
216+ _ pos: Int ,
217+ _ count: Int ? ,
218+ _ match: String ? ) -> EventLoopFuture < ( Int , T ) >
219+ {
220+ var args : [ RESPValueConvertible ] = [ key, pos]
221+
222+ if let m = match {
223+ args. append ( " match " )
224+ args. append ( m)
225+ }
226+ if let c = count {
227+ args. append ( " count " )
228+ args. append ( c)
229+ }
230+
231+ let response = send ( command: command, with: args) . mapFromRESP ( to: [ RESPValue ] . self)
232+ let position = response. flatMapThrowing { result -> Int in
233+ guard
234+ let value = result [ 0 ] . string,
235+ let position = Int ( value)
236+ else { throw RedisError ( identifier: #function, reason: " Unexpected value in response: \( result [ 0 ] ) " ) }
237+ return position
238+ }
239+ let elements = response
240+ . map { return $0 [ 1 ] }
241+ . mapFromRESP ( to: resultType)
242+
243+ return position. and ( elements)
244+ }
245+ }
0 commit comments