Skip to content

API Reference

/

Core

Builders

The query and CRUD methods of the Python SDK return builders. A builder holds one operation and sends nothing to the database until you run it. This page lists the methods of each builder, and the objects that the streaming methods return. For examples, see Executing queries, Data manipulation and Streaming results.

BuilderReturned by
CRUD builderselect(), create(), update(), upsert(), delete() and relate()
Insert builderinsert()
Query builderquery()
Into builder.into() on an asynchronous query builder
Batchbatch()

Connections, sessions and transactions return the same builders. The blocking classes start with Sync and the asynchronous classes with Async. Every class on this page except the batch is exported from surrealdb, so you can use the names in type annotations.

Blocking connectionAsynchronous connection
Run the builder.execute(), a data clause such as .merge(data), or iterationawait builder, await builder.execute(), or async for
A write given its dataRuns at once and returns the result, not a builderReturns a builder with the data set, to await
Read the records one at a timefor row in builder or .rows()async for row in builder or .rows()

These rules apply to every builder:

  • A builder runs once. Running it again returns the first result and sends no second request. That includes .execute() after a data clause, and awaiting one builder from two tasks.

  • A builder that has run cannot change. A data clause or a modifier after the builder has run raises SurrealError: Cannot reconfigure a SyncCrudBuilder after it has executed.

  • A streamed builder cannot run again. .execute() or await after .rows(), .statements() or .stream() raises SurrealError, because the operation has already run.

  • A builder that is never run warns. When Python discards a builder that never ran, the SDK emits a RuntimeWarning that names the call and the line it was made on.

  • A blocking builder is not its result. len() and indexing raise TypeError, and bool() is always True.

  • A builder has one owner. Running a blocking builder from several threads sends one request, but changing it from several threads at the same time is not safe.

SyncCrudBuilder[T] on a blocking connection, AsyncCrudBuilder[T] on an asynchronous connection. T is the type of the result: a record as a dict, None, a list of records, or the class that into= names.

A data clause sets the data of a write. On a blocking connection, it runs the statement and returns the result. On an asynchronous connection, it returns the builder, so you can add modifiers before await.

ClauseSurrealQLTaken by
.content(data)CONTENTcreate(), update(), upsert(), relate()
.replace(data)REPLACEcreate(), update(), upsert()
.merge(data)MERGEcreate(), update(), upsert()
.patch(data)PATCHcreate(), update(), upsert()

A clause on a builder that does not take it raises SurrealError.

Sets the whole content of each record. create(target, data), update(target, data), upsert(target, data) and relate(from_, edge, to, data) use this clause.

Syntax
builder.content(data)

Returns: the result of the statement on a blocking connection, or the builder on an asynchronous connection.

Replaces the whole content of each record, with the SurrealQL REPLACE clause. Unlike CONTENT, it raises an error when data changes a READONLY field.

Syntax
builder.replace(data)

Returns: the result of the statement on a blocking connection, or the builder on an asynchronous connection.

Changes the fields that data names and keeps every other field. A nested object merges at every level, and an array replaces the stored array.

Syntax
builder.merge(data)

Returns: the result of the statement on a blocking connection, or the builder on an asynchronous connection.

Applies a list of JSON Patch operations. data is the list, and each operation is a dictionary such as {"op": "replace", "path": "/age", "value": 36}.

Syntax
builder.patch(data)

Returns: the result of the statement on a blocking connection, or the builder on an asynchronous connection.

A modifier adds a clause to the statement and returns the builder, so you can chain modifiers. A modifier that the statement does not take raises SurrealError when you call it. On a blocking connection, call the modifiers before the data clause, because the data clause runs the statement.

ModifierSurrealQLselectcreateupdateupsertdeleterelate
.where()WHEREYesYesYesYes
.fetch()FETCHYes
.limit()LIMITYes
.start()STARTYes
.version()VERSIONYes
.output()RETURNYesYesYesYesYes
.timeout()TIMEOUTYesYesYesYesYesYes

Limits the statement to the records that match a condition.

Syntax
builder.where(condition, variables=None)

Parameter

Type

Description

conditionstr

A SurrealQL expression, such as

"name = $name"

. An empty condition raises

ValueError

.

variablesMapping[str, Value] | None

The values of the

$name

variables in

condition

. The names

_resource

,

_content

,

_data

,

_patches

,

_version

,

_from

,

_to

and

_edge

raise

ValueError

, because the builder uses them itself.

Returns: the builder

db.select(Table("person")).where("age > $min_age", {"min_age": 30}).execute()

Replaces each record link at the field paths that you name with the record that the link points to.

Syntax
builder.fetch(*fields)

