Atoll provides full SQL language integration. SQL is a first-class part of Atoll source: the lexer and parser understand query forms, semantic analysis resolves models and columns, the type checker verifies expressions and result rows, and the compiler emits fixed prepared statements for the selected database engine.
This is not a library that builds SQL strings. Integrated queries participate in Atoll’s type, error, effect, module, and tooling systems just like other expressions.
schema shop
model Order {
@id
id: int
customer_id: int
total: float
}
fn open_orders(wanted_customer_id: int): []Order ! QueryError {
return FROM Order
WHERE customer_id == wanted_customer_id
ORDER BY id DESC?
}The function’s return type is checked against the query result. The local
wanted_customer_id becomes a typed prepared parameter. The query’s postfix
? propagates QueryError, and execution can suspend without introducing a
second function syntax.
Language integration
Full integration means each layer has an explicit responsibility:
| Layer | SQL responsibility |
|---|---|
| Source | Query verbs, clauses, projections, joins, writes, transactions, and model declarations have grammar |
| Names | Models, fields, relations, schemas, functions, and source locals resolve by identity |
| Types | Predicates, parameters, projections, aggregates, keys, and returned rows are checked |
| Effects | Execution contributes fallibility, suspension, and configured host capabilities |
| Planning | Queries become typed plans rather than runtime strings |
| Dialects | One checked plan renders to the selected engine’s fixed SQL |
| Runtime | Values cross the SQL ABI as parameters and typed row carriers |
| Tooling | Diagnostics point to Atoll query source rather than generated SQL offsets |
An integrated SQL expression can be assigned, returned, matched as a
Result, composed through a QueryBuilder, or placed in a transaction:
fn find_order(order_id: int): Order? ! QueryError {
order := GET Order(order_id)?
return order
}SQL remains SQL—the guide uses familiar FROM, WHERE, JOIN, GROUP BY,
ORDER BY, INSERT, UPDATE, DELETE, and RETURNING forms—but its values
and errors belong to the surrounding Atoll program.
Compilation
An executable query passes through a fixed pipeline:
- resolve the model, fields, relations, and schema;
- type-check clauses, projections, parameters, and result shape;
- select a datasource dialect and apply its feature gates;
- render one or more fixed prepared statements;
- hash and register each statement with its row encoding;
- emit a suspending host call that binds runtime arguments.
Runtime values fill prepared parameters. They do not become table names, column names, keywords, or arbitrary SQL fragments. Features such as runtime sort direction work by pre-rendering bounded statement alternatives.
The generated SQL is therefore fixed for a compiled query plan. User input cannot escape parameter encoding and become executable query text. Dynamic identifiers or arbitrary SQL fragments require a separately authorized raw host integration; they are not hidden escape hatches in the integrated language.
SQL surface
The section covers the complete integrated workflow:
| Area | Atoll forms |
|---|---|
| Persistence | model, keys, relations, indexes, and schema |
| Routing | Datasources, dialect selection, and read-only policy |
| Reads | FROM, ONE FROM, and primary-key GET |
| Relational clauses | filters, joins, projections, grouping, aggregates, ordering, and paging |
| Writes | SAVE, INSERT, UPDATE, UPSERT, DELETE, REMOVE, and RETURNING |
| Composition | Compile-time QueryBuilder[T] templates |
| Analytics | Host-resident Frame[Row] plans |
| Atomicity | Checked transaction blocks |
| Advanced SQL | CTEs, subqueries, sets, windows, search, vectors, locking, and conditional dialect plans |
Support for a particular advanced construct can still depend on the selected database. Full language integration means unsupported combinations are diagnosed at compilation; it does not pretend PostgreSQL, MySQL, SQLite, Turso, DataFusion, and DuckDB expose identical features.
Results
Every executable query returns Result[..., QueryError]. The success carrier
depends on the verb:
| Query family | Typical success |
|---|---|
| Scanning read | []Model |
| Single read | Model? |
| Batch primary-key read | Map[Key, Model] |
| Write | Saved row, projected rows, boolean, or affected count |
AS FRAME |
Host-resident Frame[Row] |
Postfix ? applies to the whole query and propagates QueryError.
Errors
QueryError separates engine failures, row-encoding failures, and missing
runtime backends. Portable error codes classify constraints, conflicts,
connection failures, missing objects, timeouts, permissions, and read-only
violations without parsing a human message.
Guide map
The guide separates declarations, query clauses, execution forms, and engine-gated features:
- Models, Schemas, and Datasources define persistence and routing.
- Reads, Filters, Projections, Joins, and Aggregates cover read queries.
- Writes and Transactions cover mutation and atomicity.
- Composition, Frames, and Advanced cover reusable and engine-specific query forms.
The legacy docs/model.md describes inheritance, abstract/data models,
behaviors, and validation DSLs that are not represented by the current
ModelDecl. They are not part of this guide.
Pages marked provisional describe a parser or semantic surface whose engine,
DDL, or runtime coverage is not yet uniform. They identify those boundaries
instead of treating every accepted syntax form as production-complete.