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.
parent 5d6c3d3f
Pipeline #105874583 passed with stage
in 3 minutes and 25 seconds
......@@ -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?
......
......@@ -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),
......
......@@ -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])
}
}
}
......@@ -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 {