Skip to content

Commit 5e64e61

Browse files
committed
Add ValkeyClient.transaction
Signed-off-by: Adam Fowler <[email protected]>
1 parent 2939660 commit 5e64e61

File tree

4 files changed

+99
-12
lines changed

4 files changed

+99
-12
lines changed

Sources/Valkey/Connection/ValkeyConnection.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,10 @@ public final actor ValkeyConnection: ValkeyClientProtocol, Sendable {
243243
}
244244
}
245245

246-
/// Pipeline a series of commands to Valkey connection
246+
/// Pipeline a series of commands as a transaction to Valkey connection
247+
///
248+
/// Another client will never be served in the middle of the execution of these
249+
/// commands. See https://valkey.io/topics/transactions/ for more information.
247250
///
248251
/// Once all the responses for the commands have been received the function returns
249252
/// a parameter pack of Results, one for each command.
@@ -280,12 +283,15 @@ public final actor ValkeyConnection: ValkeyClientProtocol, Sendable {
280283
}.get()
281284
}
282285

283-
/// Pipeline a series of commands to Valkey connection
286+
/// Pipeline a series of commands as a transaction to Valkey connection
287+
///
288+
/// Another client will never be served in the middle of the execution of these
289+
/// commands. See https://valkey.io/topics/transactions/ for more information.
284290
///
285291
/// Once all the responses for the commands have been received the function returns
286292
/// an array of RESPToken Results, one for each command.
287293
///
288-
/// This is an alternative version of the pipelining function ``ValkeyConnection/execute(_:)->(_,_)``
294+
/// This is an alternative version of the pipelining function ``ValkeyConnection/transaction(_:)->(_,_)``
289295
/// that allows for a collection of ValkeyCommands. It provides more flexibility but is
290296
/// slightly more expensive to run and the command responses are returned as ``RESPToken``
291297
/// instead of the response type for the command.

