Skip to content

Commit 27f7dbe

Browse files
committed
Throw error when command returns an error
1 parent efd35cd commit 27f7dbe

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

Sources/Valkey/Connection/ValkeyChannelHandler.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,18 @@ final class ValkeyChannelHandler: ChannelInboundHandler {
140140
}
141141

142142
func handleToken(context: ChannelHandlerContext, token: RESPToken) {
143-
guard let promise = commands.popFirst() else {
144-
preconditionFailure("Unexpected response")
143+
switch token.identifier {
144+
case .simpleError, .bulkError:
145+
guard let promise = commands.popFirst() else {
146+
preconditionFailure("Unexpected response")
147+
}
148+
promise.fail(ValkeyClientError(.commandError, message: token.errorString.map { String(buffer: $0) }))
149+
default:
150+
guard let promise = commands.popFirst() else {
151+
preconditionFailure("Unexpected response")
152+
}
153+
promise.succeed(token)
145154
}
146-
promise.succeed(token)
147155
}
148156

149157
func handleError(context: ChannelHandlerContext, error: Error) {

Sources/Valkey/RESP/RESPToken.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public struct RESPToken: Hashable, Sendable {
117117

118118
return .bulkString(local.readSlice(length: length)!)
119119

120-
case .blobError:
120+
case .bulkError:
121121
var lengthSlice = try! local.readCRLFTerminatedSlice2()!
122122
let lengthString = lengthSlice.readString(length: lengthSlice.readableBytes)!
123123
let length = Int(lengthString)!
@@ -197,7 +197,7 @@ public struct RESPToken: Hashable, Sendable {
197197
case .simpleError:
198198
let slice = try! local.readCRLFTerminatedSlice2()!
199199
return slice
200-
case .blobError:
200+
case .bulkError:
201201
var lengthSlice = try! local.readCRLFTerminatedSlice2()!
202202
let lengthString = lengthSlice.readString(length: lengthSlice.readableBytes)!
203203
let length = Int(lengthString)!
@@ -207,6 +207,10 @@ public struct RESPToken: Hashable, Sendable {
207207
}
208208
}
209209

210+
public var identifier: RESPTypeIdentifier {
211+
self.base.getValidatedRESP3TypeIdentifier()
212+
}
213+
210214
public init?(consuming buffer: inout ByteBuffer) throws {
211215
try self.init(consuming: &buffer, depth: 0)
212216
}
@@ -223,7 +227,7 @@ public struct RESPToken: Hashable, Sendable {
223227

224228
case .some(.bulkString),
225229
.some(.verbatimString),
226-
.some(.blobError):
230+
.some(.bulkError):
227231
validated = try buffer.readRESPBlobStringSlice()
228232

229233
case .some(.simpleString),
@@ -260,7 +264,7 @@ public struct RESPToken: Hashable, Sendable {
260264
}
261265

262266
extension ByteBuffer {
263-
fileprivate mutating func getRESP3TypeIdentifier(at index: Int) throws -> RESPTypeIdentifier? {
267+
fileprivate func getRESP3TypeIdentifier(at index: Int) throws -> RESPTypeIdentifier? {
264268
guard let int = self.getInteger(at: index, as: UInt8.self) else {
265269
return nil
266270
}
@@ -272,6 +276,11 @@ extension ByteBuffer {
272276
return id
273277
}
274278

279+
fileprivate func getValidatedRESP3TypeIdentifier() -> RESPTypeIdentifier {
280+
let int = self.getInteger(at: self.readerIndex, as: UInt8.self)!
281+
return RESPTypeIdentifier(rawValue: int)!
282+
}
283+
275284
fileprivate mutating func readValidatedRESP3TypeIdentifier() -> RESPTypeIdentifier {
276285
let int = self.readInteger(as: UInt8.self)!
277286
return RESPTypeIdentifier(rawValue: int)!
@@ -311,7 +320,7 @@ extension ByteBuffer {
311320

312321
fileprivate mutating func readRESPBlobStringSlice() throws -> ByteBuffer? {
313322
let marker = try self.getRESP3TypeIdentifier(at: self.readerIndex)!
314-
precondition(marker == .bulkString || marker == .verbatimString || marker == .blobError)
323+
precondition(marker == .bulkString || marker == .verbatimString || marker == .bulkError)
315324
guard var lengthSlice = try self.getCRLFTerminatedSlice(at: self.readerIndex + 1) else {
316325
return nil
317326
}

Sources/Valkey/RESP/RESPTypeIdentifier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public enum RESPTypeIdentifier: UInt8 {
1818
case simpleString = 43 // UInt8.plus
1919
case simpleError = 45 // UInt8.min
2020
case bulkString = 36 // UInt8.dollar
21-
case blobError = 33 // UInt8.exclamationMark
21+
case bulkError = 33 // UInt8.exclamationMark
2222
case verbatimString = 61 // UInt8.equals
2323
case boolean = 35 // UInt8.pound
2424
case null = 95 // UInt8.underscore

Tests/IntegrationTests/ValkeyTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,18 @@ struct GeneratedCommands {
171171
}
172172
}
173173

174+
@Test("Test command error is thrown")
175+
func testCommandError() async throws {
176+
var logger = Logger(label: "Valkey")
177+
logger.logLevel = .debug
178+
try await ValkeyClient(.hostname(valkeyHostname, port: 6379), logger: logger).withConnection(logger: logger) { connection in
179+
try await withKey(connection: connection) { key in
180+
_ = try await connection.set(key: key, value: "Hello")
181+
await #expect(throws: ValkeyClientError.self) { _ = try await connection.rpop(key: key) }
182+
}
183+
}
184+
}
185+
174186
@Test
175187
func testMultiplexing() async throws {
176188
var logger = Logger(label: "Valkey")

0 commit comments

Comments
 (0)