Skip to content

Commit 868f4b3

Browse files
author
Nilanshu Sharma
committed
Converting all errors in Cluster commands to RESPDecodeError
Signed-off-by: Nilanshu Sharma <[email protected]>
1 parent deeae68 commit 868f4b3

File tree

1 file changed

+33
-58
lines changed

1 file changed

+33
-58
lines changed

Sources/Valkey/Commands/Custom/ClusterCustomCommands.swift

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,6 @@ extension CLUSTER.SLOTS {
3535
public typealias Response = [ValkeyClusterSlotRange]
3636
}
3737

38-
package struct ValkeyClusterParseError: Error, Equatable {
39-
package enum Reason: Error {
40-
case clusterDescriptionTokenIsNotAnArray
41-
case shardTokenIsNotAnArrayOrMap
42-
case nodesTokenIsNotAnArray
43-
case nodeTokenIsNotAnArrayOrMap
44-
case slotsTokenIsNotAnArray
45-
case invalidNodeRole
46-
case invalidNodeHealth
47-
case missingRequiredValueForNode
48-
case shardIsMissingHashSlots
49-
case shardIsMissingNode
50-
}
51-
52-
package var reason: Reason
53-
package var token: RESPToken
54-
55-
package init(reason: Reason, token: RESPToken) {
56-
self.reason = reason
57-
self.token = token
58-
}
59-
}
60-
6138
/// A description of a Valkey cluster.
6239
///
6340
/// A description is return when you call ``ValkeyClientProtocol/clusterShards()``.
@@ -204,11 +181,7 @@ public struct ValkeyClusterDescription: Hashable, Sendable, RESPTokenDecodable {
204181
/// Creates a cluster description from the response token you provide.
205182
/// - Parameter respToken: The response token.
206183
public init(fromRESP respToken: RESPToken) throws {
207-
do {
208-
self = try Self.makeClusterDescription(respToken: respToken)
209-
} catch {
210-
throw ValkeyClusterParseError(reason: error, token: respToken)
211-
}
184+
self = try Self.makeClusterDescription(respToken: respToken)
212185
}
213186

214187
/// Creates a cluster description from a list of shards you provide.
@@ -399,28 +372,28 @@ public struct ValkeyClusterSlotRange: Hashable, Sendable, RESPTokenDecodable {
399372
}
400373

401374
extension ValkeyClusterDescription {
402-
fileprivate static func makeClusterDescription(respToken: RESPToken) throws(ValkeyClusterParseError.Reason) -> ValkeyClusterDescription {
375+
fileprivate static func makeClusterDescription(respToken: RESPToken) throws(RESPDecodeError) -> ValkeyClusterDescription {
403376
guard case .array(let shardsToken) = respToken.value else {
404-
throw .clusterDescriptionTokenIsNotAnArray
377+
throw RESPDecodeError.tokenMismatch(expected: [.array], token: respToken)
405378
}
406-
let shards = try shardsToken.map { shardToken throws(ValkeyClusterParseError.Reason) in
379+
let shards = try shardsToken.map { shardToken throws(RESPDecodeError) in
407380
try ValkeyClusterDescription.Shard(shardToken)
408381
}
409382
return ValkeyClusterDescription(shards)
410383
}
411384
}
412385

413386
extension HashSlots {
414-
fileprivate init(_ iterator: inout RESPToken.Array.Iterator) throws(ValkeyClusterParseError.Reason) {
387+
fileprivate init(_ iterator: inout RESPToken.Array.Iterator) throws(RESPDecodeError) {
415388
guard let token = iterator.next() else {
416-
throw .slotsTokenIsNotAnArray
389+
throw RESPDecodeError(.tokenMismatch, token: .null, message: "Expected to find an array token but reached end of input")
417390
}
418391
self = try HashSlots(token)
419392
}
420393

421-
fileprivate init(_ token: RESPToken) throws(ValkeyClusterParseError.Reason) {
394+
fileprivate init(_ token: RESPToken) throws(RESPDecodeError) {
422395
guard case .array(let array) = token.value else {
423-
throw .slotsTokenIsNotAnArray
396+
throw RESPDecodeError.tokenMismatch(expected: [.array], token: token)
424397
}
425398

426399
var slotRanges = [ClosedRange<HashSlot>]()
@@ -441,29 +414,29 @@ extension HashSlots {
441414
}
442415

443416
extension [ValkeyClusterDescription.Node] {
444-
fileprivate init(_ iterator: inout RESPToken.Array.Iterator) throws(ValkeyClusterParseError.Reason) {
417+
fileprivate init(_ iterator: inout RESPToken.Array.Iterator) throws(RESPDecodeError) {
445418
guard let token = iterator.next() else {
446-
throw .nodesTokenIsNotAnArray
419+
throw RESPDecodeError(.tokenMismatch, token: .null, message: "Expected to find an array token but reached end of input")
447420
}
448421
self = try Self(token)
449422
}
450423

451-
fileprivate init(_ token: RESPToken) throws(ValkeyClusterParseError.Reason) {
424+
fileprivate init(_ token: RESPToken) throws(RESPDecodeError) {
452425
guard case .array(let array) = token.value else {
453-
throw .nodesTokenIsNotAnArray
426+
throw RESPDecodeError.tokenMismatch(expected: [.array], token: token)
454427
}
455428

456-
self = try array.map { token throws(ValkeyClusterParseError.Reason) in
429+
self = try array.map { token throws(RESPDecodeError) in
457430
try ValkeyClusterDescription.Node(token)
458431
}
459432
}
460433
}
461434

462435
extension ValkeyClusterDescription.Shard {
463-
fileprivate init(_ token: RESPToken) throws(ValkeyClusterParseError.Reason) {
436+
fileprivate init(_ token: RESPToken) throws(RESPDecodeError) {
464437
switch token.value {
465438
case .array(let array):
466-
self = try Self.makeFromTokenSequence(MapStyleArray(underlying: array))
439+
self = try Self.makeFromTokenSequence(MapStyleArray(underlying: array), token)
467440

468441
case .map(let map):
469442
let mapped = map.lazy.compactMap { (keyNode, value) -> (String, RESPToken)? in
@@ -473,16 +446,17 @@ extension ValkeyClusterDescription.Shard {
473446
return nil
474447
}
475448
}
476-
self = try Self.makeFromTokenSequence(mapped)
449+
self = try Self.makeFromTokenSequence(mapped, token)
477450

478451
default:
479-
throw ValkeyClusterParseError.Reason.shardTokenIsNotAnArrayOrMap
452+
throw RESPDecodeError.tokenMismatch(expected: [.array, .map], token: token)
480453
}
481454
}
482455

483456
fileprivate static func makeFromTokenSequence<TokenSequence: Sequence>(
484-
_ sequence: TokenSequence
485-
) throws(ValkeyClusterParseError.Reason) -> Self where TokenSequence.Element == (String, RESPToken) {
457+
_ sequence: TokenSequence,
458+
_ token: RESPToken
459+
) throws(RESPDecodeError) -> Self where TokenSequence.Element == (String, RESPToken) {
486460
var slotRanges = HashSlots()
487461
var nodes: [ValkeyClusterDescription.Node] = []
488462

@@ -499,18 +473,18 @@ extension ValkeyClusterDescription.Shard {
499473
}
500474
}
501475

502-
if nodes.isEmpty { throw .shardIsMissingNode }
503-
if slotRanges.isEmpty { throw .shardIsMissingHashSlots }
476+
if nodes.isEmpty { throw RESPDecodeError.missingToken(key: "nodes", token: token) }
477+
if slotRanges.isEmpty { throw RESPDecodeError.missingToken(key: "shards", token: token) }
504478

505479
return .init(slots: slotRanges, nodes: nodes)
506480
}
507481
}
508482

509483
extension ValkeyClusterDescription.Node {
510-
fileprivate init(_ token: RESPToken) throws(ValkeyClusterParseError.Reason) {
484+
fileprivate init(_ token: RESPToken) throws(RESPDecodeError) {
511485
switch token.value {
512486
case .array(let array):
513-
self = try Self.makeFromTokenSequence(MapStyleArray(underlying: array))
487+
self = try Self.makeFromTokenSequence(MapStyleArray(underlying: array), token)
514488

515489
case .map(let map):
516490
let mapped = map.lazy.compactMap { (keyNode, value) -> (String, RESPToken)? in
@@ -520,16 +494,17 @@ extension ValkeyClusterDescription.Node {
520494
return nil
521495
}
522496
}
523-
self = try Self.makeFromTokenSequence(mapped)
497+
self = try Self.makeFromTokenSequence(mapped, token)
524498

525499
default:
526-
throw .nodeTokenIsNotAnArrayOrMap
500+
throw RESPDecodeError.tokenMismatch(expected: [.array, .map], token: token)
527501
}
528502
}
529503

530504
fileprivate static func makeFromTokenSequence<TokenSequence: Sequence>(
531-
_ sequence: TokenSequence
532-
) throws(ValkeyClusterParseError.Reason) -> Self where TokenSequence.Element == (String, RESPToken) {
505+
_ sequence: TokenSequence,
506+
_ respToken: RESPToken
507+
) throws(RESPDecodeError) -> Self where TokenSequence.Element == (String, RESPToken) {
533508
var id: String?
534509
var port: Int64?
535510
var tlsPort: Int64?
@@ -557,7 +532,7 @@ extension ValkeyClusterDescription.Node {
557532
endpoint = try? String(fromRESP: nodeVal)
558533
case "role":
559534
guard let roleString = try? String(fromRESP: nodeVal), let roleValue = ValkeyClusterDescription.Node.Role(rawValue: roleString) else {
560-
throw .invalidNodeRole
535+
throw RESPDecodeError.missingToken(key: "role", token: respToken)
561536
}
562537
role = roleValue
563538

@@ -567,7 +542,7 @@ extension ValkeyClusterDescription.Node {
567542
guard let healthString = try? String(fromRESP: nodeVal),
568543
let healthValue = ValkeyClusterDescription.Node.Health(rawValue: healthString)
569544
else {
570-
throw .invalidNodeHealth
545+
throw RESPDecodeError.missingToken(key: "health", token: respToken)
571546
}
572547
health = healthValue
573548

@@ -579,12 +554,12 @@ extension ValkeyClusterDescription.Node {
579554
guard let id = id, let ip = ip, let endpoint = endpoint, let role = role,
580555
let replicationOffset = replicationOffset, let health = health
581556
else {
582-
throw .missingRequiredValueForNode
557+
throw RESPDecodeError.missingToken(key: "id or ip or endpoint or role or replication-offset or health", token: respToken)
583558
}
584559

585560
// we need at least port or tlsport
586561
if port == nil && tlsPort == nil {
587-
throw .missingRequiredValueForNode
562+
throw RESPDecodeError.missingToken(key: "port or tls-port", token: respToken)
588563
}
589564

590565
return ValkeyClusterDescription.Node(

0 commit comments

Comments
 (0)