TinyStore
Reference / SQL API for Python
On this page

Reference / SQL API for Python

SQL API for Python

Every public class, function and type of the SQL engine in tinystore, generated from its source. The SQL guide explains how to use them, and the Bun and Node, Go and Rust pages list the same API.

Sql

python
@dataclass(frozen=True, slots=True)
class Sql:
    text: str
    values: tuple[SqlArg, ...] = ()
    bare: bool = False  # whether it stands beside others in an and or an or without parentheses: one column's comparison

A piece of SQL and the values of its ?s, which are always values and never SQL.

sql makes one; a call, a batch and a table's query take it.

sql

python
sql = SqlMaker()

Done

python
@dataclass(frozen=True, slots=True)
class Done:
    changes: int
    last_insert_rowid: int

What a write changed: the rows, and SQLite's rowid of the row it inserted, 0 when none.

Database

python
class Database:
    name: str

An application's database: await store.database("app", migrations=...).

The verb says what comes back: all the rows, one or none, one value, or what a write changed. A write with returning goes through a read's verb and runs on the writer, its rows given once it is durable.

Database.describe

python
@property
def describe() -> str: ...

Database.handle

python
async def handle(connection: Connection) -> int: ...

Database.keep

python
def keep(
    method: int,
    body: bytes,
    make: Callable[[Connection], Awaitable[bytes]],
) -> Opener: ...

Database.via

python
def via(what: str) -> Via: ...

Database.refuse_around

python
def refuse_around(what: str) -> None: ...

Refuses a call made around the database's transaction from inside its function.

It would wait for the writer the transaction holds until the store rolled the transaction back, and then commit alone.

Database.bucket

python
@overload
def bucket[T](
    name: str,
    of: type[T],
    *,
    ttl: Duration | None = None,
    idle: Duration | None = None,
    encrypted: bool = False,
) -> Bucket[T]: ...
@overload
def bucket(
    name: str,
    of: None = None,
    *,
    ttl: Duration | None = None,
    idle: Duration | None = None,
    encrypted: bool = False,
) -> Bucket[Any]: ...
def bucket(
    name: str,
    of: Any = None,
    *,
    ttl: Duration | None = None,
    idle: Duration | None = None,
    encrypted: bool = False,
) -> Bucket[Any]: ...

A bucket of values by key kept in this database's file, beside its tables.

The same calls as store.bucket's, and its writes commit with the rows in db.tx, through tx.with_(bucket):

sessions = db.bucket("sessions", Session, idle="30d")

Database.search_index

python
@overload
def search_index[T](
    name: str,
    of: type[T],
    *,
    table: str,
    key: str | None = None,
    fields: Fields,
    filters: Sequence[str] = (),
    typo_tolerance: bool | None = None,
    vectors: Vectors | None = None,
    hybrid: Hybrid | None = None,
    rebuild: Literal['automatic', 'manual'] | None = None,
) -> TableIndex[T]: ...
@overload
def search_index(
    name: str,
    of: None = None,
    *,
    table: str,
    key: str | None = None,
    fields: Fields,
    filters: Sequence[str] = (),
    typo_tolerance: bool | None = None,
    vectors: Vectors | None = None,
    hybrid: Hybrid | None = None,
    rebuild: Literal['automatic', 'manual'] | None = None,
) -> TableIndex[dict[str, Any]]: ...
def search_index(
    name: str,
    of: Any = None,
    *,
    table: str,
    key: str | None = None,
    fields: Fields,
    filters: Sequence[str] = (),
    typo_tolerance: bool | None = None,
    vectors: Vectors | None = None,
    hybrid: Hybrid | None = None,
    rebuild: Literal['automatic', 'manual'] | None = None,
) -> TableIndex[Any]: ...

An index of a table of this database, kept in its file: its rows found again by their words or vectors.

Each hit's value is its row as all reads it. The table owns the rows and the index follows them: every change of a row, by any statement, trigger or migration, reaches it in the commit that makes it, and one by a process beside the store within a second:

articles = db.search_index("articles_search", Article, table="articles", fields={"title": 2, "body": 1})

Database.drop_search_index

python
async def drop_search_index(name: str) -> bool: ...

Drops a table's index this database keeps, its triggers off the table; says whether there was one.

