Class CatalogBuilder
java.lang.Object
com.darkcollective.relix.semantic.internal.CatalogBuilder
Builds the read-only system catalog relations — the
relix.* namespace that lets a script query the engine's own knowledge about
itself (the information_schema analogue; see ADR-0007).
Strategy (ADR-0007, Decision 3 — Strategy A)
Catalogs are registered asSystemRelationSymbol — a dedicated, first-class
read-only symbol kind in the reserved relix namespace. This promotes the
v1 Strategy-B approach (reusing InlineRelationSymbol) to the Strategy-A
escape hatch described in the issue, giving callers a structural signal that these
relations are engine-computed and not user-defined inline data. The IR now labels
them SYS instead of INL. relix.dependencies is the
exception: it is a QueryRelationSymbol derived from
relix.plan, so it has no Java-computed extent at all — it is planned
and executed lazily like any other view (see buildDependencies()).
Two-step registration (the ordering constraint)
relix.relations has a collection-time extent, so
registerInto(com.darkcollective.relix.symbol.table.SymbolTable, java.util.Map<java.lang.String, com.darkcollective.relix.lang.ast.ConnectionDeclaration>, java.util.Map<java.lang.String, com.darkcollective.relix.symbol.RelationStatistics>, java.util.List<com.darkcollective.relix.events.QueryEvent>, com.darkcollective.relix.function.FunctionCatalog, com.darkcollective.relix.semantic.internal.ComponentInventory, com.darkcollective.relix.semantic.internal.RelationBoundedness) computes and registers it in full
before schema inference. relix.columns and relix.plan
are different: their rows need the inferred output schemas of views
(which only resolve during inference), yet the symbol must already exist
before inference for a query to reference it. Both are therefore
handled with the same placeholder-then-fill pattern the engine already uses for
views:
registerInto(com.darkcollective.relix.symbol.table.SymbolTable, java.util.Map<java.lang.String, com.darkcollective.relix.lang.ast.ConnectionDeclaration>, java.util.Map<java.lang.String, com.darkcollective.relix.symbol.RelationStatistics>, java.util.List<com.darkcollective.relix.events.QueryEvent>, com.darkcollective.relix.function.FunctionCatalog, com.darkcollective.relix.semantic.internal.ComponentInventory, com.darkcollective.relix.semantic.internal.RelationBoundedness)registers them with their (fixed, known) schema but an empty extent, so references resolve and infer correctly.fillColumns/fillPlanre-register them after inference with the real extent, read off the now-resolved symbol schemas (columns) and per-node schema annotations (plan).
Reservation
Catalog symbols live in therelix namespace with Provenance.BUILTIN;
a user := (always in a user namespace) can never name one. The
single-registration catalogs use ShadowPolicy.FORBIDDEN;
relix.columns uses ShadowPolicy.PERMITTED so its post-inference fill
can overwrite the placeholder.
Self-exclusion (ADR-0007, Decision 4)
Every extent is computed from the relation symbols outside the
relix namespace, so the catalog never describes itself or its siblings; the
extents are stable and acyclic.
relix.catalog is the one deliberate exception, and it is opt-in by
being a relation of its own: naming it is how you ask. It changes no other
extent — relix.relations, relix.columns and
relix.functions still describe only the user's namespace — and it cannot
recurse, because it is computed in Java from the symbol table rather than
derived over another catalog view. It exists because the exclusion above left
the introspection surface as the one thing that could not be introspected.
Structural vs temporal extents
Every catalog above answers "what is" — it is a projection of the model being analysed, so its extent is fixed the moment analysis finishes.relix.events is the one that answers "what happened": its rows
are the observability feed of the previously executed statement,
handed in by the session host. It has to be the previous one, because the
feed a statement produces does not exist until the optimizer, planner, and
executor have run — all of which come strictly after the catalog is built. A
batch script analysed once therefore sees an empty relix.events; a
session that re-analyses per statement sees the run before it. This is the
push→pull bridge of ADR-0017 Decision 3, and it is the only catalog whose
extent is not a function of the script.
Scope
Shipsrelix.relations, relix.dependencies, relix.columns,
relix.keys (candidate keys, the one collected statistic with no flat
column to sit in), relix.functions, relix.connections (the last
redacted — no raw URLs; ADR-0007 Decision 5), relix.plan (the queryable
logical expression tree), relix.events (the previous run's feed), and
relix.catalog (the reserved namespace describing itself).-
Method Summary