@@ -117,6 +117,33 @@ extension RedisClient {
117
117
public func rpoplpush( from source: String , to dest: String ) -> EventLoopFuture < RESPValue > {
118
118
return send ( command: " RPOPLPUSH " , with: [ source, dest] )
119
119
}
120
+
121
+ /// Pops the last element from a source list and pushes it to a destination list, blocking until
122
+ /// an element is available from the source list.
123
+ ///
124
+ /// - Important:
125
+ /// This will block the connection from completing further commands until an element
126
+ /// is available to pop from the source list.
127
+ ///
128
+ /// It is **highly** recommended to set a reasonable `timeout`
129
+ /// or to use the non-blocking `rpoplpush` method where possible.
130
+ ///
131
+ /// See [https://redis.io/commands/brpoplpush](https://redis.io/commands/brpoplpush)
132
+ /// - Parameters:
133
+ /// - source: The key of the list to pop from.
134
+ /// - dest: The key of the list to push to.
135
+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
136
+ /// - Returns: The element popped from the source list and pushed to the destination,
137
+ /// or `nil` if the timeout was reached.
138
+ @inlinable
139
+ public func brpoplpush(
140
+ from source: String ,
141
+ to dest: String ,
142
+ timeout: Int = 0
143
+ ) -> EventLoopFuture < RESPValue ? > {
144
+ return send ( command: " BRPOPLPUSH " , with: [ source, dest, timeout] )
145
+ . map { $0. isNull ? nil : $0 }
146
+ }
120
147
}
121
148
122
149
// MARK: Insert
@@ -250,3 +277,116 @@ extension RedisClient {
250
277
. mapFromRESP ( )
251
278
}
252
279
}
280
+
281
+ // MARK: Blocking Pop
282
+
283
+ extension RedisClient {
284
+ /// Removes the first element of a list, blocking until an element is available.
285
+ ///
286
+ /// - Important:
287
+ /// This will block the connection from completing further commands until an element
288
+ /// is available to pop from the list.
289
+ ///
290
+ /// It is **highly** recommended to set a reasonable `timeout`
291
+ /// or to use the non-blocking `lpop` method where possible.
292
+ ///
293
+ /// See [https://redis.io/commands/blpop](https://redis.io/commands/blpop)
294
+ /// - Parameters:
295
+ /// - key: The key of the list to pop from.
296
+ /// - Returns: The element that was popped from the list, or `nil` if the timout was reached.
297
+ @inlinable
298
+ public func blpop( from key: String , timeout: Int = 0 ) -> EventLoopFuture < RESPValue ? > {
299
+ return blpop ( from: [ key] , timeout: timeout)
300
+ . map { $0? . 1 }
301
+ }
302
+
303
+ /// Removes the first element of a list, blocking until an element is available.
304
+ ///
305
+ /// - Important:
306
+ /// This will block the connection from completing further commands until an element
307
+ /// is available to pop from the group of lists.
308
+ ///
309
+ /// It is **highly** recommended to set a reasonable `timeout`
310
+ /// or to use the non-blocking `lpop` method where possible.
311
+ ///
312
+ /// See [https://redis.io/commands/blpop](https://redis.io/commands/blpop)
313
+ /// - Parameters:
314
+ /// - keys: The keys of lists in Redis that should be popped from.
315
+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
316
+ /// - Returns:
317
+ /// If timeout was reached, `nil`.
318
+ ///
319
+ /// Otherwise, the key of the list the element was removed from and the popped element.
320
+ @inlinable
321
+ public func blpop(
322
+ from keys: [ String ] ,
323
+ timeout: Int = 0
324
+ ) -> EventLoopFuture < ( String , RESPValue ) ? > {
325
+ return _bpop ( command: " BLPOP " , keys, timeout)
326
+ }
327
+
328
+ /// Removes the last element of a list, blocking until an element is available.
329
+ ///
330
+ /// - Important:
331
+ /// This will block the connection from completing further commands until an element
332
+ /// is available to pop from the list.
333
+ ///
334
+ /// It is **highly** recommended to set a reasonable `timeout`
335
+ /// or to use the non-blocking `rpop` method where possible.
336
+ ///
337
+ /// See [https://redis.io/commands/brpop](https://redis.io/commands/brpop)
338
+ /// - Parameters:
339
+ /// - key: The key of the list to pop from.
340
+ /// - Returns: The element that was popped from the list, or `nil` if the timout was reached.
341
+ @inlinable
342
+ public func brpop( from key: String , timeout: Int = 0 ) -> EventLoopFuture < RESPValue ? > {
343
+ return brpop ( from: [ key] , timeout: timeout)
344
+ . map { $0? . 1 }
345
+ }
346
+
347
+ /// Removes the last element of a list, blocking until an element is available.
348
+ ///
349
+ /// - Important:
350
+ /// This will block the connection from completing further commands until an element
351
+ /// is available to pop from the group of lists.
352
+ ///
353
+ /// It is **highly** recommended to set a reasonable `timeout`
354
+ /// or to use the non-blocking `rpop` method where possible.
355
+ ///
356
+ /// See [https://redis.io/commands/brpop](https://redis.io/commands/brpop)
357
+ /// - Parameters:
358
+ /// - keys: The keys of lists in Redis that should be popped from.
359
+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
360
+ /// - Returns:
361
+ /// If timeout was reached, `nil`.
362
+ ///
363
+ /// Otherwise, the key of the list the element was removed from and the popped element.
364
+ @inlinable
365
+ public func brpop(
366
+ from keys: [ String ] ,
367
+ timeout: Int = 0
368
+ ) -> EventLoopFuture < ( String , RESPValue ) ? > {
369
+ return _bpop ( command: " BRPOP " , keys, timeout)
370
+ }
371
+
372
+ @usableFromInline
373
+ func _bpop(
374
+ command: String ,
375
+ _ keys: [ String ] ,
376
+ _ timeout: Int
377
+ ) -> EventLoopFuture < ( String , RESPValue ) ? > {
378
+ let args = keys as [ RESPValueConvertible ] + [ timeout]
379
+ return send ( command: command, with: args)
380
+ . flatMapThrowing {
381
+ guard !$0. isNull else { return nil }
382
+ guard let response = [ RESPValue] ( $0) else {
383
+ throw NIORedisError . responseConversion ( to: [ RESPValue ] . self)
384
+ }
385
+ assert ( response. count == 2 , " Unexpected response size returned! " )
386
+ guard let key = response [ 0 ] . string else {
387
+ throw NIORedisError . assertionFailure ( message: " Unexpected structure in response: \( response) " )
388
+ }
389
+ return ( key, response [ 1 ] )
390
+ }
391
+ }
392
+ }
0 commit comments