Add type-safe representation of Redis keys

Motivation:

Inspired by Swift by Sundell's article on type-safe identifers, the goal of this commit is to have the compiler
assist in preventing incorrect Redis key values from being used in API calls.

See https://www.swiftbysundell.com/articles/type-safe-identifiers-in-swift/ for the inspiration.

Modifications:

- Add new `RedisKey` struct that wraps around a single `String` value that conforms to several expected protocols
  (Hashable, Comparable, Codable, etc.)
- Change all command APIs to require `RedisKey` rather than plain strings

Result:

When encountering an API requiring a RedisKey, it should be much more apparant at the use site what form a value should take.
This commit is contained in:
Nathan Harris
2019-12-27 21:38:35 -08:00
parent 5d6c3d3f28
commit ea6f427993
14 changed files with 303 additions and 192 deletions
@@ -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<Int> {
public func delete(_ keys: [RedisKey]) -> EventLoopFuture<Int> {
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<Int> {
public func delete(_ keys: RedisKey...) -> EventLoopFuture<Int> {
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<Bool> {
public func expire(_ key: RedisKey, after timeout: TimeAmount) -> EventLoopFuture<Bool> {
let amount = timeout.nanoseconds / 1_000_000_000
let args: [RESPValue] = [
.init(bulk: key),
@@ -153,7 +153,7 @@ extension RedisClient {
internal func _scan<T>(
command: String,
resultType: T.Type = T.self,
_ key: String?,
_ key: RedisKey?,
_ pos: Int,
_ count: Int?,
_ match: String?
+18 -18
View File
@@ -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<Int> {
public func hdel(_ fields: [String], from key: RedisKey) -> EventLoopFuture<Int> {
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<Int> {
public func hdel(_ fields: String..., from key: RedisKey) -> EventLoopFuture<Int> {
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<Bool> {
public func hexists(_ field: String, in key: RedisKey) -> EventLoopFuture<Bool> {
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<Int> {
public func hlen(of key: RedisKey) -> EventLoopFuture<Int> {
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<Int> {
public func hstrlen(of field: String, in key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(
_ field: String,
to value: Value,
in key: String
in key: RedisKey
) -> EventLoopFuture<Bool> {
let args: [RESPValue] = [
.init(bulk: key),
@@ -204,7 +204,7 @@ extension RedisClient {
public func hsetnx<Value: RESPValueConvertible>(
_ field: String,
to value: Value,
in key: String
in key: RedisKey
) -> EventLoopFuture<Bool> {
let args: [RESPValue] = [
.init(bulk: key),
@@ -226,7 +226,7 @@ extension RedisClient {
@inlinable
public func hmset<Value: RESPValueConvertible>(
_ fields: [String: Value],
in key: String
in key: RedisKey
) -> EventLoopFuture<Void> {
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<String?> {
public func hget(_ field: String, from key: RedisKey) -> EventLoopFuture<String?> {
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<Int> {
public func hincrby(_ amount: Int, field: String, in key: RedisKey) -> EventLoopFuture<Int> {
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<Value>(_ amount: Value, field: String, in key: String) -> EventLoopFuture<Value>
public func hincrbyfloat<Value>(_ amount: Value, field: String, in key: RedisKey) -> EventLoopFuture<Value>
where
Value: BinaryFloatingPoint,
Value: RESPValueConvertible
@@ -344,7 +344,7 @@ extension RedisClient {
command: String,
_ amount: Value,
_ field: String,
_ key: String
_ key: RedisKey
) -> EventLoopFuture<Value> {
let args: [RESPValue] = [
.init(bulk: key),
+29 -29
View File
@@ -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<Int> {
public func llen(of key: RedisKey) -> EventLoopFuture<Int> {
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<RESPValue> {
public func lindex(_ index: Int, from key: RedisKey) -> EventLoopFuture<RESPValue> {
let args: [RESPValue] = [
.init(bulk: key),
.init(bulk: index)
@@ -57,7 +57,7 @@ extension RedisClient {
public func lset<Value: RESPValueConvertible>(
index: Int,
to value: Value,
in key: String
in key: RedisKey
) -> EventLoopFuture<Void> {
let args: [RESPValue] = [
.init(bulk: key),
@@ -79,7 +79,7 @@ extension RedisClient {
@inlinable
public func lrem<Value: RESPValueConvertible>(
_ value: Value,
from key: String,
from key: RedisKey,
count: Int = 0
) -> EventLoopFuture<Int> {
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<Void> {
public func ltrim(_ key: RedisKey, before start: Int, after stop: Int) -> EventLoopFuture<Void> {
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<RESPValue> {
public func rpoplpush(from source: RedisKey, to dest: RedisKey) -> EventLoopFuture<RESPValue> {
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<RESPValue?> {
let args: [RESPValue] = [
@@ -194,7 +194,7 @@ extension RedisClient {
@inlinable
public func linsert<Value: RESPValueConvertible>(
_ element: Value,
into key: String,
into key: RedisKey,
before pivot: Value
) -> EventLoopFuture<Int> {
return _linsert(pivotKeyword: "BEFORE", element, key, pivot)
@@ -211,7 +211,7 @@ extension RedisClient {
@inlinable
public func linsert<Value: RESPValueConvertible>(
_ element: Value,
into key: String,
into key: RedisKey,
after pivot: Value
) -> EventLoopFuture<Int> {
return _linsert(pivotKeyword: "AFTER", element, key, pivot)
@@ -221,7 +221,7 @@ extension RedisClient {
func _linsert<Value: RESPValueConvertible>(
pivotKeyword: String,
_ element: Value,
_ key: String,
_ key: RedisKey,
_ pivot: Value
) -> EventLoopFuture<Int> {
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<RESPValue> {
public func lpop(from key: RedisKey) -> EventLoopFuture<RESPValue> {
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<Value: RESPValueConvertible>(_ elements: [Value], into key: String) -> EventLoopFuture<Int> {
public func lpush<Value: RESPValueConvertible>(_ elements: [Value], into key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: Value..., into key: String) -> EventLoopFuture<Int> {
public func lpush<Value: RESPValueConvertible>(_ elements: Value..., into key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ element: Value, into key: String) -> EventLoopFuture<Int> {
public func lpushx<Value: RESPValueConvertible>(_ element: Value, into key: RedisKey) -> EventLoopFuture<Int> {
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<RESPValue> {
public func rpop(from key: RedisKey) -> EventLoopFuture<RESPValue> {
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<Value: RESPValueConvertible>(_ elements: [Value], into key: String) -> EventLoopFuture<Int> {
public func rpush<Value: RESPValueConvertible>(_ elements: [Value], into key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: Value..., into key: String) -> EventLoopFuture<Int> {
public func rpush<Value: RESPValueConvertible>(_ elements: Value..., into key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ element: Value, into key: String) -> EventLoopFuture<Int> {
public func rpushx<Value: RESPValueConvertible>(_ element: Value, into key: RedisKey) -> EventLoopFuture<Int> {
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<RESPValue?> {
public func blpop(from key: RedisKey, timeout: Int = 0) -> EventLoopFuture<RESPValue?> {
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<RESPValue?> {
public func brpop(from key: RedisKey, timeout: Int = 0) -> EventLoopFuture<RESPValue?> {
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])
}
}
}
+21 -21
View File
@@ -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<Value: RESPValueConvertible>(_ element: Value, of key: String) -> EventLoopFuture<Bool> {
public func sismember<Value: RESPValueConvertible>(_ element: Value, of key: RedisKey) -> EventLoopFuture<Bool> {
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<Int> {
public func scard(of key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: [Value], to key: String) -> EventLoopFuture<Int> {
public func sadd<Value: RESPValueConvertible>(_ elements: [Value], to key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: Value..., to key: String) -> EventLoopFuture<Int> {
public func sadd<Value: RESPValueConvertible>(_ elements: Value..., to key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: [Value], from key: String) -> EventLoopFuture<Int> {
public func srem<Value: RESPValueConvertible>(_ elements: [Value], from key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: Value..., from key: String) -> EventLoopFuture<Int> {
public func srem<Value: RESPValueConvertible>(_ elements: Value..., from key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(
_ element: Value,
from sourceKey: String,
to destKey: String
from sourceKey: RedisKey,
to destKey: RedisKey
) -> EventLoopFuture<Bool> {
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<Int> {
public func sdiffstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture<Int> {
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<Int> {
public func sinterstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture<Int> {
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<Int> {
public func sunionstore(as destination: RedisKey, sources keys: [RedisKey]) -> EventLoopFuture<Int> {
assert(keys.count > 0, "At least 1 key should be provided.")
var args: [RESPValue] = [.init(bulk: destination)]
@@ -73,7 +73,7 @@ extension RedisClient {
@inlinable
public func zadd<Value: RESPValueConvertible>(
_ elements: [(element: Value, score: Double)],
to key: String,
to key: RedisKey,
option: RedisSortedSetAddOption? = nil,
returnChangedCount: Bool = false
) -> EventLoopFuture<Int> {
@@ -110,7 +110,7 @@ extension RedisClient {
@inlinable
public func zadd<Value: RESPValueConvertible>(
_ elements: (element: Value, score: Double)...,
to key: String,
to key: RedisKey,
option: RedisSortedSetAddOption? = nil,
returnChangedCount: Bool = false
) -> EventLoopFuture<Int> {
@@ -132,7 +132,7 @@ extension RedisClient {
@inlinable
public func zadd<Value: RESPValueConvertible>(
_ element: (element: Value, score: Double),
to key: String,
to key: RedisKey,
option: RedisSortedSetAddOption? = nil,
returnChangedCount: Bool = false
) -> EventLoopFuture<Bool> {
@@ -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<Int> {
public func zcard(of key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(of element: Value, in key: String) -> EventLoopFuture<Double?> {
public func zscore<Value: RESPValueConvertible>(of element: Value, in key: RedisKey) -> EventLoopFuture<Double?> {
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<Value: RESPValueConvertible>(of element: Value, in key: String) -> EventLoopFuture<Int?> {
public func zrank<Value: RESPValueConvertible>(of element: Value, in key: RedisKey) -> EventLoopFuture<Int?> {
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<Value: RESPValueConvertible>(of element: Value, in key: String) -> EventLoopFuture<Int?> {
public func zrevrank<Value: RESPValueConvertible>(of element: Value, in key: RedisKey) -> EventLoopFuture<Int?> {
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<Int> {
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<Int> {
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<Value: RESPValueConvertible>(
_ amount: Double,
element: Value,
in key: String
in key: RedisKey
) -> EventLoopFuture<Double> {
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<Int> {
@@ -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<Int> {
@@ -583,8 +583,8 @@ extension RedisClient {
@usableFromInline
func _zopstore(
command: String,
_ sources: [String],
_ destination: String,
_ sources: [RedisKey],
_ destination: RedisKey,
_ weights: [Int]?,
_ aggregate: RedisSortedSetAggregateMethod?
) -> EventLoopFuture<Int> {
@@ -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<Value: RESPValueConvertible>(_ elements: [Value], from key: String) -> EventLoopFuture<Int> {
public func zrem<Value: RESPValueConvertible>(_ elements: [Value], from key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ elements: Value..., from key: String) -> EventLoopFuture<Int> {
public func zrem<Value: RESPValueConvertible>(_ elements: Value..., from key: RedisKey) -> EventLoopFuture<Int> {
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<Int> {
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<Int> {
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<Int> {
let args: [RESPValue] = [
.init(bulk: key),
+14 -14
View File
@@ -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<String?> {
public func get(_ key: RedisKey) -> EventLoopFuture<String?> {
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<StoredType: RESPValueConvertible>(
_ key: String,
_ key: RedisKey,
as type: StoredType.Type
) -> EventLoopFuture<StoredType?> {
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: RESPValueConvertible>(_ value: Value, to key: String) -> EventLoopFuture<Int> {
public func append<Value: RESPValueConvertible>(_ value: Value, to key: RedisKey) -> EventLoopFuture<Int> {
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<Value: RESPValueConvertible>(_ key: String, to value: Value) -> EventLoopFuture<Void> {
public func set<Value: RESPValueConvertible>(_ key: RedisKey, to value: Value) -> EventLoopFuture<Void> {
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<Value: RESPValueConvertible>(_ operations: [String: Value]) -> EventLoopFuture<Void> {
public func mset<Value: RESPValueConvertible>(_ operations: [RedisKey: Value]) -> EventLoopFuture<Void> {
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<Value: RESPValueConvertible>(_ operations: [String: Value]) -> EventLoopFuture<Bool> {
public func msetnx<Value: RESPValueConvertible>(_ operations: [RedisKey: Value]) -> EventLoopFuture<Bool> {
return _mset(command: "MSETNX", operations)
.convertFromRESPValue(to: Int.self)
.map { return $0 == 1 }
@@ -139,7 +139,7 @@ extension RedisClient {
@usableFromInline
func _mset<Value: RESPValueConvertible>(
command: String,
_ operations: [String: Value]
_ operations: [RedisKey: Value]
) -> EventLoopFuture<RESPValue> {
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<Int> {
public func increment(_ key: RedisKey) -> EventLoopFuture<Int> {
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<Int> {
public func increment(_ key: RedisKey, by count: Int) -> EventLoopFuture<Int> {
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<Value>(_ key: String, by count: Value) -> EventLoopFuture<Value>
public func increment<Value>(_ key: RedisKey, by count: Value) -> EventLoopFuture<Value>
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<Int> {
public func decrement(_ key: RedisKey) -> EventLoopFuture<Int> {
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<Int> {
public func decrement(_ key: RedisKey, by count: Int) -> EventLoopFuture<Int> {
let args: [RESPValue] = [
.init(bulk: key),
.init(bulk: count)
+12
View File
@@ -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
}
}
@@ -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)
+16
View File
@@ -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)
}
}
+114
View File
@@ -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)
}
}
@@ -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()
}
@@ -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",
@@ -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)
}
@@ -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
]