Integrated reads are expressions. Every executed read returns
Result[T, QueryError]; postfix ? unwraps the success value and propagates a
query failure.
bookings := FROM Booking?The query execution call may suspend. Its error and suspension effects propagate through the enclosing function just like other typed host operations.
Result shapes
| Query | Unwrapped success type |
|---|---|
FROM Booking |
[]Booking |
ONE FROM Booking |
Booking? |
GET Booking(id) |
Booking? |
GET Booking(ids) |
Map[int, Booking] |
projected FROM |
list of projection rows |
projected ONE FROM |
optional projection row |
... AS FRAME |
Frame[Row] |
Without ?, wrap each success type in Result[..., QueryError].
The distinction between “no row” and “query failed” is preserved:
match GET Booking(booking_id) {
Ok(Some(booking)) => use(booking)
Ok(None) => report_missing(booking_id)
Err(error) => report_query_error(error)
}Do not convert both cases into one empty sentinel when the caller needs to respond differently.
Scans
FROM loads every matching row:
recent := FROM Booking
WHERE created_at >= cutoff
ORDER BY created_at DESC
LIMIT 25?ONE FROM requests at most one row and returns None when no row matches:
booking := ONE FROM Booking
WHERE reference == wanted?Ordering is important when several rows could match.
Without ORDER BY, the engine can choose any matching row. Use ONE FROM
only when uniqueness is guaranteed by a key/constraint or when an explicit
order defines which row is wanted.
Primary keys
GET is primary-key lookup sugar:
booking := GET Booking(booking_id)?Batch lookup accepts a list and returns a map. Missing keys are absent:
by_id := GET Booking(ids)?
match by_id.get(wanted_id) {
Some(booking) => use(booking)
None => report_missing(wanted_id)
}For a composite primary key, pass each component positionally. A batch uses a list of key tuples or compatible records.
Batch results are keyed for lookup, not source-order preservation. If output must follow the input key order, iterate the original key list and query the result map. Duplicate input keys correspond to one map entry.
Query boundaries
The query begins at its verb and consumes following query clauses. The postfix
? applies to the entire query:
rows := FROM Booking WHERE active?
count := rows.size()Parenthesize when continuing with normal Atoll member calls or embedding a query in a larger expression.
Query clauses belong to the parser’s integrated query expression, so formatting
one clause per line makes its boundary and final ? much easier to review.
Parameters
Source locals used inside a query become prepared parameters:
fn for_customer(customer_id: int): []Booking ! QueryError {
return FROM Booking
WHERE Booking.customer_id == customer_id?
}Qualifying the field makes a same-named local unambiguous. Parameters retain their Atoll types and are encoded through the SQL ABI; they are never pasted into SQL text.
Failures
QueryError provides portable classifications and helpers such as
is_constraint(), is_conflict(), is_retryable(), and is_not_found().
The runtime does not generally retry application transactions; retry only when
your operation is safe to repeat.
QueryError.Engine retains a portable SqlErrorCode, the engine’s native code,
and a human message. Encoding reports a typed result-carrier problem.
Backend reports missing or malformed runtime execution support. Branch on
portable codes first and reserve native codes for engine-specific policy.