@@ -292,6 +292,149 @@ extension RedisClient {
292292 }
293293}
294294
295+ // MARK: Blocking Pop
296+
297+ extension RedisClient {
298+ /// Removes the element from a sorted set with the lowest score, blocking until an element is
299+ /// available.
300+ ///
301+ /// - Important:
302+ /// This will block the connection from completing further commands until an element
303+ /// is available to pop from the set.
304+ ///
305+ /// It is **highly** recommended to set a reasonable `timeout`
306+ /// or to use the non-blocking `zpopmin` method where possible.
307+ ///
308+ /// See [https://redis.io/commands/bzpopmin](https://redis.io/commands/bzpopmin)
309+ /// - Parameters:
310+ /// - key: The key identifying the sorted set in Redis.
311+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
312+ /// - Returns:
313+ /// The element and its associated score that was popped from the sorted set,
314+ /// or `nil` if the timeout was reached.
315+ @inlinable
316+ public func bzpopmin(
317+ from key: String ,
318+ timeout: Int = 0
319+ ) -> EventLoopFuture < ( Double , RESPValue ) ? > {
320+ return bzpopmin ( from: [ key] , timeout: timeout)
321+ . map {
322+ guard let response = $0 else { return nil }
323+ return ( response. 1 , response. 2 )
324+ }
325+ }
326+
327+ /// Removes the element from a sorted set with the lowest score, blocking until an element is
328+ /// available.
329+ ///
330+ /// - Important:
331+ /// This will block the connection from completing further commands until an element
332+ /// is available to pop from the group of sets.
333+ ///
334+ /// It is **highly** recommended to set a reasonable `timeout`
335+ /// or to use the non-blocking `zpopmin` method where possible.
336+ ///
337+ /// See [https://redis.io/commands/bzpopmin](https://redis.io/commands/bzpopmin)
338+ /// - Parameters:
339+ /// - keys: A list of sorted set keys in Redis.
340+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
341+ /// - Returns:
342+ /// If timeout was reached, `nil`.
343+ ///
344+ /// Otherwise, the key of the sorted set the element was removed from, the element itself,
345+ /// and its associated score is returned.
346+ @inlinable
347+ public func bzpopmin(
348+ from keys: [ String ] ,
349+ timeout: Int = 0
350+ ) -> EventLoopFuture < ( String , Double , RESPValue ) ? > {
351+ return self . _bzpop ( command: " BZPOPMIN " , keys, timeout)
352+ }
353+
354+ /// Removes the element from a sorted set with the highest score, blocking until an element is
355+ /// available.
356+ ///
357+ /// - Important:
358+ /// This will block the connection from completing further commands until an element
359+ /// is available to pop from the set.
360+ ///
361+ /// It is **highly** recommended to set a reasonable `timeout`
362+ /// or to use the non-blocking `zpopmax` method where possible.
363+ ///
364+ /// See [https://redis.io/commands/bzpopmax](https://redis.io/commands/bzpopmax)
365+ /// - Parameters:
366+ /// - key: The key identifying the sorted set in Redis.
367+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
368+ /// - Returns:
369+ /// The element and its associated score that was popped from the sorted set,
370+ /// or `nil` if the timeout was reached.
371+ @inlinable
372+ public func bzpopmax(
373+ from key: String ,
374+ timeout: Int = 0
375+ ) -> EventLoopFuture < ( Double , RESPValue ) ? > {
376+ return self . bzpopmax ( from: [ key] , timeout: timeout)
377+ . map {
378+ guard let response = $0 else { return nil }
379+ return ( response. 1 , response. 2 )
380+ }
381+ }
382+
383+ /// Removes the element from a sorted set with the highest score, blocking until an element is
384+ /// available.
385+ ///
386+ /// - Important:
387+ /// This will block the connection from completing further commands until an element
388+ /// is available to pop from the group of sets.
389+ ///
390+ /// It is **highly** recommended to set a reasonable `timeout`
391+ /// or to use the non-blocking `zpopmax` method where possible.
392+ ///
393+ /// See [https://redis.io/commands/bzpopmax](https://redis.io/commands/bzpopmax)
394+ /// - Parameters:
395+ /// - keys: A list of sorted set keys in Redis.
396+ /// - timeout: The time (in seconds) to wait. `0` means indefinitely.
397+ /// - Returns:
398+ /// If timeout was reached, `nil`.
399+ ///
400+ /// Otherwise, the key of the sorted set the element was removed from, the element itself,
401+ /// and its associated score is returned.
402+ @inlinable
403+ public func bzpopmax(
404+ from keys: [ String ] ,
405+ timeout: Int = 0
406+ ) -> EventLoopFuture < ( String , Double , RESPValue ) ? > {
407+ return self . _bzpop ( command: " BZPOPMAX " , keys, timeout)
408+ }
409+
410+ @usableFromInline
411+ func _bzpop(
412+ command: String ,
413+ _ keys: [ String ] ,
414+ _ timeout: Int
415+ ) -> EventLoopFuture < ( String , Double , RESPValue ) ? > {
416+ let args = keys as [ RESPValueConvertible ] + [ timeout]
417+ return send ( command: command, with: args)
418+ // per the Redis docs,
419+ // we will receive either a nil response,
420+ // or an array with 3 elements in the form [Set Key, Element Score, Element Value]
421+ . flatMapThrowing {
422+ guard !$0. isNull else { return nil }
423+ guard let response = [ RESPValue] ( $0) else {
424+ throw NIORedisError . responseConversion ( to: [ RESPValue ] . self)
425+ }
426+ assert ( response. count == 3 , " Unexpected response size returned! " )
427+ guard
428+ let key = response [ 0 ] . string,
429+ let score = Double ( response [ 1 ] )
430+ else {
431+ throw NIORedisError . assertionFailure ( message: " Unexpected structure in response: \( response) " )
432+ }
433+ return ( key, score, response [ 2 ] )
434+ }
435+ }
436+ }
437+
295438// MARK: Increment
296439
297440extension RedisClient {
0 commit comments