basalt library Getting Started

Basalt — a type-safe query builder and ORM for Dart, inspired by basalt.

Stage 1 surface: typed schema (TableColumn/TableRef), expressions, the select*/insertInto/update/deleteFrom builders, SQL serialization, and the dialect-agnostic Connection interface. Concrete backends live in separate packages (e.g. basalt_sqlite).

Classes

Agg Annotations & Codegen
Binds an aggregate field to a private static select tear-off that returns the SQL projection (e.g. @Agg(CategoryRevenueRow._revenue)).
Aggregate<T> Schema & Columns
An aggregate over a column (or COUNT(*)), usable in select(...) and readable from a row via its readKey. Build with TableColumn.count, countAll, or the numeric aggregates (IntColumnAggregates).
AsChangeset Annotations & Codegen
Marks a data class for UPDATE generation against table (e.g. @AsChangeset(Users.table)). The generator emits a toUpdate() extension method returning an UpdateStatement whose SET clause is built from each writable field; the caller appends the .where(...) (typically on the primary key). @Column(readOnly: true) fields are skipped.
BlobSqlType Types & Codecs
BooleanSqlType Types & Codecs
Encodes a canonical Dart bool; each dialect's encodeParam maps it to the driver form (SQLite: bool->int). decode is lenient so it reads back either representation.
Column Annotations & Codegen
Maps a constructor field to a schema column and/or tunes its read/write direction. Without it, the field name selects the column by matching the generated schema's camelCase accessor.
ColumnValue<Tbl> Schema & Columns
A column-scoped assignment (column = value) for INSERT/UPDATE. The value is already encoded; Tbl keeps it bound to its table.
Connection Connection & Backends
Database-agnostic execution surface. The query builder produces statements; a Connection implementation serializes and runs them against a driver.
DateTimeSqlType Types & Codecs
Stored as epoch milliseconds (sortable and timezone-free).
DeleteStatement<Tbl> Insert, Update & Delete
DELETE FROM table WHERE ....
DoubleSqlType Types & Codecs
Expression<T, Tbl> Predicates & Expressions
A typed SQL expression.
FoldMappedQuery<R> Query Builder
A JOIN Query whose SQL rows are folded into fewer parents via folder.
ForeignKey Connection & Backends
A foreign-key target discovered during introspection.
HasMany Annotations & Codegen
Marks a one-to-many relation: column is the child's foreign key pointing at this row's primary key (e.g. @HasMany(Addresses.customerId) on a customer view). The field must be List<ChildRow> where ChildRow is @Queryable.
Insertable Annotations & Codegen
Marks a data class for INSERT generation against table (e.g. @Insertable(Users.table)). The generator emits two toInsert() extension methods returning an InsertStatement, mapping each writable field (everything except @Column(readOnly: true)) through TableColumn.set: one on the class itself (single-row insert) and one on Iterable of it, which batches every element into a single multi-row INSERT ... VALUES (...), (...).
InsertStatement<Tbl> Insert, Update & Delete
INSERT INTO table (...) VALUES (...).
IntrospectedColumn Connection & Backends
IntrospectedTable Connection & Backends
IntSqlType Types & Codecs
MappedQuery<R> Query Builder
A Query finished with a decoder — the executable SelectQuery.
NullableSqlType<T extends Object> Types & Codecs
Nullable variant of any SqlType: null passes through in both directions, non-null values delegate to inner.
OnConflict<Tbl> Insert, Update & Delete
Fluent builder for an ON CONFLICT clause (from InsertStatement.onConflict).
Ordering Query Builder
One ORDER BY term.
PrimaryKey<T, Tbl> Schema & Columns
A primary-key column.
Projection
One item in a SELECT projection: an expression plus an optional AS alias. Built from a Selection so the serializer stays purely AST-level.
Query<Scope> Query Builder
Immutable SELECT builder.
Queryable Annotations & Codegen
Marks a data class for query generation against table (e.g. @Queryable(Posts.table)). The generator emits a ThisClassQuery companion that is the canonical query, carrying a static fromRow reader (one RowReader.get per mapped field) and its RowMapper.
QueryBuilder SQL Serialization
Walks an untyped AST and emits (sql, params) for a given SqlDialect.
QuerySource<Tbl>
Something a query can read FROM or JOIN: a real table (TableRef) or an aliased one (TableAlias). columns are bound to the source's effective name (alias ?? table), so reads/predicates address the right instance.
RawSelection<T> Schema & Columns
A raw, typed SQL selection (escape hatch): emitted verbatim in the projection and read back by its readKey (the raw as alias). Uses ? placeholders.
Ref<T, Tbl, Target> Schema & Columns
A foreign-key column on Tbl that references the PrimaryKey of Target. Referencing the PK column object (a leaf) keeps it const-cycle free even for mutual foreign keys, and the shared T enforces matching key types.
Relation Annotations & Codegen
Marks a relation field filled by joining the table referenced by FK column and nesting the related object via its own generated reader, e.g. @Relation(Posts.authorId) final User? author;. The field MUST be a nullable, optional (named) parameter whose type is another @Queryable class.
Returning Insert, Update & Delete
Intermediate builder from WriteReturning.returning; call map / mapWith to attach a row decoder and produce an executable ReturningQuery.
ReturningQuery<R> Insert, Update & Delete
A write statement finished with a RETURNING projection and a row decoder — the executable analog of MappedQuery for INSERT/UPDATE/DELETE.
RowMapper<R> Query Builder
A reusable, codegen-friendly row decoder for a data class. @Queryable(Users) emits one of these (a single read built from RowReader.get calls). They compose freely — a Comment reader can call a Post reader on the same RowReader to nest objects, with no arity-specific machinery.
RowReader Query Builder
Reads typed values out of one result row, addressed by selection (a column or an aggregate), not by position. This is what makes a single map decoder work for any number of columns/tables: r.get(Users.name) returns a String regardless of where name sits in the projection, joins stay unambiguous (each column is keyed by table.name), and aggregates are keyed by their alias.
Selection<T>
Something selectable in a query's projection — a TableColumn or an Aggregate. Carries the SQL selectExpression to emit, an optional AS selectAlias, the readKey a RowReader uses to find the value, and the SqlType used to decode it.
SelectQuery<R>
The shape the serializer and Connection consume. Implemented by the terminal MappedQuery and FoldMappedQuery; Query is the builder that produces them.
SerialLock Connection & Backends
A minimal FIFO async mutex: serializes the run callbacks handed to it so that at most one is in flight at a time, in submission order.
SqlDialect SQL Serialization
SQL-dialect differences the serializer must account for. Keeping this behind an interface is the seam that lets each backend (SQLite, Postgres, ...) plug in its own quoting and placeholder style without touching the query builder. Concrete implementations live in the backend packages (e.g. basalt_sqlite).
SqlType<T> Types & Codecs
StringSqlType Types & Codecs
TableAlias<Tbl> Schema & Columns
An aliased table for self-joins (the same table joined more than once). Columns are rebound to the alias, so sender.col(Users.id) serializes as "sender"."id" and is distinct from recipient.col(Users.id).
TableColumn<T, Tbl> Schema & Columns
A typed column belonging to table Tbl.
TableRef<Tbl> Schema & Columns
Table descriptor: its name and full column list (the default projection for from/joins). Cycle-safe even with foreign keys because Ref points at a PrimaryKey leaf, not back at a TableRef.
UpdateAllStatement<Tbl> Insert, Update & Delete
Batch UPDATE: one statement that updates many rows with per-row values, joining the target table against a VALUES table on the key column(s):
UpdateStatement<Tbl> Insert, Update & Delete
UPDATE table SET ... WHERE ....
ValueColumn<T, Tbl> Schema & Columns
An ordinary value column.
WriteStatement Insert, Update & Delete
Statements that mutate rows and return an affected-row count rather than a result set. Sealed so the serializer can exhaustively switch over them.

