query
query-decl ::= attribute* 'pub'? 'query' Ident '(' param-list ')' '->' TypeExpr
('across' '[' standpoint (',' …)* ']')?
'{' query-body '}'
query-body ::= ('with' Ident '=' query-body ';')*
'select' projection
'from' rule-body // Rule-atom grammar
('optional' 'from' rule-body)*
('where' rule-body)? // additional atoms
('group' 'by' expr ('having' expr)?)?
('order' 'by' expr ('asc' | 'desc')?)?
('limit' Nat ('offset' Nat)?)?
projection ::= expr | '{' struct-init-list '}' | 'path' Ident | aggregate
role-step ::= Ident quantifier? ('(' role-binders ')')? ('as' Ident)? mode-spec?
quantifier ::= '+' | '*' | '{' expr (',' expr)? '}' // expr of type Nat
mode-spec ::= 'mode' ('walk' | 'trail' | 'acyclic' | 'simple')
| 'shortest' | 'all-shortest' | 'any' | 'k-shortest' Nat
Role-step path-traversal chains (a.role+(b), c.ParentOf{1, n}(p: Person)) are admitted as predicate-call atoms in the rule-atom grammar (Rule-atom grammar) and are not separately defined here.
The evaluated query-body is select … from … (where …)?. Every other form
parse-refuses loudly with a feature-named code — never a generic
OE0001, never silently ignored: the result-shaping clauses (group by … having, order by … asc|desc, limit … offset) with OE0007; the
with CTE clause with OE1344; the graph-/path-traversal projections
(select shortest path …, select path …, … as <name> mode …) with
OE1345; optional from with OE1346; and the result-table set
operators (union / union all / intersect / except) with OE1347.
pub query active_leases_for(t: Person) -> [Lease] {
select l from l: Lease, l.tenant == t where is_active(l)
}
pub query ancestors_within(p: Person, n: Nat) -> Set<Person> {
select a from p.ParentOf{1, n}(a: Person)
}
pub query shortest_route(a: City, b: City) -> Path<City, Road> {
select shortest path r from a.road+(b) as r
}
pub query avg_age_by_dept() -> Map<Department, Real> {
select { dept: avg(p.age) }
from p: Person, p.works_in(dept: Department)
group by dept
}
pub query rich_friends_of(p: Person) -> Set<Person> {
with rich = select x from x: Person where x.net_worth > 1_000_000;
select f from p.knows(f: Person) where f in rich
}
pub query agreed_across(p: Person) -> Truth4Of<Bool>
across [LegalGround, MedicalGround]
{
select consents(p)
}
Subquery forms. Brace-bracketed inner queries used as expressions:
subquery ::= subquery-kind '{' rule-body '}' // Rule-atom grammar; no `from` keyword
subquery-kind ::= 'collect' | 'set' | 'one' | 'count' | 'exists'
The subquery body is a bare rule-atom list — there is no from keyword inside the braces (that prefix belongs to the top-level query-body only; an inner from parse-refuses with OE0001).
| Form | Returns | Notes |
|---|---|---|
collect { … } | List<T> | Projection-carrying; supports order/limit. |
set { … } | Set<T> | Projection-carrying; deduplicated. |
one { … } | Option<T> | Projection-carrying; None if no match. |
count { … } | Nat | No projection (counts matched tuples). |
exists { … } | Bool | No projection (K3 fail-closed; false on unknown). |
The cardinality-fold kinds count and exists evaluate over the bare atom
list above (count { p: Person }, exists { p: Person }). The
projection-carrying kinds collect / set / one parse but refuse at
ox check / ox build (OE1312); they never silently lower to a
cardinality fold. Use a derive head plus a top-level query projection.
Set operations on result tables: union, union all, intersect, except.
Subquery aggregates (admitted as aggregate projections inside subquery bodies and as the subquery-form <aggregate> { atoms }): count, count distinct, sum, avg, min, max, collect, set_collect, string_join, percentile. The expression-level comprehension form sum(expr for x in coll where pred) (Expression grammar) admits a subset (sum, count, min, max, avg) for non-subquery contexts.
Default lattice context: K3. With across [...]: FDE.