Query expressions resolve bare model fields as columns and ordinary source locals as prepared-statement parameters.
fn page(minimum: int, limit: int): []Booking ! QueryError {
return FROM Booking
WHERE passengers >= minimum
ORDER BY created_at DESC, id ASC
LIMIT limit?
}The compiler checks column names, operator types, parameter encodings, and the selected engine’s clause support.
Qualify a field with its model name when a source local has the same spelling or when a join introduces another column with that name.
Predicates
Repeat WHERE for an implicit conjunction, or use &&, ||, and !:
rows := FROM Booking
WHERE active
WHERE total > minimum && status != cancelled?Arithmetic, scalar functions, IN, EXISTS, and scalar subqueries can appear
inside predicates where their types fit.
rows := FROM Booking
WHERE status in allowed_statuses
WHERE total >= minimum?Bound collections and subqueries use compiler-supported IN encodings. The
right-hand query must project one compatible column.
Optional database values follow SQL null semantics. Use the query language’s
supported null checks rather than assuming ordinary boolean equality turns a
missing value into false in every dialect.
Ordering
Use ASC or DESC after each key:
rows := FROM Booking
ORDER BY priority DESC, created_at ASC?An expression of type SortDir or bool may choose a runtime direction for a
plain key. The compiler pre-renders statement permutations rather than binding
an SQL keyword. At most six runtime-direction keys are accepted.
direction: SortDir = if descending { Desc } else { Asc }
rows := FROM Booking
ORDER BY created_at direction?With bool, true means descending. The bounded six-key limit prevents an
unbounded prepared-statement explosion.
Paging
LIMIT and OFFSET accept checked integer expressions:
rows := FROM Booking
ORDER BY id
LIMIT page_size
OFFSET page * page_size?Paging without stable ordering may return different rows between executions.
Validate untrusted page sizes and offsets in Atoll before executing the query. The compiler checks types and dialect support; application range policy remains the caller’s responsibility.
For keyset pagination, express a stable key predicate and ordering rather than
increasing OFFSET indefinitely.
Guards
Selected clauses accept an if guard:
rows := FROM Booking
WHERE status == wanted if filter_status
ORDER BY created_at DESC if newest_first?Guarded WHERE and HAVING use boolean parameter gates. A guarded static
ORDER BY key uses a CASE gate. This remains one fixed prepared statement.
The guarded expression is still type-checked even when a particular runtime
call supplies false. Guards control SQL behavior, not source reachability.
Shape-changing guards are rejected. Current unsupported combinations include:
- conditional joins;
- conditional update assignments;
- guarded set-operation ordering;
- a runtime sort direction and
ifguard on the same key.
Choose between two complete queries with ordinary if when a guard changes
row cardinality or statement shape.
Statement stability
Column names, operators, clause order, and SQL keywords remain compile-time choices. Runtime values can affect predicates, limits, offsets, guards, and a bounded direction selector. This keeps statement registration and row decoding fixed for the compiled program.