Sources/Valkey/Node/ValkeyNodeClient.swift

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ extension ValkeyNodeClient {
146146
/// - Parameter commands: Parameter pack of ValkeyCommands
147147
/// - Returns: Parameter pack holding the results of all the commands
148148
@inlinable
149-
public func execute<each Command: ValkeyCommand>(
149+
func execute<each Command: ValkeyCommand>(
150150
_ commands: repeat each Command
151151
) async -> sending (repeat Result<(each Command).Response, Error>) {
152152
do {
@@ -171,7 +171,7 @@ extension ValkeyNodeClient {
171171
/// - Parameter commands: Collection of ValkeyCommands
172172
/// - Returns: Array holding the RESPToken responses of all the commands
173173
@inlinable
174-
public func execute<Commands: Collection & Sendable>(
174+
func execute<Commands: Collection & Sendable>(
175175
_ commands: Commands
176176
) async -> sending [Result<RESPToken, Error>] where Commands.Element == any ValkeyCommand {
177177
do {
@@ -183,6 +183,49 @@ extension ValkeyNodeClient {
183183
}
184184
}
185185

186+
/// Pipeline a series of commands as a transaction to Valkey connection
187+
///
188+
/// Another client will never be served in the middle of the execution of these
189+
/// commands. See https://valkey.io/topics/transactions/ for more information.
190+
///
191+
/// Once all the responses for the commands have been received the function returns
192+
/// a parameter pack of Results, one for each command.
193+
///
194+
/// - Parameter commands: Parameter pack of ValkeyCommands
195+
/// - Returns: Parameter pack holding the responses of all the commands
196+
@inlinable
197+
func transaction<each Command: ValkeyCommand>(
198+
_ commands: repeat each Command
199+
) async throws -> sending (repeat Result<(each Command).Response, Error>) {
200+
try await self.withConnection { connection in
201+
try await connection.transaction(repeat (each commands))
202+
}
203+
}
204+
205+
/// Pipeline a series of commands as a transaction to Valkey connection
206+
///
207+
/// Another client will never be served in the middle of the execution of these
208+
/// commands. See https://valkey.io/topics/transactions/ for more information.
209+
///
210+
/// Once all the responses for the commands have been received the function returns
211+
/// an array of RESPToken Results, one for each command.
212+
///
213+
/// This is an alternative version of the pipelining function ``ValkeyNodeClient/transaction(_:)->(_,_)``
214+
/// that allows for a collection of ValkeyCommands. It provides more flexibility but is
215+
/// slightly more expensive to run and the command responses are returned as ``RESPToken``
216+
/// instead of the response type for the command.
217+
///
218+
/// - Parameter commands: Collection of ValkeyCommands
219+
/// - Returns: Array holding the RESPToken responses of all the commands
220+
@inlinable
221+
func transaction<Commands: Collection & Sendable>(
222+
_ commands: Commands
223+
) async throws -> sending [Result<RESPToken, Error>] where Commands.Element == any ValkeyCommand {
224+
try await self.withConnection { connection in
225+
try await connection.transaction(commands)
226+
}
227+
}
228+
186229
/// Internal command used by cluster client, that precedes each command with a ASKING
187230
/// command
188231
func executeWithAsk<Commands: Collection & Sendable>(

Sources/Valkey/ValkeyClient.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,44 @@ extension ValkeyClient {
217217
) async -> sending [Result<RESPToken, Error>] where Commands.Element == any ValkeyCommand {
218218
await node.execute(commands)
219219
}
220+
/// Pipeline a series of commands as a transaction to Valkey connection
221+
///
222+
/// Another client will never be served in the middle of the execution of these
223+
/// commands. See https://valkey.io/topics/transactions/ for more information.
224+
///
225+
/// Once all the responses for the commands have been received the function returns
226+
/// a parameter pack of Results, one for each command.
227+
///
228+
/// - Parameter commands: Parameter pack of ValkeyCommands
229+
/// - Returns: Parameter pack holding the responses of all the commands
230+
@inlinable
231+
public func transaction<each Command: ValkeyCommand>(
232+
_ commands: repeat each Command
233+
) async throws -> sending (repeat Result<(each Command).Response, Error>) {
234+
try await node.transaction(repeat each commands)
235+
}
236+
237+
/// Pipeline a series of commands as a transaction to Valkey connection
238+
///
239+
/// Another client will never be served in the middle of the execution of these
240+
/// commands. See https://valkey.io/topics/transactions/ for more information.
241+
///
242+
/// Once all the responses for the commands have been received the function returns
243+
/// an array of RESPToken Results, one for each command.
244+
///
245+
/// This is an alternative version of the pipelining function ``ValkeyClient/transaction(_:)->(_,_)``
246+
/// that allows for a collection of ValkeyCommands. It provides more flexibility but is
247+
/// slightly more expensive to run and the command responses are returned as ``RESPToken``
248+
/// instead of the response type for the command.
249+
///
250+
/// - Parameter commands: Collection of ValkeyCommands
251+
/// - Returns: Array holding the RESPToken responses of all the commands
252+
@inlinable
253+
public func transaction<Commands: Collection & Sendable>(
254+
_ commands: Commands
255+
) async throws -> sending [Result<RESPToken, Error>] where Commands.Element == any ValkeyCommand {
256+
try await node.transaction(commands)
257+
}
220258
}
221259

222260
#if ServiceLifecycleSupport

Tests/IntegrationTests/ClientIntegrationTests.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ struct ClientIntegratedTests {
258258
func testTransactionSetIncrGet() async throws {
259259
var logger = Logger(label: "Valkey")
260260
logger.logLevel = .debug
261-
try await withValkeyConnection(.hostname(valkeyHostname, port: 6379), logger: logger) { connection in
262-
try await withKey(connection: connection) { key in
263-
let responses = try await connection.transaction(
261+
try await withValkeyClient(.hostname(valkeyHostname, port: 6379), logger: logger) { client in
262+
try await withKey(connection: client) { key in
263+
let responses = try await client.transaction(
264264
SET(key, value: "100"),
265265
INCR(key),
266266
GET(key)
@@ -275,10 +275,10 @@ struct ClientIntegratedTests {
275275
func testInvalidTransactionSetIncrGet() async throws {
276276
var logger = Logger(label: "Valkey")
277277
logger.logLevel = .debug
278-
try await withValkeyConnection(.hostname(valkeyHostname, port: 6379), logger: logger) { connection in
279-
try await withKey(connection: connection) { key in
280-
try await connection.set(key, value: "100")
281-
let responses = try await connection.transaction(
278+
try await withValkeyClient(.hostname(valkeyHostname, port: 6379), logger: logger) { client in
279+
try await withKey(connection: client) { key in
280+
try await client.set(key, value: "100")
281+
let responses = try await client.transaction(
282282
LPUSH(key, elements: ["Hello"]),
283283
INCR(key),
284284
GET(key)

0 commit comments

Comments
 (0)