Skip to content

Commit c96054c

Browse files
authored
Fix pure token rendering issues (#123)
* Render optional pure tokens in blocks correctly * Don't add block members for non optional tokens * Don't require user to create types with no options * Add tests for token rendering
1 parent 14aae56 commit c96054c

File tree

7 files changed

+132
-57
lines changed

7 files changed

+132
-57
lines changed

Sources/Valkey/Commands/GeoCommands.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,13 @@ public struct GEORADIUS: ValkeyCommand {
206206

207207
@inlinable
208208
public var respEntries: Int {
209-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
209+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
210210
}
211211

212212
@inlinable
213213
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
214214
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
215-
"ANY".encode(into: &commandEncoder)
215+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
216216
}
217217
}
218218
public enum Order: RESPRenderable, Sendable, Hashable {
@@ -316,13 +316,13 @@ public struct GEORADIUSBYMEMBER<Member: RESPStringRenderable>: ValkeyCommand {
316316

317317
@inlinable
318318
public var respEntries: Int {
319-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
319+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
320320
}
321321

322322
@inlinable
323323
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
324324
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
325-
"ANY".encode(into: &commandEncoder)
325+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
326326
}
327327
}
328328
public enum Order: RESPRenderable, Sendable, Hashable {
@@ -424,13 +424,13 @@ public struct GEORADIUSBYMEMBERRO<Member: RESPStringRenderable>: ValkeyCommand {
424424

425425
@inlinable
426426
public var respEntries: Int {
427-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
427+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
428428
}
429429

430430
@inlinable
431431
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
432432
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
433-
"ANY".encode(into: &commandEncoder)
433+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
434434
}
435435
}
436436
public enum Order: RESPRenderable, Sendable, Hashable {
@@ -514,13 +514,13 @@ public struct GEORADIUSRO: ValkeyCommand {
514514

515515
@inlinable
516516
public var respEntries: Int {
517-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
517+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
518518
}
519519

520520
@inlinable
521521
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
522522
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
523-
"ANY".encode(into: &commandEncoder)
523+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
524524
}
525525
}
526526
public enum Order: RESPRenderable, Sendable, Hashable {
@@ -743,13 +743,13 @@ public struct GEOSEARCH: ValkeyCommand {
743743

744744
@inlinable
745745
public var respEntries: Int {
746-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
746+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
747747
}
748748

749749
@inlinable
750750
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
751751
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
752-
"ANY".encode(into: &commandEncoder)
752+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
753753
}
754754
}
755755
public typealias Response = RESPToken.Array
@@ -953,13 +953,13 @@ public struct GEOSEARCHSTORE: ValkeyCommand {
953953

954954
@inlinable
955955
public var respEntries: Int {
956-
RESPWithToken("COUNT", count).respEntries + "ANY".respEntries
956+
RESPWithToken("COUNT", count).respEntries + RESPPureToken("ANY", any).respEntries
957957
}
958958

959959
@inlinable
960960
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
961961
RESPWithToken("COUNT", count).encode(into: &commandEncoder)
962-
"ANY".encode(into: &commandEncoder)
962+
RESPPureToken("ANY", any).encode(into: &commandEncoder)
963963
}
964964
}
965965
public typealias Response = Int

Sources/Valkey/Commands/HashCommands.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,13 @@ public struct HRANDFIELD: ValkeyCommand {
264264

265265
@inlinable
266266
public var respEntries: Int {
267-
count.respEntries + "WITHVALUES".respEntries
267+
count.respEntries + RESPPureToken("WITHVALUES", withvalues).respEntries
268268
}
269269

270270
@inlinable
271271
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
272272
count.encode(into: &commandEncoder)
273-
"WITHVALUES".encode(into: &commandEncoder)
273+
RESPPureToken("WITHVALUES", withvalues).encode(into: &commandEncoder)
274274
}
275275
}
276276
public typealias Response = RESPToken?

