diff --git a/Sources/RediStack/Commands/BasicCommands.swift b/Sources/RediStack/Commands/BasicCommands.swift index 674162e..c380d25 100644 --- a/Sources/RediStack/Commands/BasicCommands.swift +++ b/Sources/RediStack/Commands/BasicCommands.swift @@ -90,7 +90,7 @@ extension RedisClient { /// - Parameter keys: A list of keys to delete from the database. /// - Returns: The number of keys deleted from the database. @inlinable - public func delete(_ keys: [String]) -> EventLoopFuture { + public func delete(_ keys: [RedisKey]) -> EventLoopFuture { guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture(0) } let args = keys.map(RESPValue.init) @@ -104,7 +104,7 @@ extension RedisClient { /// - Parameter keys: A list of keys to delete from the database. /// - Returns: The number of keys deleted from the database. @inlinable - public func delete(_ keys: String...) -> EventLoopFuture { + public func delete(_ keys: RedisKey...) -> EventLoopFuture { return self.delete(keys) } @@ -117,7 +117,7 @@ extension RedisClient { /// - timeout: The time from now the key will expire at. /// - Returns: `true` if the expiration was set. @inlinable - public func expire(_ key: String, after timeout: TimeAmount) -> EventLoopFuture { + public func expire(_ key: RedisKey, after timeout: TimeAmount) -> EventLoopFuture { let amount = timeout.nanoseconds / 1_000_000_000 let args: [RESPValue] = [ .init(bulk: key), @@ -153,7 +153,7 @@ extension RedisClient { internal func _scan( command: String, resultType: T.Type = T.self, - _ key: String?, + _ key: RedisKey?, _ pos: Int, _ count: Int?, _ match: String? diff --git a/Sources/RediStack/Commands/HashCommands.swift b/Sources/RediStack/Commands/HashCommands.swift index 4605820..c8547b3 100644 --- a/Sources/RediStack/Commands/HashCommands.swift +++ b/Sources/RediStack/Commands/HashCommands.swift @@ -46,7 +46,7 @@ extension RedisClient { /// - key: The key of the hash to delete from. /// - Returns: The number of fields that were deleted. @inlinable - public func hdel(_ fields: [String], from key: String) -> EventLoopFuture { + public func hdel(_ fields: [String], from key: RedisKey) -> EventLoopFuture { guard fields.count > 0 else { return self.eventLoop.makeSucceededFuture(0) } var args: [RESPValue] = [.init(bulk: key)] @@ -64,7 +64,7 @@ extension RedisClient { /// - key: The key of the hash to delete from. /// - Returns: The number of fields that were deleted. @inlinable - public func hdel(_ fields: String..., from key: String) -> EventLoopFuture { + public func hdel(_ fields: String..., from key: RedisKey) -> EventLoopFuture { return self.hdel(fields, from: key) } @@ -76,7 +76,7 @@ extension RedisClient { /// - key: The key of the hash to look within. /// - Returns: `true` if the hash contains the field, `false` if either the key or field do not exist. @inlinable - public func hexists(_ field: String, in key: String) -> EventLoopFuture { + public func hexists(_ field: String, in key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: field) @@ -92,7 +92,7 @@ extension RedisClient { /// - Parameter key: The key of the hash to get field count of. /// - Returns: The number of fields in the hash, or `0` if the key doesn't exist. @inlinable - public func hlen(of key: String) -> EventLoopFuture { + public func hlen(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "HLEN", with: args) .convertFromRESPValue() @@ -106,7 +106,7 @@ extension RedisClient { /// - key: The key of the hash. /// - Returns: The string length of the hash field's value, or `0` if the field or hash do not exist. @inlinable - public func hstrlen(of field: String, in key: String) -> EventLoopFuture { + public func hstrlen(of field: String, in key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: field) @@ -121,7 +121,7 @@ extension RedisClient { /// - Parameter key: The key of the hash. /// - Returns: A list of field names stored within the hash. @inlinable - public func hkeys(in key: String) -> EventLoopFuture<[String]> { + public func hkeys(in key: RedisKey) -> EventLoopFuture<[String]> { let args = [RESPValue(bulk: key)] return send(command: "HKEYS", with: args) .convertFromRESPValue() @@ -133,7 +133,7 @@ extension RedisClient { /// - Parameter key: The key of the hash. /// - Returns: A list of all values stored in a hash. @inlinable - public func hvals(in key: String) -> EventLoopFuture<[RESPValue]> { + public func hvals(in key: RedisKey) -> EventLoopFuture<[RESPValue]> { let args = [RESPValue(bulk: key)] return send(command: "HVALS", with: args) .convertFromRESPValue() @@ -150,7 +150,7 @@ extension RedisClient { /// - Returns: A cursor position for additional invocations with a limited collection of found fields and their values. @inlinable public func hscan( - _ key: String, + _ key: RedisKey, startingFrom position: Int = 0, count: Int? = nil, matching match: String? = nil @@ -179,7 +179,7 @@ extension RedisClient { public func hset( _ field: String, to value: Value, - in key: String + in key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -204,7 +204,7 @@ extension RedisClient { public func hsetnx( _ field: String, to value: Value, - in key: String + in key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -226,7 +226,7 @@ extension RedisClient { @inlinable public func hmset( _ fields: [String: Value], - in key: String + in key: RedisKey ) -> EventLoopFuture { assert(fields.count > 0, "At least 1 key-value pair should be specified") @@ -252,7 +252,7 @@ extension RedisClient { /// - key: The key of the hash being accessed. /// - Returns: The value of the hash field, or `nil` if either the key or field does not exist. @inlinable - public func hget(_ field: String, from key: String) -> EventLoopFuture { + public func hget(_ field: String, from key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: field) @@ -269,7 +269,7 @@ extension RedisClient { /// - key: The key of the hash being accessed. /// - Returns: A list of values in the same order as the `fields` argument. Non-existent fields return `nil` values. @inlinable - public func hmget(_ fields: [String], from key: String) -> EventLoopFuture<[String?]> { + public func hmget(_ fields: [String], from key: RedisKey) -> EventLoopFuture<[String?]> { guard fields.count > 0 else { return self.eventLoop.makeSucceededFuture([]) } var args: [RESPValue] = [.init(bulk: key)] @@ -288,7 +288,7 @@ extension RedisClient { /// - key: The key of the hash being accessed. /// - Returns: A list of values in the same order as the `fields` argument. Non-existent fields return `nil` values. @inlinable - public func hmget(_ fields: String..., from key: String) -> EventLoopFuture<[String?]> { + public func hmget(_ fields: String..., from key: RedisKey) -> EventLoopFuture<[String?]> { return self.hmget(fields, from: key) } @@ -298,7 +298,7 @@ extension RedisClient { /// - Parameter key: The key of the hash to pull from. /// - Returns: A key-value pair list of fields and their values. @inlinable - public func hgetall(from key: String) -> EventLoopFuture<[String: String]> { + public func hgetall(from key: RedisKey) -> EventLoopFuture<[String: String]> { let args = [RESPValue(bulk: key)] return send(command: "HGETALL", with: args) .convertFromRESPValue(to: [String].self) @@ -318,7 +318,7 @@ extension RedisClient { /// - key: The key of the hash the field is stored in. /// - Returns: The new value of the hash field. @inlinable - public func hincrby(_ amount: Int, field: String, in key: String) -> EventLoopFuture { + public func hincrby(_ amount: Int, field: String, in key: RedisKey) -> EventLoopFuture { return _hincr(command: "HINCRBY", amount, field, key) } @@ -331,7 +331,7 @@ extension RedisClient { /// - key: The key of the hash the field is stored in. /// - Returns: The new value of the hash field. @inlinable - public func hincrbyfloat(_ amount: Value, field: String, in key: String) -> EventLoopFuture + public func hincrbyfloat(_ amount: Value, field: String, in key: RedisKey) -> EventLoopFuture where Value: BinaryFloatingPoint, Value: RESPValueConvertible @@ -344,7 +344,7 @@ extension RedisClient { command: String, _ amount: Value, _ field: String, - _ key: String + _ key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), diff --git a/Sources/RediStack/Commands/ListCommands.swift b/Sources/RediStack/Commands/ListCommands.swift index c610444..2193d19 100644 --- a/Sources/RediStack/Commands/ListCommands.swift +++ b/Sources/RediStack/Commands/ListCommands.swift @@ -23,7 +23,7 @@ extension RedisClient { /// - Parameter key: The key of the list. /// - Returns: The number of elements in the list. @inlinable - public func llen(of key: String) -> EventLoopFuture { + public func llen(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "LLEN", with: args) .convertFromRESPValue() @@ -37,7 +37,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The element stored at index, or `.null` if out of bounds. @inlinable - public func lindex(_ index: Int, from key: String) -> EventLoopFuture { + public func lindex(_ index: Int, from key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: index) @@ -57,7 +57,7 @@ extension RedisClient { public func lset( index: Int, to value: Value, - in key: String + in key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -79,7 +79,7 @@ extension RedisClient { @inlinable public func lrem( _ value: Value, - from key: String, + from key: RedisKey, count: Int = 0 ) -> EventLoopFuture { let args: [RESPValue] = [ @@ -100,7 +100,7 @@ extension RedisClient { /// - stop: The index of the last element to keep. /// - Returns: An `EventLoopFuture` that resolves when the operation has succeeded, or fails with a `RedisError`. @inlinable - public func ltrim(_ key: String, before start: Int, after stop: Int) -> EventLoopFuture { + public func ltrim(_ key: RedisKey, before start: Int, after stop: Int) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: start), @@ -120,7 +120,7 @@ extension RedisClient { @inlinable public func lrange( within range: (startIndex: Int, endIndex: Int), - from key: String + from key: RedisKey ) -> EventLoopFuture<[RESPValue]> { let args: [RESPValue] = [ .init(bulk: key), @@ -139,7 +139,7 @@ extension RedisClient { /// - dest: The key of the list to push to. /// - Returns: The element that was moved. @inlinable - public func rpoplpush(from source: String, to dest: String) -> EventLoopFuture { + public func rpoplpush(from source: RedisKey, to dest: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: source), .init(bulk: dest) @@ -166,8 +166,8 @@ extension RedisClient { /// or `nil` if the timeout was reached. @inlinable public func brpoplpush( - from source: String, - to dest: String, + from source: RedisKey, + to dest: RedisKey, timeout: Int = 0 ) -> EventLoopFuture { let args: [RESPValue] = [ @@ -194,7 +194,7 @@ extension RedisClient { @inlinable public func linsert( _ element: Value, - into key: String, + into key: RedisKey, before pivot: Value ) -> EventLoopFuture { return _linsert(pivotKeyword: "BEFORE", element, key, pivot) @@ -211,7 +211,7 @@ extension RedisClient { @inlinable public func linsert( _ element: Value, - into key: String, + into key: RedisKey, after pivot: Value ) -> EventLoopFuture { return _linsert(pivotKeyword: "AFTER", element, key, pivot) @@ -221,7 +221,7 @@ extension RedisClient { func _linsert( pivotKeyword: String, _ element: Value, - _ key: String, + _ key: RedisKey, _ pivot: Value ) -> EventLoopFuture { let args: [RESPValue] = [ @@ -244,7 +244,7 @@ extension RedisClient { /// - Parameter key: The key of the list to pop from. /// - Returns: The element that was popped from the list, or `.null`. @inlinable - public func lpop(from key: String) -> EventLoopFuture { + public func lpop(from key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "LPOP", with: args) } @@ -258,7 +258,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func lpush(_ elements: [Value], into key: String) -> EventLoopFuture { + public func lpush(_ elements: [Value], into key: RedisKey) -> EventLoopFuture { assert(elements.count > 0, "At least 1 element should be provided.") var args: [RESPValue] = [.init(bulk: key)] @@ -277,7 +277,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func lpush(_ elements: Value..., into key: String) -> EventLoopFuture { + public func lpush(_ elements: Value..., into key: RedisKey) -> EventLoopFuture { return self.lpush(elements, into: key) } @@ -290,7 +290,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func lpushx(_ element: Value, into key: String) -> EventLoopFuture { + public func lpushx(_ element: Value, into key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -309,7 +309,7 @@ extension RedisClient { /// - Parameter key: The key of the list to pop from. /// - Returns: The element that was popped from the list, else `.null`. @inlinable - public func rpop(from key: String) -> EventLoopFuture { + public func rpop(from key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "RPOP", with: args) } @@ -322,7 +322,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func rpush(_ elements: [Value], into key: String) -> EventLoopFuture { + public func rpush(_ elements: [Value], into key: RedisKey) -> EventLoopFuture { assert(elements.count > 0, "At least 1 element should be provided.") var args: [RESPValue] = [.init(bulk: key)] @@ -340,7 +340,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func rpush(_ elements: Value..., into key: String) -> EventLoopFuture { + public func rpush(_ elements: Value..., into key: RedisKey) -> EventLoopFuture { return self.rpush(elements, into: key) } @@ -353,7 +353,7 @@ extension RedisClient { /// - key: The key of the list. /// - Returns: The length of the list after adding the new elements. @inlinable - public func rpushx(_ element: Value, into key: String) -> EventLoopFuture { + public func rpushx(_ element: Value, into key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -380,7 +380,7 @@ extension RedisClient { /// - key: The key of the list to pop from. /// - Returns: The element that was popped from the list, or `nil` if the timout was reached. @inlinable - public func blpop(from key: String, timeout: Int = 0) -> EventLoopFuture { + public func blpop(from key: RedisKey, timeout: Int = 0) -> EventLoopFuture { return blpop(from: [key], timeout: timeout) .map { $0?.1 } } @@ -403,7 +403,7 @@ extension RedisClient { /// /// Otherwise, the key of the list the element was removed from and the popped element. @inlinable - public func blpop(from keys: [String], timeout: Int = 0) -> EventLoopFuture<(String, RESPValue)?> { + public func blpop(from keys: [RedisKey], timeout: Int = 0) -> EventLoopFuture<(RedisKey, RESPValue)?> { return _bpop(command: "BLPOP", keys, timeout) } @@ -425,7 +425,7 @@ extension RedisClient { /// /// Otherwise, the key of the list the element was removed from and the popped element. @inlinable - public func blpop(from keys: String..., timeout: Int = 0) -> EventLoopFuture<(String, RESPValue)?> { + public func blpop(from keys: RedisKey..., timeout: Int = 0) -> EventLoopFuture<(RedisKey, RESPValue)?> { return self.blpop(from: keys, timeout: timeout) } @@ -443,7 +443,7 @@ extension RedisClient { /// - key: The key of the list to pop from. /// - Returns: The element that was popped from the list, or `nil` if the timout was reached. @inlinable - public func brpop(from key: String, timeout: Int = 0) -> EventLoopFuture { + public func brpop(from key: RedisKey, timeout: Int = 0) -> EventLoopFuture { return brpop(from: [key], timeout: timeout) .map { $0?.1 } } @@ -466,7 +466,7 @@ extension RedisClient { /// /// Otherwise, the key of the list the element was removed from and the popped element. @inlinable - public func brpop(from keys: [String], timeout: Int = 0) -> EventLoopFuture<(String, RESPValue)?> { + public func brpop(from keys: [RedisKey], timeout: Int = 0) -> EventLoopFuture<(RedisKey, RESPValue)?> { return _bpop(command: "BRPOP", keys, timeout) } @@ -488,16 +488,16 @@ extension RedisClient { /// /// Otherwise, the key of the list the element was removed from and the popped element. @inlinable - public func brpop(from keys: String..., timeout: Int = 0) -> EventLoopFuture<(String, RESPValue)?> { + public func brpop(from keys: RedisKey..., timeout: Int = 0) -> EventLoopFuture<(RedisKey, RESPValue)?> { return self.brpop(from: keys, timeout: timeout) } @usableFromInline func _bpop( command: String, - _ keys: [String], + _ keys: [RedisKey], _ timeout: Int - ) -> EventLoopFuture<(String, RESPValue)?> { + ) -> EventLoopFuture<(RedisKey, RESPValue)?> { var args = keys.map(RESPValue.init) args.append(.init(bulk: timeout)) @@ -511,7 +511,7 @@ extension RedisClient { guard let key = response[0].string else { throw RedisClientError.assertionFailure(message: "Unexpected structure in response: \(response)") } - return (key, response[1]) + return (.init(key), response[1]) } } } diff --git a/Sources/RediStack/Commands/SetCommands.swift b/Sources/RediStack/Commands/SetCommands.swift index 7a40417..18aaf55 100644 --- a/Sources/RediStack/Commands/SetCommands.swift +++ b/Sources/RediStack/Commands/SetCommands.swift @@ -26,7 +26,7 @@ extension RedisClient { /// - Parameter key: The key of the set. /// - Returns: A list of elements found within the set. @inlinable - public func smembers(of key: String) -> EventLoopFuture<[RESPValue]> { + public func smembers(of key: RedisKey) -> EventLoopFuture<[RESPValue]> { let args = [RESPValue(bulk: key)] return send(command: "SMEMBERS", with: args) .convertFromRESPValue() @@ -40,7 +40,7 @@ extension RedisClient { /// - key: The key of the set to look in. /// - Returns: `true` if the element is in the set. @inlinable - public func sismember(_ element: Value, of key: String) -> EventLoopFuture { + public func sismember(_ element: Value, of key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -56,7 +56,7 @@ extension RedisClient { /// - Parameter key: The key of the set. /// - Returns: The total count of elements in the set. @inlinable - public func scard(of key: String) -> EventLoopFuture { + public func scard(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "SCARD", with: args) .convertFromRESPValue() @@ -70,7 +70,7 @@ extension RedisClient { /// - key: The key of the set to insert into. /// - Returns: The number of elements that were added to the set. @inlinable - public func sadd(_ elements: [Value], to key: String) -> EventLoopFuture { + public func sadd(_ elements: [Value], to key: RedisKey) -> EventLoopFuture { guard elements.count > 0 else { return self.eventLoop.makeSucceededFuture(0) } var args: [RESPValue] = [.init(bulk: key)] @@ -88,7 +88,7 @@ extension RedisClient { /// - key: The key of the set to insert into. /// - Returns: The number of elements that were added to the set. @inlinable - public func sadd(_ elements: Value..., to key: String) -> EventLoopFuture { + public func sadd(_ elements: Value..., to key: RedisKey) -> EventLoopFuture { return self.sadd(elements, to: key) } @@ -100,7 +100,7 @@ extension RedisClient { /// - key: The key of the set to remove from. /// - Returns: The number of elements that were removed from the set. @inlinable - public func srem(_ elements: [Value], from key: String) -> EventLoopFuture { + public func srem(_ elements: [Value], from key: RedisKey) -> EventLoopFuture { guard elements.count > 0 else { return self.eventLoop.makeSucceededFuture(0) } var args: [RESPValue] = [.init(bulk: key)] @@ -118,7 +118,7 @@ extension RedisClient { /// - key: The key of the set to remove from. /// - Returns: The number of elements that were removed from the set. @inlinable - public func srem(_ elements: Value..., from key: String) -> EventLoopFuture { + public func srem(_ elements: Value..., from key: RedisKey) -> EventLoopFuture { return self.srem(elements, from: key) } @@ -130,7 +130,7 @@ extension RedisClient { /// - count: The max number of elements to pop from the set. /// - Returns: The element that was popped from the set. @inlinable - public func spop(from key: String, max count: Int = 1) -> EventLoopFuture<[RESPValue]> { + public func spop(from key: RedisKey, max count: Int = 1) -> EventLoopFuture<[RESPValue]> { assert(count >= 0, "A negative max count is nonsense.") guard count > 0 else { return self.eventLoop.makeSucceededFuture([]) } @@ -155,7 +155,7 @@ extension RedisClient { /// - count: The max number of elements to select from the set. /// - Returns: The elements randomly selected from the set. @inlinable - public func srandmember(from key: String, max count: Int = 1) -> EventLoopFuture<[RESPValue]> { + public func srandmember(from key: RedisKey, max count: Int = 1) -> EventLoopFuture<[RESPValue]> { guard count != 0 else { return self.eventLoop.makeSucceededFuture([]) } let args: [RESPValue] = [ @@ -177,8 +177,8 @@ extension RedisClient { @inlinable public func smove( _ element: Value, - from sourceKey: String, - to destKey: String + from sourceKey: RedisKey, + to destKey: RedisKey ) -> EventLoopFuture { guard sourceKey != destKey else { return self.eventLoop.makeSucceededFuture(true) } @@ -203,7 +203,7 @@ extension RedisClient { /// - Returns: A cursor position for additional invocations with a limited collection of elements found in the set. @inlinable public func sscan( - _ key: String, + _ key: RedisKey, startingFrom position: Int = 0, count: Int? = nil, matching match: String? = nil @@ -221,7 +221,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the difference of. /// - Returns: A list of elements resulting from the difference. @inlinable - public func sdiff(of keys: [String]) -> EventLoopFuture<[RESPValue]> { + public func sdiff(of keys: [RedisKey]) -> EventLoopFuture<[RESPValue]> { guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture([]) } let args = keys.map(RESPValue.init) @@ -235,7 +235,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the difference of. /// - Returns: A list of elements resulting from the difference. @inlinable - public func sdiff(of keys: String...) -> EventLoopFuture<[RESPValue]> { + public func sdiff(of keys: RedisKey...) -> EventLoopFuture<[RESPValue]> { return self.sdiff(of: keys) } @@ -248,7 +248,7 @@ extension RedisClient { /// - sources: The list of source sets to calculate the difference of. /// - Returns: The number of elements in the difference result. @inlinable - public func sdiffstore(as destination: String, sources keys: [String]) -> EventLoopFuture { + public func sdiffstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture { assert(keys.count > 0, "At least 1 key should be provided.") var args: [RESPValue] = [.init(bulk: destination)] @@ -268,7 +268,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the intersection of. /// - Returns: A list of elements resulting from the intersection. @inlinable - public func sinter(of keys: [String]) -> EventLoopFuture<[RESPValue]> { + public func sinter(of keys: [RedisKey]) -> EventLoopFuture<[RESPValue]> { guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture([]) } let args = keys.map(RESPValue.init) @@ -282,7 +282,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the intersection of. /// - Returns: A list of elements resulting from the intersection. @inlinable - public func sinter(of keys: String...) -> EventLoopFuture<[RESPValue]> { + public func sinter(of keys: RedisKey...) -> EventLoopFuture<[RESPValue]> { return self.sinter(of: keys) } @@ -295,7 +295,7 @@ extension RedisClient { /// - sources: A list of source sets to calculate the intersection of. /// - Returns: The number of elements in the intersection result. @inlinable - public func sinterstore(as destination: String, sources keys: [String]) -> EventLoopFuture { + public func sinterstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture { assert(keys.count > 0, "At least 1 key should be provided.") var args: [RESPValue] = [.init(bulk: destination)] @@ -315,7 +315,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the union of. /// - Returns: A list of elements resulting from the union. @inlinable - public func sunion(of keys: [String]) -> EventLoopFuture<[RESPValue]> { + public func sunion(of keys: [RedisKey]) -> EventLoopFuture<[RESPValue]> { guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture([]) } let args = keys.map(RESPValue.init) @@ -329,7 +329,7 @@ extension RedisClient { /// - Parameter keys: The source sets to calculate the union of. /// - Returns: A list of elements resulting from the union. @inlinable - public func sunion(of keys: String...) -> EventLoopFuture<[RESPValue]> { + public func sunion(of keys: RedisKey...) -> EventLoopFuture<[RESPValue]> { return self.sunion(of: keys) } @@ -342,7 +342,7 @@ extension RedisClient { /// - sources: A list of source sets to calculate the union of. /// - Returns: The number of elements in the union result. @inlinable - public func sunionstore(as destination: String, sources keys: [String]) -> EventLoopFuture { + public func sunionstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture { assert(keys.count > 0, "At least 1 key should be provided.") var args: [RESPValue] = [.init(bulk: destination)] diff --git a/Sources/RediStack/Commands/SortedSetCommands.swift b/Sources/RediStack/Commands/SortedSetCommands.swift index ab005e8..0dd73ad 100644 --- a/Sources/RediStack/Commands/SortedSetCommands.swift +++ b/Sources/RediStack/Commands/SortedSetCommands.swift @@ -73,7 +73,7 @@ extension RedisClient { @inlinable public func zadd( _ elements: [(element: Value, score: Double)], - to key: String, + to key: RedisKey, option: RedisSortedSetAddOption? = nil, returnChangedCount: Bool = false ) -> EventLoopFuture { @@ -110,7 +110,7 @@ extension RedisClient { @inlinable public func zadd( _ elements: (element: Value, score: Double)..., - to key: String, + to key: RedisKey, option: RedisSortedSetAddOption? = nil, returnChangedCount: Bool = false ) -> EventLoopFuture { @@ -132,7 +132,7 @@ extension RedisClient { @inlinable public func zadd( _ element: (element: Value, score: Double), - to key: String, + to key: RedisKey, option: RedisSortedSetAddOption? = nil, returnChangedCount: Bool = false ) -> EventLoopFuture { @@ -146,7 +146,7 @@ extension RedisClient { /// - Parameter key: The key of the sorted set. /// - Returns: The number of elements in the sorted set. @inlinable - public func zcard(of key: String) -> EventLoopFuture { + public func zcard(of key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "ZCARD", with: args) .convertFromRESPValue() @@ -160,7 +160,7 @@ extension RedisClient { /// - key: The key of the sorted set. /// - Returns: The score of the element provided, or `nil` if the element is not found in the set or the set does not exist. @inlinable - public func zscore(of element: Value, in key: String) -> EventLoopFuture { + public func zscore(of element: Value, in key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -180,7 +180,7 @@ extension RedisClient { /// - Returns: A cursor position for additional invocations with a limited collection of elements found in the sorted set with their scores. @inlinable public func zscan( - _ key: String, + _ key: RedisKey, startingFrom position: Int = 0, count: Int? = nil, matching match: String? = nil @@ -206,7 +206,7 @@ extension RedisClient { /// - key: The key of the sorted set to search. /// - Returns: The index of the element, or `nil` if the key was not found. @inlinable - public func zrank(of element: Value, in key: String) -> EventLoopFuture { + public func zrank(of element: Value, in key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -225,7 +225,7 @@ extension RedisClient { /// - key: The key of the sorted set to search. /// - Returns: The index of the element, or `nil` if the key was not found. @inlinable - public func zrevrank(of element: Value, in key: String) -> EventLoopFuture { + public func zrevrank(of element: Value, in key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), element.convertedToRESPValue() @@ -247,7 +247,7 @@ extension RedisClient { /// - Returns: The number of elements in the sorted set that fit within the score range. @inlinable public func zcount( - of key: String, + of key: RedisKey, within range: (min: String, max: String) ) -> EventLoopFuture { let args: [RESPValue] = [ @@ -269,7 +269,7 @@ extension RedisClient { /// - Returns: The number of elements in the sorted set that fit within the value range. @inlinable public func zlexcount( - of key: String, + of key: RedisKey, within range: (min: String, max: String) ) -> EventLoopFuture { let args: [RESPValue] = [ @@ -293,7 +293,7 @@ extension RedisClient { /// - count: The max number of elements to pop from the set. /// - Returns: A list of elements popped from the sorted set with their associated score. @inlinable - public func zpopmin(from key: String, max count: Int) -> EventLoopFuture<[(RESPValue, Double)]> { + public func zpopmin(from key: RedisKey, max count: Int) -> EventLoopFuture<[(RESPValue, Double)]> { return _zpop(command: "ZPOPMIN", count, key) } @@ -303,7 +303,7 @@ extension RedisClient { /// - Parameter key: The key identifying the sorted set in Redis. /// - Returns: The element and its associated score that was popped from the sorted set, or `nil` if set was empty. @inlinable - public func zpopmin(from key: String) -> EventLoopFuture<(RESPValue, Double)?> { + public func zpopmin(from key: RedisKey) -> EventLoopFuture<(RESPValue, Double)?> { return _zpop(command: "ZPOPMIN", nil, key) .map { return $0.count > 0 ? $0[0] : nil } } @@ -316,7 +316,7 @@ extension RedisClient { /// - count: The max number of elements to pop from the set. /// - Returns: A list of elements popped from the sorted set with their associated score. @inlinable - public func zpopmax(from key: String, max count: Int) -> EventLoopFuture<[(RESPValue, Double)]> { + public func zpopmax(from key: RedisKey, max count: Int) -> EventLoopFuture<[(RESPValue, Double)]> { return _zpop(command: "ZPOPMAX", count, key) } @@ -326,7 +326,7 @@ extension RedisClient { /// - Parameter key: The key identifying the sorted set in Redis. /// - Returns: The element and its associated score that was popped from the sorted set, or `nil` if set was empty. @inlinable - public func zpopmax(from key: String) -> EventLoopFuture<(RESPValue, Double)?> { + public func zpopmax(from key: RedisKey) -> EventLoopFuture<(RESPValue, Double)?> { return _zpop(command: "ZPOPMAX", nil, key) .map { return $0.count > 0 ? $0[0] : nil } } @@ -335,7 +335,7 @@ extension RedisClient { func _zpop( command: String, _ count: Int?, - _ key: String + _ key: RedisKey ) -> EventLoopFuture<[(RESPValue, Double)]> { var args: [RESPValue] = [.init(bulk: key)] @@ -373,7 +373,7 @@ extension RedisClient { /// or `nil` if the timeout was reached. @inlinable public func bzpopmin( - from key: String, + from key: RedisKey, timeout: Int = 0 ) -> EventLoopFuture<(Double, RESPValue)?> { return bzpopmin(from: [key], timeout: timeout) @@ -404,7 +404,7 @@ extension RedisClient { /// and its associated score is returned. @inlinable public func bzpopmin( - from keys: [String], + from keys: [RedisKey], timeout: Int = 0 ) -> EventLoopFuture<(String, Double, RESPValue)?> { return self._bzpop(command: "BZPOPMIN", keys, timeout) @@ -429,7 +429,7 @@ extension RedisClient { /// or `nil` if the timeout was reached. @inlinable public func bzpopmax( - from key: String, + from key: RedisKey, timeout: Int = 0 ) -> EventLoopFuture<(Double, RESPValue)?> { return self.bzpopmax(from: [key], timeout: timeout) @@ -460,7 +460,7 @@ extension RedisClient { /// and its associated score is returned. @inlinable public func bzpopmax( - from keys: [String], + from keys: [RedisKey], timeout: Int = 0 ) -> EventLoopFuture<(String, Double, RESPValue)?> { return self._bzpop(command: "BZPOPMAX", keys, timeout) @@ -469,7 +469,7 @@ extension RedisClient { @usableFromInline func _bzpop( command: String, - _ keys: [String], + _ keys: [RedisKey], _ timeout: Int ) -> EventLoopFuture<(String, Double, RESPValue)?> { var args = keys.map(RESPValue.init) @@ -511,7 +511,7 @@ extension RedisClient { public func zincrby( _ amount: Double, element: Value, - in key: String + in key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -552,8 +552,8 @@ extension RedisClient { /// - Returns: The number of elements in the new sorted set. @inlinable public func zunionstore( - as destination: String, - sources: [String], + as destination: RedisKey, + sources: [RedisKey], weights: [Int]? = nil, aggregateMethod aggregate: RedisSortedSetAggregateMethod? = nil ) -> EventLoopFuture { @@ -572,8 +572,8 @@ extension RedisClient { /// - Returns: The number of elements in the new sorted set. @inlinable public func zinterstore( - as destination: String, - sources: [String], + as destination: RedisKey, + sources: [RedisKey], weights: [Int]? = nil, aggregateMethod aggregate: RedisSortedSetAggregateMethod? = nil ) -> EventLoopFuture { @@ -583,8 +583,8 @@ extension RedisClient { @usableFromInline func _zopstore( command: String, - _ sources: [String], - _ destination: String, + _ sources: [RedisKey], + _ destination: RedisKey, _ weights: [Int]?, _ aggregate: RedisSortedSetAggregateMethod? ) -> EventLoopFuture { @@ -631,7 +631,7 @@ extension RedisClient { @inlinable public func zrange( within range: (start: Int, stop: Int), - from key: String, + from key: RedisKey, withScores: Bool = false ) -> EventLoopFuture<[RESPValue]> { return _zrange(command: "ZRANGE", key, range.start, range.stop, withScores) @@ -651,7 +651,7 @@ extension RedisClient { @inlinable public func zrevrange( within range: (start: Int, stop: Int), - from key: String, + from key: RedisKey, withScores: Bool = false ) -> EventLoopFuture<[RESPValue]> { return _zrange(command: "ZREVRANGE", key, range.start, range.stop, withScores) @@ -660,7 +660,7 @@ extension RedisClient { @usableFromInline func _zrange( command: String, - _ key: String, + _ key: RedisKey, _ start: Int, _ stop: Int, _ withScores: Bool @@ -696,7 +696,7 @@ extension RedisClient { @inlinable public func zrangebyscore( within range: (min: String, max: String), - from key: String, + from key: RedisKey, withScores: Bool = false, limitBy limit: (offset: Int, count: Int)? = nil ) -> EventLoopFuture<[RESPValue]> { @@ -718,7 +718,7 @@ extension RedisClient { @inlinable public func zrevrangebyscore( within range: (min: String, max: String), - from key: String, + from key: RedisKey, withScores: Bool = false, limitBy limit: (offset: Int, count: Int)? = nil ) -> EventLoopFuture<[RESPValue]> { @@ -728,7 +728,7 @@ extension RedisClient { @usableFromInline func _zrangebyscore( command: String, - _ key: String, + _ key: RedisKey, _ range: (min: String, max: String), _ withScores: Bool, _ limit: (offset: Int, count: Int)? @@ -769,7 +769,7 @@ extension RedisClient { @inlinable public func zrangebylex( within range: (min: String, max: String), - from key: String, + from key: RedisKey, limitBy limit: (offset: Int, count: Int)? = nil ) -> EventLoopFuture<[RESPValue]> { return _zrangebylex(command: "ZRANGEBYLEX", key, range, limit) @@ -790,7 +790,7 @@ extension RedisClient { @inlinable public func zrevrangebylex( within range: (min: String, max: String), - from key: String, + from key: RedisKey, limitBy limit: (offset: Int, count: Int)? = nil ) -> EventLoopFuture<[RESPValue]> { return _zrangebylex(command: "ZREVRANGEBYLEX", key, (range.max, range.min), limit) @@ -799,7 +799,7 @@ extension RedisClient { @usableFromInline func _zrangebylex( command: String, - _ key: String, + _ key: RedisKey, _ range: (min: String, max: String), _ limit: (offset: Int, count: Int)? ) -> EventLoopFuture<[RESPValue]> { @@ -832,7 +832,7 @@ extension RedisClient { /// - key: The key of the sorted set. /// - Returns: The number of elements removed from the set. @inlinable - public func zrem(_ elements: [Value], from key: String) -> EventLoopFuture { + public func zrem(_ elements: [Value], from key: RedisKey) -> EventLoopFuture { guard elements.count > 0 else { return self.eventLoop.makeSucceededFuture(0) } var args: [RESPValue] = [.init(bulk: key)] @@ -850,7 +850,7 @@ extension RedisClient { /// - key: The key of the sorted set. /// - Returns: The number of elements removed from the set. @inlinable - public func zrem(_ elements: Value..., from key: String) -> EventLoopFuture { + public func zrem(_ elements: Value..., from key: RedisKey) -> EventLoopFuture { return self.zrem(elements, from: key) } @@ -865,7 +865,7 @@ extension RedisClient { @inlinable public func zremrangebylex( within range: (min: String, max: String), - from key: String + from key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -886,7 +886,7 @@ extension RedisClient { @inlinable public func zremrangebyrank( within range: (start: Int, stop: Int), - from key: String + from key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), @@ -907,7 +907,7 @@ extension RedisClient { @inlinable public func zremrangebyscore( within range: (min: String, max: String), - from key: String + from key: RedisKey ) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), diff --git a/Sources/RediStack/Commands/StringCommands.swift b/Sources/RediStack/Commands/StringCommands.swift index 6a60e31..dc712c3 100644 --- a/Sources/RediStack/Commands/StringCommands.swift +++ b/Sources/RediStack/Commands/StringCommands.swift @@ -23,7 +23,7 @@ extension RedisClient { /// - Parameter key: The key to fetch the value from. /// - Returns: The string value stored at the key provided, otherwise `nil` if the key does not exist. @inlinable - public func get(_ key: String) -> EventLoopFuture { + public func get(_ key: RedisKey) -> EventLoopFuture { return self.get(key, as: String.self) } @@ -36,7 +36,7 @@ extension RedisClient { /// - Returns: The converted value stored at the key provided, otherwise `nil` if the key does not exist or fails the conversion. @inlinable public func get( - _ key: String, + _ key: RedisKey, as type: StoredType.Type ) -> EventLoopFuture { let args = [RESPValue(bulk: key)] @@ -50,7 +50,7 @@ extension RedisClient { /// - Parameter keys: The list of keys to fetch the values from. /// - Returns: The values stored at the keys provided, matching the same order. @inlinable - public func mget(_ keys: [String]) -> EventLoopFuture<[RESPValue]> { + public func mget(_ keys: [RedisKey]) -> EventLoopFuture<[RESPValue]> { guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture([]) } let args = keys.map(RESPValue.init) @@ -64,7 +64,7 @@ extension RedisClient { /// - Parameter keys: The list of keys to fetch the values from. /// - Returns: The values stored at the keys provided, matching the same order. @inlinable - public func mget(_ keys: String...) -> EventLoopFuture<[RESPValue]> { + public func mget(_ keys: RedisKey...) -> EventLoopFuture<[RESPValue]> { return self.mget(keys) } } @@ -81,7 +81,7 @@ extension RedisClient { /// - key: The key to use to uniquely identify this value. /// - Returns: The length of the key's value after appending the additional value. @inlinable - public func append(_ value: Value, to key: String) -> EventLoopFuture { + public func append(_ value: Value, to key: RedisKey) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), value.convertedToRESPValue() @@ -102,7 +102,7 @@ extension RedisClient { /// - value: The value to set the key to. /// - Returns: An `EventLoopFuture` that resolves if the operation was successful. @inlinable - public func set(_ key: String, to value: Value) -> EventLoopFuture { + public func set(_ key: RedisKey, to value: Value) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), value.convertedToRESPValue() @@ -118,7 +118,7 @@ extension RedisClient { /// - Parameter operations: The key-value list of SET operations to execute. /// - Returns: An `EventLoopFuture` that resolves if the operation was successful. @inlinable - public func mset(_ operations: [String: Value]) -> EventLoopFuture { + public func mset(_ operations: [RedisKey: Value]) -> EventLoopFuture { return _mset(command: "MSET", operations) .map { _ in () } } @@ -130,7 +130,7 @@ extension RedisClient { /// - Parameter operations: The key-value list of SET operations to execute. /// - Returns: `true` if the operation successfully completed. @inlinable - public func msetnx(_ operations: [String: Value]) -> EventLoopFuture { + public func msetnx(_ operations: [RedisKey: Value]) -> EventLoopFuture { return _mset(command: "MSETNX", operations) .convertFromRESPValue(to: Int.self) .map { return $0 == 1 } @@ -139,7 +139,7 @@ extension RedisClient { @usableFromInline func _mset( command: String, - _ operations: [String: Value] + _ operations: [RedisKey: Value] ) -> EventLoopFuture { assert(operations.count > 0, "At least 1 key-value pair should be provided.") @@ -164,7 +164,7 @@ extension RedisClient { /// - Parameter key: The key whose value should be incremented. /// - Returns: The new value after the operation. @inlinable - public func increment(_ key: String) -> EventLoopFuture { + public func increment(_ key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "INCR", with: args) .convertFromRESPValue() @@ -178,7 +178,7 @@ extension RedisClient { /// - count: The amount that this value should be incremented, supporting both positive and negative values. /// - Returns: The new value after the operation. @inlinable - public func increment(_ key: String, by count: Int) -> EventLoopFuture { + public func increment(_ key: RedisKey, by count: Int) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: count) @@ -195,7 +195,7 @@ extension RedisClient { /// - count: The amount that this value should be incremented, supporting both positive and negative values. /// - Returns: The new value after the operation. @inlinable - public func increment(_ key: String, by count: Value) -> EventLoopFuture + public func increment(_ key: RedisKey, by count: Value) -> EventLoopFuture where Value: BinaryFloatingPoint, Value: RESPValueConvertible @@ -218,7 +218,7 @@ extension RedisClient { /// - Parameter key: The key whose value should be decremented. /// - Returns: The new value after the operation. @inlinable - public func decrement(_ key: String) -> EventLoopFuture { + public func decrement(_ key: RedisKey) -> EventLoopFuture { let args = [RESPValue(bulk: key)] return send(command: "DECR", with: args) .convertFromRESPValue() @@ -231,7 +231,7 @@ extension RedisClient { /// - key: The key whose value should be decremented. /// - count: The amount that this value should be decremented, supporting both positive and negative values. /// - Returns: The new value after the operation. - public func decrement(_ key: String, by count: Int) -> EventLoopFuture { + public func decrement(_ key: RedisKey, by count: Int) -> EventLoopFuture { let args: [RESPValue] = [ .init(bulk: key), .init(bulk: count) diff --git a/Sources/RediStack/RESP/RESPValue.swift b/Sources/RediStack/RESP/RESPValue.swift index 9edaa64..ee580d5 100644 --- a/Sources/RediStack/RESP/RESPValue.swift +++ b/Sources/RediStack/RESP/RESPValue.swift @@ -150,3 +150,15 @@ extension RESPValue: Equatable { } } } + +// MARK: RESPValueConvertible + +extension RESPValue: RESPValueConvertible { + public init?(fromRESP value: RESPValue) { + self = value + } + + public func convertedToRESPValue() -> RESPValue { + return self + } +} diff --git a/Sources/RediStack/RESP/RESPValueConvertible.swift b/Sources/RediStack/RESP/RESPValueConvertible.swift index 9a843af..31188c2 100644 --- a/Sources/RediStack/RESP/RESPValueConvertible.swift +++ b/Sources/RediStack/RESP/RESPValueConvertible.swift @@ -29,33 +29,6 @@ public protocol RESPValueConvertible { func convertedToRESPValue() -> RESPValue } -extension RESPValue: RESPValueConvertible { - /// See `RESPValueConvertible.init(fromRESP:)` - public init?(fromRESP value: RESPValue) { - self = value - } - - /// See `RESPValueConvertible.convertedToRESPValue()` - public func convertedToRESPValue() -> RESPValue { - return self - } -} - -extension RedisError: RESPValueConvertible { - /// Unwraps an `.error` representation directly into a `RedisError` instance. - /// - /// See `RESPValueConvertible.init(fromRESP:)` - public init?(fromRESP value: RESPValue) { - guard case let .error(e) = value else { return nil } - self = e - } - - /// See `RESPValueConvertible.convertedToRESPValue()` - public func convertedToRESPValue() -> RESPValue { - return .error(self) - } -} - extension String: RESPValueConvertible { /// Attempts to provide a UTF-8 representation of the `RESPValue` provided. /// @@ -80,7 +53,6 @@ extension String: RESPValueConvertible { } } - /// See `RESPValueConvertible.convertedToRESPValue()` public func convertedToRESPValue() -> RESPValue { return .init(bulk: self) } @@ -104,7 +76,6 @@ extension FixedWidthInteger { } } - /// See `RESPValueConvertible.convertedToRESPValue()` public func convertedToRESPValue() -> RESPValue { return .init(bulk: self.description) } @@ -135,7 +106,6 @@ extension Double: RESPValueConvertible { self = double } - /// See `RESPValueConvertible.convertedToRESPValue()` public func convertedToRESPValue() -> RESPValue { return .init(bulk: self.description) } @@ -155,7 +125,6 @@ extension Float: RESPValueConvertible { self = float } - /// See `RESPValueConvertible.convertedToRESPValue()` public func convertedToRESPValue() -> RESPValue { return .init(bulk: self.description) } @@ -224,7 +193,6 @@ extension Optional: RESPValueConvertible where Wrapped: RESPValueConvertible { import struct Foundation.Data extension Data: RESPValueConvertible { - /// See `RESPValueConvertible.init(fromRESP:)` public init?(fromRESP value: RESPValue) { switch value { case let .simpleString(buffer), @@ -236,7 +204,6 @@ extension Data: RESPValueConvertible { } } - /// See `RESPValueConvertible.convertedToRESPValue()` public func convertedToRESPValue() -> RESPValue { var buffer = RESPValue.allocator.buffer(capacity: self.count) buffer.writeBytes(self) diff --git a/Sources/RediStack/RedisErrors.swift b/Sources/RediStack/RedisErrors.swift index 42acd17..f879d89 100644 --- a/Sources/RediStack/RedisErrors.swift +++ b/Sources/RediStack/RedisErrors.swift @@ -50,3 +50,19 @@ public struct RedisError: LocalizedError, Equatable { return lhs.message == rhs.message } } + +// MARK: RESPValueConvertible + +extension RedisError: RESPValueConvertible { + /// Unwraps an `.error` representation directly into a `RedisError` instance. + /// + /// See `RESPValueConvertible.init(fromRESP:)` + public init?(fromRESP value: RESPValue) { + guard case let .error(e) = value else { return nil } + self = e + } + + public func convertedToRESPValue() -> RESPValue { + return .error(self) + } +} diff --git a/Sources/RediStack/RedisKey.swift b/Sources/RediStack/RedisKey.swift new file mode 100644 index 0000000..2516715 --- /dev/null +++ b/Sources/RediStack/RedisKey.swift @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the RediStack open source project +// +// Copyright (c) 2019 RediStack project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of RediStack project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +/// A representation of a key in Redis. +/// +/// `RedisKey` is a thin wrapper around `String`, to provide stronger type-safety at compile-time. +/// +/// It conforms to `ExpressibleByStringLiteral`, so creating a key is simple: +/// ```swift +/// let key: RedisKey = "foo" +/// ``` +public struct RedisKey: RawRepresentable { + public typealias RawValue = String + + public let rawValue: String + + /// Initializes a type-safe representation of a key to a value in a Redis instance. + /// - Parameter key: The key of a value in a Redis instance. + public init(_ key: String) { + self.rawValue = key + } + + public init?(rawValue: String) { + self.rawValue = rawValue + } +} + +// MARK: ExpressibleByStringLiteral + +extension RedisKey: ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + self.rawValue = value + } +} + +// MARK: CustomStringConvertible + +extension RedisKey: CustomStringConvertible { + public var description: String { return self.rawValue } +} + +// MARK: CustomDebugStringConvertible + +extension RedisKey: CustomDebugStringConvertible { + public var debugDescription: String { return "RedisKey: \(self.rawValue)" } +} + +// MARK: Comparable && Equatable + +extension RedisKey: Comparable { + public static func <(lhs: RedisKey, rhs: RedisKey) -> Bool { + return lhs.rawValue < rhs.rawValue + } + + public static func ==(lhs: RedisKey, rhs: RedisKey) -> Bool { + return lhs.rawValue == rhs.rawValue + } +} + +// MARK: Hashable + +extension RedisKey: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(self.rawValue) + } +} + +// MARK: Codable + +extension RedisKey: Codable { + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + self.rawValue = try container.decode(String.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.rawValue) + } +} + +// MARK: RESPValue + +extension RESPValue { + /// Initializes a `bulkString` value from the `RedisKey`. + /// - Prameter key: The RedisKey to store in a `.bulkString` representation. + public init(bulk key: RedisKey) { + self = .init(bulk: key.rawValue) + } +} + +// MARK: RESPValueConvertible + +extension RedisKey: RESPValueConvertible { + public init?(fromRESP value: RESPValue) { + guard let string = value.string else { return nil } + self.rawValue = string + } + + public func convertedToRESPValue() -> RESPValue { + return .init(bulk: self.rawValue) + } +} diff --git a/Tests/RediStackIntegrationTests/Commands/BasicCommandsTests.swift b/Tests/RediStackIntegrationTests/Commands/BasicCommandsTests.swift index 2af1984..f799120 100644 --- a/Tests/RediStackIntegrationTests/Commands/BasicCommandsTests.swift +++ b/Tests/RediStackIntegrationTests/Commands/BasicCommandsTests.swift @@ -22,7 +22,7 @@ final class BasicCommandsTests: RediStackIntegrationTestCase { } func test_delete() throws { - let keys = [ #function + "1", #function + "2", #function + "3" ] + let keys = [ #function + "1", #function + "2", #function + "3" ].map(RedisKey.init(_:)) try connection.set(keys[0], to: "value").wait() try connection.set(keys[1], to: "value").wait() try connection.set(keys[2], to: "value").wait() @@ -87,9 +87,9 @@ final class BasicCommandsTests: RediStackIntegrationTestCase { } func test_scan() throws { - var dataset: [String] = .init(repeating: "", count: 10) + var dataset: [RedisKey] = .init(repeating: "", count: 10) for index in 1...15 { - let key = "key\(index)\(index % 2 == 0 ? "_even" : "_odd")" + let key = RedisKey("key\(index)\(index % 2 == 0 ? "_even" : "_odd")") dataset.append(key) _ = try connection.set(key, to: "\(index)").wait() } diff --git a/Tests/RediStackIntegrationTests/Commands/SetCommandsTests.swift b/Tests/RediStackIntegrationTests/Commands/SetCommandsTests.swift index 0064784..f843317 100644 --- a/Tests/RediStackIntegrationTests/Commands/SetCommandsTests.swift +++ b/Tests/RediStackIntegrationTests/Commands/SetCommandsTests.swift @@ -88,9 +88,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sdiff() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([3, 4, 5], to: key2).wait() @@ -110,9 +110,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sdiffstore() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([3, 4, 5], to: key2).wait() @@ -125,9 +125,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sinter() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([3, 4, 5], to: key2).wait() @@ -147,9 +147,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sinterstore() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([3, 4, 5], to: key2).wait() @@ -178,9 +178,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sunion() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([3, 4, 5], to: key2).wait() @@ -197,9 +197,9 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sunionstore() throws { - let key1 = #function - let key2 = #file - let key3 = key1 + key2 + let key1: RedisKey = #function + let key2: RedisKey = #file + let key3 = RedisKey(key1.rawValue + key2.rawValue) _ = try connection.sadd([1, 2, 3], to: key1).wait() _ = try connection.sadd([2, 3, 4], to: key2).wait() @@ -214,7 +214,7 @@ final class SetCommandsTests: RediStackIntegrationTestCase { } func test_sscan() throws { - let key = #function + let key: RedisKey = #function let dataset = [ "Copenhagen, Denmark", "Roskilde, Denmark", diff --git a/Tests/RediStackIntegrationTests/Commands/SortedSetCommandsTests.swift b/Tests/RediStackIntegrationTests/Commands/SortedSetCommandsTests.swift index 3483080..8008dde 100644 --- a/Tests/RediStackIntegrationTests/Commands/SortedSetCommandsTests.swift +++ b/Tests/RediStackIntegrationTests/Commands/SortedSetCommandsTests.swift @@ -18,9 +18,9 @@ import RediStackTestUtils import XCTest final class SortedSetCommandsTests: RediStackIntegrationTestCase { - private static let testKey = "SortedSetCommandsTests" + private static let testKey: RedisKey = "SortedSetCommandsTests" - private var key: String { return SortedSetCommandsTests.testKey } + private var key: RedisKey { return SortedSetCommandsTests.testKey } override func setUp() { super.setUp() @@ -158,7 +158,7 @@ final class SortedSetCommandsTests: RediStackIntegrationTestCase { let min1 = try connection.bzpopmin(from: key).wait() XCTAssertEqual(min1?.0, 1) let min2 = try connection.bzpopmin(from: [#function, key]).wait() - XCTAssertEqual(min2?.0, key) + XCTAssertEqual(min2?.0, key.rawValue) XCTAssertEqual(min2?.1, 2) let blockingConnection = try self.makeNewConnection() @@ -192,7 +192,7 @@ final class SortedSetCommandsTests: RediStackIntegrationTestCase { let max1 = try connection.bzpopmax(from: key).wait() XCTAssertEqual(max1?.0, 10) let max2 = try connection.bzpopmax(from: [#function, key]).wait() - XCTAssertEqual(max2?.0, key) + XCTAssertEqual(max2?.0, key.rawValue) XCTAssertEqual(max2?.1, 9) let blockingConnection = try self.makeNewConnection() @@ -219,19 +219,21 @@ final class SortedSetCommandsTests: RediStackIntegrationTestCase { } func test_zunionstore() throws { + let testKey = RedisKey(#function + #file) + _ = try connection.zadd([(1, 1), (2, 2)], to: #function).wait() _ = try connection.zadd([(3, 3), (4, 4)], to: #file).wait() let unionCount = try connection.zunionstore( - as: #function+#file, + as: testKey, sources: [key, #function, #file], weights: [3, 2, 1], aggregateMethod: .max ).wait() XCTAssertEqual(unionCount, 10) - let rank = try connection.zrank(of: 10, in: #function+#file).wait() + let rank = try connection.zrank(of: 10, in: testKey).wait() XCTAssertEqual(rank, 9) - let score = try connection.zscore(of: 10, in: #function+#file).wait() + let score = try connection.zscore(of: 10, in: testKey).wait() XCTAssertEqual(score, 30) } diff --git a/Tests/RediStackIntegrationTests/Commands/StringCommandsTests.swift b/Tests/RediStackIntegrationTests/Commands/StringCommandsTests.swift index 5805e05..efaa9de 100644 --- a/Tests/RediStackIntegrationTests/Commands/StringCommandsTests.swift +++ b/Tests/RediStackIntegrationTests/Commands/StringCommandsTests.swift @@ -30,7 +30,7 @@ final class StringCommandsTests: RediStackIntegrationTestCase { } func test_mget() throws { - let keys = ["one", "two"] + let keys = ["one", "two"].map(RedisKey.init(_:)) try keys.forEach { _ = try connection.set($0, to: $0).wait() } let values = try connection.mget(keys + ["empty"]).wait() @@ -58,7 +58,7 @@ final class StringCommandsTests: RediStackIntegrationTestCase { } func test_mset() throws { - let data = [ + let data: [RedisKey: Int] = [ "first": 1, "second": 2 ] @@ -74,7 +74,7 @@ final class StringCommandsTests: RediStackIntegrationTestCase { } func test_msetnx() throws { - let data = [ + let data: [RedisKey: Int] = [ "first": 1, "second": 2 ]