@nicia-ai/typegraph 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/postgres/index.cjs +16 -16
- package/dist/backend/postgres/index.d.cts +5 -5
- package/dist/backend/postgres/index.d.ts +5 -5
- package/dist/backend/postgres/index.js +6 -6
- package/dist/backend/postgres/pglite.cjs +9 -9
- package/dist/backend/postgres/pglite.d.cts +2 -2
- package/dist/backend/postgres/pglite.d.ts +2 -2
- package/dist/backend/postgres/pglite.js +6 -6
- package/dist/backend/sqlite/index.cjs +14 -14
- package/dist/backend/sqlite/index.d.cts +6 -6
- package/dist/backend/sqlite/index.d.ts +6 -6
- package/dist/backend/sqlite/index.js +5 -5
- package/dist/backend/sqlite/libsql.cjs +10 -10
- package/dist/backend/sqlite/libsql.d.cts +2 -2
- package/dist/backend/sqlite/libsql.d.ts +2 -2
- package/dist/backend/sqlite/libsql.js +6 -6
- package/dist/backend/sqlite/local.cjs +10 -10
- package/dist/backend/sqlite/local.d.cts +2 -2
- package/dist/backend/sqlite/local.d.ts +2 -2
- package/dist/backend/sqlite/local.js +6 -6
- package/dist/{chunk-XKJQQQVR.js → chunk-2BVHPOIG.js} +3 -3
- package/dist/{chunk-XKJQQQVR.js.map → chunk-2BVHPOIG.js.map} +1 -1
- package/dist/{chunk-RZ4DH4E7.cjs → chunk-2LAT5BIK.cjs} +662 -217
- package/dist/chunk-2LAT5BIK.cjs.map +1 -0
- package/dist/{chunk-CIINW6PS.cjs → chunk-3HQDMOBK.cjs} +64 -64
- package/dist/{chunk-CIINW6PS.cjs.map → chunk-3HQDMOBK.cjs.map} +1 -1
- package/dist/{chunk-6SA7UIQJ.cjs → chunk-3QRBXYT5.cjs} +6 -6
- package/dist/{chunk-6SA7UIQJ.cjs.map → chunk-3QRBXYT5.cjs.map} +1 -1
- package/dist/{chunk-4A4GUZTQ.js → chunk-7WW3WL6E.js} +5 -5
- package/dist/{chunk-4A4GUZTQ.js.map → chunk-7WW3WL6E.js.map} +1 -1
- package/dist/{chunk-2HZGWCB4.js → chunk-C4C4Q7A6.js} +3 -3
- package/dist/chunk-C4C4Q7A6.js.map +1 -0
- package/dist/{chunk-SFFJ2IKN.cjs → chunk-CAMMC3E4.cjs} +58 -58
- package/dist/{chunk-SFFJ2IKN.cjs.map → chunk-CAMMC3E4.cjs.map} +1 -1
- package/dist/{chunk-O4VUR6SI.js → chunk-CEF2QOTO.js} +3 -3
- package/dist/{chunk-O4VUR6SI.js.map → chunk-CEF2QOTO.js.map} +1 -1
- package/dist/{chunk-V4IQYOQ4.cjs → chunk-CFNT3ITG.cjs} +3 -3
- package/dist/chunk-CFNT3ITG.cjs.map +1 -0
- package/dist/{chunk-LJLMDDCW.js → chunk-CWFPJ3RC.js} +3 -3
- package/dist/{chunk-LJLMDDCW.js.map → chunk-CWFPJ3RC.js.map} +1 -1
- package/dist/{chunk-7JGLPAFV.cjs → chunk-EEYV6UOE.cjs} +16 -16
- package/dist/chunk-EEYV6UOE.cjs.map +1 -0
- package/dist/{chunk-ASYQDPPU.cjs → chunk-FDN43KXV.cjs} +19 -19
- package/dist/{chunk-ASYQDPPU.cjs.map → chunk-FDN43KXV.cjs.map} +1 -1
- package/dist/{chunk-THX25XW6.js → chunk-HFBRAOF7.js} +27 -7
- package/dist/chunk-HFBRAOF7.js.map +1 -0
- package/dist/{chunk-54JVNOAQ.cjs → chunk-JKRKIEVA.cjs} +5 -5
- package/dist/{chunk-54JVNOAQ.cjs.map → chunk-JKRKIEVA.cjs.map} +1 -1
- package/dist/{chunk-5DTPBFX5.cjs → chunk-LAZGHOZW.cjs} +10 -10
- package/dist/{chunk-5DTPBFX5.cjs.map → chunk-LAZGHOZW.cjs.map} +1 -1
- package/dist/{chunk-N2MBPTAF.cjs → chunk-LM2IC4ZJ.cjs} +14 -14
- package/dist/{chunk-N2MBPTAF.cjs.map → chunk-LM2IC4ZJ.cjs.map} +1 -1
- package/dist/{chunk-STP7QVUB.js → chunk-NDM5PXEH.js} +5 -5
- package/dist/{chunk-STP7QVUB.js.map → chunk-NDM5PXEH.js.map} +1 -1
- package/dist/{chunk-2ZY4K43M.js → chunk-PIHXFF73.js} +3 -3
- package/dist/{chunk-2ZY4K43M.js.map → chunk-PIHXFF73.js.map} +1 -1
- package/dist/{chunk-ATTXBMAX.js → chunk-PRMKPFN5.js} +3 -3
- package/dist/{chunk-ATTXBMAX.js.map → chunk-PRMKPFN5.js.map} +1 -1
- package/dist/{chunk-3JBJEYWE.cjs → chunk-SB65GJNY.cjs} +32 -12
- package/dist/chunk-SB65GJNY.cjs.map +1 -0
- package/dist/{chunk-VZX2KSY3.js → chunk-TUA3MEJJ.js} +5 -5
- package/dist/{chunk-VZX2KSY3.js.map → chunk-TUA3MEJJ.js.map} +1 -1
- package/dist/{chunk-MAQJYNJR.js → chunk-W4ZX2GCP.js} +14 -16
- package/dist/chunk-W4ZX2GCP.js.map +1 -0
- package/dist/{chunk-UIFEEPME.js → chunk-WNORITK6.js} +593 -149
- package/dist/chunk-WNORITK6.js.map +1 -0
- package/dist/{chunk-VMEWZU2N.cjs → chunk-WWVV44DY.cjs} +11 -11
- package/dist/{chunk-VMEWZU2N.cjs.map → chunk-WWVV44DY.cjs.map} +1 -1
- package/dist/{chunk-UJ4V3YUQ.js → chunk-XKNAK27R.js} +3 -3
- package/dist/{chunk-UJ4V3YUQ.js.map → chunk-XKNAK27R.js.map} +1 -1
- package/dist/{chunk-GKFWM3DS.js → chunk-XQFAJVYW.js} +3 -3
- package/dist/{chunk-GKFWM3DS.js.map → chunk-XQFAJVYW.js.map} +1 -1
- package/dist/{chunk-FLOI7QOT.cjs → chunk-YL4F3CMD.cjs} +59 -59
- package/dist/{chunk-FLOI7QOT.cjs.map → chunk-YL4F3CMD.cjs.map} +1 -1
- package/dist/{chunk-5CN7B4CZ.cjs → chunk-YW7GHMF4.cjs} +17 -17
- package/dist/{chunk-5CN7B4CZ.cjs.map → chunk-YW7GHMF4.cjs.map} +1 -1
- package/dist/{ddl-BJcPrB4L.d.ts → ddl-C8e8zDAE.d.ts} +3 -3
- package/dist/{ddl-CPZ7mB7X.d.cts → ddl-CwyG4HoQ.d.cts} +3 -3
- package/dist/graph-merge/index.cjs +193 -49
- package/dist/graph-merge/index.cjs.map +1 -1
- package/dist/graph-merge/index.d.cts +3 -3
- package/dist/graph-merge/index.d.ts +3 -3
- package/dist/graph-merge/index.js +180 -36
- package/dist/graph-merge/index.js.map +1 -1
- package/dist/index.cjs +89 -85
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +12 -12
- package/dist/indexes/index.cjs +10 -10
- package/dist/indexes/index.d.cts +4 -4
- package/dist/indexes/index.d.ts +4 -4
- package/dist/indexes/index.js +3 -3
- package/dist/interchange/index.cjs +15 -15
- package/dist/interchange/index.d.cts +7 -7
- package/dist/interchange/index.d.ts +7 -7
- package/dist/interchange/index.js +2 -2
- package/dist/{manager-By-WEd8M.d.ts → manager-8htmuGr-.d.ts} +1 -1
- package/dist/{manager-Np7VVSlE.d.cts → manager-aVgxbGt-.d.cts} +1 -1
- package/dist/{postgres-BdIb7tS_.d.ts → postgres-Dhom7iiX.d.ts} +1 -1
- package/dist/{postgres-4J2tmauh.d.cts → postgres-jgXmD45C.d.cts} +1 -1
- package/dist/profiler/index.d.cts +5 -5
- package/dist/profiler/index.d.ts +5 -5
- package/dist/schema/index.cjs +26 -26
- package/dist/schema/index.d.cts +4 -4
- package/dist/schema/index.d.ts +4 -4
- package/dist/schema/index.js +3 -3
- package/dist/{sqlite-aM_PAz-O.d.ts → sqlite-BfLsCEqO.d.ts} +1 -1
- package/dist/{sqlite-Gatk_iw_.d.cts → sqlite-DcQ_BCUW.d.cts} +1 -1
- package/dist/{store-DuCbdqsh.d.cts → store-view-lTcb_cnp.d.cts} +639 -311
- package/dist/{store-MloRPwb9.d.ts → store-view-pBOUrQte.d.ts} +639 -311
- package/dist/{types-DoByHGyU.d.cts → types-5RQwzWXx.d.cts} +1 -1
- package/dist/{types-K3vpaJAL.d.ts → types-DGDiXAYc.d.ts} +1 -1
- package/dist/{types-BKQljXom.d.ts → types-Dk8r09KY.d.ts} +1 -1
- package/dist/{types-C1CYxWrL.d.cts → types-Dvmn-eal.d.cts} +1 -1
- package/dist/{where-Dt49bvo6.d.ts → where-CHZFELX0.d.ts} +1 -1
- package/dist/{where-DydZjGOb.d.cts → where-Cx_glEEB.d.cts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-2HZGWCB4.js.map +0 -1
- package/dist/chunk-3JBJEYWE.cjs.map +0 -1
- package/dist/chunk-7JGLPAFV.cjs.map +0 -1
- package/dist/chunk-MAQJYNJR.js.map +0 -1
- package/dist/chunk-RZ4DH4E7.cjs.map +0 -1
- package/dist/chunk-THX25XW6.js.map +0 -1
- package/dist/chunk-UIFEEPME.js.map +0 -1
- package/dist/chunk-V4IQYOQ4.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/backend/drizzle/columns/vector.ts","../src/query/dialect/vector/pgvector-strategy.ts"],"names":["customType","assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","quotedTableName","vectorScoreExpression","vectorMinScoreCondition"],"mappings":"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","file":"chunk-5CN7B4CZ.cjs","sourcesContent":["/**\n * Custom Drizzle column type for pgvector's VECTOR type.\n *\n * Provides native support for PostgreSQL vector embeddings without\n * requiring runtime casts in queries.\n *\n * @example\n * ```typescript\n * import { pgTable, text, integer } from \"drizzle-orm/pg-core\";\n * import { vector } from \"./columns/vector\";\n *\n * const embeddings = pgTable(\"embeddings\", {\n * id: text(\"id\").primaryKey(),\n * embedding: vector(\"embedding\"),\n * dimensions: integer(\"dimensions\"),\n * });\n * ```\n */\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * PostgreSQL vector column type for pgvector extension.\n *\n * Stores embeddings as native VECTOR type, enabling efficient\n * similarity search without runtime casts.\n *\n * The column type is unparameterized (`VECTOR` not `VECTOR(N)`)\n * to support multiple embedding dimensions in a single table.\n * Dimension validation is handled at the application level.\n *\n * @example\n * ```typescript\n * // In table definition\n * embedding: vector(\"embedding\").notNull(),\n *\n * // In queries - no cast needed\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector([0.1, 0.2, 0.3])} < 0.5\n * `);\n * ```\n */\nexport const vector = customType<{\n data: number[];\n driverData: string;\n config: { dimensions?: number };\n}>({\n dataType(config) {\n // Use parameterized type if dimensions specified, otherwise unparameterized\n return config?.dimensions ? `vector(${config.dimensions})` : \"vector\";\n },\n\n toDriver(value: number[]): string {\n // Format as pgvector literal: [1.0,2.0,3.0]\n return `[${value.join(\",\")}]`;\n },\n\n fromDriver(value: string): number[] {\n // pgvector returns '[1,2,3]' format\n // Handle both string and already-parsed array (some drivers differ)\n if (Array.isArray(value)) {\n return value as number[];\n }\n // Parse the string representation\n const content = value.slice(1, -1); // Remove [ and ]\n if (content === \"\") {\n return [];\n }\n return content.split(\",\").map((s) => Number.parseFloat(s.trim()));\n },\n});\n\n/**\n * Formats a number array as a pgvector literal string.\n *\n * Use this when building raw SQL queries with embeddings.\n *\n * @example\n * ```typescript\n * const embedding = [0.1, 0.2, 0.3];\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector(embedding)}::vector < 0.5\n * `);\n * ```\n */\nexport function formatVector(embedding: readonly number[]): string {\n return `[${embedding.join(\",\")}]`;\n}\n","/**\n * pgvector strategy.\n *\n * Postgres' pgvector extension is the one engine where the *same* SQL serves\n * brute-force and ANN: `ORDER BY embedding <=> q LIMIT k` scans sequentially\n * with no index and is rewritten to an HNSW/IVFFlat scan the moment a matching\n * index exists — the planner picks it up automatically. So `buildSearch` never\n * branches on `slot.indexType`; it emits one relevance scan and lets Postgres\n * decide. (Contrast libSQL/sqlite-vec, whose ANN needs distinct syntax.)\n *\n * Storage is per-`(nodeKind, fieldPath)`: a `vector(N)` column carrying the\n * field's fixed dimension `N`, with the operator-class-typed ANN index folded\n * into the same table contribution so materialization builds table + index\n * together. The typed column means the index does not need the legacy\n * `::vector(N)` cast-in-index escape hatch the old shared table relied on.\n *\n * Metric support is the full pgvector set — `cosine`, `l2`, `inner_product` —\n * advertised as data on `capabilities`, mirroring `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops` and the `<=>` / `<->` / `<#>` operators.\n *\n * Mirrors the `libsqlVectorStrategy` / `sqliteVecStrategy` structure while\n * letting Postgres' planner pick the ANN index when one exists.\n */\nimport { type SQL, sql } from \"drizzle-orm\";\n\nimport { formatVector } from \"../../../backend/drizzle/columns/vector\";\nimport { quotedTableName } from \"../../../backend/drizzle/operations/shared\";\nimport { type StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport {\n assertFiniteEmbedding,\n quoteIdentifier,\n VECTOR_CONTRIBUTION_PREFIX,\n vectorMinScoreCondition,\n vectorPhysicalName,\n vectorScoreExpression,\n type VectorSlot,\n type VectorStrategy,\n} from \"../vector-strategy\";\n\n/** Physical-name prefixes for the per-field table and its ANN index. */\nconst TABLE_PREFIX = \"tg_vec\";\nconst INDEX_PREFIX = \"tg_vecidx\";\n\n/**\n * pgvector defines `hnsw.ef_search` as an integer GUC with a valid range\n * of 1..1000; `SET hnsw.ef_search = 1001` errors at the server. The\n * backend validates a per-search `efSearch` against this ceiling before\n * inlining it into `SET LOCAL`, surfacing a clear message instead of a raw\n * pgvector error.\n */\nexport const MAX_HNSW_EF_SEARCH = 1000;\n\n/**\n * Validates a per-search `efSearch` override against pgvector's\n * `hnsw.ef_search` valid range. `undefined` (no override) is accepted.\n */\nexport function assertPgvectorEfSearch(efSearch?: number): void {\n if (efSearch === undefined) return;\n if (!Number.isInteger(efSearch) || efSearch <= 0) {\n throw new Error(`efSearch must be a positive integer, got: ${efSearch}`);\n }\n if (efSearch > MAX_HNSW_EF_SEARCH) {\n throw new RangeError(\n `efSearch must be ≤ ${MAX_HNSW_EF_SEARCH} (pgvector's hnsw.ef_search ` +\n `valid range is 1..${MAX_HNSW_EF_SEARCH}), got: ${efSearch}`,\n );\n }\n}\n\n/**\n * pgvector's `vector` type caps at 16,000 dimensions for a stored column\n * (2,000 for an indexed column, but the column-type ceiling is what governs\n * storage; recall degradation beyond 2,000 is a tuning concern, not a hard\n * limit advertised here).\n */\nconst PGVECTOR_MAX_DIMENSIONS = 16_000;\n\n/** Default HNSW `m` (max connections per layer) — pgvector's own default. */\nconst DEFAULT_HNSW_M = 16;\n/** Default HNSW `ef_construction` (build candidate list) — pgvector's own default. */\nconst DEFAULT_HNSW_EF_CONSTRUCTION = 64;\n/** Default IVFFlat `lists` (inverted lists) — pgvector's own default. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\nconst PGVECTOR_CAPABILITIES: VectorCapabilities = {\n supported: true,\n metrics: [\"cosine\", \"l2\", \"inner_product\"],\n indexTypes: [\"hnsw\", \"ivfflat\", \"none\"],\n maxDimensions: PGVECTOR_MAX_DIMENSIONS,\n};\n\n/** Whether a slot's declared index type materializes a real pgvector ANN index. */\nfunction usesAnnIndex(slot: VectorSlot): boolean {\n return slot.indexType === \"hnsw\" || slot.indexType === \"ivfflat\";\n}\n\n/**\n * pgvector operator class for a metric's ANN index — `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops`, mirroring the `<=>` / `<->` / `<#>`\n * distance operators this strategy emits.\n */\nfunction operatorClass(metric: VectorMetric): string {\n switch (metric) {\n case \"cosine\": {\n return \"vector_cosine_ops\";\n }\n case \"l2\": {\n return \"vector_l2_ops\";\n }\n case \"inner_product\": {\n return \"vector_ip_ops\";\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Formats an embedding as a `::vector` literal. The value is bound as a\n * parameter (not interpolated) — Postgres parses the `[a,b,c]` text and the\n * cast types it. Finiteness is validated first so a NaN names its index.\n */\nfunction vectorLiteral(embedding: readonly number[], name: string): SQL {\n assertFiniteEmbedding(embedding, name);\n return sql`${formatVector(embedding)}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SQL,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SQL {\n const query = vectorLiteral(queryEmbedding, \"queryEmbedding\");\n switch (metric) {\n case \"cosine\": {\n return sql`(${embeddingColumn} <=> ${query})`;\n }\n case \"l2\": {\n return sql`(${embeddingColumn} <-> ${query})`;\n }\n case \"inner_product\": {\n return sql`(${embeddingColumn} <#> ${query})`;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName(graphId, nodeKind, fieldPath) {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n },\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath);\n const name = quoteIdentifier(table);\n\n // No standalone graph_id index: the PRIMARY KEY (graph_id, node_id) already\n // covers `WHERE graph_id = ?` via its leading column, so a separate index\n // would be pure write amplification.\n const createDdl = [\n `CREATE TABLE IF NOT EXISTS ${name} (\n \"graph_id\" TEXT NOT NULL,\n \"node_id\" TEXT NOT NULL,\n \"embedding\" vector(${slot.dimensions}) NOT NULL,\n \"created_at\" TIMESTAMPTZ NOT NULL,\n \"updated_at\" TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (\"graph_id\", \"node_id\")\n);`,\n ];\n\n // The HNSW/IVFFlat index is intentionally NOT created here. pgvector\n // similarity SQL is planner-driven (`ORDER BY embedding <=> q LIMIT k`\n // uses the index when present, sequential-scans when not), so the index\n // is a pure materialization concern: `buildCreateIndex` builds it through\n // `materializeIndexes()` with the field's declared `m`/`ef_construction`/\n // `lists`. Building it eagerly here would bake in default tuning (the\n // write-ensure slot has no `indexParams`) and `CREATE INDEX IF NOT EXISTS`\n // would then mask the tuned index materialization would emit.\n\n return [\n {\n logicalName: `${VECTOR_CONTRIBUTION_PREFIX}:${slot.nodeKind}.${slot.fieldPath}`,\n owner: \"pgvector\",\n tableName: table,\n createDdl,\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(slot, params: UpsertEmbeddingParams, timestamp): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const value = vectorLiteral(params.embedding, \"embedding\");\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES (${params.graphId}, ${params.nodeId}, ${value}, ${timestamp}, ${timestamp})\n ON CONFLICT (\"graph_id\", \"node_id\")\n DO UPDATE SET \"embedding\" = EXCLUDED.\"embedding\", \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildDelete(slot, params: DeleteEmbeddingParams): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n return [\n sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId} AND \"node_id\" = ${params.nodeId}\n `,\n ];\n },\n\n buildSearch(slot, params: VectorSearchParams): SQL {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const embeddingColumn = sql`${table}.\"embedding\"`;\n const distance = distanceExpression(\n embeddingColumn,\n params.queryEmbedding,\n params.metric,\n );\n const score = vectorScoreExpression(distance, params.metric);\n\n // Same SQL for brute-force and ANN: with a matching HNSW/IVFFlat index the\n // Postgres planner rewrites this `ORDER BY distance LIMIT k` into an index\n // scan automatically, so the strategy never branches on `slot.indexType`.\n const conditions: SQL[] = [sql`${table}.\"graph_id\" = ${params.graphId}`];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n return sql`\n SELECT ${table}.\"node_id\" AS node_id, ${score} AS score\n FROM ${table}\n WHERE ${sql.join(conditions, sql` AND `)}\n ORDER BY ${distance} ASC\n LIMIT ${params.limit}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n const indexName = pgvectorIndexName(slot);\n return sql.raw(`DROP INDEX IF EXISTS ${quoteIdentifier(indexName)}`);\n },\n\n buildDropStorage(slot): readonly string[] {\n const table = quoteIdentifier(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n // CASCADE drops the ANN index along with the table.\n return [`DROP TABLE IF EXISTS ${table} CASCADE`];\n },\n};\n\nfunction pgvectorIndexName(slot: VectorSlot): string {\n return vectorPhysicalName(\n INDEX_PREFIX,\n slot.graphId,\n slot.nodeKind,\n slot.fieldPath,\n );\n}\n\nfunction pgvectorIndexDdl(\n table: string,\n slot: VectorSlot,\n concurrent: boolean,\n): string {\n const indexName = quoteIdentifier(pgvectorIndexName(slot));\n const quotedTable = quoteIdentifier(table);\n const opClass = operatorClass(slot.metric);\n // Honor the field's declared tuning; fall back to pgvector defaults.\n const m = slot.indexParams?.m ?? DEFAULT_HNSW_M;\n const efConstruction =\n slot.indexParams?.efConstruction ?? DEFAULT_HNSW_EF_CONSTRUCTION;\n const lists = slot.indexParams?.lists ?? DEFAULT_IVFFLAT_LISTS;\n // CONCURRENTLY builds without taking a write-blocking lock on the live table\n // (materializeIndexes passes concurrent on Postgres). Run outside a tx.\n const create = `CREATE INDEX${concurrent ? \" CONCURRENTLY\" : \"\"} IF NOT EXISTS`;\n\n switch (slot.indexType) {\n case \"hnsw\": {\n return `${create} ${indexName} ON ${quotedTable} USING hnsw (\"embedding\" ${opClass}) WITH (m = ${m}, ef_construction = ${efConstruction});`;\n }\n case \"ivfflat\": {\n return `${create} ${indexName} ON ${quotedTable} USING ivfflat (\"embedding\" ${opClass}) WITH (lists = ${lists});`;\n }\n case \"none\": {\n throw new Error(\n \"pgvectorIndexDdl called for a brute-force-only slot (indexType 'none').\",\n );\n }\n default: {\n const _exhaustive: never = slot.indexType;\n throw new Error(`Unsupported vector index type: ${String(_exhaustive)}`);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/backend/drizzle/columns/vector.ts","../src/query/dialect/vector/pgvector-strategy.ts"],"names":["customType","assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","quotedTableName","vectorScoreExpression","vectorMinScoreCondition"],"mappings":"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","file":"chunk-YW7GHMF4.cjs","sourcesContent":["/**\n * Custom Drizzle column type for pgvector's VECTOR type.\n *\n * Provides native support for PostgreSQL vector embeddings without\n * requiring runtime casts in queries.\n *\n * @example\n * ```typescript\n * import { pgTable, text, integer } from \"drizzle-orm/pg-core\";\n * import { vector } from \"./columns/vector\";\n *\n * const embeddings = pgTable(\"embeddings\", {\n * id: text(\"id\").primaryKey(),\n * embedding: vector(\"embedding\"),\n * dimensions: integer(\"dimensions\"),\n * });\n * ```\n */\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * PostgreSQL vector column type for pgvector extension.\n *\n * Stores embeddings as native VECTOR type, enabling efficient\n * similarity search without runtime casts.\n *\n * The column type is unparameterized (`VECTOR` not `VECTOR(N)`)\n * to support multiple embedding dimensions in a single table.\n * Dimension validation is handled at the application level.\n *\n * @example\n * ```typescript\n * // In table definition\n * embedding: vector(\"embedding\").notNull(),\n *\n * // In queries - no cast needed\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector([0.1, 0.2, 0.3])} < 0.5\n * `);\n * ```\n */\nexport const vector = customType<{\n data: number[];\n driverData: string;\n config: { dimensions?: number };\n}>({\n dataType(config) {\n // Use parameterized type if dimensions specified, otherwise unparameterized\n return config?.dimensions ? `vector(${config.dimensions})` : \"vector\";\n },\n\n toDriver(value: number[]): string {\n // Format as pgvector literal: [1.0,2.0,3.0]\n return `[${value.join(\",\")}]`;\n },\n\n fromDriver(value: string): number[] {\n // pgvector returns '[1,2,3]' format\n // Handle both string and already-parsed array (some drivers differ)\n if (Array.isArray(value)) {\n return value as number[];\n }\n // Parse the string representation\n const content = value.slice(1, -1); // Remove [ and ]\n if (content === \"\") {\n return [];\n }\n return content.split(\",\").map((s) => Number.parseFloat(s.trim()));\n },\n});\n\n/**\n * Formats a number array as a pgvector literal string.\n *\n * Use this when building raw SQL queries with embeddings.\n *\n * @example\n * ```typescript\n * const embedding = [0.1, 0.2, 0.3];\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector(embedding)}::vector < 0.5\n * `);\n * ```\n */\nexport function formatVector(embedding: readonly number[]): string {\n return `[${embedding.join(\",\")}]`;\n}\n","/**\n * pgvector strategy.\n *\n * Postgres' pgvector extension is the one engine where the *same* SQL serves\n * brute-force and ANN: `ORDER BY embedding <=> q LIMIT k` scans sequentially\n * with no index and is rewritten to an HNSW/IVFFlat scan the moment a matching\n * index exists — the planner picks it up automatically. So `buildSearch` never\n * branches on `slot.indexType`; it emits one relevance scan and lets Postgres\n * decide. (Contrast libSQL/sqlite-vec, whose ANN needs distinct syntax.)\n *\n * Storage is per-`(nodeKind, fieldPath)`: a `vector(N)` column carrying the\n * field's fixed dimension `N`, with the operator-class-typed ANN index folded\n * into the same table contribution so materialization builds table + index\n * together. The typed column means the index does not need the legacy\n * `::vector(N)` cast-in-index escape hatch the old shared table relied on.\n *\n * Metric support is the full pgvector set — `cosine`, `l2`, `inner_product` —\n * advertised as data on `capabilities`, mirroring `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops` and the `<=>` / `<->` / `<#>` operators.\n *\n * Mirrors the `libsqlVectorStrategy` / `sqliteVecStrategy` structure while\n * letting Postgres' planner pick the ANN index when one exists.\n */\nimport { type SQL, sql } from \"drizzle-orm\";\n\nimport { formatVector } from \"../../../backend/drizzle/columns/vector\";\nimport { quotedTableName } from \"../../../backend/drizzle/operations/shared\";\nimport { type StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport {\n assertFiniteEmbedding,\n quoteIdentifier,\n VECTOR_CONTRIBUTION_PREFIX,\n vectorMinScoreCondition,\n vectorPhysicalName,\n vectorScoreExpression,\n type VectorSlot,\n type VectorStrategy,\n} from \"../vector-strategy\";\n\n/** Physical-name prefixes for the per-field table and its ANN index. */\nconst TABLE_PREFIX = \"tg_vec\";\nconst INDEX_PREFIX = \"tg_vecidx\";\n\n/**\n * pgvector defines `hnsw.ef_search` as an integer GUC with a valid range\n * of 1..1000; `SET hnsw.ef_search = 1001` errors at the server. The\n * backend validates a per-search `efSearch` against this ceiling before\n * inlining it into `SET LOCAL`, surfacing a clear message instead of a raw\n * pgvector error.\n */\nexport const MAX_HNSW_EF_SEARCH = 1000;\n\n/**\n * Validates a per-search `efSearch` override against pgvector's\n * `hnsw.ef_search` valid range. `undefined` (no override) is accepted.\n */\nexport function assertPgvectorEfSearch(efSearch?: number): void {\n if (efSearch === undefined) return;\n if (!Number.isInteger(efSearch) || efSearch <= 0) {\n throw new Error(`efSearch must be a positive integer, got: ${efSearch}`);\n }\n if (efSearch > MAX_HNSW_EF_SEARCH) {\n throw new RangeError(\n `efSearch must be ≤ ${MAX_HNSW_EF_SEARCH} (pgvector's hnsw.ef_search ` +\n `valid range is 1..${MAX_HNSW_EF_SEARCH}), got: ${efSearch}`,\n );\n }\n}\n\n/**\n * pgvector's `vector` type caps at 16,000 dimensions for a stored column\n * (2,000 for an indexed column, but the column-type ceiling is what governs\n * storage; recall degradation beyond 2,000 is a tuning concern, not a hard\n * limit advertised here).\n */\nconst PGVECTOR_MAX_DIMENSIONS = 16_000;\n\n/** Default HNSW `m` (max connections per layer) — pgvector's own default. */\nconst DEFAULT_HNSW_M = 16;\n/** Default HNSW `ef_construction` (build candidate list) — pgvector's own default. */\nconst DEFAULT_HNSW_EF_CONSTRUCTION = 64;\n/** Default IVFFlat `lists` (inverted lists) — pgvector's own default. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\nconst PGVECTOR_CAPABILITIES: VectorCapabilities = {\n supported: true,\n metrics: [\"cosine\", \"l2\", \"inner_product\"],\n indexTypes: [\"hnsw\", \"ivfflat\", \"none\"],\n maxDimensions: PGVECTOR_MAX_DIMENSIONS,\n};\n\n/** Whether a slot's declared index type materializes a real pgvector ANN index. */\nfunction usesAnnIndex(slot: VectorSlot): boolean {\n return slot.indexType === \"hnsw\" || slot.indexType === \"ivfflat\";\n}\n\n/**\n * pgvector operator class for a metric's ANN index — `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops`, mirroring the `<=>` / `<->` / `<#>`\n * distance operators this strategy emits.\n */\nfunction operatorClass(metric: VectorMetric): string {\n switch (metric) {\n case \"cosine\": {\n return \"vector_cosine_ops\";\n }\n case \"l2\": {\n return \"vector_l2_ops\";\n }\n case \"inner_product\": {\n return \"vector_ip_ops\";\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Formats an embedding as a `::vector` literal. The value is bound as a\n * parameter (not interpolated) — Postgres parses the `[a,b,c]` text and the\n * cast types it. Finiteness is validated first so a NaN names its index.\n */\nfunction vectorLiteral(embedding: readonly number[], name: string): SQL {\n assertFiniteEmbedding(embedding, name);\n return sql`${formatVector(embedding)}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SQL,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SQL {\n const query = vectorLiteral(queryEmbedding, \"queryEmbedding\");\n switch (metric) {\n case \"cosine\": {\n return sql`(${embeddingColumn} <=> ${query})`;\n }\n case \"l2\": {\n return sql`(${embeddingColumn} <-> ${query})`;\n }\n case \"inner_product\": {\n return sql`(${embeddingColumn} <#> ${query})`;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName(graphId, nodeKind, fieldPath) {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n },\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath);\n const name = quoteIdentifier(table);\n\n // No standalone graph_id index: the PRIMARY KEY (graph_id, node_id) already\n // covers `WHERE graph_id = ?` via its leading column, so a separate index\n // would be pure write amplification.\n const createDdl = [\n `CREATE TABLE IF NOT EXISTS ${name} (\n \"graph_id\" TEXT NOT NULL,\n \"node_id\" TEXT NOT NULL,\n \"embedding\" vector(${slot.dimensions}) NOT NULL,\n \"created_at\" TIMESTAMPTZ NOT NULL,\n \"updated_at\" TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (\"graph_id\", \"node_id\")\n);`,\n ];\n\n // The HNSW/IVFFlat index is intentionally NOT created here. pgvector\n // similarity SQL is planner-driven (`ORDER BY embedding <=> q LIMIT k`\n // uses the index when present, sequential-scans when not), so the index\n // is a pure materialization concern: `buildCreateIndex` builds it through\n // `materializeIndexes()` with the field's declared `m`/`ef_construction`/\n // `lists`. Building it eagerly here would bake in default tuning (the\n // write-ensure slot has no `indexParams`) and `CREATE INDEX IF NOT EXISTS`\n // would then mask the tuned index materialization would emit.\n\n return [\n {\n logicalName: `${VECTOR_CONTRIBUTION_PREFIX}:${slot.nodeKind}.${slot.fieldPath}`,\n owner: \"pgvector\",\n tableName: table,\n createDdl,\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(slot, params: UpsertEmbeddingParams, timestamp): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const value = vectorLiteral(params.embedding, \"embedding\");\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES (${params.graphId}, ${params.nodeId}, ${value}, ${timestamp}, ${timestamp})\n ON CONFLICT (\"graph_id\", \"node_id\")\n DO UPDATE SET \"embedding\" = EXCLUDED.\"embedding\", \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildDelete(slot, params: DeleteEmbeddingParams): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n return [\n sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId} AND \"node_id\" = ${params.nodeId}\n `,\n ];\n },\n\n buildSearch(slot, params: VectorSearchParams): SQL {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const embeddingColumn = sql`${table}.\"embedding\"`;\n const distance = distanceExpression(\n embeddingColumn,\n params.queryEmbedding,\n params.metric,\n );\n const score = vectorScoreExpression(distance, params.metric);\n\n // Same SQL for brute-force and ANN: with a matching HNSW/IVFFlat index the\n // Postgres planner rewrites this `ORDER BY distance LIMIT k` into an index\n // scan automatically, so the strategy never branches on `slot.indexType`.\n const conditions: SQL[] = [sql`${table}.\"graph_id\" = ${params.graphId}`];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n return sql`\n SELECT ${table}.\"node_id\" AS node_id, ${score} AS score\n FROM ${table}\n WHERE ${sql.join(conditions, sql` AND `)}\n ORDER BY ${distance} ASC\n LIMIT ${params.limit}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n const indexName = pgvectorIndexName(slot);\n return sql.raw(`DROP INDEX IF EXISTS ${quoteIdentifier(indexName)}`);\n },\n\n buildDropStorage(slot): readonly string[] {\n const table = quoteIdentifier(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n // CASCADE drops the ANN index along with the table.\n return [`DROP TABLE IF EXISTS ${table} CASCADE`];\n },\n};\n\nfunction pgvectorIndexName(slot: VectorSlot): string {\n return vectorPhysicalName(\n INDEX_PREFIX,\n slot.graphId,\n slot.nodeKind,\n slot.fieldPath,\n );\n}\n\nfunction pgvectorIndexDdl(\n table: string,\n slot: VectorSlot,\n concurrent: boolean,\n): string {\n const indexName = quoteIdentifier(pgvectorIndexName(slot));\n const quotedTable = quoteIdentifier(table);\n const opClass = operatorClass(slot.metric);\n // Honor the field's declared tuning; fall back to pgvector defaults.\n const m = slot.indexParams?.m ?? DEFAULT_HNSW_M;\n const efConstruction =\n slot.indexParams?.efConstruction ?? DEFAULT_HNSW_EF_CONSTRUCTION;\n const lists = slot.indexParams?.lists ?? DEFAULT_IVFFLAT_LISTS;\n // CONCURRENTLY builds without taking a write-blocking lock on the live table\n // (materializeIndexes passes concurrent on Postgres). Run outside a tx.\n const create = `CREATE INDEX${concurrent ? \" CONCURRENTLY\" : \"\"} IF NOT EXISTS`;\n\n switch (slot.indexType) {\n case \"hnsw\": {\n return `${create} ${indexName} ON ${quotedTable} USING hnsw (\"embedding\" ${opClass}) WITH (m = ${m}, ef_construction = ${efConstruction});`;\n }\n case \"ivfflat\": {\n return `${create} ${indexName} ON ${quotedTable} USING ivfflat (\"embedding\" ${opClass}) WITH (lists = ${lists});`;\n }\n case \"none\": {\n throw new Error(\n \"pgvectorIndexDdl called for a brute-force-only slot (indexType 'none').\",\n );\n }\n default: {\n const _exhaustive: never = slot.indexType;\n throw new Error(`Unsupported vector index type: ${String(_exhaustive)}`);\n }\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as FulltextStrategy } from './types-
|
|
2
|
-
import { P as PostgresTables } from './postgres-
|
|
3
|
-
import { S as SqliteTables } from './sqlite-
|
|
1
|
+
import { F as FulltextStrategy } from './types-Dk8r09KY.js';
|
|
2
|
+
import { P as PostgresTables } from './postgres-Dhom7iiX.js';
|
|
3
|
+
import { S as SqliteTables } from './sqlite-BfLsCEqO.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Generates all DDL statements for the given SQLite tables.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as FulltextStrategy } from './types-
|
|
2
|
-
import { P as PostgresTables } from './postgres-
|
|
3
|
-
import { S as SqliteTables } from './sqlite-
|
|
1
|
+
import { F as FulltextStrategy } from './types-Dvmn-eal.cjs';
|
|
2
|
+
import { P as PostgresTables } from './postgres-jgXmD45C.cjs';
|
|
3
|
+
import { S as SqliteTables } from './sqlite-DcQ_BCUW.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Generates all DDL statements for the given SQLite tables.
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk2LAT5BIK_cjs = require('../chunk-2LAT5BIK.cjs');
|
|
4
4
|
require('../chunk-HTGDWIDE.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
require('../chunk-
|
|
5
|
+
var chunkSB65GJNY_cjs = require('../chunk-SB65GJNY.cjs');
|
|
6
|
+
var chunkLAZGHOZW_cjs = require('../chunk-LAZGHOZW.cjs');
|
|
7
|
+
var chunkEEYV6UOE_cjs = require('../chunk-EEYV6UOE.cjs');
|
|
8
|
+
require('../chunk-3QRBXYT5.cjs');
|
|
9
9
|
require('../chunk-6RMLO5O4.cjs');
|
|
10
10
|
require('../chunk-YQGLVWB2.cjs');
|
|
11
11
|
require('../chunk-ZFWNO3GE.cjs');
|
|
12
12
|
var chunkKTIEB7VH_cjs = require('../chunk-KTIEB7VH.cjs');
|
|
13
13
|
require('../chunk-6G35I3VW.cjs');
|
|
14
14
|
var chunkRP7YITHX_cjs = require('../chunk-RP7YITHX.cjs');
|
|
15
|
-
require('../chunk-
|
|
15
|
+
require('../chunk-CFNT3ITG.cjs');
|
|
16
16
|
var chunk73KASJGO_cjs = require('../chunk-73KASJGO.cjs');
|
|
17
17
|
var chunkJIEJCTDS_cjs = require('../chunk-JIEJCTDS.cjs');
|
|
18
18
|
require('../chunk-FLRCVI2G.cjs');
|
|
@@ -228,8 +228,8 @@ function byId(left, right) {
|
|
|
228
228
|
}
|
|
229
229
|
async function diffAgainstBase(baseStore, forkStore) {
|
|
230
230
|
const graph = baseStore.graph;
|
|
231
|
-
const nodeKinds =
|
|
232
|
-
const edgeKinds =
|
|
231
|
+
const nodeKinds = chunkEEYV6UOE_cjs.getNodeKinds(graph);
|
|
232
|
+
const edgeKinds = chunkEEYV6UOE_cjs.getEdgeKinds(graph);
|
|
233
233
|
const newNodes = [];
|
|
234
234
|
const modifiedNodes = [];
|
|
235
235
|
const deletedNodes = [];
|
|
@@ -311,19 +311,16 @@ async function readActiveSchemaVersion(backend, graphId) {
|
|
|
311
311
|
}
|
|
312
312
|
async function computeSchemaComponent(store) {
|
|
313
313
|
const version = await readActiveSchemaVersion(store.backend, store.graphId);
|
|
314
|
-
return
|
|
314
|
+
return chunkLAZGHOZW_cjs.computeSchemaHash(chunkLAZGHOZW_cjs.serializeSchema(store.graph, version));
|
|
315
315
|
}
|
|
316
316
|
function byDigestEntry(left, right) {
|
|
317
317
|
const byKind = compareStrings(left.kind, right.kind);
|
|
318
318
|
return byKind === 0 ? compareStrings(left.id, right.id) : byKind;
|
|
319
319
|
}
|
|
320
320
|
var CONTENT_FINGERPRINT_BYTES = 16;
|
|
321
|
-
async function
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
const graph = store.graph;
|
|
325
|
-
const nodeKinds = chunk7JGLPAFV_cjs.getNodeKinds(graph);
|
|
326
|
-
const edgeKinds = chunk7JGLPAFV_cjs.getEdgeKinds(graph);
|
|
321
|
+
async function computeContentComponent(backend, graphId, graph) {
|
|
322
|
+
const nodeKinds = chunkEEYV6UOE_cjs.getNodeKinds(graph);
|
|
323
|
+
const edgeKinds = chunkEEYV6UOE_cjs.getEdgeKinds(graph);
|
|
327
324
|
const nodeDigest = [];
|
|
328
325
|
for (const kind of nodeKinds) {
|
|
329
326
|
const rows = await enumerateAllNodes(backend, graphId, kind);
|
|
@@ -369,12 +366,16 @@ async function computeContentFingerprint(store) {
|
|
|
369
366
|
async function computeBaseVersion(store) {
|
|
370
367
|
const [schemaComponent, contentComponent] = await Promise.all([
|
|
371
368
|
computeSchemaComponent(store),
|
|
372
|
-
|
|
369
|
+
computeContentComponent(store.backend, store.graphId, store.graph)
|
|
373
370
|
]);
|
|
374
371
|
return asBaseVersion(
|
|
375
372
|
`${schemaComponent}${TOKEN_SEPARATOR}${contentComponent}`
|
|
376
373
|
);
|
|
377
374
|
}
|
|
375
|
+
function contentComponentOf(version) {
|
|
376
|
+
const separatorIndex = version.indexOf(TOKEN_SEPARATOR);
|
|
377
|
+
return separatorIndex === -1 ? version : version.slice(separatorIndex + 1);
|
|
378
|
+
}
|
|
378
379
|
|
|
379
380
|
// src/graph-merge/errors.ts
|
|
380
381
|
var MERGE_ERROR_CODES = {
|
|
@@ -445,17 +446,17 @@ var CLONE_IMPORT_BATCH_SIZE = 1e3;
|
|
|
445
446
|
function cloneWorkingCopyStrategy(makeBackend) {
|
|
446
447
|
return {
|
|
447
448
|
create: async (baseStore) => {
|
|
448
|
-
const data = await
|
|
449
|
+
const data = await chunkSB65GJNY_cjs.exportGraph(baseStore, {
|
|
449
450
|
includeMeta: true,
|
|
450
451
|
includeDeleted: false
|
|
451
452
|
});
|
|
452
453
|
const backend = await makeBackend();
|
|
453
454
|
try {
|
|
454
|
-
const [freshStore] = await
|
|
455
|
+
const [freshStore] = await chunk2LAT5BIK_cjs.createStoreWithSchema(
|
|
455
456
|
baseStore.graph,
|
|
456
457
|
backend
|
|
457
458
|
);
|
|
458
|
-
const result = await
|
|
459
|
+
const result = await chunkSB65GJNY_cjs.importGraph(freshStore, data, {
|
|
459
460
|
onConflict: "error",
|
|
460
461
|
onUnknownProperty: "error",
|
|
461
462
|
validateReferences: true,
|
|
@@ -483,7 +484,7 @@ function cloneWorkingCopyStrategy(makeBackend) {
|
|
|
483
484
|
async function branch(baseStore, makeBackend, options, strategy) {
|
|
484
485
|
try {
|
|
485
486
|
const base = await computeBaseVersion(baseStore);
|
|
486
|
-
const id = options?.id ?? asBranchId(
|
|
487
|
+
const id = options?.id ?? asBranchId(chunk2LAT5BIK_cjs.generateId());
|
|
487
488
|
const workingCopyStrategy = strategy ?? cloneWorkingCopyStrategy(makeBackend);
|
|
488
489
|
const store = await workingCopyStrategy.create(baseStore);
|
|
489
490
|
return chunkKTIEB7VH_cjs.ok({ id, base, store });
|
|
@@ -512,7 +513,7 @@ function constraintSignature(node, constraint) {
|
|
|
512
513
|
return void 0;
|
|
513
514
|
}
|
|
514
515
|
}
|
|
515
|
-
return `${constraint.name}${KEY_PART_SEPARATOR}${
|
|
516
|
+
return `${constraint.name}${KEY_PART_SEPARATOR}${chunk2LAT5BIK_cjs.computeUniqueKey(
|
|
516
517
|
props,
|
|
517
518
|
constraint.fields,
|
|
518
519
|
constraint.collation
|
|
@@ -2055,7 +2056,7 @@ function normalizeMergeOptions(options = {}) {
|
|
|
2055
2056
|
...provenanceWeights === void 0 ? {} : { provenanceWeights }
|
|
2056
2057
|
};
|
|
2057
2058
|
}
|
|
2058
|
-
var Provenance =
|
|
2059
|
+
var Provenance = chunkLAZGHOZW_cjs.defineNode("Provenance", {
|
|
2059
2060
|
schema: zod.z.object({
|
|
2060
2061
|
targetGraphId: zod.z.string(),
|
|
2061
2062
|
role: zod.z.enum(["node", "edge"]),
|
|
@@ -2069,14 +2070,14 @@ function provenanceGraphId(targetGraphId) {
|
|
|
2069
2070
|
return `${targetGraphId}::merge-provenance`;
|
|
2070
2071
|
}
|
|
2071
2072
|
function buildProvenanceGraph(targetGraphId) {
|
|
2072
|
-
return
|
|
2073
|
+
return chunkEEYV6UOE_cjs.defineGraph({
|
|
2073
2074
|
id: provenanceGraphId(targetGraphId),
|
|
2074
2075
|
nodes: { Provenance: { type: Provenance } },
|
|
2075
2076
|
edges: {}
|
|
2076
2077
|
});
|
|
2077
2078
|
}
|
|
2078
2079
|
async function openProvenanceStore(backend, targetGraphId) {
|
|
2079
|
-
const [store] = await
|
|
2080
|
+
const [store] = await chunk2LAT5BIK_cjs.createStoreWithSchema(
|
|
2080
2081
|
buildProvenanceGraph(targetGraphId),
|
|
2081
2082
|
backend
|
|
2082
2083
|
);
|
|
@@ -2507,6 +2508,48 @@ async function stageBranches(baseStore, branches) {
|
|
|
2507
2508
|
};
|
|
2508
2509
|
}
|
|
2509
2510
|
|
|
2511
|
+
// src/graph-merge/tx-retry.ts
|
|
2512
|
+
var RETRYABLE_SQLSTATES = /* @__PURE__ */ new Set(["40001", "40P01"]);
|
|
2513
|
+
var RETRYABLE_MESSAGE_PATTERN = /could not serialize access|deadlock detected/i;
|
|
2514
|
+
var MAX_COMMIT_ATTEMPTS = 3;
|
|
2515
|
+
function isRetryableTxConflict(error) {
|
|
2516
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2517
|
+
let current = error;
|
|
2518
|
+
while (current !== void 0 && current !== null && typeof current === "object" && !seen.has(current)) {
|
|
2519
|
+
seen.add(current);
|
|
2520
|
+
const candidate = current;
|
|
2521
|
+
if (typeof candidate.code === "string" && RETRYABLE_SQLSTATES.has(candidate.code)) {
|
|
2522
|
+
return true;
|
|
2523
|
+
}
|
|
2524
|
+
if (typeof candidate.message === "string" && RETRYABLE_MESSAGE_PATTERN.test(candidate.message)) {
|
|
2525
|
+
return true;
|
|
2526
|
+
}
|
|
2527
|
+
current = candidate.cause;
|
|
2528
|
+
}
|
|
2529
|
+
return false;
|
|
2530
|
+
}
|
|
2531
|
+
async function withTxConflictRetry(commit) {
|
|
2532
|
+
let lastConflict;
|
|
2533
|
+
for (let attempt = 1; attempt <= MAX_COMMIT_ATTEMPTS; attempt += 1) {
|
|
2534
|
+
try {
|
|
2535
|
+
return await commit();
|
|
2536
|
+
} catch (error) {
|
|
2537
|
+
if (!isRetryableTxConflict(error)) {
|
|
2538
|
+
throw error;
|
|
2539
|
+
}
|
|
2540
|
+
lastConflict = error;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
throw new MergeError(
|
|
2544
|
+
`Merge commit aborted by transaction conflicts (serialization failure or deadlock) on ${MAX_COMMIT_ATTEMPTS} consecutive attempts; giving up.`,
|
|
2545
|
+
{
|
|
2546
|
+
cause: lastConflict,
|
|
2547
|
+
details: { attempts: MAX_COMMIT_ATTEMPTS },
|
|
2548
|
+
suggestion: "Reduce concurrent writes to the merge target, or serialize merges against it."
|
|
2549
|
+
}
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2510
2553
|
// src/graph-merge/type-reconcile.ts
|
|
2511
2554
|
var INCOMPATIBLE_TYPES_FLAG_REASON = "type-reconcile:incompatible-kinds";
|
|
2512
2555
|
function distinctKinds(kinds) {
|
|
@@ -3226,20 +3269,48 @@ async function applyMergePlan(plan, nodesApi, edgesApi) {
|
|
|
3226
3269
|
}
|
|
3227
3270
|
return { nodes: committedNodeIds.size, edges: committedEdges };
|
|
3228
3271
|
}
|
|
3229
|
-
async function commitPlan(target, plan) {
|
|
3272
|
+
async function commitPlan(target, plan, expectedBaseVersion) {
|
|
3230
3273
|
if (!target.backend.capabilities.transactions) {
|
|
3231
3274
|
throw new MergeError(
|
|
3232
3275
|
"merge() requires a transaction-capable target backend. The merged plan (canonical upserts, soft-deletes, edge upserts) must commit atomically; a non-transactional fallback would leave a partially-merged graph on a mid-commit failure. (mergeIncremental() enforces the same requirement.)",
|
|
3233
3276
|
{ details: { capability: "transactions" } }
|
|
3234
3277
|
);
|
|
3235
3278
|
}
|
|
3236
|
-
return
|
|
3237
|
-
(tx) =>
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3279
|
+
return withTxConflictRetry(
|
|
3280
|
+
() => target.transaction(async (tx) => {
|
|
3281
|
+
if (expectedBaseVersion !== void 0) {
|
|
3282
|
+
await assertTargetUnchanged(tx.backend, target, expectedBaseVersion);
|
|
3283
|
+
}
|
|
3284
|
+
return applyMergePlan(
|
|
3285
|
+
plan,
|
|
3286
|
+
tx.nodes,
|
|
3287
|
+
tx.edges
|
|
3288
|
+
);
|
|
3289
|
+
}, MERGE_COMMIT_TX_OPTIONS)
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3292
|
+
var MERGE_COMMIT_TX_OPTIONS = {
|
|
3293
|
+
isolationLevel: "serializable"
|
|
3294
|
+
};
|
|
3295
|
+
async function assertTargetUnchanged(txBackend, target, expectedBaseVersion) {
|
|
3296
|
+
const liveContent = await computeContentComponent(
|
|
3297
|
+
txBackend,
|
|
3298
|
+
target.graphId,
|
|
3299
|
+
target.graph
|
|
3242
3300
|
);
|
|
3301
|
+
const expectedContent = contentComponentOf(expectedBaseVersion);
|
|
3302
|
+
if (liveContent !== expectedContent) {
|
|
3303
|
+
throw new BaseVersionMismatchError(
|
|
3304
|
+
"The merge target was modified between the base@V check and the commit transaction; the resolved plan no longer describes the live target and was not applied.",
|
|
3305
|
+
{
|
|
3306
|
+
details: {
|
|
3307
|
+
expectedContentFingerprint: expectedContent,
|
|
3308
|
+
liveContentFingerprint: liveContent
|
|
3309
|
+
},
|
|
3310
|
+
suggestion: "Re-run the merge (and re-branch if the divergence is real), or serialize writers against merges on this target."
|
|
3311
|
+
}
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3243
3314
|
}
|
|
3244
3315
|
function nodeCollection(nodes, kind) {
|
|
3245
3316
|
const collection = nodes[kind];
|
|
@@ -3277,7 +3348,7 @@ async function validateBaseVersions(target, branches) {
|
|
|
3277
3348
|
);
|
|
3278
3349
|
}
|
|
3279
3350
|
}
|
|
3280
|
-
return chunkKTIEB7VH_cjs.ok();
|
|
3351
|
+
return chunkKTIEB7VH_cjs.ok(targetVersion);
|
|
3281
3352
|
}
|
|
3282
3353
|
function tryNormalize(optionsInput) {
|
|
3283
3354
|
try {
|
|
@@ -3286,7 +3357,7 @@ function tryNormalize(optionsInput) {
|
|
|
3286
3357
|
return chunkKTIEB7VH_cjs.err(new MergeError("Invalid merge options.", { cause: error }));
|
|
3287
3358
|
}
|
|
3288
3359
|
}
|
|
3289
|
-
async function resolveMerge(store, target, branches, options, useBaseSources, incremental) {
|
|
3360
|
+
async function resolveMerge(store, target, branches, options, useBaseSources, incremental, expectedBaseVersion) {
|
|
3290
3361
|
let targetBranchSeen = false;
|
|
3291
3362
|
for (const branch2 of branches) {
|
|
3292
3363
|
if (branch2.id === BASE_PROVENANCE_BRANCH) {
|
|
@@ -3357,7 +3428,16 @@ async function resolveMerge(store, target, branches, options, useBaseSources, in
|
|
|
3357
3428
|
subClassClosure,
|
|
3358
3429
|
preferredBranchId
|
|
3359
3430
|
);
|
|
3360
|
-
const merged = incremental === void 0 ? await commitPlan(target, plan) : await commitIncrementalPlan(target, plan
|
|
3431
|
+
const merged = incremental === void 0 ? await commitPlan(target, plan, expectedBaseVersion) : await commitIncrementalPlan(target, plan, {
|
|
3432
|
+
stagedNewByKind: newNodesByKind(staging),
|
|
3433
|
+
options,
|
|
3434
|
+
introspectionKinds,
|
|
3435
|
+
// The committed (kind, id) keys the base sources matched at PLAN time;
|
|
3436
|
+
// anything NEW the in-tx re-probe surfaces is a window write.
|
|
3437
|
+
plannedBaseMatchKeys: new Set(
|
|
3438
|
+
candidates.data.baseMembers.map((member) => mergeKeyOf(member))
|
|
3439
|
+
)
|
|
3440
|
+
});
|
|
3361
3441
|
const provenance = options.provenance ? buildProvenanceIndex(plan.provenanceRecords) : { byBranch: () => ({ nodeIds: [], edgeIds: [] }) };
|
|
3362
3442
|
const warnings = [...plan.warnings];
|
|
3363
3443
|
let provenancePersisted;
|
|
@@ -3418,7 +3498,15 @@ async function merge(store, branches, optionsInput = {}) {
|
|
|
3418
3498
|
if (chunkKTIEB7VH_cjs.isErr(precondition)) {
|
|
3419
3499
|
return chunkKTIEB7VH_cjs.err(precondition.error);
|
|
3420
3500
|
}
|
|
3421
|
-
return resolveMerge(
|
|
3501
|
+
return resolveMerge(
|
|
3502
|
+
store,
|
|
3503
|
+
target,
|
|
3504
|
+
branches,
|
|
3505
|
+
options,
|
|
3506
|
+
false,
|
|
3507
|
+
void 0,
|
|
3508
|
+
precondition.data
|
|
3509
|
+
);
|
|
3422
3510
|
}
|
|
3423
3511
|
async function validateForkPointVersions(forkPoint, branches) {
|
|
3424
3512
|
const forkVersion = await computeBaseVersion(forkPoint);
|
|
@@ -3651,13 +3739,12 @@ async function validateIncrementalEdgeWrites(target, edgesApi, plan) {
|
|
|
3651
3739
|
}
|
|
3652
3740
|
const notFound = [...plannedKindById.keys()].filter((id) => !existingById.has(id)).sort((left, right) => compareStrings(left, right));
|
|
3653
3741
|
if (notFound.length > 0) {
|
|
3654
|
-
const perKind = await Promise.all(
|
|
3655
|
-
Object.keys(target.graph.edges).map(
|
|
3656
|
-
(kind) => edgeCollection(edgesApi, kind).getByIds(notFound, INCLUDE_TOMBSTONES)
|
|
3657
|
-
)
|
|
3658
|
-
);
|
|
3659
3742
|
const crossKindById = /* @__PURE__ */ new Map();
|
|
3660
|
-
for (const
|
|
3743
|
+
for (const kind of Object.keys(target.graph.edges)) {
|
|
3744
|
+
const rows = await edgeCollection(edgesApi, kind).getByIds(
|
|
3745
|
+
notFound,
|
|
3746
|
+
INCLUDE_TOMBSTONES
|
|
3747
|
+
);
|
|
3661
3748
|
for (const [index, id] of notFound.entries()) {
|
|
3662
3749
|
const row = rows[index];
|
|
3663
3750
|
if (row !== void 0 && !crossKindById.has(id)) {
|
|
@@ -3725,20 +3812,77 @@ async function validateIncrementalEdgeWrites(target, edgesApi, plan) {
|
|
|
3725
3812
|
}
|
|
3726
3813
|
}
|
|
3727
3814
|
}
|
|
3728
|
-
async function
|
|
3815
|
+
async function collectBaseMatchKeys(lookupStore, guard) {
|
|
3816
|
+
const matched = /* @__PURE__ */ new Set();
|
|
3817
|
+
for (const [kind, stagedNodes] of guard.stagedNewByKind) {
|
|
3818
|
+
const resolveConfig = guard.options.resolve[kind];
|
|
3819
|
+
if (resolveConfig === void 0) {
|
|
3820
|
+
continue;
|
|
3821
|
+
}
|
|
3822
|
+
const collection = lookupStore.nodes[kind];
|
|
3823
|
+
if (collection === void 0 || stagedNodes.length === 0) {
|
|
3824
|
+
continue;
|
|
3825
|
+
}
|
|
3826
|
+
const items = stagedNodes.map((staged) => ({ props: staged.node.props }));
|
|
3827
|
+
for (const constraint of uniqueConstraintsFor(
|
|
3828
|
+
guard.introspectionKinds,
|
|
3829
|
+
kind
|
|
3830
|
+
)) {
|
|
3831
|
+
const matches = await collection.bulkFindByConstraint(
|
|
3832
|
+
constraint.name,
|
|
3833
|
+
items
|
|
3834
|
+
);
|
|
3835
|
+
for (const base of matches) {
|
|
3836
|
+
if (base !== void 0) {
|
|
3837
|
+
matched.add(mergeKeyOf(base));
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
if (resolveConfig.blockIndex !== void 0) {
|
|
3842
|
+
const matchesByItem = await collection.bulkFindByIndex(
|
|
3843
|
+
resolveConfig.blockIndex,
|
|
3844
|
+
items
|
|
3845
|
+
);
|
|
3846
|
+
for (const perItem of matchesByItem) {
|
|
3847
|
+
for (const base of perItem) {
|
|
3848
|
+
matched.add(mergeKeyOf(base));
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
return matched;
|
|
3854
|
+
}
|
|
3855
|
+
async function assertBaseResolutionStable(lookupStore, guard) {
|
|
3856
|
+
const liveKeys = await collectBaseMatchKeys(lookupStore, guard);
|
|
3857
|
+
const appeared = [...liveKeys].filter((key) => !guard.plannedBaseMatchKeys.has(key)).sort((left, right) => compareMergeKeys(left, right));
|
|
3858
|
+
if (appeared.length === 0) {
|
|
3859
|
+
return;
|
|
3860
|
+
}
|
|
3861
|
+
throw new BaseVersionMismatchError(
|
|
3862
|
+
`mergeIncremental() resolved its branch additions against the target as of planning, but ${appeared.length} committed row(s) matching a branch addition's identity key (a unique constraint or block index) were inserted before the commit transaction. Committing the plan would create duplicate entities the base-source resolution would otherwise have collapsed.`,
|
|
3863
|
+
{
|
|
3864
|
+
details: { appeared },
|
|
3865
|
+
suggestion: "Re-run mergeIncremental(); the re-planned merge resolves the branch additions against the now-committed rows."
|
|
3866
|
+
}
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3869
|
+
async function commitIncrementalPlan(target, plan, guard) {
|
|
3729
3870
|
if (!target.backend.capabilities.transactions) {
|
|
3730
3871
|
throw new MergeError(
|
|
3731
3872
|
"mergeIncremental() requires a transaction-capable target backend. Incremental writes must preflight existing rows and commit atomically; non-transactional fallback would allow partial graph writes.",
|
|
3732
3873
|
{ details: { capability: "transactions" } }
|
|
3733
3874
|
);
|
|
3734
3875
|
}
|
|
3735
|
-
return
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3876
|
+
return withTxConflictRetry(
|
|
3877
|
+
() => target.transaction(async (tx) => {
|
|
3878
|
+
const nodesApi = tx.nodes;
|
|
3879
|
+
const edgesApi = tx.edges;
|
|
3880
|
+
await assertBaseResolutionStable(tx, guard);
|
|
3881
|
+
await validateIncrementalNodeWrites(target, nodesApi, plan);
|
|
3882
|
+
await validateIncrementalEdgeWrites(target, edgesApi, plan);
|
|
3883
|
+
return applyMergePlan(plan, nodesApi, edgesApi);
|
|
3884
|
+
}, MERGE_COMMIT_TX_OPTIONS)
|
|
3885
|
+
);
|
|
3742
3886
|
}
|
|
3743
3887
|
async function mergeIncremental(args) {
|
|
3744
3888
|
const { forkPoint, target, branches } = args;
|