Skip to content

Commit d7b029f

Browse files
committed
Add scan convenience method and refactor sscan to use new generic internal implementation for scan
1 parent 9a51cf9 commit d7b029f

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

Sources/NIORedis/Commands/BasicCommands.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

Sources/NIORedis/Commands/SetCommands.swift

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -138,42 +138,19 @@ extension RedisCommandExecutor {
138138
.mapFromRESP()
139139
}
140140

141-
/// Incrementally iterates over a set, returning a cursor position for additional calls with a limited collection
142-
/// of the entire set.
141+
/// Incrementally iterates over all values in a set.
143142
///
144143
/// [https://redis.io/commands/sscan](https://redis.io/commands/sscan)
145144
/// - Parameters:
146145
/// - count: The number of elements to advance by. Redis default is 10.
147146
/// - matching: A glob-style pattern to filter values to be selected from the result set.
147+
/// - Returns: A cursor position for additional invocations with a limited collection of values stored at the keys.
148148
public func sscan(
149149
_ key: String,
150150
atPosition pos: Int = 0,
151151
count: Int? = nil,
152-
matching match: String? = nil
153-
) -> EventLoopFuture<(Int, [RESPValue])> {
154-
var args: [RESPValueConvertible] = [key, pos]
155-
156-
if let m = match {
157-
args.append("match")
158-
args.append(m)
159-
}
160-
if let c = count {
161-
args.append("count")
162-
args.append(c)
163-
}
164-
165-
let response = send(command: "SSCAN", with: args).mapFromRESP(to: [RESPValue].self)
166-
let position = response.flatMapThrowing { result -> Int in
167-
guard
168-
let value = result[0].string,
169-
let position = Int(value)
170-
else { throw RedisError(identifier: #function, reason: "Unexpected value in response: \(result[0])") }
171-
return position
172-
}
173-
let elements = response
174-
.map { return $0[1] }
175-
.mapFromRESP(to: [RESPValue].self)
176-
177-
return position.and(elements)
152+
matching match: String? = nil) -> EventLoopFuture<(Int, [RESPValue])>
153+
{
154+
return _scan(command: "SSCAN", resultType: [RESPValue].self, key, pos, count, match)
178155
}
179156
}

0 commit comments

Comments
 (0)