PostgresQueryIndexes

The expression indexes of an aggregate type's snapshot table. Each index the aggregate declares in the Manifest becomes

CREATE INDEX CONCURRENTLY IF NOT EXISTS "<table>_<name>" ON "<table>" (tenant_id, <key> NULLS FIRST, ..., aggregate_id)
WHERE NOT deleted

on that aggregate's own table, led by the tenant, which admission adds to every query, and partial on the snapshots that are not deleted, its default scope. A key is a system column or the typed expression of a state.* path, exactly the text the SQL compiler compares and sorts by (PostgresSnapshotQueryExpressions.value, with the type of the binding the query model compiles for it), so the planner matches the two; NULLS FIRST is the compiler's ascending order. The name is PostgresIdentifiers.limited, since PostgreSQL index names are unique per schema, not per table.

A B-tree index ends with the columns the compiler ends a snapshot sort with (PostgresQueryLayout.SNAPSHOT's tie-breakers but the tenant): aggregate_id. A sort by its keys whose tie-breaker runs in the same direction is the index's order, forward or backward, with no sort: the compiler ends a sort with the tie-breaker in the direction of its last field (me.ahoo.wow.query.backend.tieBreakerDirection), so a sort by the keys in one direction is read in index order. An existing index whose definition is not the planned one is drift (PostgresQueryIndex.fingerprint).

An index of one key that holds many values (a multiple access attribute) is a GIN index of its jsonb node, USING gin ((<node>) jsonb_path_ops) WHERE NOT deleted: it serves the containment @> the SQL compiler writes for an equality, a membership and a containment of such a key, each value one @>. A GIN index takes no tenant; the planner ANDs it with the scope's.

The access attributes are indexed on the log tables too (planLog), for the events model's queries under an access policy: the same keys, partial on the key holding a value.

Functions

Link copied to clipboard
fun plan(context: String, aggregate: String, plan: QueryIndexPlan): List<PostgresQueryIndex>

The indexes of plan on the snapshot table of aggregate in context, keyed by the expressions of its keys' physical fields. Fails on a key with many values (an array): a B-tree indexes one.

Link copied to clipboard
fun planLog(context: String, aggregate: String, plan: QueryIndexPlan): List<PostgresQueryIndex>

The indexes of plan, the access attributes of aggregate in context, on its log table, keyed as the events model's SQL compiler reads them (PostgresEventQueryExpressions) and each partial on its key holding a value (WHERE <key> IS NOT NULL) rather than on the snapshots not deleted: a stream not stamped, or of an aggregate without an owner or a space, adds nothing to an index, and every comparison an access policy makes implies the key holds one. No tie-breaker ends them: they narrow the streams an access policy lets a reader see, and are not read for an order, which for an events query ends with the stream key (tenant, aggregate, version).