Database.queue

python
@overload
def queue[T](
    name: str,
    of: type[T],
    *,
    attempts: int | None = None,
    backoff: Backoff | None = None,
    timeout: Duration | None = None,
    concurrency: int | Concurrency | None = None,
    rate: str | None = None,
    dedupe: Duration | None = None,
    keep: Duration | None = None,
    max_waiting: int | None = None,
) -> Queue[T]: ...
@overload
def queue(
    name: str,
    of: None = None,
    *,
    attempts: int | None = None,
    backoff: Backoff | None = None,
    timeout: Duration | None = None,
    concurrency: int | Concurrency | None = None,
    rate: str | None = None,
    dedupe: Duration | None = None,
    keep: Duration | None = None,
    max_waiting: int | None = None,
) -> Queue[Any]: ...
def queue(
    name: str,
    of: Any = None,
    *,
    attempts: int | None = None,
    backoff: Backoff | None = None,
    timeout: Duration | None = None,
    concurrency: int | Concurrency | None = None,
    rate: str | None = None,
    dedupe: Duration | None = None,
    keep: Duration | None = None,
    max_waiting: int | None = None,
) -> Queue[Any]: ...

A queue of jobs kept in this database's file, as store.queue keeps one in jobs.db.

The same calls and workers, and its jobs commit with the rows in db.tx, through tx.with_(queue). It shares the database's writer, which is the point and its cost.

Database.all

python
@overload
async def all[T](of: type[T], statement: Statement, /, *values: Any) -> list[T]: ...
@overload
async def all(statement: Statement, /, *values: Any) -> list[dict[str, Any]]: ...
async def all(first: Any, /, *rest: Any) -> list[Any]: ...

Every row a statement gives: await db.all(Note, "select * from notes where author_id = ?", user_id).

Database.one

python
@overload
async def one[T](of: type[T], statement: Statement, /, *values: Any) -> T | None: ...
@overload
async def one(statement: Statement, /, *values: Any) -> dict[str, Any] | None: ...
async def one(first: Any, /, *rest: Any) -> Any: ...

The one row a statement gives, or None; two are InvalidError, and a write that gave them rolls back.

Database.scalar

python
@overload
async def scalar[T](of: type[T], statement: Statement, /, *values: Any) -> T: ...
@overload
async def scalar(statement: Statement, /, *values: Any) -> Any: ...
async def scalar(first: Any, /, *rest: Any) -> Any: ...

The one value of the one row a statement gives, as count(*) does; None as SQL answers it.

Database.columns

python
async def columns(statement: Statement, /, *values: Any) -> dict[str, list[Any]]: ...

What all gives, by its columns: a list a column, by the column's name.

For rows by the thousand, a chart's points: they come faster, and nobody turns rows into columns after.

Database.each

python
@overload
def each[T](of: type[T], statement: Statement, /, *values: Any) -> AsyncIterator[T]: ...
@overload
def each(statement: Statement, /, *values: Any) -> AsyncIterator[dict[str, Any]]: ...
def each(first: Any, /, *rest: Any) -> AsyncIterator[Any]: ...

The rows a statement gives, one at a time as their parts arrive, from one snapshot.

Database.table

python
@overload
def table[T](name: str, of: type[T]) -> Table[T]: ...
@overload
def table(name: str, of: None = None) -> Table[dict[str, Any]]: ...
def table(name: str, of: Any = None) -> Table[Any]: ...

A table of the database, typed where it opens: its rows' inserts and upserts, and queries.

It costs nothing until its first call; open each once, in the module that owns it: notes = db.table("notes", Note).

Database.exec

python
async def exec(statement: Statement, /, *values: Any) -> Done: ...

Runs a write once it is durable; writes from many callers share a commit, each failing alone.

Database.batch

python
async def batch(statements: Sequence[Sql]) -> list[Done]: ...

Statements known before they run, written as one: all of them or none, in a shared commit.

Database.tx

python
async def tx[R](fn: Callable[[SqlTx], Awaitable[R]]) -> R: ...

Runs fn in a transaction that holds the writer, for writes that depend on what its reads found.

Returning commits, an exception rolls back. It runs once, five seconds at most, past which the store rolls it back; inside it, call nothing that waits on the world.

Database.rows

