SurrealDB wraps every query RPC in its own implicit BEGIN/COMMIT, so a transaction has to live inside a single multi-statement query. The Mojo SDK gives you two ways to do this.
Atomic multi-statement transactions
transaction_multi takes a list of statements, wraps them in BEGIN TRANSACTION; and COMMIT TRANSACTION;, and sends them as a single atomic query. This works on any transport and is the recommended approach over HTTP.
var stmts = List[String]()
stmts.append("CREATE car:a SET wheels = 4;")
stmts.append("CREATE car:b SET wheels = 4;")
var resp = client.transaction_multi(stmts)If any statement fails, the whole transaction is rolled back.
Session transactions
Over a stateful WebSocket session, begin_transaction() returns a handle that buffers statements and flushes them on commit(). The handle exposes query(), create(), select(), commit(), and cancel().
from surrealdb import AsyncSurrealClient, CborCodec, ConnectOptions
from std.collections import Optional, List
def main():
var client = AsyncSurrealClient()
_ = client.connect(
"ws://localhost:8000/rpc",
ConnectOptions(
namespace=Optional(String("test")),
database=Optional(String("test")),
),
)
var codec = CborCodec()
var pairs = List[Tuple[String, List[UInt8]]]()
pairs.append(Tuple(String("user"), codec.encode_text("root")))
pairs.append(Tuple(String("pass"), codec.encode_text("root")))
_ = client.signin(codec.encode_map(pairs))
client.use("test", "test")
# BEGIN, do work, COMMIT.
var txn = client.begin_transaction()
_ = txn.query("CREATE person:alice SET age = 30;")
_ = txn.query("CREATE person:bob SET age = 31;")
txn.commit()Call cancel() instead of commit() to discard the buffered statements.
Session transactions run over a stateful WebSocket session. WebSocket support is rolling out; for atomic transactions over HTTP, use transaction_multi.
See the method reference for transaction_multi and begin_transaction.