Query, Live, Transactions
Auto-generated from docstrings. For narrative usage, see the Guide.
Query and CRUD
SurrealDB.query — Function
query(client, sql::String; vars=Dict{String, Any}())Execute a raw SurrealQL query with optional parameterized variables.
Returns Vector{Dict{String, Any}} — one result dict per statement.
Examples
result = SurrealDB.query(db, "SELECT * FROM stream WHERE active = true")
result = SurrealDB.query(db, "SELECT * FROM $table WHERE x > $min",
vars=Dict("table" => "stream", "min" => 10))query(client, ::Type{T}, sql::String; vars=Dict{String, Any}())Execute a raw SurrealQL query and map results to typed Julia structs.
T must be a type for which StructTypes.StructType(T) returns StructTypes.Struct(). Each result row is converted to an instance of T via StructTypes.constructfrom.
Returns Vector{T} — one instance per result row.
Examples
struct Stream
id::SurrealDB.RecordID
name::String
mature::Bool
end
StructTypes.StructType(::Type{Stream}) = StructTypes.Struct()
streams = SurrealDB.query(db, Stream, "SELECT * FROM stream")SurrealDB.query_verbose — Function
query_verbose(client, sql::String, vars=Dict{String,Any}()) -> Vector{QueryStatement}Execute a SurrealQL query and return per-statement metadata, including status, execution time, result, and any typed error — one QueryStatement per server-reported statement in order.
Unlike query, query_verbose never throws on statement errors. Each statement's outcome is captured in the returned QueryStatement. Transport- level failures (network errors, ConnectionError, etc.) still propagate as exceptions.
Use cases:
- Multi-statement transactions — inspect which statements succeeded or failed before deciding to retry.
- Batch ETL with partial failure — continue processing successful statements while logging errors.
- Per-statement performance profiling — read the
timefield from eachQueryStatementto identify slow statements. - Observability pipelines — emit structured per-statement metrics without losing the result data.
Examples
# Partial failure: second INSERT has a duplicate id
stmts = SurrealDB.query_verbose(db, """
INSERT INTO user { id: user:1, name: "Alice" };
INSERT INTO user { id: user:1, name: "Duplicate" };
SELECT * FROM user;
""")
# stmts[1] → QueryStatement(:ok, ..., rows=1)
# stmts[2] → QueryStatement(:err, ..., error=AlreadyExistsError(...))
# stmts[3] → QueryStatement(:ok, ..., rows=1)
successes = filter(isok, stmts)
failures = filter(iserr, stmts)
times_ms = [s.time for s in stmts]For simple queries where you want the result or an exception, use query.
See also: QueryStatement, isok, iserr, query.
SurrealDB.QueryStatement — Type
QueryStatementPer-statement metadata returned by query_verbose. Exposes the server-reported status, execution time, result value, and any typed error without discarding statements that errored.
Fields:
status::Symbol—:okor:errtime::String— server-reported execution time, e.g."1.2ms"result::Any— the parsed result value;nothingon:errerror::Union{ServerError, Nothing}— typed error;nothingon:ok
Use isok / iserr to discriminate:
stmts = SurrealDB.query_verbose(db, "SELECT * FROM a; BAD QUERY; SELECT * FROM b")
filter(isok, stmts) # statements that succeeded
filter(iserr, stmts) # statements that failedSurrealDB.isok — Function
isok(s::QueryStatement) -> BoolReturn true when the statement completed without error.
SurrealDB.iserr — Function
iserr(s::QueryStatement) -> BoolReturn true when the statement produced a server error.
SurrealDB.query_table — Function
query_table(client, sql::String; vars=Dict{String, Any}()) -> Vector{QueryResultTable}Like query but returns one QueryResultTable per statement instead of nested vectors. Lets multi-statement queries preserve their per-statement structure as Tables.jl-compatible sources.
Remote (WS/HTTP) preserves per-statement results. Embedded (libsurreal) flattens all rows from all statements into a single result list (the C library does not expose statement boundaries). On embedded, query_table therefore returns a single-element Vector regardless of how many ;s the SQL contains. Run multi-statement queries one at a time on embedded if you need per-statement separation.
Examples
tables = SurrealDB.query_table(db, "SELECT * FROM stream; SELECT * FROM event")
using DataFrames
streams_df = DataFrame(tables[1])
events_df = DataFrame(tables[2])SurrealDB.query_one — Function
query_one(client, sql::String; vars=Dict{String, Any}()) -> QueryResultTableConvenience wrapper around query_table for single-statement queries. Asserts the SQL produced exactly one statement-result and returns its QueryResultTable. Throws ArgumentError if the query produced zero or multiple statements.
Examples
table = SurrealDB.query_one(db, "SELECT * FROM stream WHERE active = true")
using DataFrames
df = DataFrame(table)See also: query, query_table.
SurrealDB.create — Function
create(client, what, data::Dict{String, Any})Create a new record in the table or with a specific ID.
Returns the created record(s) as a Dict or Vector of Dicts.
create(client, ::Type{T}, what, data)Create a record and return it as a typed struct T.
Examples
stream = SurrealDB.create(db, Stream, "stream", Dict("name" => "new"))SurrealDB.select — Function
select(client, what) -> AnySelect all records from a table or fetch a specific record by ID.
Returns a Vector of records when what is a table, or a single record (Dict) when what is a record ID. Returns an empty vector / nothing when the target does not exist.
select(client, ::Type{T}, what)Select a record or table and map results to typed Julia struct T.
For table selects, returns Vector{T}. For record selects, returns T.
Examples
struct Stream
id::SurrealDB.RecordID
name::String
end
StructTypes.StructType(::Type{Stream}) = StructTypes.Struct()
all_streams = SurrealDB.select(db, Stream, "stream")
one_stream = SurrealDB.select(db, Stream, "stream:abc")SurrealDB.update — Function
update(client, what, data) -> AnyReplace the contents of a record (or every record in a table) with data. Existing fields not present in data are removed; for partial updates use merge instead.
what: Table name or record IDdata: Replacement record contents (Dict)
Returns the updated record(s).
SurrealDB.delete — Function
delete(client, what) -> AnyDelete a record or every record in a table.
what: Table name or record ID
Returns the deleted record(s). Deleting a nonexistent record is not an error on SurrealDB v3 (returns nothing).
SurrealDB.insert — Function
insert(client, table, data) -> AnyInsert one or many records into a table. Unlike create, data may be a single Dict or a Vector of Dicts for batch inserts; ids are auto-assigned when not provided.
table: Table name (String orTable)data: Single Dict or Vector of Dicts
Returns the inserted record(s).
See also: create, insert_relation.
SurrealDB.upsert — Function
upsert(client, what, data) -> AnyCreate the record if it does not exist, otherwise replace it. Same payload shape as update; the difference is that update on a missing record may not create it on all SurrealDB versions.
SurrealDB.merge — Function
merge(client, what, data) -> AnyPartially update a record by merging data into the existing record. Fields present in data overwrite existing fields; fields absent are preserved (unlike update which replaces the whole record).
what: Table name or record IDdata: Partial record contents (Dict)
SurrealDB.relate — Function
relate(client, from, edge, to; data=nothing) -> Any
relate(client, rel::Relationship) -> AnyCreate a graph edge from from to to via edge. The flat-arg form is the canonical first-class signature; the Relationship form is convenient for storing/passing pre-built edges.
from: source record id (RecordIDor"table:id"string)edge: edge table (Tableor String) or specific edge record idto: target record iddata: optional Dict of edge fields
Returns the created edge record.
Examples
SurrealDB.relate(db, "person:john", "knows", "person:jane";
data=Dict("met" => "2024-01-01"))
# Or via the bulk struct
rel = Relationship("person:john", Table("knows"), "person:jane",
Dict("met" => "2024-01-01"))
SurrealDB.relate(db, rel)See also: insert_relation, Relationship.
SurrealDB.insert_relation — Function
insert_relation(client, relationship::Relationship) -> AnyInsert a graph edge defined by a Relationship. Equivalent to SurrealQL INSERT RELATION INTO <table> { in, out, ... }.
Differs from relate in that insert_relation is intended for batch / seeded edges; relate is the canonical first-class edge primitive.
See also: relate, Relationship.
SurrealDB.patch — Function
patch(client, what, patches::Vector{Dict{String, Any}})Apply JSON Patch operations to a record.
Examples
SurrealDB.patch(db, "user:1", [
Dict("op" => "replace", "path" => "/name", "value" => "New Name"),
Dict("op" => "add", "path" => "/tags/0", "value" => "new-tag")
])SurrealDB.patch_add — Function
patch_add(client, what, path::String, value)Convenience wrapper around patch that issues a single JSON-Patch add operation at path. what is a table name, Table, or RecordID.
SurrealDB.patch_remove — Function
patch_remove(client, what, path::String)Convenience wrapper around patch that issues a single JSON-Patch remove operation at path.
SurrealDB.patch_replace — Function
patch_replace(client, what, path::String, value)Convenience wrapper around patch that issues a single JSON-Patch replace operation at path.
SurrealDB.run — Function
run(client, fn_name::String, args=Any[]; version=nothing) -> AnyInvoke a SurrealDB function — builtin (type::*, string::*, ...) or user-defined (fn::*).
fn_name: Function name including namespace, e.g."fn::greet"or"type::is::array"args: Positional args as aVectorversion: Optional semver string for versioned user functions
Examples
SurrealDB.run(db, "type::is::array", [[1, 2, 3]]) # → true
SurrealDB.run(db, "fn::greet", ["world"])SurrealDB.ping — Function
ping(client::SurrealClient) -> BoolSend a lightweight RPC ping. Returns true if the server responds. Backs the keepalive timer; exposed for callers who want a manual liveness check without health()'s trivial-query fallback.
SurrealDB.let! — Function
let!(client, key::String, value)Set a session variable. These variables can be referenced in SurrealQL queries using $key syntax.
Examples
SurrealDB.let!(db, "min_age", 18)
result = SurrealDB.query(db, "SELECT * FROM user WHERE age > $min_age")SurrealDB.unset! — Function
unset!(client, key::String)Remove a previously set session variable.
Live queries
SurrealDB.live — Function
live(client, table; diff=false)Start a live query subscription on a table.
Returns a LiveSubscription with a channel field you can iterate over to receive real-time notifications.
table: Table name (String orTable)diff: Iftrue, notifications include the diff between old and new values
Examples
sub = SurrealDB.live(db, "stream")
for notification in sub.channel
println("Action: ", notification["action"])
println("Data: ", notification["data"])
break # or loop forever
end
SurrealDB.kill!(sub)SurrealDB.subscribe — Function
subscribe(sub::LiveSubscription) -> LiveSubscriptionRegister an additional consumer on sub's server-side live query. The returned subscription shares query_id with the input but holds a fresh channel; both channels receive every notification (fan-out at the SDK level).
kill!(original_sub) (or kill!(client, query_id)) tears down ALL subscribers sharing the UUID — per-consumer teardown is not supported. WS-only.
sub = SurrealDB.live(db, "stream")
sub2 = SurrealDB.subscribe(sub)
@async for n in sub.channel; process(n); end # consumer A
@async for n in sub2.channel; log(n); end # consumer B
SurrealDB.kill!(sub) # both channels closeSurrealDB.kill! — Function
kill!(client, query_id::String)Terminate a live query by its UUID. If a LiveSubscription handle was registered for this id (i.e. created via live), its active flag is flipped to false and its channel is closed so consumers iterating it observe the termination.
kill!(sub::LiveSubscription)Terminate a live query subscription. Delegates to kill! by id, which flips sub.active and closes the channel.
SurrealDB.LiveSubscription — Type
LiveSubscription(query_id, channel, client)A live query subscription. Iterate over sub.channel (or sub directly) to receive LiveNotification events. Call kill!(sub) to terminate.
Fields:
query_id::String: UUID string identifying the live query on the serverchannel::Channel: receivesLiveNotificationeventsactive::Bool: subscription state
SurrealDB.LiveNotification — Type
LiveNotification(action, query_id, record, result, session)One live-query event delivered to a LiveSubscription channel. Subtype of AbstractDict{String, Any} so legacy n["action"] access keeps working alongside the typed n.action form.
Fields:
action::String:"CREATE","UPDATE", or"DELETE"("KILLED"events are dropped by the dispatcher)query_id::String: live UUID matchingsub.query_idrecord::Union{String, Nothing}: affected record id, e.g."users:abc"result::Any: payload — the record on CREATE/UPDATE, the pre-delete record on DELETEsession::Union{String, Nothing}: v3 session id;nothingon v2
Transactions and sessions
SurrealDB.begin! — Function
begin!(client)Start a new transaction. All subsequent operations within the transaction are isolated until commit! or cancel! is called.
On SurrealDB v3+ remote connections, begin!/commit!/cancel! RPC methods may return "Expected transaction UUID". Use raw SurrealQL instead:
SurrealDB.query(db, "BEGIN TRANSACTION; ...; COMMIT TRANSACTION;")begin!(session::SurrealSession) -> SurrealTransactionStart a transaction within a v3+ session. Returns a SurrealTransaction handle; pass it to commit! or cancel! to finalize.
SurrealDB.commit! — Function
commit!(client)Commit the active transaction, persisting all changes made within it. For v3+ remote connections, prefer raw SurrealQL COMMIT TRANSACTION;.
commit!(txn::SurrealTransaction)Commit a v3+ session transaction. Flips txn.closed = true even if the RPC throws, so a stale handle can't be re-used.
SurrealDB.cancel! — Function
cancel!(client)Cancel / rollback the active transaction, discarding all changes made within it. For v3+ remote connections, prefer raw SurrealQL CANCEL TRANSACTION;.
cancel!(txn::SurrealTransaction)Cancel/rollback a v3+ session transaction. Flips txn.closed = true even if the RPC throws.
SurrealDB.SurrealTransaction — Type
SurrealTransactionA v3+ interactive transaction handle. Returned by begin!(session). Call commit!(txn) or cancel!(txn) to finalize; either flips txn.closed = true so a stale handle can't be re-committed against a server-side transaction that no longer exists.
Matches the wrapper pattern used by surrealdb-go (Transaction struct with closed bool, external/sdk-refs/go/transaction.go:24) and surrealdb-js (SurrealTransaction extends SurrealQueryable, external/sdk-refs/js/.../api/transaction.ts:13).
SurrealDB.attach! — Function
attach!(client) -> SurrealSessionCreate a new ephemeral session on the server (SurrealDB v3+) and return a SurrealSession wrapper. The session is independent: its own namespace, database, auth, and variables. Close with close!.
Matches the wrapped-session API used by surrealdb-go (db.Attach), surrealdb-py (AsyncSurrealSession / BlockingSurrealSession), and surrealdb-js (newSession).
WebSocket-only (not supported on HTTP connections).
SurrealDB.detach! — Function
detach!(client, session_id::UUID)Destroy a server-side session by raw UUID (SurrealDB v3+). Prefer close! on a SurrealSession; use this when you only have a bare UUID (e.g. from sessions listing).
SurrealDB.sessions — Function
sessions(client)List active session UUIDs on the server (SurrealDB v3+).
Returns Vector{UUID}.
SurrealDB.SurrealSession — Type
SurrealSessionA v3+ server-side session wrapping a SurrealClient.
Fields:
client::SurrealClient— the underlying connectionsession_id::UUID— the server-assigned session identifier
All operations on this session are scoped to the session's namespace, database, auth, and variables.
Import / Export
SurrealDB.export_db — Function
export_db(client::SurrealClient, filepath::String)Export the current namespace and database to a file.
SurrealDB.import_db — Function
import_db(client::SurrealClient, filepath::String)Import data from a file into the current namespace and database.