@@ -117,6 +117,33 @@ extension RedisClient {
117117 public func rpoplpush( from source: String , to dest: String ) -> EventLoopFuture < RESPValue > {
118118 return send ( command: " RPOPLPUSH " , with: [ source, dest] )
119119 }
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+ }
120147}
121148
122149// MARK: Insert
@@ -250,3 +277,116 @@ extension RedisClient {
250277 . mapFromRESP ( )
251278 }
252279}
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