fields are one or more field paths, such as "author" or "author.friends". A path that is not a field name, or field names separated by dots, raises ValueError.

Returns: the builder

Returns at most count records.

Syntax
builder.limit(count)

count is a whole number of at least 0, or the call raises ValueError.

Returns: the builder

Skips the first offset records.

Syntax
builder.start(offset)

offset is a whole number of at least 0, or the call raises ValueError.

Returns: the builder

Reads the records as they were at a point in time. Needs a datastore that keeps versions, such as SurrealKV with versioning (surrealkv+versioned://). Other datastores raise ConfigurationError.

Syntax
builder.version(at)

at is a datetime.datetime or a Datetime. A datetime without a time zone is read as UTC.

Returns: the builder

Sets what the statement returns, with the SurrealQL RETURN clause.

Syntax
builder.output(mode)

Parameter

Type

Description

modestr | Sequence[str]"after"

for each record after the change, the default for every write except

delete()

.

"before"

for each record before the change, the default for

delete()

.

"diff"

for the change as JSON Patch operations,

"none"

for nothing,

"null"

for

Null

, or a list of field paths for only those fields. Another string raises

ValueError

.

Returns: the builder

db.update(RecordID("person", "tobie")).output("diff").merge({"age": 37})

Makes the server stop the statement when it takes longer than duration, with the SurrealQL TIMEOUT clause. A statement that takes too long raises QueryError, with is_timed_out set to True. How long the client waits for a reply is a separate setting: see db.timeout().

Syntax
builder.timeout(duration)

duration is a Duration, a datetime.timedelta, a duration string such as "5s", or a whole number of seconds as an int. A duration of zero or less raises ValueError, and a float raises TypeError.

Returns: the builder

Runs the statement, with the data clause and modifiers that you set, and returns its result.

Syntax
builder.execute()

Returns: T, the result of the statement. On an asynchronous connection, await it: await builder.execute() is the same as await builder.

Reads the records that the statement returns, one at a time, as the server produces them. Nothing is sent until the iteration starts. See Streaming results.

Syntax
builder.rows(*, into=None, require_streaming=False)

Parameter

Type

Description

intotype | None

A class to map each record onto. Defaults to the

into=

of the method that made the builder.

require_streamingboolTrue

raises

UnsupportedFeatureError

where the records cannot be streamed, instead of reading them the buffered way. Defaults to

False

.

Returns: SyncRows[T], or AsyncRows[T] on an asynchronous connection

Iterating a CRUD builder is the same as iterating builder.rows(): for row in builder on a blocking connection, and async for row in builder on an asynchronous connection. Awaiting an asynchronous CRUD builder is the same as await builder.execute().

SyncInsertBuilder[T] on a blocking connection, AsyncInsertBuilder[T] on an asynchronous connection. insert(table, data) on a blocking connection runs at once, so you get this builder from insert(table) without data, or from any insert() on an asynchronous connection.

Sets the records to insert: a dict for one record, or a list of them.

Syntax
builder.content(data)

Returns: the inserted records as a list on a blocking connection, or the builder on an asynchronous connection

Makes the statement INSERT RELATION, so each record is an edge record with an in and an out field. insert(table, data, relation=True) does the same.

Syntax
builder.relation()

Returns: the builder, also on a blocking connection

The insert builder takes .output() and .timeout(), which work as on the CRUD builder. It takes no other modifier.

Runs the INSERT statement. A builder without data raises SurrealError.

Syntax
builder.execute()

Returns: list[T], the inserted records, also for one record

Reads the inserted records one at a time. It takes the same arguments as the .rows() of the CRUD builder, and iterating the builder is the same as iterating .rows().

Syntax
builder.rows(*, into=None, require_streaming=False)

Returns: SyncRows[T], or AsyncRows[T] on an asynchronous connection

SyncQueryBuilder on a blocking connection, AsyncQueryBuilder on an asynchronous connection, which query() returns.

Runs the query and returns one result for each statement. When a statement fails, it raises the error of the first statement that failed, after the server has run the whole query.

Syntax
builder.execute()

Returns: list[Value], one entry for each statement, also for one statement. On an asynchronous connection, await builder is the same as await builder.execute().

Runs the query and returns the result of the first statement.

Syntax
builder.first()

Returns: Value, or None when the query has no statements

Maps the results of the query onto a class: a dataclass, a pydantic BaseModel, or any class that takes keyword arguments.

Syntax
builder.into(cls, *, rows=False)

Parameter

Type

Description

clstype

The class to map onto. A value that is not a class raises

TypeError

.

rowsboolFalse

maps the results of the statements, in order, onto the fields of

cls

, so

cls

needs one field for each statement.

True

maps each record of the first statement's result onto

cls

. Defaults to

False

.

Returns: on a blocking connection, the query runs and the call returns one cls, or a list[cls] with rows=True. On an asynchronous connection, an into builder to await. A result that does not match the class raises UnexpectedResponseError.

Reads the rows of every statement of the query, one statement after the other, as the server produces them. A statement with one value gives that value as one row, and a statement whose result is NONE gives no row.

Syntax
builder.rows(*, into=None, require_streaming=False)

Parameter

Type

Description

intotype | None

A class to map each row onto. Each row must then be a record. Defaults to

None

.

require_streamingboolTrue

raises

UnsupportedFeatureError

where the rows cannot be streamed. Defaults to

False

.

Returns: SyncRows, or AsyncRows on an asynchronous connection

Reads one complete result for each statement, as each statement finishes. The loop raises the error of the first statement that fails.

Syntax
builder.statements(*, require_streaming=False)

Returns: a stream of StatementResult values: a QueryStream, or an AsyncQueryStream on an asynchronous connection. You use it in the same way as SyncRows.

Reads every value, error and completion of the query as a frame. A statement that fails gives an ErrorFrame and does not stop the loop. A query that cannot finish at all still raises.

Syntax
builder.stream(*, require_streaming=False)

Returns: a stream of ValueFrame, ErrorFrame and DoneFrame values: a QueryStream, or an AsyncQueryStream on an asynchronous connection

Iterating a query builder is the same as iterating builder.rows(). Awaiting an asynchronous query builder is the same as await builder.execute().

AsyncQueryIntoBuilder[T], which .into() returns on an asynchronous query builder. It shares the request of its query builder, so awaiting the query builder and its into builder sends one request.

Syntax
await builder.into(cls, rows=False)
await builder.into(cls, rows=False).execute()

Returns: when awaited, one cls, or a list[cls] with rows=True

The object that batch() returns on a connection or a session. It collects statements and sends them in one request, as one transaction. See Executing queries for the rules.

Adds statements to the batch.

Syntax
batch.query(query, vars=None)

Parameter

Type

Description

querystr

One or more SurrealQL statements. A statement that begins, commits or cancels a transaction raises

ValueError

.

varsMapping[str, Value] | None

Variables for the statements. Every statement of the batch can use them, and a name that the batch already holds with another value raises

ValueError

.

Returns: the batch, so you can chain calls

Sends the statements, wrapped in BEGIN TRANSACTION and COMMIT TRANSACTION. When a statement fails, it raises the error of that statement, and none of the statements are applied. An empty batch, or a RETURN that is not the last statement, raises ValueError.

Syntax
batch.execute()

Returns: list[Value], one result for each statement that you added. On an asynchronous connection, await it: the batch itself is not awaitable.

SyncRows[T] on a blocking connection, AsyncRows[T] on an asynchronous connection, which .rows() returns. A row is one item of the result of a statement: usually a record, or a value such as a name from SELECT VALUE. Both classes are exported for type annotations. The streams that .statements() and .stream() return, QueryStream and AsyncQueryStream, work in the same way.

UseBlockingAsynchronous
Read the rowsfor row in rows:async for row in rows:
Stop the query when the block endswith rows as stream:async with rows as stream:
Stop the queryrows.close()await rows.aclose()

A stream is read once: a second loop raises SurrealError. The query starts when the loop starts. Rows are provisional until the loop ends without an exception, because a statement that fails raises from the loop after its rows have arrived.

One complete result of a statement, which .statements() yields and DoneFrame holds. It is a frozen dataclass.

FieldTypeDescription
indexintThe position of the statement in the query, from 0
valueValueThe result of the statement: a list of rows, or one value when single is True
timestrThe time that the server took, as text such as "1.5ms"
query_typestr | None"live" for a LIVE SELECT, "kill" for a KILL, otherwise None
singleboolTrue when value is one value, such as the result of RETURN 1 or SELECT ... FROM ONLY

The values that .stream() yields. Each one is a frozen dataclass with the index of the statement that it belongs to.

One row of a statement, or the whole value of a statement with one value. The value is provisional until the DoneFrame of the same statement.

FieldTypeDescription
indexintThe position of the statement in the query
valueValueThe row or the value

A statement that failed. It takes back every ValueFrame of the same statement. The statements after it still run.

FieldTypeDescription
indexintThe position of the statement in the query
errorServerErrorThe error of the statement, such as a ThrownError
timestrThe time that the server took
query_typestr | None"live", "kill" or None, as for StatementResult

A statement that is complete.

FieldTypeDescription
indexintThe position of the statement in the query
resultStatementResultThe complete result of the statement

Was this page helpful?