Sources/Valkey/Commands/ServerCommands.swift

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,14 +1039,14 @@ public struct FAILOVER: ValkeyCommand {
10391039

10401040
@inlinable
10411041
public var respEntries: Int {
1042-
host.respEntries + port.respEntries + "FORCE".respEntries
1042+
host.respEntries + port.respEntries + RESPPureToken("FORCE", force).respEntries
10431043
}
10441044

10451045
@inlinable
10461046
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
10471047
host.encode(into: &commandEncoder)
10481048
port.encode(into: &commandEncoder)
1049-
"FORCE".encode(into: &commandEncoder)
1049+
RESPPureToken("FORCE", force).encode(into: &commandEncoder)
10501050
}
10511051
}
10521052
public var target: Target?
@@ -1220,12 +1220,8 @@ public struct REPLICAOF: ValkeyCommand {
12201220
}
12211221
}
12221222
public struct ArgsNoOne: RESPRenderable, Sendable, Hashable {
1223-
@usableFromInline let no: Bool
1224-
@usableFromInline let one: Bool
12251223

1226-
@inlinable public init(no: Bool = false, one: Bool = false) {
1227-
self.no = no
1228-
self.one = one
1224+
@inlinable public init() {
12291225
}
12301226

12311227
@inlinable
@@ -1241,21 +1237,21 @@ public struct REPLICAOF: ValkeyCommand {
12411237
}
12421238
public enum Args: RESPRenderable, Sendable, Hashable {
12431239
case hostPort(ArgsHostPort)
1244-
case noOne(ArgsNoOne)
1240+
case noOne
12451241

12461242
@inlinable
12471243
public var respEntries: Int {
12481244
switch self {
12491245
case .hostPort(let hostPort): hostPort.respEntries
1250-
case .noOne(let noOne): noOne.respEntries
1246+
case .noOne: ArgsNoOne().respEntries
12511247
}
12521248
}
12531249

12541250
@inlinable
12551251
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
12561252
switch self {
12571253
case .hostPort(let hostPort): hostPort.encode(into: &commandEncoder)
1258-
case .noOne(let noOne): noOne.encode(into: &commandEncoder)
1254+
case .noOne: ArgsNoOne().encode(into: &commandEncoder)
12591255
}
12601256
}
12611257
}
@@ -1327,14 +1323,14 @@ public struct SHUTDOWN: ValkeyCommand {
13271323

13281324
@inlinable
13291325
public var respEntries: Int {
1330-
saveSelector.respEntries + "NOW".respEntries + "FORCE".respEntries
1326+
saveSelector.respEntries + RESPPureToken("NOW", now).respEntries + RESPPureToken("FORCE", force).respEntries
13311327
}
13321328

13331329
@inlinable
13341330
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
13351331
saveSelector.encode(into: &commandEncoder)
1336-
"NOW".encode(into: &commandEncoder)
1337-
"FORCE".encode(into: &commandEncoder)
1332+
RESPPureToken("NOW", now).encode(into: &commandEncoder)
1333+
RESPPureToken("FORCE", force).encode(into: &commandEncoder)
13381334
}
13391335
}
13401336
public enum AbortSelector: RESPRenderable, Sendable, Hashable {
@@ -1392,12 +1388,8 @@ public struct SLAVEOF: ValkeyCommand {
13921388
}
13931389
}
13941390
public struct ArgsNoOne: RESPRenderable, Sendable, Hashable {
1395-
@usableFromInline let no: Bool
1396-
@usableFromInline let one: Bool
13971391

1398-
@inlinable public init(no: Bool = false, one: Bool = false) {
1399-
self.no = no
1400-
self.one = one
1392+
@inlinable public init() {
14011393
}
14021394

14031395
@inlinable
@@ -1413,21 +1405,21 @@ public struct SLAVEOF: ValkeyCommand {
14131405
}
14141406
public enum Args: RESPRenderable, Sendable, Hashable {
14151407
case hostPort(ArgsHostPort)
1416-
case noOne(ArgsNoOne)
1408+
case noOne
14171409

14181410
@inlinable
14191411
public var respEntries: Int {
14201412
switch self {
14211413
case .hostPort(let hostPort): hostPort.respEntries
1422-
case .noOne(let noOne): noOne.respEntries
1414+
case .noOne: ArgsNoOne().respEntries
14231415
}
14241416
}
14251417

14261418
@inlinable
14271419
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
14281420
switch self {
14291421
case .hostPort(let hostPort): hostPort.encode(into: &commandEncoder)
1430-
case .noOne(let noOne): noOne.encode(into: &commandEncoder)
1422+
case .noOne: ArgsNoOne().encode(into: &commandEncoder)
14311423
}
14321424
}
14331425
}

Sources/Valkey/Commands/SortedSetCommands.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,13 +524,13 @@ public struct ZRANDMEMBER: ValkeyCommand {
524524

525525
@inlinable
526526
public var respEntries: Int {
527-
count.respEntries + "WITHSCORES".respEntries
527+
count.respEntries + RESPPureToken("WITHSCORES", withscores).respEntries
528528
}
529529

530530
@inlinable
531531
public func encode(into commandEncoder: inout ValkeyCommandEncoder) {
532532
count.encode(into: &commandEncoder)
533-
"WITHSCORES".encode(into: &commandEncoder)
533+
RESPPureToken("WITHSCORES", withscores).encode(into: &commandEncoder)
534534
}
535535
}
536536
public typealias Response = RESPToken?

Sources/Valkey/Commands/StreamCommands.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,9 @@ public enum XINFO {
252252
@_documentation(visibility: internal)
253253
public struct STREAM: ValkeyCommand {
254254
public struct FullBlock: RESPRenderable, Sendable, Hashable {
255-
@usableFromInline let full: Bool
256255
@usableFromInline let count: Int?
257256

258-
@inlinable public init(full: Bool = false, count: Int? = nil) {
259-
self.full = full
257+
@inlinable public init(count: Int? = nil) {
260258
self.count = count
261259
}
262260

Sources/_ValkeyCommandsBuilder/ValkeyCommandsRender.swift

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ extension String {
207207
for arg in arguments {
208208
if case .pureToken = arg.type {
209209
self.append("\(tab) case \(arg.swiftArgument)\n")
210+
} else if !arg.hasParameters() {
211+
allPureTokens = false
212+
self.append("\(tab) case \(arg.swiftArgument)\n")
210213
} else {
211214
allPureTokens = false
212215
self.append(
@@ -224,9 +227,15 @@ extension String {
224227
self.append("\(tab) switch self {\n")
225228
for arg in arguments {
226229
if case .pureToken = arg.type {
230+
// shouldn't be optional
231+
precondition(!arg.optional)
227232
self.append(
228233
"\(tab) case .\(arg.swiftArgument): \"\((arg.token ?? arg.name).escaped)\".respEntries\n"
229234
)
235+
} else if !arg.hasParameters() {
236+
self.append(
237+
"\(tab) case .\(arg.swiftArgument): \(variableType(arg, names: names, scope: nil, isArray: true, genericStrings: false))().respEntries\n"
238+
)
230239
} else {
231240
self.append(
232241
"\(tab) case .\(arg.swiftArgument)(let \(arg.swiftArgument)): \(arg.respRepresentable(isArray: false, genericString: false)).respEntries\n"
@@ -241,9 +250,14 @@ extension String {
241250
self.append("\(tab) switch self {\n")
242251
for arg in arguments {
243252
if case .pureToken = arg.type {
253+
// shouldn't be optional
244254
self.append(
245255
"\(tab) case .\(arg.swiftArgument): \"\((arg.token ?? arg.name).escaped)\".encode(into: &commandEncoder)\n"
246256
)
257+
} else if !arg.hasParameters() {
258+
self.append(
259+
"\(tab) case .\(arg.swiftArgument): \(variableType(arg, names: names, scope: nil, isArray: true, genericStrings: false))().encode(into: &commandEncoder)\n"
260+
)
247261
} else {
248262
self.append(
249263
"\(tab) case .\(arg.swiftArgument)(let \(arg.swiftArgument)): \(arg.respRepresentable(isArray: false, genericString: false)).encode(into: &commandEncoder)\n"
@@ -259,6 +273,9 @@ extension String {
259273
guard let arguments = argument.arguments, arguments.count > 0 else {
260274
preconditionFailure("OneOf without arguments")
261275
}
276+
let argumentsWithoutNonOptionalTokens = arguments.filter {
277+
!($0.type == .pureToken && $0.optional == false)
278+
}
262279
let names = names + [argument.name.swiftTypename]
263280
let blockName = enumName(names: names)
264281
for arg in arguments {
@@ -269,44 +286,36 @@ extension String {
269286
}
270287
}
271288
self.append("\(tab) public struct \(blockName): RESPRenderable, Sendable, Hashable {\n")
272-
for arg in arguments {
289+
for arg in argumentsWithoutNonOptionalTokens {
273290
self.append(
274291
"\(tab) @usableFromInline let \(arg.swiftVariable): \(variableType(arg, names: names, scope: nil, isArray: true, genericStrings: genericStrings))\n"
275292
)
276293
}
277294
self.append("\n")
278295
let commandParametersString =
279-
arguments
296+
argumentsWithoutNonOptionalTokens
280297
.map { "\($0.name.swiftVariable): \(parameterType($0, names: names, scope: nil, isArray: true, genericStrings: genericStrings))" }
281298
.joined(separator: ", ")
282299
self.append("\(tab) @inlinable public init(\(commandParametersString)) {\n")
283-
for arg in arguments {
300+
for arg in argumentsWithoutNonOptionalTokens {
284301
self.append("\(tab) self.\(arg.name.swiftVariable) = \(arg.name.swiftVariable)\n")
285302
}
286303
self.append("\(tab) }\n\n")
287304
self.append("\(tab) @inlinable\n")
288305
self.append("\(tab) public var respEntries: Int {\n")
289306
self.append("\(tab) ")
290307
let entries = arguments.map {
291-
if case .pureToken = $0.type {
292-
"\"\($0.token!)\".respEntries"
293-
} else {
294-
"\($0.respRepresentable(isArray: false, genericString: genericStrings)).respEntries"
295-
}
308+
"\($0.respRepresentable(isArray: false, genericString: genericStrings)).respEntries"
296309
}
297310
self.append(entries.joined(separator: " + "))
298311
self.append("\n")
299312
self.append("\(tab) }\n\n")
300313
self.append("\(tab) @inlinable\n")
301314
self.append("\(tab) public func encode(into commandEncoder: inout ValkeyCommandEncoder) {\n")
302315
for arg in arguments {
303-
if case .pureToken = arg.type {
304-
self.append("\(tab) \"\(arg.token!)\".encode(into: &commandEncoder)\n")
305-
} else {
306-
self.append(
307-
"\(tab) \(arg.respRepresentable(isArray: false, genericString: genericStrings)).encode(into: &commandEncoder)\n"
308-
)
309-
}
316+
self.append(
317+
"\(tab) \(arg.respRepresentable(isArray: false, genericString: genericStrings)).encode(into: &commandEncoder)\n"
318+
)
310319
}
311320
self.append("\(tab) }\n")
312321
self.append("\(tab) }\n")
@@ -725,7 +734,12 @@ extension ValkeyCommand.Argument {
725734
var variable = self.functionLabel(isArray: multiple && isArray)
726735
switch self.type
727736
{
728-
case .pureToken: return "RESPPureToken(\"\(self.token!)\", \(variable))"
737+
case .pureToken:
738+
if self.optional {
739+
return "RESPPureToken(\"\(self.token!)\", \(variable))"
740+
} else {
741+
return "\"\(self.token!)\""
742+
}
729743
default:
730744
if self.type == .unixTime {
731745
if self.optional {
@@ -762,6 +776,22 @@ extension ValkeyCommand.Argument {
762776
}
763777
}
764778

779+
// return if argument can be configurated by parameters
780+
func hasParameters() -> Bool {
781+
switch self.type {
782+
case .pureToken:
783+
self.optional
784+
case .block:
785+
if let arguments = self.arguments {
786+
arguments.reduce(false) { $0 || $1.hasParameters() }
787+
} else {
788+
false
789+
}
790+
default:
791+
true
792+
}
793+
}
794+
765795
var swiftVariable: String {
766796
self.name.swiftVariable
767797
}

0 commit comments

Comments
 (0)