Enums

ColumnType
Canonical column type — the backend normalizes its native type into one of these, and codegen maps it to a Dart type + SqlType.

Extensions

BoolExpression on Expression<bool, Tbl>
Boolean combinators are only meaningful on predicates, so they live on an extension over Expression<bool, Tbl> rather than the general class.
DoubleColumnAggregates on TableColumn<double, Tbl>
Numeric aggregates for double columns.
FoldMappedQueryExecute on FoldMappedQuery<R> Query Builder
Terminal helpers for FoldMappedQuery — one SQL round-trip, fold in Dart.
IntColumnAggregates on TableColumn<int, Tbl>
Numeric aggregates for integer columns. SQLite returns NULL over an empty set, so these decode to nullable Dart types.
MappedQueryExecute on MappedQuery<R> Query Builder
basalt-style terminal helpers so a finished query reads like query.load(db) / query.first(db) / query.optional(db).
NumColumnArithmetic on TableColumn<num, Tbl>
Typed arithmetic on numeric columns and expressions.
NumExpressionArithmetic on Expression<num, Tbl>
Typed arithmetic that chains on the result of a previous numeric expression.
QueryMapFold on Query<Object?>
Attach a row folder after JOINs — use the FoldMappedQueryExecute.load extension to run.
TextColumn on TableColumn<String, Tbl>
LIKE only makes sense for text columns.
WriteReturning on WriteStatement
Attaches a RETURNING clause to any write statement.