python
async def rows(statement: Sql, want: Want) -> Answered: ...

Database.exec_piece

python
async def exec_piece(statement: Sql) -> Done: ...

Database.each_piece

python
def each_piece(statement: Sql) -> AsyncIterator[dict[str, SqlValue]] | None: ...

TxQueue

python
class TxQueue[T]:
    ...

A queue's calls inside a database's transaction, from tx.with_(queue).

A job it adds is there only if the transaction commits, and the queue's workers find it once it has. A worker, a watch and a page work outside.

TxQueue.add

python
async def add(value: T, **options: Any) -> bool: ...

Adds a job unless its id is taken, as queue.add does, with the transaction.

TxQueue.set

python
async def set(id: str, value: T, **options: Any) -> None: ...

TxQueue.update

python
async def update(id: str, value: T, **options: Any) -> bool: ...

TxQueue.cancel

python
async def cancel(id: str) -> bool: ...

TxQueue.get

python
async def get(id: str) -> Job[T] | None: ...

The job under id as the transaction sees it, its own writes among it.

SqlTx

python
class SqlTx:
    ...

A database's transaction, from db.tx.

Its reads see its writes, and a call that fails leaves it as it was before the call. Its calls go one at a time, in order.

SqlTx.describe

python
@property
def describe() -> str: ...

SqlTx.with_

python
@overload
def with_[T](handle: Bucket[T]) -> Bucket[T]: ...
@overload
def with_[T](handle: Queue[T]) -> TxQueue[T]: ...
@overload
def with_[T](handle: Channel[T]) -> TxChannel[T]: ...
def with_(
    handle: Bucket[Any] | Queue[Any] | Channel[Any],
) -> Bucket[Any] | TxQueue[Any] | TxChannel[Any]: ...

A bucket or a queue opened from this database, or a channel, inside the transaction.

What it writes commits with the rows or not at all, and what it reads sees what the transaction wrote; a message is handed over at the commit.

SqlTx.all

python
@overload
async def all[T](of: type[T], statement: Statement, /, *values: Any) -> list[T]: ...
@overload
async def all(statement: Statement, /, *values: Any) -> list[dict[str, Any]]: ...
async def all(first: Any, /, *rest: Any) -> list[Any]: ...

SqlTx.one

python
@overload
async def one[T](of: type[T], statement: Statement, /, *values: Any) -> T | None: ...
@overload
async def one(statement: Statement, /, *values: Any) -> dict[str, Any] | None: ...
async def one(first: Any, /, *rest: Any) -> Any: ...

SqlTx.scalar

python
@overload
async def scalar[T](of: type[T], statement: Statement, /, *values: Any) -> T: ...
@overload
async def scalar(statement: Statement, /, *values: Any) -> Any: ...
async def scalar(first: Any, /, *rest: Any) -> Any: ...

SqlTx.exec

python
async def exec(statement: Statement, /, *values: Any) -> Done: ...

SqlTx.table

python
@overload
def table[T](name: str, of: type[T]) -> Table[T]: ...
@overload
def table(name: str, of: None = None) -> Table[dict[str, Any]]: ...
def table(name: str, of: Any = None) -> Table[Any]: ...

A table inside the transaction: its calls are the transaction's.

SqlTx.rows

python
async def rows(statement: Sql, want: Want) -> Answered: ...

SqlTx.exec_piece

python
async def exec_piece(statement: Sql) -> Done: ...

SqlTx.each_piece

python
def each_piece(statement: Sql) -> AsyncIterator[dict[str, SqlValue]] | None: ...

SqlTx.end

python
async def end(commit: bool) -> None: ...

Sends the last call, commit or roll back, and waits for the store's word.

SqlTx.nested

python
async def nested(method: int, body: bytes) -> bytes: ...

A call of kv or jobs in the transaction: its method and its request, and the method's answer.

RowPage

python
@dataclass(frozen=True, slots=True)
class RowPage[T]:
    rows: list[T]
    next: str | None

A page of a query's rows, and the cursor that reads the next; None after the last.

Query

python
class Query[T]:
    ...

A query on a table: a value, each call returning a new one, so that the first stays as it was.

all, one, scalar, count, each and list read; update and delete write.

Query.where

