{"version":3,"sources":["../src/indexes/system.ts"],"names":["shortHash","quoteIdentifier","requireDefined"],"mappings":"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","file":"chunk-MDSN3W3Z.cjs","sourcesContent":["/**\n * System-index declarations — the single source of truth for the plain\n * btree indexes TypeGraph ships on its own relations.\n *\n * Both dialect schema factories (`createSqliteTables` /\n * `createPostgresTables`) derive their Drizzle index builders from this\n * list, so the two dialects cannot drift, and\n * `materializeSystemIndexes()` derives the same indexes as runtime DDL so\n * an index added in a new library version reaches already-initialized\n * databases (bootstrap DDL only runs on first boot — see\n * `loadActiveSchemaWithBootstrap`).\n *\n * Scope: non-unique btree column indexes on the four graph relations,\n * where performance iteration actually happens. Primary keys, unique /\n * partial-unique constraints, and status-table indexes are structural —\n * they are created with their table and never retrofitted — and stay in\n * the schema files.\n *\n * Changing a declaration's shape under the same suffix is a signature\n * drift: `materializeSystemIndexes` reports `failed` for it until the\n * operator drops the old physical index. Rename (new suffix) instead,\n * exactly like graph-declared indexes. Two acknowledged limits of that\n * contract: on databases whose indexes were bootstrap-created (no status\n * rows) an in-place reshape is undetectable at runtime — the rename rule\n * is enforced by review and the parity tests; and a renamed suffix\n * strands the old physical index (the runner only adds). When the first\n * rename actually happens, add a retired-suffixes list + drop path here.\n */\nimport { quoteIdentifier, shortHash } from \"../query/dialect/vector-strategy\";\nimport { requireDefined } from \"../utils/presence\";\n\n/** The TypeGraph relations that carry system indexes. */\nexport type SystemIndexTable =\n  \"nodes\" | \"edges\" | \"recordedNodes\" | \"recordedEdges\";\n\ntype LiveColumn =\n  | \"graph_id\"\n  | \"kind\"\n  | \"id\"\n  | \"deleted_at\"\n  | \"valid_from\"\n  | \"valid_to\"\n  | \"created_at\";\n\ntype LiveEdgeColumn =\n  LiveColumn | \"from_kind\" | \"from_id\" | \"to_kind\" | \"to_id\";\n\ntype RecordedColumn =\n  | \"graph_id\"\n  | \"kind\"\n  | \"id\"\n  | \"valid_from\"\n  | \"valid_to\"\n  | \"recorded_from\"\n  | \"recorded_to\";\n\ntype RecordedEdgeColumn =\n  RecordedColumn | \"from_kind\" | \"from_id\" | \"to_kind\" | \"to_id\";\n\ntype SystemIndexColumnsFor<T extends SystemIndexTable> =\n  T extends \"nodes\" ? LiveColumn\n  : T extends \"edges\" ? LiveEdgeColumn\n  : T extends \"recordedNodes\" ? RecordedColumn\n  : RecordedEdgeColumn;\n\ntype SystemIndexDeclarationFor<T extends SystemIndexTable> = Readonly<{\n  table: T;\n  /** Physical index name is `${physicalTableName}_${suffix}`. */\n  suffix: string;\n  columns: readonly [SystemIndexColumnsFor<T>, ...SystemIndexColumnsFor<T>[]];\n}>;\n\nexport type SystemIndexDeclaration =\n  | SystemIndexDeclarationFor<\"nodes\">\n  | SystemIndexDeclarationFor<\"edges\">\n  | SystemIndexDeclarationFor<\"recordedNodes\">\n  | SystemIndexDeclarationFor<\"recordedEdges\">;\n\nexport const SYSTEM_INDEX_DECLARATIONS: readonly SystemIndexDeclaration[] = [\n  // ---------------------------------------------------------- nodes\n  { table: \"nodes\", suffix: \"kind_idx\", columns: [\"graph_id\", \"kind\"] },\n  // Listing shape: kind partition ordered by creation with the\n  // soft-delete column ahead of it so `deleted_at IS NULL` list queries\n  // stay index-served.\n  {\n    table: \"nodes\",\n    suffix: \"kind_created_idx\",\n    columns: [\"graph_id\", \"kind\", \"deleted_at\", \"created_at\"],\n  },\n  {\n    table: \"nodes\",\n    suffix: \"deleted_idx\",\n    columns: [\"graph_id\", \"deleted_at\"],\n  },\n  {\n    table: \"nodes\",\n    suffix: \"valid_idx\",\n    columns: [\"graph_id\", \"valid_from\", \"valid_to\"],\n  },\n  // Bare-id lookup: the primary key leads with `kind` (graph_id, kind,\n  // id), so a `WHERE graph_id = ? AND id = ?` probe that doesn't know the\n  // kind can't seek it — SQLite falls back to a graph_id-only scan of\n  // every node in the graph (~3M at LDBC SF1).\n  // `store.algorithms.degree`'s node-kind subquery does exactly that\n  // lookup (it resolves the seed's kind by id), so without this index\n  // degree is a full nodes scan (~95ms at SF1). See typegraph#280.\n  { table: \"nodes\", suffix: \"id_idx\", columns: [\"graph_id\", \"id\"] },\n\n  // ---------------------------------------------------------- edges\n  { table: \"edges\", suffix: \"kind_idx\", columns: [\"graph_id\", \"kind\"] },\n  // Directional traversal index (outgoing): supports endpoint lookups\n  // and extra filtering by edge kind / target kind. Includes every\n  // system column the compiled query's soft-delete/temporal-validity\n  // predicate touches (deleted_at, valid_from, valid_to), trailed by\n  // to_id — the compiled traversal join reads `n.id = e.to_id` for an\n  // outgoing traversal (standard-builders.ts), so without to_id here\n  // the join still fetches the edge's heap row for that one column\n  // even with the seek/predicate columns covered.\n  {\n    table: \"edges\",\n    suffix: \"from_idx\",\n    columns: [\n      \"graph_id\",\n      \"from_kind\",\n      \"from_id\",\n      \"kind\",\n      \"to_kind\",\n      \"deleted_at\",\n      \"valid_from\",\n      \"valid_to\",\n      \"to_id\",\n    ],\n  },\n  // Directional traversal index (incoming): mirrors from_idx for\n  // reverse traversals, trailed by from_id for the same reason\n  // (`n.id = e.from_id` for an incoming traversal).\n  {\n    table: \"edges\",\n    suffix: \"to_idx\",\n    columns: [\n      \"graph_id\",\n      \"to_kind\",\n      \"to_id\",\n      \"kind\",\n      \"from_kind\",\n      \"deleted_at\",\n      \"valid_from\",\n      \"valid_to\",\n      \"from_id\",\n    ],\n  },\n  {\n    table: \"edges\",\n    suffix: \"kind_created_idx\",\n    columns: [\"graph_id\", \"kind\", \"deleted_at\", \"created_at\"],\n  },\n  {\n    table: \"edges\",\n    suffix: \"deleted_idx\",\n    columns: [\"graph_id\", \"deleted_at\"],\n  },\n  {\n    table: \"edges\",\n    suffix: \"valid_idx\",\n    columns: [\"graph_id\", \"valid_from\", \"valid_to\"],\n  },\n  // Cardinality enforcement: the one-per-endpoint check probes for a\n  // currently-valid edge of a kind from a specific endpoint.\n  {\n    table: \"edges\",\n    suffix: \"cardinality_idx\",\n    columns: [\"graph_id\", \"kind\", \"from_kind\", \"from_id\", \"valid_to\"],\n  },\n\n  // ---------------------------------------------------------- recordedNodes\n  {\n    table: \"recordedNodes\",\n    suffix: \"entity_idx\",\n    columns: [\"graph_id\", \"kind\", \"id\", \"recorded_from\", \"recorded_to\"],\n  },\n  {\n    table: \"recordedNodes\",\n    suffix: \"open_idx\",\n    columns: [\"graph_id\", \"recorded_to\"],\n  },\n  {\n    table: \"recordedNodes\",\n    suffix: \"valid_idx\",\n    columns: [\"graph_id\", \"valid_from\", \"valid_to\"],\n  },\n  // Bare-id lookup parity with the live nodes table: recorded-pinned\n  // reads swap this relation in as the node source, and `entity_idx`\n  // leads with `kind`, so the same kind-by-bare-id probe (e.g.\n  // `degree()` at a recorded coordinate) would otherwise scan every\n  // historical version in the graph. See typegraph#280.\n  { table: \"recordedNodes\", suffix: \"id_idx\", columns: [\"graph_id\", \"id\"] },\n  // `recorded_from`-led lookup: `entity_idx` leads with `kind, id`, so it\n  // cannot serve the lineage capability's changed-since scan\n  // (`store/recorded-capture/lineage.ts`), which filters by `graph_id` and\n  // `recorded_from` alone across every kind. Without this the scan is a\n  // full per-graph table scan of every historical row.\n  {\n    table: \"recordedNodes\",\n    suffix: \"since_idx\",\n    columns: [\"graph_id\", \"recorded_from\"],\n  },\n\n  // ---------------------------------------------------------- recordedEdges\n  {\n    table: \"recordedEdges\",\n    suffix: \"entity_idx\",\n    columns: [\"graph_id\", \"kind\", \"id\", \"recorded_from\", \"recorded_to\"],\n  },\n  {\n    table: \"recordedEdges\",\n    suffix: \"open_idx\",\n    columns: [\"graph_id\", \"recorded_to\"],\n  },\n  {\n    table: \"recordedEdges\",\n    suffix: \"from_idx\",\n    columns: [\n      \"graph_id\",\n      \"from_kind\",\n      \"from_id\",\n      \"kind\",\n      \"to_kind\",\n      \"recorded_from\",\n      \"recorded_to\",\n    ],\n  },\n  {\n    table: \"recordedEdges\",\n    suffix: \"to_idx\",\n    columns: [\n      \"graph_id\",\n      \"to_kind\",\n      \"to_id\",\n      \"kind\",\n      \"from_kind\",\n      \"recorded_from\",\n      \"recorded_to\",\n    ],\n  },\n  {\n    table: \"recordedEdges\",\n    suffix: \"valid_idx\",\n    columns: [\"graph_id\", \"valid_from\", \"valid_to\"],\n  },\n  // `recorded_from`-led lookup, same rationale as recordedNodes' since_idx:\n  // the directional indexes above lead with an endpoint, not `recorded_from`\n  // alone, so they cannot serve the lineage capability's changed-since scan.\n  {\n    table: \"recordedEdges\",\n    suffix: \"since_idx\",\n    columns: [\"graph_id\", \"recorded_from\"],\n  },\n];\n\n/** Default physical table names for the system-index relations. */\nconst DEFAULT_SYSTEM_INDEX_TABLE_NAMES: Readonly<\n  Record<SystemIndexTable, string>\n> = {\n  nodes: \"typegraph_nodes\",\n  edges: \"typegraph_edges\",\n  recordedNodes: \"typegraph_recorded_nodes\",\n  recordedEdges: \"typegraph_recorded_edges\",\n};\n\n/**\n * Resolves the physical table name for a system-index relation, honoring\n * a backend's table-name overrides.\n */\nexport function resolveSystemIndexTableName(\n  table: SystemIndexTable,\n  overrides:\n    Readonly<Partial<Record<SystemIndexTable, string | undefined>>> | undefined,\n): string {\n  return overrides?.[table] ?? DEFAULT_SYSTEM_INDEX_TABLE_NAMES[table];\n}\n\n/**\n * PostgreSQL truncates identifiers to NAMEDATALEN-1 = 63 bytes SILENTLY —\n * two suffixes of one long custom table name would collide after\n * truncation, and the catalog probes (which compare by exact name) would\n * never match the stored name, re-attempting the build on every boot.\n * SQLite has no such limit but uses the same bound so the two dialects'\n * index sets stay in byte-for-byte parity. (Char-based like the vector\n * identifier bound — multibyte table names are out of scope.)\n */\nconst MAX_SQL_IDENTIFIER_LENGTH = 63;\n\n/**\n * Physical index name: `${physicalTableName}_${suffix}`, deterministically\n * truncated + hash-suffixed past the 63-char identifier bound so distinct\n * indexes stay distinct. Single choke point — the Drizzle builders, the\n * runtime DDL, the catalog probes, and the status keys all derive the\n * name here, so they can never disagree.\n */\nexport function systemIndexName(\n  physicalTableName: string,\n  suffix: string,\n): string {\n  const full = `${physicalTableName}_${suffix}`;\n  if (full.length <= MAX_SQL_IDENTIFIER_LENGTH) return full;\n  const hash = shortHash(JSON.stringify([physicalTableName, suffix]));\n  return `${full.slice(0, MAX_SQL_IDENTIFIER_LENGTH - 1 - hash.length)}_${hash}`;\n}\n\n/**\n * Every system index name for a deployment's (possibly overridden) table\n * names. Graph-declared index names must not collide with these: a\n * colliding `CREATE INDEX IF NOT EXISTS` would silently no-op against the\n * system index (wrong shape) while recording a false success — see the\n * guards in the schema factories and `materializeIndexes`.\n */\nexport function resolveSystemIndexNames(\n  overrides:\n    Readonly<Partial<Record<SystemIndexTable, string | undefined>>> | undefined,\n): ReadonlySet<string> {\n  return new Set(\n    SYSTEM_INDEX_DECLARATIONS.map((declaration) =>\n      systemIndexName(\n        resolveSystemIndexTableName(declaration.table, overrides),\n        declaration.suffix,\n      ),\n    ),\n  );\n}\n\n/**\n * Rejects graph-declared indexes whose names collide with this\n * deployment's system index names. Called by both dialect schema\n * factories so a colliding declaration fails at table-definition time\n * instead of silently no-opping against the (differently shaped) system\n * index at CREATE INDEX IF NOT EXISTS time. `materializeIndexes` applies\n * the same check per-declaration on its runtime path.\n */\nexport function assertNoSystemIndexNameCollision(\n  indexes: readonly Readonly<{ name: string }>[],\n  overrides:\n    Readonly<Partial<Record<SystemIndexTable, string | undefined>>> | undefined,\n): void {\n  if (indexes.length === 0) return;\n  const reserved = resolveSystemIndexNames(overrides);\n  for (const index of indexes) {\n    if (reserved.has(index.name)) {\n      throw new Error(\n        `Index name \"${index.name}\" collides with a TypeGraph system ` +\n          `index. Choose a different name — system index names are ` +\n          `reserved, and a same-named CREATE INDEX IF NOT EXISTS would ` +\n          `silently no-op against the system index instead of creating ` +\n          `the declared one.`,\n      );\n    }\n  }\n}\n\n/**\n * Runtime DDL for one system index — byte-compatible with the index the\n * bootstrap path creates from the Drizzle schema (same name, same\n * columns), plus `CONCURRENTLY` where the dialect supports building\n * without blocking writes.\n */\nexport function generateSystemIndexDDL(\n  declaration: SystemIndexDeclaration,\n  physicalTableName: string,\n  options: Readonly<{ concurrent: boolean }>,\n): string {\n  const name = quoteIdentifier(\n    systemIndexName(physicalTableName, declaration.suffix),\n  );\n  const table = quoteIdentifier(physicalTableName);\n  const columns = declaration.columns\n    .map((column) => quoteIdentifier(column))\n    .join(\", \");\n  const concurrently = options.concurrent ? \"CONCURRENTLY \" : \"\";\n  return `CREATE INDEX ${concurrently}IF NOT EXISTS ${name} ON ${table} (${columns});`;\n}\n\n/**\n * Runtime DDL for the base-schema release's three `since_idx (graph_id,\n * recorded_from)` indexes — the lineage capability's changed-since scan\n * (`store/recorded-capture/lineage.ts`): the two recorded relations\n * (`recordedNodes`, `recordedEdges`, declared in\n * {@link SYSTEM_INDEX_DECLARATIONS} and managed by `materializeIndexes`),\n * plus the recorded identity-assertions relation's own `since_idx`, which\n * `changesSince`'s per-revision completeness scan folds into the same\n * three-relation scan but which is NOT a {@link SystemIndexTable} — like that\n * relation's other three indexes (`entity_idx`/`a_idx`/`b_idx`), it is\n * structural, hand-declared with the table rather than run through\n * `materializeIndexes`' lazy backfill, and this function follows the same\n * pattern for it. Both dialect factories thread this into the base-schema\n * version-3 adoption step (`engine/members/base-schema-members.ts`) the\n * same way `fencesTableDdl` feeds version 2: a fresh bootstrap already\n * carries all three indexes through the schema factories' own index\n * builders, but a database that reaches adoption without re-running\n * bootstrap DDL (a reopen of an already-provisioned installation) needs\n * this explicit `CREATE INDEX IF NOT EXISTS` triple. The adoption step must\n * first ensure recorded identity-assertions storage: older provisioned\n * installations can predate that table, which originally shipped only in\n * bootstrap DDL. One owner for the\n * declaration lookup and the identity-assertions index's own name (both\n * routed through {@link systemIndexName}, the single naming choke point)\n * keeps the two dialect factories from re-spelling either and risking\n * drift between them; the identity-assertions name this renders MUST match\n * the schema factories' own hand-written `index(...)` call byte-for-byte —\n * the shape-ratchet test (`tests/base-schema-shape-ratchet.test.ts`) is\n * what would catch a drift.\n */\nexport function sinceIndexAdoptionDdl(\n  recordedTableNames: Readonly<{\n    recordedNodes: string;\n    recordedEdges: string;\n    recordedIdentityAssertions: string;\n  }>,\n): readonly [string, string, string] {\n  function sinceIndexDdlFor(table: \"recordedNodes\" | \"recordedEdges\"): string {\n    const declaration = requireDefined(\n      SYSTEM_INDEX_DECLARATIONS.find(\n        (candidate) =>\n          candidate.table === table && candidate.suffix === \"since_idx\",\n      ),\n      `No \"since_idx\" system index is declared for \"${table}\".`,\n    );\n    return generateSystemIndexDDL(declaration, recordedTableNames[table], {\n      concurrent: false,\n    });\n  }\n  function identityAssertionsSinceIndexDdl(): string {\n    const name = quoteIdentifier(\n      systemIndexName(\n        recordedTableNames.recordedIdentityAssertions,\n        \"since_idx\",\n      ),\n    );\n    const table = quoteIdentifier(\n      recordedTableNames.recordedIdentityAssertions,\n    );\n    return `CREATE INDEX IF NOT EXISTS ${name} ON ${table} (${quoteIdentifier(\"graph_id\")}, ${quoteIdentifier(\"recorded_from\")});`;\n  }\n  return [\n    sinceIndexDdlFor(\"recordedNodes\"),\n    sinceIndexDdlFor(\"recordedEdges\"),\n    identityAssertionsSinceIndexDdl(),\n  ];\n}\n"]}