QueryBackend
Aggregate-bound storage port: four primitives that only check natively, translate and execute.
The core derives every query shape from them (see single, list, paged, cursor, countBounded and aggregate in BackendQueries.kt): single is page(Offset(0, 1, withTotal = false)), list is stream, paged is page(Offset(..., withTotal = true)), cursor is page(Keyset). Windows come only from the core; the core also owns the cursor token shell, the residual aggregation operators the storage declares RESIDUAL, the empty summary row and the bound of a count.
Every input is an AdmittedQuery: validated against its schema, normalized, with each field reference resolved, and carrying the execution timeout its budget gives, which a backend passes to its storage (SET LOCAL statement_timeout, maxTimeMS); the core enforces the same timeout around every call. The gateway admits through a QueryAdmission instance, whose step 3 appends model defaults such as Snapshot ACTIVE. Direct callers admit through QueryAdmission.Trusted, which skips steps 0 to 3, so they supply any required deletion or access predicates themselves. A snapshot backend always restricts its records to its aggregateType itself: the aggregate type is not a filter of the query.
Every collection of a returned flow, and every call, must own fresh mutable ObjectNode instances. Implementations must not cache or share nodes across calls, emit cached nodes, or mutate nodes after emitting them.
Results must contain only standard JSON-tree values: the backend converts its driver's values (Map/Document, BSON values, decimals) to them. The core checks every returned row, so no backend repeats the check: a row with a NaN, an infinity, a POJO, a binary or missing node fails the query in the core.
Inheritors
Properties
The aggregate type whose records this backend reads.
Encodes and decodes the native CursorPositions page returns for a PageWindow.Keyset.
Functions
Streams the groups of query in its effective sort order, at most GroupWindow.First.limit of them, or every group for GroupWindow.All. The core has already removed from query what it computes itself.
The groups of query. The core plans the residual operators the storage declares RESIDUAL: it removes them from the query it sends down, asks for every group when an operator needs them all, and applies dense fill, windows, HAVING and top-N (or the limit) to the rows that come back. An aggregation without groups always has its summary row: when the backend emits none, because no record matched, the core emits the empty summary (EmptyAggregationValues). Such a query has no HAVING (the protocol requires a group for one, AggregationQuery rejects it at construction), so a storage's native HAVING can never be what removed a summary row; with groups, rows a HAVING removes are not replaced. When it reads every group, budget's QueryBudget.maxResidualGroups bounds how many it processes, dense fill rows included: HAVING can discard every fill row, so without counting them a sparse fine-grained dense histogram would generate rows until the timeout.
The records of query as a resumable stream: keyset pages of CursorQuery.size records, each its own QueryBackend.page call within the admitted timeout, one after the other from after the query's cursor token, until a page comes back short or limit records were emitted (null: no limit). Each record carries the token of its position.
The number of records matching query's filter. When query.query.limit is set the backend may stop counting after limit + 1 matches (count(*) over a LIMIT limit + 1 subquery, MongoDB's countDocuments limit): the core turns any count above the limit into a bounded CountResult. A null limit asks for the exact count.
The number of records matching query, bounded by its limit: QueryBackend.count, a storage failure reported as storageFault, a negative answer as a server fault. A count above the limit is the limit, not exact: "at least limit".
One cursor page of query: page(Keyset) for one row more than the page, the look-ahead that decides whether a next page exists. The next token encodes the native position of the page's last row, never a value from the rows, so no value of a row can leak into it. A token that does not decode for this model and effective sort is rejected as Invalid cursor. before any I/O.
The records of query, streamed: at most its limit, or all of them when the limit is 0.
Returns one window of query's records: for PageWindow.Offset the rows and, when asked, the total; for PageWindow.Keyset the rows after the position and each row's native position, taken before any field added for the position is stripped from the row.
One page of query with its total as PagedQuery.total asks: page(Offset(offset, size)) with the exact total for TotalMode.EXACT, the total bounded by totalLimit for TotalMode.BOUNDED (exact when totalLimit is null), and none for TotalMode.NONE.
The first record of query: page(Offset(0, 1, withTotal = false)).
Streams the records of query, at most query.limit of them, or all when the limit is 0.