Skip to content

Commit 392be14

Browse files
committed
Merge branch '59-respconvertible-generics' into '47-proposal-feedback'
59 -- Use `RESPValueConvertible` as Generic Constraint See merge request Mordil/swift-redis-nio-client!69
2 parents e964ba0 + fa227b0 commit 392be14

File tree

11 files changed

+519
-180
lines changed

11 files changed

+519
-180
lines changed

Sources/RedisNIO/Commands/BasicCommands.swift

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ extension RedisClient {
2222
/// - Returns: The message sent with the command.
2323
@inlinable
2424
public func echo(_ message: String) -> EventLoopFuture<String> {
25-
return send(command: "ECHO", with: [message])
25+
let args = [RESPValue(bulk: message)]
26+
return send(command: "ECHO", with: args)
2627
.convertFromRESPValue()
2728
}
2829

@@ -33,8 +34,10 @@ extension RedisClient {
3334
/// - Returns: The provided message or Redis' default response of `"PONG"`.
3435
@inlinable
3536
public func ping(with message: String? = nil) -> EventLoopFuture<String> {
36-
let arg = message != nil ? [message] : []
37-
return send(command: "PING", with: arg)
37+
let args: [RESPValue] = message != nil
38+
? [.init(bulk: message!)] // safe because we did a nil pre-check
39+
: []
40+
return send(command: "PING", with: args)
3841
.convertFromRESPValue()
3942
}
4043

@@ -46,7 +49,8 @@ extension RedisClient {
4649
/// - Returns: An `EventLoopFuture` that resolves when the operation has succeeded, or fails with a `RedisError`.
4750
@inlinable
4851
public func select(database index: Int) -> EventLoopFuture<Void> {
49-
return send(command: "SELECT", with: [index])
52+
let args = [RESPValue(bulk: index)]
53+
return send(command: "SELECT", with: args)
5054
.map { _ in return () }
5155
}
5256

@@ -59,8 +63,11 @@ extension RedisClient {
5963
/// - Returns: `true` if the swap was successful.
6064
@inlinable
6165
public func swapDatabase(_ first: Int, with second: Int) -> EventLoopFuture<Bool> {
62-
/// connection.swapDatabase(index: 0, withIndex: 10)
63-
return send(command: "SWAPDB", with: [first, second])
66+
let args: [RESPValue] = [
67+
.init(bulk: first),
68+
.init(bulk: second)
69+
]
70+
return send(command: "SWAPDB", with: args)
6471
.convertFromRESPValue(to: String.self)
6572
.map { return $0 == "OK" }
6673
}
@@ -74,7 +81,8 @@ extension RedisClient {
7481
public func delete(_ keys: [String]) -> EventLoopFuture<Int> {
7582
guard keys.count > 0 else { return self.eventLoop.makeSucceededFuture(0) }
7683

77-
return send(command: "DEL", with: keys)
84+
let args = keys.map(RESPValue.init)
85+
return send(command: "DEL", with: args)
7886
.convertFromRESPValue()
7987
}
8088

@@ -89,7 +97,11 @@ extension RedisClient {
8997
@inlinable
9098
public func expire(_ key: String, after timeout: TimeAmount) -> EventLoopFuture<Bool> {
9199
let amount = timeout.nanoseconds / 1_000_000_000
92-
return send(command: "EXPIRE", with: [key, amount])
100+
let args: [RESPValue] = [
101+
.init(bulk: key),
102+
.init(bulk: amount.description)
103+
]
104+
return send(command: "EXPIRE", with: args)
93105
.convertFromRESPValue(to: Int.self)
94106
.map { return $0 == 1 }
95107
}
@@ -116,7 +128,7 @@ extension RedisClient {
116128
}
117129

118130
@usableFromInline
119-
func _scan<T>(
131+
internal func _scan<T>(
120132
command: String,
121133
resultType: T.Type = T.self,
122134
_ key: String?,
@@ -127,19 +139,19 @@ extension RedisClient {
127139
where
128140
T: RESPValueConvertible
129141
{
130-
var args: [RESPValueConvertible] = [pos]
142+
var args: [RESPValue] = [.init(bulk: pos)]
131143

132144
if let k = key {
133-
args.insert(k, at: 0)
145+
args.insert(.init(bulk: k), at: 0)
134146
}
135147

136148
if let m = match {
137-
args.append("match")
138-
args.append(m)
149+
args.append(.init(bulk: "match"))
150+
args.append(.init(bulk: m))
139151
}
140152
if let c = count {
141-
args.append("count")
142-
args.append(c)
153+
args.append(.init(bulk: "count"))
154+
args.append(.init(bulk: c))
143155
}
144156

145157
let response = send(command: command, with: args).convertFromRESPValue(to: [RESPValue].self)

Sources/RedisNIO/Commands/HashCommands.swift

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import NIO
1818

1919
extension RedisClient {
2020
@usableFromInline
21-
static func _mapHashResponse(_ values: [String]) -> [String: String] {
21+
internal static func _mapHashResponse(_ values: [String]) -> [String: String] {
2222
guard values.count > 0 else { return [:] }
2323

2424
var result: [String: String] = [:]
@@ -48,8 +48,11 @@ extension RedisClient {
4848
@inlinable
4949
public func hdel(_ fields: [String], from key: String) -> EventLoopFuture<Int> {
5050
guard fields.count > 0 else { return self.eventLoop.makeSucceededFuture(0) }
51+
52+
var args: [RESPValue] = [.init(bulk: key)]
53+
args.append(convertingContentsOf: fields)
5154

52-
return send(command: "HDEL", with: [key] + fields)
55+
return send(command: "HDEL", with: args)
5356
.convertFromRESPValue()
5457
}
5558

@@ -62,7 +65,11 @@ extension RedisClient {
6265
/// - Returns: `true` if the hash contains the field, `false` if either the key or field do not exist.
6366
@inlinable
6467
public func hexists(_ field: String, in key: String) -> EventLoopFuture<Bool> {
65-
return send(command: "HEXISTS", with: [key, field])
68+
let args: [RESPValue] = [
69+
.init(bulk: key),
70+
.init(bulk: field)
71+
]
72+
return send(command: "HEXISTS", with: args)
6673
.convertFromRESPValue(to: Int.self)
6774
.map { return $0 == 1 }
6875
}
@@ -74,7 +81,8 @@ extension RedisClient {
7481
/// - Returns: The number of fields in the hash, or `0` if the key doesn't exist.
7582
@inlinable
7683
public func hlen(of key: String) -> EventLoopFuture<Int> {
77-
return send(command: "HLEN", with: [key])
84+
let args = [RESPValue(bulk: key)]
85+
return send(command: "HLEN", with: args)
7886
.convertFromRESPValue()
7987
}
8088

@@ -87,7 +95,11 @@ extension RedisClient {
8795
/// - Returns: The string length of the hash field's value, or `0` if the field or hash do not exist.
8896
@inlinable
8997
public func hstrlen(of field: String, in key: String) -> EventLoopFuture<Int> {
90-
return send(command: "HSTRLEN", with: [key, field])
98+
let args: [RESPValue] = [
99+
.init(bulk: key),
100+
.init(bulk: field)
101+
]
102+
return send(command: "HSTRLEN", with: args)
91103
.convertFromRESPValue()
92104
}
93105

@@ -98,7 +110,8 @@ extension RedisClient {
98110
/// - Returns: A list of field names stored within the hash.
99111
@inlinable
100112
public func hkeys(in key: String) -> EventLoopFuture<[String]> {
101-
return send(command: "HKEYS", with: [key])
113+
let args = [RESPValue(bulk: key)]
114+
return send(command: "HKEYS", with: args)
102115
.convertFromRESPValue()
103116
}
104117

@@ -109,7 +122,8 @@ extension RedisClient {
109122
/// - Returns: A list of all values stored in a hash.
110123
@inlinable
111124
public func hvals(in key: String) -> EventLoopFuture<[RESPValue]> {
112-
return send(command: "HVALS", with: [key])
125+
let args = [RESPValue(bulk: key)]
126+
return send(command: "HVALS", with: args)
113127
.convertFromRESPValue()
114128
}
115129

@@ -150,12 +164,17 @@ extension RedisClient {
150164
/// - key: The key that holds the hash.
151165
/// - Returns: `true` if the hash was created, `false` if it was updated.
152166
@inlinable
153-
public func hset(
167+
public func hset<Value: RESPValueConvertible>(
154168
_ field: String,
155-
to value: RESPValueConvertible,
169+
to value: Value,
156170
in key: String
157171
) -> EventLoopFuture<Bool> {
158-
return send(command: "HSET", with: [key, field, value])
172+
let args: [RESPValue] = [
173+
.init(bulk: key),
174+
.init(bulk: field),
175+
value.convertedToRESPValue()
176+
]
177+
return send(command: "HSET", with: args)
159178
.convertFromRESPValue(to: Int.self)
160179
.map { return $0 == 1 }
161180
}
@@ -170,12 +189,17 @@ extension RedisClient {
170189
/// - key: The key that holds the hash.
171190
/// - Returns: `true` if the hash was created.
172191
@inlinable
173-
public func hsetnx(
192+
public func hsetnx<Value: RESPValueConvertible>(
174193
_ field: String,
175-
to value: RESPValueConvertible,
194+
to value: Value,
176195
in key: String
177196
) -> EventLoopFuture<Bool> {
178-
return send(command: "HSETNX", with: [key, field, value])
197+
let args: [RESPValue] = [
198+
.init(bulk: key),
199+
.init(bulk: field),
200+
value.convertedToRESPValue()
201+
]
202+
return send(command: "HSETNX", with: args)
179203
.convertFromRESPValue(to: Int.self)
180204
.map { return $0 == 1 }
181205
}
@@ -188,18 +212,19 @@ extension RedisClient {
188212
/// - key: The key that holds the hash.
189213
/// - Returns: An `EventLoopFuture` that resolves when the operation has succeeded, or fails with a `RedisError`.
190214
@inlinable
191-
public func hmset(
192-
_ fields: [String: RESPValueConvertible],
215+
public func hmset<Value: RESPValueConvertible>(
216+
_ fields: [String: Value],
193217
in key: String
194218
) -> EventLoopFuture<Void> {
195219
assert(fields.count > 0, "At least 1 key-value pair should be specified")
196220

197-
let args: [RESPValueConvertible] = fields.reduce(into: [], { (result, element) in
198-
result.append(element.key)
199-
result.append(element.value)
200-
})
221+
var args: [RESPValue] = [.init(bulk: key)]
222+
args.add(contentsOf: fields, overestimatedCountBeingAdded: fields.count * 2) { (array, element) in
223+
array.append(.init(bulk: element.key))
224+
array.append(element.value.convertedToRESPValue())
225+
}
201226

202-
return send(command: "HMSET", with: [key] + args)
227+
return send(command: "HMSET", with: args)
203228
.map { _ in () }
204229
}
205230
}
@@ -216,7 +241,11 @@ extension RedisClient {
216241
/// - Returns: The value of the hash field, or `nil` if either the key or field does not exist.
217242
@inlinable
218243
public func hget(_ field: String, from key: String) -> EventLoopFuture<String?> {
219-
return send(command: "HGET", with: [key, field])
244+
let args: [RESPValue] = [
245+
.init(bulk: key),
246+
.init(bulk: field)
247+
]
248+
return send(command: "HGET", with: args)
220249
.map { return String(fromRESP: $0) }
221250
}
222251

@@ -230,8 +259,11 @@ extension RedisClient {
230259
@inlinable
231260
public func hmget(_ fields: [String], from key: String) -> EventLoopFuture<[String?]> {
232261
guard fields.count > 0 else { return self.eventLoop.makeSucceededFuture([]) }
262+
263+
var args: [RESPValue] = [.init(bulk: key)]
264+
args.append(convertingContentsOf: fields)
233265

234-
return send(command: "HMGET", with: [key] + fields)
266+
return send(command: "HMGET", with: args)
235267
.convertFromRESPValue(to: [RESPValue].self)
236268
.map { return $0.map(String.init) }
237269
}
@@ -243,7 +275,8 @@ extension RedisClient {
243275
/// - Returns: A key-value pair list of fields and their values.
244276
@inlinable
245277
public func hgetall(from key: String) -> EventLoopFuture<[String: String]> {
246-
return send(command: "HGETALL", with: [key])
278+
let args = [RESPValue(bulk: key)]
279+
return send(command: "HGETALL", with: args)
247280
.convertFromRESPValue(to: [String].self)
248281
.map(Self._mapHashResponse)
249282
}
@@ -262,9 +295,7 @@ extension RedisClient {
262295
/// - Returns: The new value of the hash field.
263296
@inlinable
264297
public func hincrby(_ amount: Int, field: String, in key: String) -> EventLoopFuture<Int> {
265-
/// connection.hincrby(20, field: "foo", in: "key")
266-
return send(command: "HINCRBY", with: [key, field, amount])
267-
.convertFromRESPValue()
298+
return _hincr(command: "HINCRBY", amount, field, key)
268299
}
269300

270301
/// Increments a hash field's value and returns the new value.
@@ -276,12 +307,27 @@ extension RedisClient {
276307
/// - key: The key of the hash the field is stored in.
277308
/// - Returns: The new value of the hash field.
278309
@inlinable
279-
public func hincrbyfloat<T>(_ amount: T, field: String, in key: String) -> EventLoopFuture<T>
310+
public func hincrbyfloat<Value>(_ amount: Value, field: String, in key: String) -> EventLoopFuture<Value>
280311
where
281-
T: BinaryFloatingPoint,
282-
T: RESPValueConvertible
312+
Value: BinaryFloatingPoint,
313+
Value: RESPValueConvertible
283314
{
284-
return send(command: "HINCRBYFLOAT", with: [key, field, amount])
315+
return _hincr(command: "HINCRBYFLOAT", amount, field, key)
316+
}
317+
318+
@usableFromInline
319+
internal func _hincr<Value: RESPValueConvertible>(
320+
command: String,
321+
_ amount: Value,
322+
_ field: String,
323+
_ key: String
324+
) -> EventLoopFuture<Value> {
325+
let args: [RESPValue] = [
326+
.init(bulk: key),
327+
.init(bulk: field),
328+
amount.convertedToRESPValue()
329+
]
330+
return send(command: command, with: args)
285331
.convertFromRESPValue()
286332
}
287333
}

0 commit comments

Comments
 (0)