Functions

avg(Object operand, {String? as}) Aggregate<double?>
AVG over a numeric column or expression — always decodes to Aggregate<double?>. Alias defaults to avg_$column for columns.
countAll() Aggregate<int>
COUNT(*) — total row count.
countDistinct(TableColumn<Object?, Object?> column, {String? as}) Aggregate<int>
COUNT(DISTINCT col). Alias defaults to count_$column.
deleteFrom<Tbl>(TableRef<Tbl> table) DeleteStatement<Tbl>
from<Tbl>(QuerySource<Tbl> source) Query<Tbl>
Start a query from source (a table or an alias). Single-table scope keeps where strictly typed.
insertInto<Tbl>(TableRef<Tbl> table) InsertStatement<Tbl>
loadGroupedByFk<Tbl, K, C>(Connection db, QuerySource<Tbl> childSource, TableColumn<K, Tbl> fk, List<K> parentKeys, C readChild(RowReader reader)) Future<Map<K, List<C>>> Query Builder
Loads the children whose foreign key fk is one of parentKeys, grouped by that key — the belonging_to(parents).grouped_by(parents) pattern in a single query (avoids N+1). Every key in parentKeys is present in the result, mapping to an empty list when it has no children.
max<T extends num>(Object operand, {String? as}) Aggregate<T?>
MAX over a numeric column or expression — typed like sum (integer columns decode to Aggregate<int?>).
min<T extends num>(Object operand, {String? as}) Aggregate<T?>
MIN over a numeric column or expression — typed like sum (integer columns decode to Aggregate<int?>).
raw<T>(String sql, SqlType<T> type, {required String as, List<Object?> params = const []}) Selection<T>
A raw typed SQL selection for select([...]), read back via r.get(...). Write valid SQL yourself (qualify columns); bind values with ? + params.
rawCondition(String sql, {List<Object?> params = const []}) Expression<bool, Object?>
A raw boolean SQL fragment for having (and joined where/filter) — uses the relaxed Object? scope; ? placeholders bind params in order.
sum<T extends num>(Object operand, {String? as}) Aggregate<T?>
SUM over a numeric column or expression.
update<Tbl>(TableRef<Tbl> table) UpdateStatement<Tbl>
updateAll<Tbl>(TableRef<Tbl> table) UpdateAllStatement<Tbl> Insert, Update & Delete
Starts a batch UPDATE of table — see UpdateAllStatement.

Typedefs

CompiledQuery = (String, List<Object?>)
A serialized statement: the SQL text and its ordered bound parameters.
RowFolder<R> = List<R> Function(List<RowReader> readers)
Folds a flat JOIN result set into parent rows (e.g. @HasMany codegen).