Package-level declarations
Types
A QueryBackendFactory that creates each aggregate's binding once and reuses it.
A query that admission let through for one subscription, with the entry it ran under and the resolution of every field reference it carries. Only QueryAdmission creates it, so a QueryBackend cannot receive a query that skipped admission.
One window of records. total is present when the window asked for it; positions holds each row's native cursor position, in row order, for a PageWindow.Keyset.
Several observers behind one: each callback reaches every delegate, a failing delegate is logged and does not stop the others, and audits are built when any delegate wants them.
A record's position in a cursor sort: one native value per sort field, in sort order, exactly as the storage orders them (BSON values for MongoDB, hit.sort() values for Elasticsearch). Only the backend that produced it interprets the values.
The backend half of a cursor token: native position values to bytes and back. decode throws on any payload it did not produce for a sort of size fields; the core reports every such failure as the invalid cursor error.
Which groups QueryBackend.aggregate returns.
Which records QueryBackend.page returns.
How a backend hands a runtime POJO operand to its driver.
The one admission pipeline of an aggregate's queries: it turns what a caller submitted into the AdmittedQuery a QueryBackend may execute, in the fixed order of the design (§5.4):
One query as an audit trail sees it: who asked (read the principal from context; Wow does not own identity), what shape of query on which model version, under which restrictions, and what came back. It never carries a filter value, so no personal data from the query reaches the audit log.
Aggregate-bound storage SPI: four primitives that only check natively, translate and execute.
What a storage supplies for one aggregate's read model: the backend that executes admitted queries and the storage adapter that reports its native facts. The QuerySchemaCatalog compiles those facts with the model's sources and sensitivity; the storage never builds the schema itself.
Pairs a query backend of read model B with its storage adapter, for each aggregate.
The registration SPI of a query storage (design §5.5): under one name, the factories that pair a query backend with its schema provider for each aggregate, one per read model the storage serves.
Every provider's read models by name; rejects two providers that supply one read model under one name.
Size limits and expensive-operator gates for one QueryEntry, checked at admission step 0: against the query as the caller submitted it plus the caller's scope from the edge, before any extension rewrites it. A route's selection (what a load route names in its URL), policy conditions, the model's default scope and cursor tie-breakers therefore never count, and a policy may use a gated operator.
Where a query came from. The gateway reads it once, when the query is subscribed, together with the caller's scope.
What a gateway requires of a query's QueryEntry before admitting it, and the budget each entry runs under.
A query the caller got right that the server failed to run: a mask strategy that failed, a cursor position that does not encode, a stored record or backend row that breaks integrity (an undeclared event bodyType, a non-finite number), a storage that timed out or failed on some shards. InternalServerError (HTTP 500), never a me.ahoo.wow.query.schema.QueryViolation: the caller cannot fix it by changing the request.
Logs every failed query by who must act on it:
Publishes one QueryAudit per query as meters (§10 可观测):
One gateway operation as QueryAdmission runs it: its queryType, the entry budget of step 0 and the finishing steps 4 to 6.
A mandatory restriction of an aggregate's queries, evaluated at admission step 2 (QueryAdmission).
A query request the client got wrong: IllegalArgument with the human errorMsg and one binding error naming where (name, a JSON path or body) and which rule (code, stable and machine-readable). violation is the catalog entry it renders, when the rule is one (QueryViolation.Kind.REQUEST); decoding errors state only a code.
The caller's scope, split by provenance. Both halves restrict the query; only the authenticated half counts as provided when a gateway requires an authenticated scope.
Where a caller's scope came from. Only AUTHENTICATED scope is a security boundary.
An HTTP query whose authenticated scope misses the field that the model requires, rejected because QueryEntryPolicy.requireAuthenticatedScope is on. A declared scope for field does not count.
One field reference of an AdmittedQuery, resolved once by admission for this request.
Routes each aggregate to the factory of its route, or to defaultFactory.
Functions
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, 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). 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 idle timeout.
Runs this query as a nested in-process query; see forInProcessQuery.
The authenticated part of the caller's scope.
Throws a QueryExecutionException with message unless value holds.
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 masking cannot 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 context for a query issued from inside a query extension, a policy or a cache loader: the inherited caller scope, route selection and entry are dropped and the entry is QueryEntry.IN_PROCESS, so an HTTP caller's budgets and scope do not leak into a nested lookup.
The records of query, streamed: at most its limit, or all of them when the limit is 0.
Masks record, a record of this schema's model, by the schema's response masks, in place.
One page of query with the total: page(Offset(offset, size, withTotal = true)).
The caller's whole scope, whatever its provenance: what restricts the query.
The route selection the query must stay within; see withQuerySelection.
This operand as a non-null scalar driver value, as a range bound or a term needs: a String, Number or Boolean, or a native POJO under PojoOperands.NATIVE.
The first record of query: page(Offset(0, 1, withTotal = false)).
Appends a declared scope; see withQueryScope.
Appends scope to the caller's scope; its authenticated half also to authenticatedQueryScope.
Appends a route selection: what a load route names in its URL, the aggregate id, a version range, and the tenant and owner its path carries. It is an operation constraint, not caller scope: admission appends it at step 2 with the caller scope, after every QueryFilter, so a rewrite can neither see nor remove it, and it is neither budgeted as scope nor reported among the audit's scope fields.