python
def where(
    condition: Condition | str | None = None,
    /,
    *values: Any,
    **equal: Any,
) -> Query[T]: ...

Adds a condition with and.

Equal values, as keywords or a dict, None as is null and a list as in (...); a piece of SQL from sql; or text and the values of its ?s.

Query.select

python
@overload
def select[R](of: type[R], columns: str | Sql, /) -> Query[R]: ...
@overload
def select(columns: str | Sql, /) -> Query[dict[str, Any]]: ...
def select(first: Any, /, *rest: Any) -> Query[Any]: ...

The columns a row holds, as SQL text, and the type of the row they make.

Query.include

python
def include(name: str, query: Query[Any]) -> Query[T]: ...

Gives each row the rows of another query as a list under name, from the same statement.

The query names the row it belongs to in its where, by this table's alias, names its columns with select, and has a limit, which counts for each row. Every value comes back as it is kept.

Query.join

python
def join(table: str, on: str | Sql) -> Query[T]: ...

Joins a table, "users as u", on a condition as SQL text or a piece of SQL.

Query.left_join

python
def left_join(table: str, on: str | Sql) -> Query[T]: ...

Joins a table whose columns may be None where no row of it meets the condition.

Query.group_by

python
def group_by(*columns: str) -> Query[T]: ...

Groups the rows by columns, quoted as names.

Query.having

python
def having(condition: Condition | str, /, *values: Any) -> Query[T]: ...

A condition on the groups, as where takes one.

Query.order_by

python
def order_by(column: str | Sql, direction: Direction = 'asc') -> Query[T]: ...

Orders the rows by a column, quoted as a name, or by a piece of SQL: order_by(sql("lower(title)")).

Query.limit

python
def limit(rows: int) -> Query[T]: ...

Query.offset

python
def offset(rows: int) -> Query[T]: ...

Query.to_sql

python
def to_sql() -> tuple[str, list[SqlArg]]: ...

The text and the values the query sends, to read or to log.

Query.embedded

python
def embedded() -> Sql: ...

The query inside another piece of SQL: a subquery, in parentheses.

Query.parts

python
@property
def parts() -> _Parts: ...

Query.of

python
@property
def of() -> Any: ...

Query.all

python
async def all() -> list[T]: ...

Query.one

python
async def one() -> T | None: ...

Query.scalar

python
async def scalar(of: Any = None) -> Any: ...

Query.count

python
async def count() -> int: ...

Every row the conditions match, without the order and the limit.

Query.each

python
async def each() -> AsyncIterator[T]: ...

The rows one at a time, as their parts arrive.

Query.list

python
async def list(*, limit: int = 100, after: str | None = None) -> RowPage[T]: ...

A page after the last row of the one before, by the query's order.

The order ends in a unique column so that no row is read twice or skipped; next reads the next page, and only of this query.

Query.explain

python
async def explain() -> list[str]: ...

SQLite's plan for the query, a line a step.

Query.update

python
async def update(
    values: Mapping[str, Any] | None = None,
    /,
    **columns: Any,
) -> Done: ...

Sets columns of the rows the conditions match, and says how many changed.

Query.delete

python
async def delete() -> Done: ...

Deletes the rows the conditions match, and says how many it deleted.

Table

python
class Table[T](Query[T]):
    ...

A table: its queries, and its rows' inserts and upserts.

notes = db.table("notes", Note), a dataclass, a TypedDict or a pydantic model, whose fields are the table's columns.

Table.insert

python
@overload
async def insert(row: T | Mapping[str, Any], /) -> T: ...
@overload
async def insert(rows: Sequence[T | Mapping[str, Any]], /) -> list[T]: ...
async def insert(given: Any, /) -> Any: ...

Inserts a row and gives it back as the file keeps it; a list of rows is one write, all or none.

Table.upsert

python
async def upsert(
    row: T | Mapping[str, Any],
    *,
    conflict: str | Sequence[str],
    update: Sequence[str],
    where: Condition | None = None,
) -> T | None: ...

Inserts a row, or, when its key is taken, sets the columns update names on the row that holds it.

It does so when that row meets where, and gives back the row as the file keeps it, or None when where kept it.

Generated from the source Updated 19 October 2026

esc
↑↓ navigate ↵ open ⇥ filter 0 results