Skip to content

SQL

Use Atoll's fully integrated, statically checked SQL language.

Updated View as Markdown

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:

  1. resolve the model, fields, relations, and schema;
  2. type-check clauses, projections, parameters, and result shape;
  3. select a datasource dialect and apply its feature gates;
  4. render one or more fixed prepared statements;
  5. hash and register each statement with its row encoding;
  6. 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:

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.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close