diff --git a/Sources/RediStack/Commands/BasicCommands.swift b/Sources/RediStack/Commands/BasicCommands.swift index c6a4b70..d302e6e 100644 --- a/Sources/RediStack/Commands/BasicCommands.swift +++ b/Sources/RediStack/Commands/BasicCommands.swift @@ -23,7 +23,7 @@ extension RedisClient { public func echo(_ message: String) -> EventLoopFuture { let args = [RESPValue(bulk: message)] return send(command: "ECHO", with: args) - .map() + .tryConverting() } /// Pings the server, which will respond with a message. @@ -36,7 +36,7 @@ extension RedisClient { ? [.init(bulk: message!)] // safe because we did a nil pre-check : [] return send(command: "PING", with: args) - .map() + .tryConverting() } /// Select the Redis logical database having the specified zero-based numeric index. @@ -64,7 +64,7 @@ extension RedisClient { .init(bulk: second) ] return send(command: "SWAPDB", with: args) - .map(to: String.self) + .tryConverting(to: String.self) .map { return $0 == "OK" } } @@ -89,7 +89,7 @@ extension RedisClient { let args = keys.map(RESPValue.init) return send(command: "DEL", with: args) - .map() + .tryConverting() } /// Removes the specified keys. A key is ignored if it does not exist. @@ -111,7 +111,7 @@ extension RedisClient { RESPValue(from: $0) } return self.send(command: "EXISTS", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) } /// Checks the existence of the provided keys in the database. @@ -137,7 +137,7 @@ extension RedisClient { .init(bulk: timeout.seconds) ] return send(command: "EXPIRE", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } } @@ -153,7 +153,7 @@ extension RedisClient { public func ttl(_ key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [RESPValue(from: key)] return self.send(command: "TTL", with: args) - .map(to: Int64.self) + .tryConverting(to: Int64.self) .map { RedisKeyLifetime(seconds: $0) } } @@ -165,7 +165,7 @@ extension RedisClient { public func pttl(_ key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [RESPValue(from: key)] return self.send(command: "PTTL", with: args) - .map(to: Int64.self) + .tryConverting(to: Int64.self) .map { RedisKeyLifetime(milliseconds: $0) } } } @@ -287,7 +287,7 @@ extension RedisClient { args.append(.init(bulk: c)) } - let response = send(command: command, with: args).map(to: [RESPValue].self) + let response = send(command: command, with: args).tryConverting(to: [RESPValue].self) let position = response.flatMapThrowing { result -> Int in guard let value = result[0].string, @@ -299,7 +299,7 @@ extension RedisClient { } let elements = response .map { return $0[1] } - .map(to: resultType) + .tryConverting(to: resultType) return position.and(elements) } diff --git a/Sources/RediStack/Commands/HashCommands.swift b/Sources/RediStack/Commands/HashCommands.swift index f31a789..66ea877 100644 --- a/Sources/RediStack/Commands/HashCommands.swift +++ b/Sources/RediStack/Commands/HashCommands.swift @@ -56,7 +56,7 @@ extension RedisClient { args.append(convertingContentsOf: fields) return send(command: "HDEL", with: args) - .map() + .tryConverting() } /// Removes the specified fields from a hash. @@ -83,7 +83,7 @@ extension RedisClient { .init(bulk: field) ] return send(command: "HEXISTS", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } @@ -95,7 +95,7 @@ extension RedisClient { public func hlen(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "HLEN", with: args) - .map() + .tryConverting() } /// Gets the string length of a hash field's value. @@ -111,7 +111,7 @@ extension RedisClient { .init(bulk: field) ] return send(command: "HSTRLEN", with: args) - .map() + .tryConverting() } /// Gets all field names in a hash. @@ -122,7 +122,7 @@ extension RedisClient { public func hkeys(in key: RedisKey) -> EventLoopFuture<[String]> { let args = [RESPValue(from: key)] return send(command: "HKEYS", with: args) - .map() + .tryConverting() } /// Gets all values stored in a hash. @@ -133,7 +133,7 @@ extension RedisClient { public func hvals(in key: RedisKey) -> EventLoopFuture<[RESPValue]> { let args = [RESPValue(from: key)] return send(command: "HVALS", with: args) - .map() + .tryConverting() } /// Gets all values stored in a hash. @@ -221,7 +221,7 @@ extension RedisClient { value.convertedToRESPValue() ] return send(command: "HSET", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } @@ -246,7 +246,7 @@ extension RedisClient { value.convertedToRESPValue() ] return send(command: "HSETNX", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } @@ -325,7 +325,7 @@ extension RedisClient { args.append(convertingContentsOf: fields) return send(command: "HMGET", with: args) - .map(to: [RESPValue].self) + .tryConverting(to: [RESPValue].self) } /// Gets the values of a hash for the fields specified as a specific type. @@ -382,7 +382,7 @@ extension RedisClient { public func hgetall(from key: RedisKey) -> EventLoopFuture<[String: RESPValue]> { let args = [RESPValue(from: key)] return send(command: "HGETALL", with: args) - .map(to: [RESPValue].self) + .tryConverting(to: [RESPValue].self) .flatMapThrowing(Self._mapHashResponse) } @@ -453,6 +453,6 @@ extension RedisClient { amount.convertedToRESPValue() ] return send(command: command, with: args) - .map() + .tryConverting() } } diff --git a/Sources/RediStack/Commands/ListCommands.swift b/Sources/RediStack/Commands/ListCommands.swift index 3445402..6f05668 100644 --- a/Sources/RediStack/Commands/ListCommands.swift +++ b/Sources/RediStack/Commands/ListCommands.swift @@ -25,7 +25,7 @@ extension RedisClient { public func llen(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "LLEN", with: args) - .map() + .tryConverting() } /// Gets the element from a list stored at the provided index position. @@ -104,7 +104,7 @@ extension RedisClient { value.convertedToRESPValue() ] return send(command: "LREM", with: args) - .map() + .tryConverting() } } @@ -266,7 +266,7 @@ extension RedisClient { .init(bulk: lastIndex) ] return send(command: "LRANGE", with: args) - .map() + .tryConverting() } /// Gets all elements from a List within the the specified inclusive bounds of 0-based indices. @@ -668,7 +668,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "LINSERT", with: args) - .map() + .tryConverting() } } @@ -714,7 +714,7 @@ extension RedisClient { args.append(convertingContentsOf: elements) return send(command: "LPUSH", with: args) - .map() + .tryConverting() } /// Pushes all of the provided elements into a list. @@ -745,7 +745,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "LPUSHX", with: args) - .map() + .tryConverting() } } @@ -788,7 +788,7 @@ extension RedisClient { args.append(convertingContentsOf: elements) return send(command: "RPUSH", with: args) - .map() + .tryConverting() } /// Pushes all of the provided elements into a list. @@ -818,7 +818,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "RPUSHX", with: args) - .map() + .tryConverting() } } diff --git a/Sources/RediStack/Commands/SetCommands.swift b/Sources/RediStack/Commands/SetCommands.swift index 35b0b60..a7fd09e 100644 --- a/Sources/RediStack/Commands/SetCommands.swift +++ b/Sources/RediStack/Commands/SetCommands.swift @@ -28,7 +28,7 @@ extension RedisClient { public func smembers(of key: RedisKey) -> EventLoopFuture<[RESPValue]> { let args = [RESPValue(from: key)] return send(command: "SMEMBERS", with: args) - .map() + .tryConverting() } /// Gets all of the elements contained in a set. @@ -61,7 +61,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "SISMEMBER", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } @@ -73,7 +73,7 @@ extension RedisClient { public func scard(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "SCARD", with: args) - .map() + .tryConverting() } /// Adds elements to a set. @@ -91,7 +91,7 @@ extension RedisClient { args.append(convertingContentsOf: elements) return send(command: "SADD", with: args) - .map() + .tryConverting() } /// Adds elements to a set. @@ -121,7 +121,7 @@ extension RedisClient { args.append(convertingContentsOf: elements) return send(command: "SREM", with: args) - .map() + .tryConverting() } /// Removes elements from a set. @@ -153,7 +153,7 @@ extension RedisClient { .init(bulk: count) ] return send(command: "SPOP", with: args) - .map() + .tryConverting() } /// Randomly selects and removes one or more elements in a set. @@ -193,7 +193,7 @@ extension RedisClient { .init(bulk: count) ] return send(command: "SRANDMEMBER", with: args) - .map() + .tryConverting() } /// Randomly selects one or more elements in a set. @@ -236,7 +236,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "SMOVE", with: args) - .map() + .tryConverting() .map { return $0 == 1 } } @@ -297,7 +297,7 @@ extension RedisClient { let args = keys.map(RESPValue.init) return send(command: "SDIFF", with: args) - .map() + .tryConverting() } /// Calculates the difference between two or more sets. @@ -349,7 +349,7 @@ extension RedisClient { args.append(convertingContentsOf: keys) return send(command: "SDIFFSTORE", with: args) - .map() + .tryConverting() } } @@ -366,7 +366,7 @@ extension RedisClient { let args = keys.map(RESPValue.init) return send(command: "SINTER", with: args) - .map() + .tryConverting() } /// Calculates the intersection of two or more sets. @@ -418,7 +418,7 @@ extension RedisClient { args.append(convertingContentsOf: keys) return send(command: "SINTERSTORE", with: args) - .map() + .tryConverting() } } @@ -435,7 +435,7 @@ extension RedisClient { let args = keys.map(RESPValue.init) return send(command: "SUNION", with: args) - .map() + .tryConverting() } /// Calculates the union of two or more sets. @@ -487,6 +487,6 @@ extension RedisClient { args.append(convertingContentsOf: keys) return send(command: "SUNIONSTORE", with: args) - .map() + .tryConverting() } } diff --git a/Sources/RediStack/Commands/SortedSetCommands.swift b/Sources/RediStack/Commands/SortedSetCommands.swift index 87a5de5..6ab55b9 100644 --- a/Sources/RediStack/Commands/SortedSetCommands.swift +++ b/Sources/RediStack/Commands/SortedSetCommands.swift @@ -123,7 +123,7 @@ extension RedisClient { } return self.send(command: "ZADD", with: args) - .map() + .tryConverting() } /// Adds elements to a sorted set, assigning their score to the values provided. @@ -177,7 +177,7 @@ extension RedisClient { public func zcard(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "ZCARD", with: args) - .map() + .tryConverting() } /// Gets the score of the specified element in a stored set. @@ -268,7 +268,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "ZRANK", with: args) - .map() + .tryConverting() } /// Returns the rank (index) of the specified element in a sorted set. @@ -287,7 +287,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "ZREVRANK", with: args) - .map() + .tryConverting() } } @@ -369,7 +369,7 @@ extension RedisClient { .init(bulk: range.max.description) ] return self.send(command: "ZCOUNT", with: args) - .map() + .tryConverting() } /// Returns the count of elements in a SortedSet with a score within the inclusive range specified. @@ -498,7 +498,7 @@ extension RedisClient { .init(bulk: range.max.description) ] return self.send(command: "ZLEXCOUNT", with: args) - .map() + .tryConverting() } /// Returns the count of elements in a SortedSet whose lexiographical value is greater than a minimum value. @@ -611,7 +611,7 @@ extension RedisClient { } return send(command: command, with: args) - .map(to: [RESPValue].self) + .tryConverting(to: [RESPValue].self) .flatMapThrowing { return try Self._mapSortedSetResponse($0, scoreIsFirst: true) } } } @@ -779,7 +779,7 @@ extension RedisClient { element.convertedToRESPValue() ] return send(command: "ZINCRBY", with: args) - .map() + .tryConverting() } } @@ -867,7 +867,7 @@ extension RedisClient { } return send(command: command, with: args) - .map() + .tryConverting() } } @@ -1266,7 +1266,7 @@ extension RedisClient { if withScores { args.append(.init(bulk: "WITHSCORES")) } return send(command: command, with: args) - .map() + .tryConverting() } } @@ -1544,7 +1544,7 @@ extension RedisClient { } return send(command: command, with: args) - .map() + .tryConverting() } } @@ -1736,7 +1736,7 @@ extension RedisClient { } return send(command: command, with: args) - .map() + .tryConverting() } } @@ -1758,7 +1758,7 @@ extension RedisClient { args.append(convertingContentsOf: elements) return send(command: "ZREM", with: args) - .map() + .tryConverting() } /// Removes the specified elements from a sorted set. @@ -1803,7 +1803,7 @@ extension RedisClient { .init(bulk: range.max.description) ] return send(command: "ZREMRANGEBYLEX", with: args) - .map() + .tryConverting() } /// Removes elements from a SortedSet whose lexiographical values are greater than a minimum value. @@ -1871,7 +1871,7 @@ extension RedisClient { .init(bulk: lastIndex) ] return self.send(command: "ZREMRANGEBYRANK", with: args) - .map() + .tryConverting() } /// Removes all elements from a SortedSet within the specified inclusive bounds of 0-based indices. @@ -1959,7 +1959,7 @@ extension RedisClient { .init(bulk: range.max.description) ] return self.send(command: "ZREMRANGEBYSCORE", with: args) - .map() + .tryConverting() } /// Removes elements from a SortedSet whose score is within the inclusive range specified. diff --git a/Sources/RediStack/Commands/StringCommands.swift b/Sources/RediStack/Commands/StringCommands.swift index 4bd531c..48500c0 100644 --- a/Sources/RediStack/Commands/StringCommands.swift +++ b/Sources/RediStack/Commands/StringCommands.swift @@ -53,7 +53,7 @@ extension RedisClient { let args = keys.map(RESPValue.init) return send(command: "MGET", with: args) - .map() + .tryConverting() } /// Gets the values of all specified keys, using `.null` to represent non-existant values. @@ -209,7 +209,7 @@ extension RedisClient { value.convertedToRESPValue() ] return send(command: "APPEND", with: args) - .map() + .tryConverting() } /// Sets the value stored in the key provided, overwriting the previous value. @@ -289,7 +289,7 @@ extension RedisClient { value.convertedToRESPValue() ] return self.send(command: "SETNX", with: args) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { $0 == 1 } } @@ -368,7 +368,7 @@ extension RedisClient { @inlinable public func msetnx(_ operations: [RedisKey: Value]) -> EventLoopFuture { return _mset(command: "MSETNX", operations) - .map(to: Int.self) + .tryConverting(to: Int.self) .map { return $0 == 1 } } @@ -402,7 +402,7 @@ extension RedisClient { public func increment(_ key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "INCR", with: args) - .map() + .tryConverting() } /// Increments the stored value by the amount desired . @@ -422,7 +422,7 @@ extension RedisClient { .init(bulk: count) ] return send(command: "INCRBY", with: args) - .map() + .tryConverting() } /// Increments the stored value by the amount desired. @@ -442,7 +442,7 @@ extension RedisClient { count.convertedToRESPValue() ] return send(command: "INCRBYFLOAT", with: args) - .map() + .tryConverting() } } @@ -458,7 +458,7 @@ extension RedisClient { public func decrement(_ key: RedisKey) -> EventLoopFuture { let args = [RESPValue(from: key)] return send(command: "DECR", with: args) - .map() + .tryConverting() } /// Decrements the stored valye by the amount desired. @@ -478,6 +478,6 @@ extension RedisClient { .init(bulk: count) ] return send(command: "DECRBY", with: args) - .map() + .tryConverting() } } diff --git a/Sources/RediStack/RESP/RESPValue.swift b/Sources/RediStack/RESP/RESPValue.swift index 3023b71..5e94f3f 100644 --- a/Sources/RediStack/RESP/RESPValue.swift +++ b/Sources/RediStack/RESP/RESPValue.swift @@ -171,20 +171,20 @@ extension RESPValue: RESPValueConvertible { import NIO extension EventLoopFuture where Value == RESPValue { - /// Attempts to convert the `RESPValue` to the desired `RESPValueConvertible` type. - /// If the `RESPValueConvertible.init(_:)` returns `nil`, then the `EventLoopFuture` will fail. + /// Attempts to convert the resolved RESPValue to the desired type. + /// + /// This method is intended to be used much like a precondition in synchronous code, where a value is expected to be available from the `RESPValue`. + /// - Important: If the `RESPValueConvertible` initializer fails, then the `NIO.EventLoopFuture` will fail. /// - Parameter to: The desired type to convert to. - /// - Returns: An `EventLoopFuture` that resolves a value of the desired type. - @inlinable - public func map( + /// - Throws: `RedisClientError.failedRESPConversion(to:)` + /// - Returns: A `NIO.EventLoopFuture` that resolves a value of the desired type or fails if the conversion does. + @usableFromInline + internal func tryConverting( to type: T.Type = T.self, - file: StaticString = #function, - function: StaticString = #function, + file: StaticString = #file, line: UInt = #line - ) -> EventLoopFuture - where T: RESPValueConvertible - { - return self.flatMapThrowing { + ) -> EventLoopFuture { + return self.flatMapThrowing(file: file, line: line) { guard let value = T(fromRESP: $0) else { throw RedisClientError.failedRESPConversion(to: type) }