@nicia-ai/typegraph 0.38.0 → 0.40.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/drizzle/indexes.cjs +8 -10
- package/dist/backend/drizzle/indexes.d.cts +2 -2
- package/dist/backend/drizzle/indexes.d.ts +2 -2
- package/dist/backend/drizzle/indexes.js +4 -6
- package/dist/backend/index.cjs +60 -39
- package/dist/backend/index.d.cts +60 -1
- package/dist/backend/index.d.ts +60 -1
- package/dist/backend/index.js +12 -3
- package/dist/backend/postgres/index.cjs +25 -27
- package/dist/backend/postgres/index.d.cts +6 -6
- package/dist/backend/postgres/index.d.ts +6 -6
- package/dist/backend/postgres/index.js +12 -14
- package/dist/backend/postgres/pglite-store.cjs +26 -27
- package/dist/backend/postgres/pglite-store.cjs.map +1 -1
- package/dist/backend/postgres/pglite-store.d.cts +6 -5
- package/dist/backend/postgres/pglite-store.d.ts +6 -5
- package/dist/backend/postgres/pglite-store.js +22 -23
- package/dist/backend/postgres/pglite-store.js.map +1 -1
- package/dist/backend/postgres/pglite.cjs +14 -16
- package/dist/backend/postgres/pglite.d.cts +3 -3
- package/dist/backend/postgres/pglite.d.ts +3 -3
- package/dist/backend/postgres/pglite.js +13 -15
- package/dist/backend/sqlite/index.cjs +26 -28
- package/dist/backend/sqlite/index.d.cts +6 -6
- package/dist/backend/sqlite/index.d.ts +6 -6
- package/dist/backend/sqlite/index.js +10 -12
- package/dist/backend/sqlite/libsql.cjs +16 -18
- package/dist/backend/sqlite/libsql.cjs.map +1 -1
- package/dist/backend/sqlite/libsql.d.cts +3 -3
- package/dist/backend/sqlite/libsql.d.ts +3 -3
- package/dist/backend/sqlite/libsql.js +15 -17
- package/dist/backend/sqlite/libsql.js.map +1 -1
- package/dist/backend/sqlite/local-store.cjs +27 -28
- package/dist/backend/sqlite/local-store.cjs.map +1 -1
- package/dist/backend/sqlite/local-store.d.cts +6 -5
- package/dist/backend/sqlite/local-store.d.ts +6 -5
- package/dist/backend/sqlite/local-store.js +23 -24
- package/dist/backend/sqlite/local-store.js.map +1 -1
- package/dist/backend/sqlite/local.cjs +15 -17
- package/dist/backend/sqlite/local.d.cts +3 -3
- package/dist/backend/sqlite/local.d.ts +3 -3
- package/dist/backend/sqlite/local.js +13 -15
- package/dist/{chunk-U4JDJKPD.js → chunk-2I3DNNBU.js} +4 -4
- package/dist/{chunk-U4JDJKPD.js.map → chunk-2I3DNNBU.js.map} +1 -1
- package/dist/{chunk-NPWACFQJ.cjs → chunk-2J5NMMVR.cjs} +43 -43
- package/dist/{chunk-NPWACFQJ.cjs.map → chunk-2J5NMMVR.cjs.map} +1 -1
- package/dist/{chunk-NU23DUSJ.cjs → chunk-2X73QTIC.cjs} +12 -13
- package/dist/chunk-2X73QTIC.cjs.map +1 -0
- package/dist/{chunk-A2FGSWMQ.js → chunk-3BL3JFHL.js} +202 -52
- package/dist/chunk-3BL3JFHL.js.map +1 -0
- package/dist/chunk-3SHAUJRB.js +79 -0
- package/dist/chunk-3SHAUJRB.js.map +1 -0
- package/dist/{chunk-UPXDVI3T.js → chunk-53BSOG3O.js} +8 -7
- package/dist/chunk-53BSOG3O.js.map +1 -0
- package/dist/chunk-5J4VNCUD.js +856 -0
- package/dist/chunk-5J4VNCUD.js.map +1 -0
- package/dist/chunk-5YBDB7UG.cjs +12 -0
- package/dist/{chunk-FMNUSGZ4.cjs.map → chunk-5YBDB7UG.cjs.map} +1 -1
- package/dist/{chunk-6XDBRDZE.js → chunk-6N7QBIWN.js} +7 -3
- package/dist/chunk-6N7QBIWN.js.map +1 -0
- package/dist/{chunk-EZH7FNUS.js → chunk-6QP4QXBR.js} +3 -3
- package/dist/{chunk-EZH7FNUS.js.map → chunk-6QP4QXBR.js.map} +1 -1
- package/dist/{chunk-E6TXEISH.cjs → chunk-7UTUKH4E.cjs} +4 -4
- package/dist/{chunk-E6TXEISH.cjs.map → chunk-7UTUKH4E.cjs.map} +1 -1
- package/dist/chunk-7WLEQIHA.cjs +605 -0
- package/dist/chunk-7WLEQIHA.cjs.map +1 -0
- package/dist/{chunk-BQITNFQJ.js → chunk-AQVDAKXH.js} +3 -3
- package/dist/{chunk-BQITNFQJ.js.map → chunk-AQVDAKXH.js.map} +1 -1
- package/dist/{chunk-X6CNEA32.js → chunk-BUZWMDNL.js} +5 -5
- package/dist/{chunk-X6CNEA32.js.map → chunk-BUZWMDNL.js.map} +1 -1
- package/dist/{chunk-7M3NACL3.cjs → chunk-CKFBZ4LV.cjs} +4 -4
- package/dist/{chunk-7M3NACL3.cjs.map → chunk-CKFBZ4LV.cjs.map} +1 -1
- package/dist/{chunk-VBH7ZXSZ.js → chunk-CU3LPYNB.js} +5 -5
- package/dist/{chunk-VBH7ZXSZ.js.map → chunk-CU3LPYNB.js.map} +1 -1
- package/dist/{chunk-YJDSPA5E.js → chunk-EFZ4S22A.js} +11 -10
- package/dist/chunk-EFZ4S22A.js.map +1 -0
- package/dist/chunk-ELA3V6UN.js +601 -0
- package/dist/chunk-ELA3V6UN.js.map +1 -0
- package/dist/{chunk-2SL7OGPR.cjs → chunk-H6I36MGT.cjs} +1037 -887
- package/dist/chunk-H6I36MGT.cjs.map +1 -0
- package/dist/chunk-HAQVISUF.cjs +1098 -0
- package/dist/chunk-HAQVISUF.cjs.map +1 -0
- package/dist/{chunk-O5H62ZWJ.cjs → chunk-HP6LWBLB.cjs} +14 -2
- package/dist/chunk-HP6LWBLB.cjs.map +1 -0
- package/dist/{chunk-BKAKAVRW.cjs → chunk-HQRZEYYB.cjs} +44 -44
- package/dist/{chunk-BKAKAVRW.cjs.map → chunk-HQRZEYYB.cjs.map} +1 -1
- package/dist/{chunk-XD6X7O5R.js → chunk-I5CRUPKO.js} +9 -10
- package/dist/{chunk-XD6X7O5R.js.map → chunk-I5CRUPKO.js.map} +1 -1
- package/dist/{chunk-RQPRCEIO.js → chunk-JHK6NPFV.js} +218 -306
- package/dist/chunk-JHK6NPFV.js.map +1 -0
- package/dist/chunk-JZYMOHHM.cjs +226 -0
- package/dist/chunk-JZYMOHHM.cjs.map +1 -0
- package/dist/{chunk-CQC6VBAF.cjs → chunk-K4FB2RMO.cjs} +10 -10
- package/dist/{chunk-CQC6VBAF.cjs.map → chunk-K4FB2RMO.cjs.map} +1 -1
- package/dist/{chunk-ERZ4QPQX.js → chunk-K6CD6W5J.js} +5 -5
- package/dist/{chunk-ERZ4QPQX.js.map → chunk-K6CD6W5J.js.map} +1 -1
- package/dist/{chunk-LZ3TVJY4.cjs → chunk-KHNKYSGP.cjs} +34 -34
- package/dist/{chunk-LZ3TVJY4.cjs.map → chunk-KHNKYSGP.cjs.map} +1 -1
- package/dist/{chunk-CWX77JB4.cjs → chunk-KLR77R5A.cjs} +13 -13
- package/dist/{chunk-CWX77JB4.cjs.map → chunk-KLR77R5A.cjs.map} +1 -1
- package/dist/{chunk-AOL64O4Z.js → chunk-L3DDZUZP.js} +3 -3
- package/dist/{chunk-AOL64O4Z.js.map → chunk-L3DDZUZP.js.map} +1 -1
- package/dist/{chunk-PZHC5GCD.js → chunk-L5ET7FYQ.js} +3 -3
- package/dist/{chunk-PZHC5GCD.js.map → chunk-L5ET7FYQ.js.map} +1 -1
- package/dist/{chunk-B63IFHXR.cjs → chunk-LFFVD5ZR.cjs} +41 -41
- package/dist/{chunk-B63IFHXR.cjs.map → chunk-LFFVD5ZR.cjs.map} +1 -1
- package/dist/chunk-LL5D5T5W.cjs +157 -0
- package/dist/chunk-LL5D5T5W.cjs.map +1 -0
- package/dist/{chunk-GUUWKPTK.cjs → chunk-LLE25NRD.cjs} +7 -7
- package/dist/{chunk-GUUWKPTK.cjs.map → chunk-LLE25NRD.cjs.map} +1 -1
- package/dist/chunk-LLHMAHG4.cjs +886 -0
- package/dist/chunk-LLHMAHG4.cjs.map +1 -0
- package/dist/{chunk-ZHX4KEM7.cjs → chunk-M2RPZS7J.cjs} +10 -10
- package/dist/{chunk-ZHX4KEM7.cjs.map → chunk-M2RPZS7J.cjs.map} +1 -1
- package/dist/chunk-MNURF4RF.cjs +85 -0
- package/dist/chunk-MNURF4RF.cjs.map +1 -0
- package/dist/chunk-QOHTVDHU.js +144 -0
- package/dist/chunk-QOHTVDHU.js.map +1 -0
- package/dist/{chunk-7VLCN3JB.cjs → chunk-QXKVUJLI.cjs} +113 -112
- package/dist/chunk-QXKVUJLI.cjs.map +1 -0
- package/dist/{chunk-GNPGGLAE.cjs → chunk-QYDUCWD2.cjs} +4 -4
- package/dist/{chunk-GNPGGLAE.cjs.map → chunk-QYDUCWD2.cjs.map} +1 -1
- package/dist/{chunk-TE5ZA4VX.js → chunk-QZYGZVUI.js} +45 -41
- package/dist/chunk-QZYGZVUI.js.map +1 -0
- package/dist/{chunk-YLINFV7Z.cjs → chunk-SAMJLDGG.cjs} +114 -110
- package/dist/chunk-SAMJLDGG.cjs.map +1 -0
- package/dist/{chunk-DOVMTPKE.cjs → chunk-SE422RES.cjs} +27 -27
- package/dist/{chunk-DOVMTPKE.cjs.map → chunk-SE422RES.cjs.map} +1 -1
- package/dist/{chunk-NWYCOFEZ.cjs → chunk-UCHW2MGP.cjs} +332 -433
- package/dist/chunk-UCHW2MGP.cjs.map +1 -0
- package/dist/{chunk-XFY73JWD.cjs → chunk-UDS5DZNY.cjs} +498 -1098
- package/dist/chunk-UDS5DZNY.cjs.map +1 -0
- package/dist/{chunk-KFLXWVUJ.js → chunk-UUIBACKJ.js} +14 -3
- package/dist/chunk-UUIBACKJ.js.map +1 -0
- package/dist/{chunk-VDYA2HMS.js → chunk-VWEFXG73.js} +3 -3
- package/dist/{chunk-VDYA2HMS.js.map → chunk-VWEFXG73.js.map} +1 -1
- package/dist/{chunk-G32AO634.js → chunk-W66YCXWT.js} +464 -1048
- package/dist/chunk-W66YCXWT.js.map +1 -0
- package/dist/{chunk-E6YZRKMM.js → chunk-XMEYZYGE.js} +6 -6
- package/dist/{chunk-E6YZRKMM.js.map → chunk-XMEYZYGE.js.map} +1 -1
- package/dist/{chunk-G3CSQLLT.js → chunk-Y5UC3IXF.js} +461 -6
- package/dist/chunk-Y5UC3IXF.js.map +1 -0
- package/dist/{chunk-SDHV2MWU.js → chunk-YGX4PMG6.js} +5 -5
- package/dist/{chunk-SDHV2MWU.js.map → chunk-YGX4PMG6.js.map} +1 -1
- package/dist/{chunk-KCLZHYPU.cjs → chunk-YIX3BEBR.cjs} +86 -85
- package/dist/chunk-YIX3BEBR.cjs.map +1 -0
- package/dist/{chunk-X6RDQ5NB.cjs → chunk-YX3H63VV.cjs} +8 -2
- package/dist/chunk-YX3H63VV.cjs.map +1 -0
- package/dist/chunk-YYLMXERH.js +211 -0
- package/dist/chunk-YYLMXERH.js.map +1 -0
- package/dist/{chunk-6G5CQ6JX.js → chunk-ZE7E46IZ.js} +5 -5
- package/dist/{chunk-6G5CQ6JX.js.map → chunk-ZE7E46IZ.js.map} +1 -1
- package/dist/{chunk-Z2PPIVOO.js → chunk-ZVME6OSV.js} +5 -5
- package/dist/{chunk-Z2PPIVOO.js.map → chunk-ZVME6OSV.js.map} +1 -1
- package/dist/core/index.cjs +15 -3
- package/dist/core/index.d.cts +4 -3
- package/dist/core/index.d.ts +4 -3
- package/dist/core/index.js +2 -2
- package/dist/{ddl-Dx3Z0_WC.d.ts → ddl-BLEzHw6j.d.ts} +3 -3
- package/dist/{ddl-J6sDyABg.d.cts → ddl-KnCdF_le.d.cts} +3 -3
- package/dist/{define-graph-CzEvA_8F.d.cts → define-graph-Cv3CFwKm.d.cts} +1 -1
- package/dist/{define-graph-DRo9xpYN.d.ts → define-graph-DQnj3fNH.d.ts} +1 -1
- package/dist/graph-merge/index.cjs +40 -43
- package/dist/graph-merge/index.cjs.map +1 -1
- package/dist/graph-merge/index.d.cts +15 -9
- package/dist/graph-merge/index.d.ts +15 -9
- package/dist/graph-merge/index.js +19 -22
- package/dist/graph-merge/index.js.map +1 -1
- package/dist/index.cjs +143 -119
- package/dist/index.d.cts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.js +23 -23
- package/dist/indexes/index.cjs +12 -14
- package/dist/indexes/index.d.cts +5 -5
- package/dist/indexes/index.d.ts +5 -5
- package/dist/indexes/index.js +5 -7
- package/dist/interchange/index.cjs +29 -30
- package/dist/interchange/index.cjs.map +1 -1
- package/dist/interchange/index.d.cts +6 -5
- package/dist/interchange/index.d.ts +6 -5
- package/dist/interchange/index.js +10 -11
- package/dist/interchange/index.js.map +1 -1
- package/dist/{manager-CASfhmzV.d.ts → manager-DjE6Mhag.d.ts} +2 -2
- package/dist/{manager-nCEJiYBb.d.cts → manager-mqee5MVB.d.cts} +2 -2
- package/dist/{postgres-DMgIKQU-.d.cts → postgres-Bm4DyFQU.d.cts} +100 -49
- package/dist/{postgres-Cl1ZAN1G.d.ts → postgres-DtaVALOZ.d.ts} +100 -49
- package/dist/profiler/index.d.cts +8 -7
- package/dist/profiler/index.d.ts +8 -7
- package/dist/provenance/index.cjs +20 -20
- package/dist/provenance/index.d.cts +6 -5
- package/dist/provenance/index.d.ts +6 -5
- package/dist/provenance/index.js +7 -7
- package/dist/schema/index.cjs +26 -28
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +5 -5
- package/dist/schema/index.d.ts +5 -5
- package/dist/schema/index.js +7 -9
- package/dist/schema/index.js.map +1 -1
- package/dist/{temporal-DqtOEo_B.d.ts → searchable-BxlJQVFw.d.cts} +3 -58
- package/dist/{temporal-BC_NQV5Y.d.cts → searchable-ChJ29MCd.d.ts} +3 -58
- package/dist/{sqlite-BDkW39aa.d.cts → sqlite-DT6tTHOG.d.cts} +124 -97
- package/dist/{sqlite-CYfhvESj.d.ts → sqlite-m9Izphk_.d.ts} +124 -97
- package/dist/{store-view-BoHqdHjB.d.cts → store-view-C-buB8Q8.d.cts} +46 -31
- package/dist/{store-view-Ctq-3OHy.d.ts → store-view-CagdeyNn.d.ts} +46 -31
- package/dist/temporal-CyFsSPe8.d.ts +73 -0
- package/dist/temporal-Dn_JADWY.d.cts +73 -0
- package/dist/{types-CUevi_D1.d.ts → types-CYdXzZef.d.ts} +1 -1
- package/dist/{types-COq3-vMC.d.cts → types-CqSfMRW3.d.cts} +1 -1
- package/dist/{where-C92TXCzT.d.cts → where-C3-HRgUq.d.cts} +1 -1
- package/dist/{where-BdE_cYtx.d.ts → where-sQL4u5h-.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-2SL7OGPR.cjs.map +0 -1
- package/dist/chunk-6XDBRDZE.js.map +0 -1
- package/dist/chunk-7VLCN3JB.cjs.map +0 -1
- package/dist/chunk-A2FGSWMQ.js.map +0 -1
- package/dist/chunk-DDCIXXOO.js +0 -9
- package/dist/chunk-DDCIXXOO.js.map +0 -1
- package/dist/chunk-DDCYVIVV.cjs +0 -44
- package/dist/chunk-DDCYVIVV.cjs.map +0 -1
- package/dist/chunk-EOJFGECD.cjs +0 -284
- package/dist/chunk-EOJFGECD.cjs.map +0 -1
- package/dist/chunk-FMNUSGZ4.cjs +0 -12
- package/dist/chunk-G32AO634.js.map +0 -1
- package/dist/chunk-G3CSQLLT.js.map +0 -1
- package/dist/chunk-I6FX7AAG.js +0 -39
- package/dist/chunk-I6FX7AAG.js.map +0 -1
- package/dist/chunk-J6IJARLG.js +0 -94
- package/dist/chunk-J6IJARLG.js.map +0 -1
- package/dist/chunk-KCLZHYPU.cjs.map +0 -1
- package/dist/chunk-KFLXWVUJ.js.map +0 -1
- package/dist/chunk-MTNEGGM2.js +0 -273
- package/dist/chunk-MTNEGGM2.js.map +0 -1
- package/dist/chunk-NU23DUSJ.cjs.map +0 -1
- package/dist/chunk-NWYCOFEZ.cjs.map +0 -1
- package/dist/chunk-O5H62ZWJ.cjs.map +0 -1
- package/dist/chunk-RQPRCEIO.js.map +0 -1
- package/dist/chunk-SVUKGWSN.cjs +0 -102
- package/dist/chunk-SVUKGWSN.cjs.map +0 -1
- package/dist/chunk-TE5ZA4VX.js.map +0 -1
- package/dist/chunk-UH2USOMG.cjs +0 -627
- package/dist/chunk-UH2USOMG.cjs.map +0 -1
- package/dist/chunk-UPXDVI3T.js.map +0 -1
- package/dist/chunk-X6RDQ5NB.cjs.map +0 -1
- package/dist/chunk-XFY73JWD.cjs.map +0 -1
- package/dist/chunk-Y7M44XEK.js +0 -462
- package/dist/chunk-Y7M44XEK.js.map +0 -1
- package/dist/chunk-YJDSPA5E.js.map +0 -1
- package/dist/chunk-YLINFV7Z.cjs.map +0 -1
- package/dist/chunk-Z5QHVL5U.cjs +0 -12
- package/dist/chunk-Z5QHVL5U.cjs.map +0 -1
- package/dist/chunk-ZKZAIX42.cjs +0 -479
- package/dist/chunk-ZKZAIX42.cjs.map +0 -1
- package/dist/{index-CrFL_ENI.d.cts → types-C5pZeKTl.d.cts} +1 -1
- package/dist/{index-Bq7vSPHy.d.ts → types-D8szWDUo.d.ts} +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunk5YBDB7UG_cjs = require('./chunk-5YBDB7UG.cjs');
|
|
4
|
+
var chunkHAQVISUF_cjs = require('./chunk-HAQVISUF.cjs');
|
|
5
|
+
var chunkYX3H63VV_cjs = require('./chunk-YX3H63VV.cjs');
|
|
6
6
|
|
|
7
7
|
// src/query/dialect/vector/pgvector-strategy.ts
|
|
8
8
|
var TABLE_PREFIX = "tg_vec";
|
|
@@ -63,20 +63,20 @@ function operatorClass(metric) {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
function vectorLiteral(embedding, name) {
|
|
66
|
-
|
|
67
|
-
return
|
|
66
|
+
chunkHAQVISUF_cjs.assertFiniteEmbedding(embedding, name);
|
|
67
|
+
return chunkYX3H63VV_cjs.sql`${`[${embedding.join(",")}]`}::vector`;
|
|
68
68
|
}
|
|
69
69
|
function distanceExpression(embeddingColumn, queryEmbedding, metric) {
|
|
70
70
|
const query = vectorLiteral(queryEmbedding, "queryEmbedding");
|
|
71
71
|
switch (metric) {
|
|
72
72
|
case "cosine": {
|
|
73
|
-
return
|
|
73
|
+
return chunkYX3H63VV_cjs.sql`(${embeddingColumn} <=> ${query})`;
|
|
74
74
|
}
|
|
75
75
|
case "l2": {
|
|
76
|
-
return
|
|
76
|
+
return chunkYX3H63VV_cjs.sql`(${embeddingColumn} <-> ${query})`;
|
|
77
77
|
}
|
|
78
78
|
case "inner_product": {
|
|
79
|
-
return
|
|
79
|
+
return chunkYX3H63VV_cjs.sql`(${embeddingColumn} <#> ${query})`;
|
|
80
80
|
}
|
|
81
81
|
default: {
|
|
82
82
|
const _exhaustive = metric;
|
|
@@ -85,7 +85,7 @@ function distanceExpression(embeddingColumn, queryEmbedding, metric) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
function tableName(graphId, nodeKind, fieldPath) {
|
|
88
|
-
return
|
|
88
|
+
return chunkHAQVISUF_cjs.vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);
|
|
89
89
|
}
|
|
90
90
|
var pgvectorStrategy = {
|
|
91
91
|
name: "pgvector",
|
|
@@ -93,7 +93,7 @@ var pgvectorStrategy = {
|
|
|
93
93
|
tableName,
|
|
94
94
|
ownedTables(slot) {
|
|
95
95
|
const table = tableName(slot.graphId, slot.nodeKind, slot.fieldPath);
|
|
96
|
-
const name =
|
|
96
|
+
const name = chunkHAQVISUF_cjs.quoteIdentifier(table);
|
|
97
97
|
const createDdl = [
|
|
98
98
|
`CREATE TABLE IF NOT EXISTS ${name} (
|
|
99
99
|
"graph_id" TEXT NOT NULL,
|
|
@@ -106,7 +106,7 @@ var pgvectorStrategy = {
|
|
|
106
106
|
];
|
|
107
107
|
return [
|
|
108
108
|
{
|
|
109
|
-
logicalName: `${
|
|
109
|
+
logicalName: `${chunkHAQVISUF_cjs.VECTOR_CONTRIBUTION_PREFIX}:${slot.nodeKind}.${slot.fieldPath}`,
|
|
110
110
|
owner: "pgvector",
|
|
111
111
|
tableName: table,
|
|
112
112
|
createDdl,
|
|
@@ -115,12 +115,12 @@ var pgvectorStrategy = {
|
|
|
115
115
|
];
|
|
116
116
|
},
|
|
117
117
|
buildUpsert(slot, params, timestamp) {
|
|
118
|
-
const table =
|
|
118
|
+
const table = chunkYX3H63VV_cjs.sql.identifier(
|
|
119
119
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath)
|
|
120
120
|
);
|
|
121
121
|
const value = vectorLiteral(params.embedding, "embedding");
|
|
122
122
|
return [
|
|
123
|
-
|
|
123
|
+
chunkYX3H63VV_cjs.sql`
|
|
124
124
|
INSERT INTO ${table} ("graph_id", "node_id", "embedding", "created_at", "updated_at")
|
|
125
125
|
VALUES (${params.graphId}, ${params.nodeId}, ${value}, ${timestamp}, ${timestamp})
|
|
126
126
|
ON CONFLICT ("graph_id", "node_id")
|
|
@@ -129,17 +129,17 @@ var pgvectorStrategy = {
|
|
|
129
129
|
];
|
|
130
130
|
},
|
|
131
131
|
buildUpsertBatch(slot, params, timestamp) {
|
|
132
|
-
const table =
|
|
132
|
+
const table = chunkYX3H63VV_cjs.sql.identifier(
|
|
133
133
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath)
|
|
134
134
|
);
|
|
135
|
-
const valueRows =
|
|
135
|
+
const valueRows = chunkYX3H63VV_cjs.sql.join(
|
|
136
136
|
params.rows.map(
|
|
137
|
-
(row) =>
|
|
137
|
+
(row) => chunkYX3H63VV_cjs.sql`(${params.graphId}, ${row.nodeId}, ${vectorLiteral(row.embedding, "embedding")}, ${timestamp}, ${timestamp})`
|
|
138
138
|
),
|
|
139
|
-
|
|
139
|
+
chunkYX3H63VV_cjs.sql`, `
|
|
140
140
|
);
|
|
141
141
|
return [
|
|
142
|
-
|
|
142
|
+
chunkYX3H63VV_cjs.sql`
|
|
143
143
|
INSERT INTO ${table} ("graph_id", "node_id", "embedding", "created_at", "updated_at")
|
|
144
144
|
VALUES ${valueRows}
|
|
145
145
|
ON CONFLICT ("graph_id", "node_id")
|
|
@@ -148,60 +148,60 @@ var pgvectorStrategy = {
|
|
|
148
148
|
];
|
|
149
149
|
},
|
|
150
150
|
buildDelete(slot, params) {
|
|
151
|
-
const table =
|
|
151
|
+
const table = chunkYX3H63VV_cjs.sql.identifier(
|
|
152
152
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath)
|
|
153
153
|
);
|
|
154
154
|
return [
|
|
155
|
-
|
|
155
|
+
chunkYX3H63VV_cjs.sql`
|
|
156
156
|
DELETE FROM ${table}
|
|
157
157
|
WHERE "graph_id" = ${params.graphId} AND "node_id" = ${params.nodeId}
|
|
158
158
|
`
|
|
159
159
|
];
|
|
160
160
|
},
|
|
161
161
|
buildSearch(slot, params, candidates) {
|
|
162
|
-
const table =
|
|
162
|
+
const table = chunkYX3H63VV_cjs.sql.identifier(
|
|
163
163
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath)
|
|
164
164
|
);
|
|
165
|
-
const embeddingColumn =
|
|
165
|
+
const embeddingColumn = chunkYX3H63VV_cjs.sql`${table}."embedding"`;
|
|
166
166
|
const distance = distanceExpression(
|
|
167
167
|
embeddingColumn,
|
|
168
168
|
params.queryEmbedding,
|
|
169
169
|
params.metric
|
|
170
170
|
);
|
|
171
|
-
const score =
|
|
171
|
+
const score = chunkHAQVISUF_cjs.vectorScoreExpression(distance, params.metric);
|
|
172
172
|
const conditions = [
|
|
173
|
-
|
|
173
|
+
chunkYX3H63VV_cjs.sql`${table}."graph_id" = ${params.graphId}`
|
|
174
174
|
];
|
|
175
175
|
if (params.minScore !== void 0) {
|
|
176
176
|
conditions.push(
|
|
177
|
-
|
|
177
|
+
chunkHAQVISUF_cjs.vectorMinScoreCondition(distance, params.metric, params.minScore)
|
|
178
178
|
);
|
|
179
179
|
}
|
|
180
180
|
if (candidates !== void 0) {
|
|
181
|
-
conditions.push(
|
|
181
|
+
conditions.push(chunkYX3H63VV_cjs.sql`${table}."node_id" IN (${candidates})`);
|
|
182
182
|
}
|
|
183
183
|
const pageOffset = params.offset ?? 0;
|
|
184
|
-
const pageClause =
|
|
184
|
+
const pageClause = chunk5YBDB7UG_cjs.vectorPageClause(params.limit, params.offset);
|
|
185
185
|
if (slot.indexType === "ivfflat") {
|
|
186
|
-
const direction = params.metric === "cosine" ?
|
|
187
|
-
const relaxedBody =
|
|
186
|
+
const direction = params.metric === "cosine" ? chunkYX3H63VV_cjs.sql.raw("DESC") : chunkYX3H63VV_cjs.sql.raw("ASC");
|
|
187
|
+
const relaxedBody = chunkYX3H63VV_cjs.sql`
|
|
188
188
|
SELECT ${table}."node_id" AS node_id, ${score} AS score
|
|
189
189
|
FROM ${table}
|
|
190
|
-
WHERE ${
|
|
190
|
+
WHERE ${chunkYX3H63VV_cjs.sql.join(conditions, chunkYX3H63VV_cjs.sql` AND `)}
|
|
191
191
|
ORDER BY ${distance} ASC
|
|
192
192
|
LIMIT ${params.limit + pageOffset}
|
|
193
193
|
`;
|
|
194
|
-
return
|
|
194
|
+
return chunkYX3H63VV_cjs.sql`
|
|
195
195
|
WITH tg_vec_relaxed AS MATERIALIZED (${relaxedBody})
|
|
196
196
|
SELECT node_id, score FROM tg_vec_relaxed
|
|
197
197
|
ORDER BY score ${direction}, node_id ASC
|
|
198
198
|
${pageClause}
|
|
199
199
|
`;
|
|
200
200
|
}
|
|
201
|
-
return
|
|
201
|
+
return chunkYX3H63VV_cjs.sql`
|
|
202
202
|
SELECT ${table}."node_id" AS node_id, ${score} AS score
|
|
203
203
|
FROM ${table}
|
|
204
|
-
WHERE ${
|
|
204
|
+
WHERE ${chunkYX3H63VV_cjs.sql.join(conditions, chunkYX3H63VV_cjs.sql` AND `)}
|
|
205
205
|
ORDER BY ${distance} ASC
|
|
206
206
|
${pageClause}
|
|
207
207
|
`;
|
|
@@ -211,7 +211,7 @@ var pgvectorStrategy = {
|
|
|
211
211
|
},
|
|
212
212
|
buildCreateIndex(slot, options) {
|
|
213
213
|
if (!usesAnnIndex(slot)) return void 0;
|
|
214
|
-
return
|
|
214
|
+
return chunkYX3H63VV_cjs.sql.raw(
|
|
215
215
|
pgvectorIndexDdl(
|
|
216
216
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath),
|
|
217
217
|
slot,
|
|
@@ -222,17 +222,17 @@ var pgvectorStrategy = {
|
|
|
222
222
|
buildDropIndex(slot) {
|
|
223
223
|
if (!usesAnnIndex(slot)) return void 0;
|
|
224
224
|
const indexName = pgvectorIndexName(slot);
|
|
225
|
-
return
|
|
225
|
+
return chunkYX3H63VV_cjs.sql.raw(`DROP INDEX IF EXISTS ${chunkHAQVISUF_cjs.quoteIdentifier(indexName)}`);
|
|
226
226
|
},
|
|
227
227
|
buildDropStorage(slot) {
|
|
228
|
-
const table =
|
|
228
|
+
const table = chunkHAQVISUF_cjs.quoteIdentifier(
|
|
229
229
|
tableName(slot.graphId, slot.nodeKind, slot.fieldPath)
|
|
230
230
|
);
|
|
231
231
|
return [`DROP TABLE IF EXISTS ${table} CASCADE`];
|
|
232
232
|
}
|
|
233
233
|
};
|
|
234
234
|
function pgvectorIndexName(slot) {
|
|
235
|
-
return
|
|
235
|
+
return chunkHAQVISUF_cjs.vectorPhysicalName(
|
|
236
236
|
INDEX_PREFIX,
|
|
237
237
|
slot.graphId,
|
|
238
238
|
slot.nodeKind,
|
|
@@ -240,8 +240,8 @@ function pgvectorIndexName(slot) {
|
|
|
240
240
|
);
|
|
241
241
|
}
|
|
242
242
|
function pgvectorIndexDdl(table, slot, concurrent) {
|
|
243
|
-
const indexName =
|
|
244
|
-
const quotedTable =
|
|
243
|
+
const indexName = chunkHAQVISUF_cjs.quoteIdentifier(pgvectorIndexName(slot));
|
|
244
|
+
const quotedTable = chunkHAQVISUF_cjs.quoteIdentifier(table);
|
|
245
245
|
const opClass = operatorClass(slot.metric);
|
|
246
246
|
const m = slot.indexParams?.m ?? DEFAULT_HNSW_M;
|
|
247
247
|
const efConstruction = slot.indexParams?.efConstruction ?? DEFAULT_HNSW_EF_CONSTRUCTION;
|
|
@@ -268,5 +268,5 @@ function pgvectorIndexDdl(table, slot, concurrent) {
|
|
|
268
268
|
|
|
269
269
|
exports.assertPgvectorEfSearch = assertPgvectorEfSearch;
|
|
270
270
|
exports.pgvectorStrategy = pgvectorStrategy;
|
|
271
|
-
//# sourceMappingURL=chunk-
|
|
272
|
-
//# sourceMappingURL=chunk-
|
|
271
|
+
//# sourceMappingURL=chunk-LFFVD5ZR.cjs.map
|
|
272
|
+
//# sourceMappingURL=chunk-LFFVD5ZR.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/query/dialect/vector/pgvector-strategy.ts"],"names":["assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","vectorScoreExpression","vectorMinScoreCondition","vectorPageClause"],"mappings":"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","file":"chunk-B63IFHXR.cjs","sourcesContent":["/**\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 StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingBatchParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport { sql, type SqlFragment } from \"../../sql-fragment\";\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\";\nimport { vectorPageClause } from \"./pagination\";\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 // The backend probes `pg_extension.extversion` once and turns on\n // `hnsw.iterative_scan` / `ivfflat.iterative_scan` when pgvector >= 0.8, so a\n // filtered scan re-enters the index for more candidates.\n //\n // NOT a full-page guarantee, on either axis. The iterative scan stops at\n // `hnsw.max_scan_tuples` / `ivfflat.max_probes`; and on pgvector < 0.8 there\n // is no iterative scan at all, so the search stays `ef_search`-bounded and\n // behaves like a post-filter. A statically-declared mode cannot express\n // either, which is why the guarantee is its own field.\n filteredApproximateSearch: {\n mode: \"iterative-scan\",\n guaranteesFullPage: false,\n },\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(\n embedding: readonly number[],\n name: string,\n): SqlFragment {\n assertFiniteEmbedding(embedding, name);\n return sql`${`[${embedding.join(\",\")}]`}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SqlFragment,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SqlFragment {\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\nfunction tableName(\n graphId: string,\n nodeKind: string,\n fieldPath: string,\n): string {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName,\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = 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(\n slot,\n params: UpsertEmbeddingParams,\n timestamp,\n ): readonly SqlFragment[] {\n const table = sql.identifier(\n 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 buildUpsertBatch(\n slot,\n params: UpsertEmbeddingBatchParams,\n timestamp,\n ): readonly SqlFragment[] {\n const table = sql.identifier(\n tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const valueRows = sql.join(\n params.rows.map(\n (row) =>\n sql`(${params.graphId}, ${row.nodeId}, ${vectorLiteral(row.embedding, \"embedding\")}, ${timestamp}, ${timestamp})`,\n ),\n sql`, `,\n );\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES ${valueRows}\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 SqlFragment[] {\n const table = sql.identifier(\n 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(\n slot,\n params: VectorSearchParams,\n candidates?: SqlFragment,\n ): SqlFragment {\n const table = sql.identifier(\n 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: SqlFragment[] = [\n sql`${table}.\"graph_id\" = ${params.graphId}`,\n ];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n // Candidate pushdown keeps the HNSW scan (verified plan: HNSW Index Scan\n // -> Nested Loop probe of the nodes pkey -> Limit). Exact under\n // `hnsw.iterative_scan` (pgvector >= 0.8, applied by the backend);\n // bounded by `ef_search` on older pgvector — still strictly better than\n // ranking tombstones into top-k and dropping them post-hoc.\n //\n // Plain `IN (subquery)`: with fresh statistics the planner hashes it\n // (brute-force scans) or drives per-row probes of the nodes pkey\n // under the ordered HNSW scan — the plan-verified shape the liveness\n // pushdown was built on. Stale statistics degrade any membership\n // form; the answer is `store.refreshStatistics()` after bulk loads,\n // not a cleverer SQL shape.\n if (candidates !== undefined) {\n conditions.push(sql`${table}.\"node_id\" IN (${candidates})`);\n }\n // Pagination is rank-relative: the scan fetches `limit + offset`\n // ordered candidates and OFFSET discards the leading page.\n const pageOffset = params.offset ?? 0;\n const pageClause = vectorPageClause(params.limit, params.offset);\n // IVFFlat's iterative scan only offers `relaxed_order` (no\n // strict_order mode), so under the backend-applied\n // `ivfflat.iterative_scan` the index may emit the candidate set\n // slightly out of distance order. Re-sort the bounded set inside a\n // MATERIALIZED wrapper — the fence stops the planner from collapsing\n // the sort back into the index scan's claimed ordering — and page in\n // the wrapper: an OFFSET inside the relaxed scan could discard the\n // wrong rows. Score is monotone in distance, so ordering by score per\n // the metric's direction restores exact ranking.\n if (slot.indexType === \"ivfflat\") {\n const direction =\n params.metric === \"cosine\" ? sql.raw(\"DESC\") : sql.raw(\"ASC\");\n const relaxedBody = 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 + pageOffset}\n `;\n return sql`\n WITH tg_vec_relaxed AS MATERIALIZED (${relaxedBody})\n SELECT node_id, score FROM tg_vec_relaxed\n ORDER BY score ${direction}, node_id ASC\n ${pageClause}\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 ${pageClause}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SqlFragment | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SqlFragment | 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 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/query/dialect/vector/pgvector-strategy.ts"],"names":["assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","vectorScoreExpression","vectorMinScoreCondition","vectorPageClause"],"mappings":"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","file":"chunk-LFFVD5ZR.cjs","sourcesContent":["/**\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 StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingBatchParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport { sql, type SqlFragment } from \"../../sql-fragment\";\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\";\nimport { vectorPageClause } from \"./pagination\";\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 // The backend probes `pg_extension.extversion` once and turns on\n // `hnsw.iterative_scan` / `ivfflat.iterative_scan` when pgvector >= 0.8, so a\n // filtered scan re-enters the index for more candidates.\n //\n // NOT a full-page guarantee, on either axis. The iterative scan stops at\n // `hnsw.max_scan_tuples` / `ivfflat.max_probes`; and on pgvector < 0.8 there\n // is no iterative scan at all, so the search stays `ef_search`-bounded and\n // behaves like a post-filter. A statically-declared mode cannot express\n // either, which is why the guarantee is its own field.\n filteredApproximateSearch: {\n mode: \"iterative-scan\",\n guaranteesFullPage: false,\n },\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(\n embedding: readonly number[],\n name: string,\n): SqlFragment {\n assertFiniteEmbedding(embedding, name);\n return sql`${`[${embedding.join(\",\")}]`}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SqlFragment,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SqlFragment {\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\nfunction tableName(\n graphId: string,\n nodeKind: string,\n fieldPath: string,\n): string {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName,\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = 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(\n slot,\n params: UpsertEmbeddingParams,\n timestamp,\n ): readonly SqlFragment[] {\n const table = sql.identifier(\n 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 buildUpsertBatch(\n slot,\n params: UpsertEmbeddingBatchParams,\n timestamp,\n ): readonly SqlFragment[] {\n const table = sql.identifier(\n tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const valueRows = sql.join(\n params.rows.map(\n (row) =>\n sql`(${params.graphId}, ${row.nodeId}, ${vectorLiteral(row.embedding, \"embedding\")}, ${timestamp}, ${timestamp})`,\n ),\n sql`, `,\n );\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES ${valueRows}\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 SqlFragment[] {\n const table = sql.identifier(\n 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(\n slot,\n params: VectorSearchParams,\n candidates?: SqlFragment,\n ): SqlFragment {\n const table = sql.identifier(\n 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: SqlFragment[] = [\n sql`${table}.\"graph_id\" = ${params.graphId}`,\n ];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n // Candidate pushdown keeps the HNSW scan (verified plan: HNSW Index Scan\n // -> Nested Loop probe of the nodes pkey -> Limit). Exact under\n // `hnsw.iterative_scan` (pgvector >= 0.8, applied by the backend);\n // bounded by `ef_search` on older pgvector — still strictly better than\n // ranking tombstones into top-k and dropping them post-hoc.\n //\n // Plain `IN (subquery)`: with fresh statistics the planner hashes it\n // (brute-force scans) or drives per-row probes of the nodes pkey\n // under the ordered HNSW scan — the plan-verified shape the liveness\n // pushdown was built on. Stale statistics degrade any membership\n // form; the answer is `store.refreshStatistics()` after bulk loads,\n // not a cleverer SQL shape.\n if (candidates !== undefined) {\n conditions.push(sql`${table}.\"node_id\" IN (${candidates})`);\n }\n // Pagination is rank-relative: the scan fetches `limit + offset`\n // ordered candidates and OFFSET discards the leading page.\n const pageOffset = params.offset ?? 0;\n const pageClause = vectorPageClause(params.limit, params.offset);\n // IVFFlat's iterative scan only offers `relaxed_order` (no\n // strict_order mode), so under the backend-applied\n // `ivfflat.iterative_scan` the index may emit the candidate set\n // slightly out of distance order. Re-sort the bounded set inside a\n // MATERIALIZED wrapper — the fence stops the planner from collapsing\n // the sort back into the index scan's claimed ordering — and page in\n // the wrapper: an OFFSET inside the relaxed scan could discard the\n // wrong rows. Score is monotone in distance, so ordering by score per\n // the metric's direction restores exact ranking.\n if (slot.indexType === \"ivfflat\") {\n const direction =\n params.metric === \"cosine\" ? sql.raw(\"DESC\") : sql.raw(\"ASC\");\n const relaxedBody = 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 + pageOffset}\n `;\n return sql`\n WITH tg_vec_relaxed AS MATERIALIZED (${relaxedBody})\n SELECT node_id, score FROM tg_vec_relaxed\n ORDER BY score ${direction}, node_id ASC\n ${pageClause}\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 ${pageClause}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SqlFragment | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SqlFragment | 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 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"]}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkMNURF4RF_cjs = require('./chunk-MNURF4RF.cjs');
|
|
4
|
+
var chunkSAFZ6JTI_cjs = require('./chunk-SAFZ6JTI.cjs');
|
|
5
|
+
|
|
6
|
+
// src/core/temporal.ts
|
|
7
|
+
var RECORDED_INSTANT_VERSION = "r1";
|
|
8
|
+
var RECORDED_REVISION_WIDTH = 16;
|
|
9
|
+
var RECORDED_MAX_REVISION = Number.MAX_SAFE_INTEGER;
|
|
10
|
+
var RECORDED_INSTANT_PATTERN = /^r1:(\d{16}):(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)$/;
|
|
11
|
+
function invalidRecordedInstant(value, path) {
|
|
12
|
+
return new chunkSAFZ6JTI_cjs.ValidationError(
|
|
13
|
+
`${path} must be a canonical versioned recorded instant.`,
|
|
14
|
+
{
|
|
15
|
+
issues: [
|
|
16
|
+
{
|
|
17
|
+
path,
|
|
18
|
+
message: `Expected ${RECORDED_INSTANT_VERSION}:<${RECORDED_REVISION_WIDTH}-digit revision>:YYYY-MM-DDTHH:mm:ss.sssZ, got "${value}"`
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
suggestion: "Persist the exact string returned by store.recordedNow(); migrate preview-schema checkpoints with migrateLegacyRecordedTime() and migrateRecordedAnchor()."
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function parseRecordedInstant(value, path = "RecordedInstant") {
|
|
28
|
+
const match = RECORDED_INSTANT_PATTERN.exec(value);
|
|
29
|
+
if (match === null) throw invalidRecordedInstant(value, path);
|
|
30
|
+
const revisionText = match[1];
|
|
31
|
+
const recordedAt = match[2];
|
|
32
|
+
if (revisionText === void 0 || recordedAt === void 0) {
|
|
33
|
+
throw invalidRecordedInstant(value, path);
|
|
34
|
+
}
|
|
35
|
+
const revision = Number(revisionText);
|
|
36
|
+
if (!Number.isSafeInteger(revision) || revision < 1 || revision >= RECORDED_MAX_REVISION) {
|
|
37
|
+
throw invalidRecordedInstant(value, path);
|
|
38
|
+
}
|
|
39
|
+
chunkMNURF4RF_cjs.validateCanonicalIsoDate(recordedAt, path);
|
|
40
|
+
return { revision, recordedAt };
|
|
41
|
+
}
|
|
42
|
+
function assertValidRecordedInstant(value, path) {
|
|
43
|
+
parseRecordedInstant(value, path);
|
|
44
|
+
}
|
|
45
|
+
function createRecordedInstant(revision, recordedAt) {
|
|
46
|
+
if (!Number.isSafeInteger(revision) || revision < 1 || revision >= RECORDED_MAX_REVISION) {
|
|
47
|
+
throw new chunkSAFZ6JTI_cjs.ValidationError(
|
|
48
|
+
"createRecordedInstant revision must be a valid recorded revision.",
|
|
49
|
+
{
|
|
50
|
+
issues: [
|
|
51
|
+
{
|
|
52
|
+
path: "createRecordedInstant.revision",
|
|
53
|
+
message: `Expected a safe integer from 1 through ${String(RECORDED_MAX_REVISION - 1)}, got ${String(revision)}`
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const revisionText = revision.toString().padStart(RECORDED_REVISION_WIDTH, "0");
|
|
60
|
+
return asRecordedInstant(
|
|
61
|
+
`${RECORDED_INSTANT_VERSION}:${revisionText}:${recordedAt}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function recordedInstantWallTime(instant) {
|
|
65
|
+
return parseRecordedInstant(instant).recordedAt;
|
|
66
|
+
}
|
|
67
|
+
function recordedInstantRevision(instant) {
|
|
68
|
+
return parseRecordedInstant(instant).revision;
|
|
69
|
+
}
|
|
70
|
+
function compareRecordedInstants(left, right) {
|
|
71
|
+
const leftRevision = recordedInstantRevision(left);
|
|
72
|
+
const rightRevision = recordedInstantRevision(right);
|
|
73
|
+
if (leftRevision < rightRevision) return -1;
|
|
74
|
+
if (leftRevision > rightRevision) return 1;
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
function asRecordedInstant(value) {
|
|
78
|
+
assertValidRecordedInstant(value, "asRecordedInstant");
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
function resolveReadCoordinate(mode, asOf, suggestion) {
|
|
82
|
+
if (mode !== "asOf" && asOf !== void 0) {
|
|
83
|
+
throw new chunkSAFZ6JTI_cjs.ValidationError(
|
|
84
|
+
`Temporal mode "${mode}" does not take an asOf timestamp.`,
|
|
85
|
+
{
|
|
86
|
+
issues: [
|
|
87
|
+
{
|
|
88
|
+
path: "asOf",
|
|
89
|
+
message: `asOf is only valid with mode "asOf", not "${mode}"`
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
suggestion: 'Pin an instant with store.asOf(timestamp) or store.view({ mode: "asOf", asOf }); drop asOf for other modes.'
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
assertValidAsOf(
|
|
99
|
+
mode,
|
|
100
|
+
asOf,
|
|
101
|
+
suggestion === void 0 ? void 0 : { suggestion }
|
|
102
|
+
);
|
|
103
|
+
return { valid: asOf === void 0 ? { mode } : { mode, asOf } };
|
|
104
|
+
}
|
|
105
|
+
function withRecordedCoordinate(coordinate, recordedAsOf) {
|
|
106
|
+
assertValidRecordedInstant(recordedAsOf, "asOfRecorded");
|
|
107
|
+
return {
|
|
108
|
+
...coordinate,
|
|
109
|
+
recorded: { asOf: recordedAsOf }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function assertValidAsOf(mode, asOf, options) {
|
|
113
|
+
if (mode === "asOf" && asOf === void 0) {
|
|
114
|
+
throw new chunkSAFZ6JTI_cjs.ValidationError(
|
|
115
|
+
'Temporal mode "asOf" requires a timestamp',
|
|
116
|
+
{
|
|
117
|
+
issues: [
|
|
118
|
+
{ path: "asOf", message: "Timestamp is required for asOf mode" }
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
suggestion: options?.suggestion ?? 'Provide an ISO-8601 timestamp for asOf mode, e.g. "2026-01-01T00:00:00.000Z".'
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
if (asOf !== void 0) {
|
|
127
|
+
chunkMNURF4RF_cjs.validateCanonicalIsoDate(asOf, "asOf");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function describeCoordinate(coordinate) {
|
|
131
|
+
const { mode, asOf } = coordinate.valid;
|
|
132
|
+
const valid = asOf === void 0 ? `mode "${mode}"` : `mode "${mode}" asOf ${asOf}`;
|
|
133
|
+
return coordinate.recorded === void 0 ? valid : `${valid}, recorded asOf ${coordinate.recorded.asOf}`;
|
|
134
|
+
}
|
|
135
|
+
function coordinateContext(coordinate) {
|
|
136
|
+
const { mode, asOf } = coordinate.valid;
|
|
137
|
+
return {
|
|
138
|
+
temporalMode: mode,
|
|
139
|
+
...asOf !== void 0 && { asOf },
|
|
140
|
+
...coordinate.recorded === void 0 ? {} : { recordedAsOf: coordinate.recorded.asOf }
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
exports.RECORDED_MAX_REVISION = RECORDED_MAX_REVISION;
|
|
145
|
+
exports.asRecordedInstant = asRecordedInstant;
|
|
146
|
+
exports.assertValidRecordedInstant = assertValidRecordedInstant;
|
|
147
|
+
exports.compareRecordedInstants = compareRecordedInstants;
|
|
148
|
+
exports.coordinateContext = coordinateContext;
|
|
149
|
+
exports.createRecordedInstant = createRecordedInstant;
|
|
150
|
+
exports.describeCoordinate = describeCoordinate;
|
|
151
|
+
exports.parseRecordedInstant = parseRecordedInstant;
|
|
152
|
+
exports.recordedInstantRevision = recordedInstantRevision;
|
|
153
|
+
exports.recordedInstantWallTime = recordedInstantWallTime;
|
|
154
|
+
exports.resolveReadCoordinate = resolveReadCoordinate;
|
|
155
|
+
exports.withRecordedCoordinate = withRecordedCoordinate;
|
|
156
|
+
//# sourceMappingURL=chunk-LL5D5T5W.cjs.map
|
|
157
|
+
//# sourceMappingURL=chunk-LL5D5T5W.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/temporal.ts"],"names":["ValidationError","validateCanonicalIsoDate"],"mappings":"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","file":"chunk-LL5D5T5W.cjs","sourcesContent":["/**\n * Shared temporal coordinate + validation.\n */\nimport { ValidationError } from \"../errors\";\nimport { validateCanonicalIsoDate } from \"../utils/date\";\nimport { type TemporalMode } from \"./types\";\n\nconst RECORDED_INSTANT_VERSION = \"r1\";\nconst RECORDED_REVISION_WIDTH = 16;\n/** Open interval ceiling for numeric recorded-revision columns. */\nexport const RECORDED_MAX_REVISION = Number.MAX_SAFE_INTEGER;\nconst RECORDED_INSTANT_PATTERN =\n /^r1:(\\d{16}):(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z)$/;\n\ndeclare const RECORDED_INSTANT_BRAND: unique symbol;\n\n/**\n * A versioned recorded-time anchor containing a fixed-width logical revision\n * and a canonical UTC physical timestamp:\n * `r1:0000000000000001:YYYY-MM-DDTHH:mm:ss.sssZ`.\n *\n * Logical revisions are strictly monotonic per graph and make every commit\n * addressable even when many commits share one wall-clock millisecond. The\n * timestamp is a non-decreasing physical wall-time high-water mark used by\n * diagonal valid-time reads. Same-millisecond commits repeat it; backward clock\n * corrections hold it at the previous value until wall time catches up. The\n * string is canonical and lexicographically ordered by revision, so it can\n * round-trip through plain string checkpoint columns without a custom\n * serializer.\n */\nexport type RecordedInstant = string & {\n readonly [RECORDED_INSTANT_BRAND]: \"RecordedInstant\";\n};\n\nexport type RecordedInstantParts = Readonly<{\n revision: number;\n recordedAt: string;\n}>;\n\nfunction invalidRecordedInstant(value: string, path: string): ValidationError {\n return new ValidationError(\n `${path} must be a canonical versioned recorded instant.`,\n {\n issues: [\n {\n path,\n message: `Expected ${RECORDED_INSTANT_VERSION}:<${RECORDED_REVISION_WIDTH}-digit revision>:YYYY-MM-DDTHH:mm:ss.sssZ, got \"${value}\"`,\n },\n ],\n },\n {\n suggestion:\n \"Persist the exact string returned by store.recordedNow(); migrate preview-schema checkpoints with migrateLegacyRecordedTime() and migrateRecordedAnchor().\",\n },\n );\n}\n\nexport function parseRecordedInstant(\n value: string,\n path = \"RecordedInstant\",\n): RecordedInstantParts {\n const match = RECORDED_INSTANT_PATTERN.exec(value);\n if (match === null) throw invalidRecordedInstant(value, path);\n const revisionText = match[1];\n const recordedAt = match[2];\n if (revisionText === undefined || recordedAt === undefined) {\n throw invalidRecordedInstant(value, path);\n }\n const revision = Number(revisionText);\n if (\n !Number.isSafeInteger(revision) ||\n revision < 1 ||\n revision >= RECORDED_MAX_REVISION\n ) {\n throw invalidRecordedInstant(value, path);\n }\n validateCanonicalIsoDate(recordedAt, path);\n return { revision, recordedAt };\n}\n\nexport function assertValidRecordedInstant(value: string, path: string): void {\n parseRecordedInstant(value, path);\n}\n\nexport function createRecordedInstant(\n revision: number,\n recordedAt: string,\n): RecordedInstant {\n if (\n !Number.isSafeInteger(revision) ||\n revision < 1 ||\n revision >= RECORDED_MAX_REVISION\n ) {\n throw new ValidationError(\n \"createRecordedInstant revision must be a valid recorded revision.\",\n {\n issues: [\n {\n path: \"createRecordedInstant.revision\",\n message: `Expected a safe integer from 1 through ${String(RECORDED_MAX_REVISION - 1)}, got ${String(revision)}`,\n },\n ],\n },\n );\n }\n const revisionText = revision\n .toString()\n .padStart(RECORDED_REVISION_WIDTH, \"0\");\n return asRecordedInstant(\n `${RECORDED_INSTANT_VERSION}:${revisionText}:${recordedAt}`,\n );\n}\n\n/**\n * Returns the canonical UTC wall-time component of a recorded anchor.\n *\n * The value is non-decreasing per graph, but it is not the commit-order key;\n * use the complete {@link RecordedInstant} when ordering or replaying commits.\n */\nexport function recordedInstantWallTime(instant: RecordedInstant): string {\n return parseRecordedInstant(instant).recordedAt;\n}\n\n/** Returns the strict per-graph logical revision carried by an anchor. */\nexport function recordedInstantRevision(instant: RecordedInstant): number {\n return parseRecordedInstant(instant).revision;\n}\n\n/**\n * Compares two recorded anchors by logical revision.\n *\n * Revisions are local to a graph, so only compare anchors produced by the same\n * graph. The physical wall-time component deliberately does not participate.\n */\nexport function compareRecordedInstants(\n left: RecordedInstant,\n right: RecordedInstant,\n): -1 | 0 | 1 {\n const leftRevision = recordedInstantRevision(left);\n const rightRevision = recordedInstantRevision(right);\n if (leftRevision < rightRevision) return -1;\n if (leftRevision > rightRevision) return 1;\n return 0;\n}\n\n/**\n * Brands a canonical versioned anchor string as a {@link RecordedInstant}.\n *\n * The escape hatch for an instant that round-trips through untyped storage:\n * captured from {@link Store.recordedNow}, persisted as a plain string, read\n * back, and replayed into `asOfRecorded`. Validates the canonical form eagerly —\n * the same check `asOfRecorded` applies — so a malformed value fails here, at the\n * brand site, rather than deeper in a read. Does *not* assert the instant is a\n * real captured commit; it only guarantees the value is well-formed enough to\n * compare correctly against the recorded relations.\n *\n * @throws {ValidationError} when `value` is not a canonical versioned anchor.\n */\nexport function asRecordedInstant(value: string): RecordedInstant {\n assertValidRecordedInstant(value, \"asRecordedInstant\");\n return value as RecordedInstant;\n}\n\n/**\n * The single opaque temporal coordinate every pinned read is resolved\n * against. It carries the valid-time axis plus an optional recorded/system-time\n * axis, so every surface can inject one coordinate object instead of threading\n * each temporal dimension separately.\n */\nexport type ReadCoordinate = Readonly<{\n /**\n * The valid-time axis: a resolved temporal mode and (only for `\"asOf\"`) the\n * instant it is pinned to.\n */\n valid: Readonly<{\n mode: TemporalMode;\n /** Defined only when `mode` is `\"asOf\"`. */\n asOf?: string;\n }>;\n /** The recorded/system-time axis. Defined only for recorded-pinned views. */\n recorded?: Readonly<{ asOf: RecordedInstant }>;\n}>;\n\n/**\n * Resolves and validates a `(mode, asOf)` pair into a {@link ReadCoordinate}.\n * Rejects an `asOf` paired with any non-`\"asOf\"` mode rather than silently\n * dropping it — pinning an instant is only meaningful in `\"asOf\"` mode, so a\n * `view({ mode: \"current\", asOf })` is a caller mistake, not a coordinate to\n * quietly discard. Then validates via {@link assertValidAsOf}.\n *\n * @param mode - The temporal mode to pin.\n * @param asOf - The supplied timestamp. Required for `\"asOf\"`; rejected for\n * every other mode.\n * @param suggestion - Caller-specific remediation hint for the\n * missing/invalid-timestamp case.\n */\nexport function resolveReadCoordinate(\n mode: TemporalMode,\n asOf: string | undefined,\n suggestion?: string,\n): ReadCoordinate {\n if (mode !== \"asOf\" && asOf !== undefined) {\n throw new ValidationError(\n `Temporal mode \"${mode}\" does not take an asOf timestamp.`,\n {\n issues: [\n {\n path: \"asOf\",\n message: `asOf is only valid with mode \"asOf\", not \"${mode}\"`,\n },\n ],\n },\n {\n suggestion:\n 'Pin an instant with store.asOf(timestamp) or store.view({ mode: \"asOf\", asOf }); drop asOf for other modes.',\n },\n );\n }\n assertValidAsOf(\n mode,\n asOf,\n suggestion === undefined ? undefined : { suggestion },\n );\n return { valid: asOf === undefined ? { mode } : { mode, asOf } };\n}\n\n/**\n * Adds a recorded/system-time pin to an existing valid-time coordinate.\n * Direct `store.asOfRecorded(T)` passes the diagonal valid-time coordinate\n * (`mode: \"asOf\", asOf: T`); `store.asOf(vt).asOfRecorded(rt)` passes the\n * already-resolved valid coordinate and adds the recorded sibling.\n */\nexport function withRecordedCoordinate(\n coordinate: ReadCoordinate,\n recordedAsOf: RecordedInstant,\n): ReadCoordinate {\n assertValidRecordedInstant(recordedAsOf, \"asOfRecorded\");\n return {\n ...coordinate,\n recorded: { asOf: recordedAsOf },\n };\n}\n\n/**\n * Validates the `asOf` coordinate of a temporal read: `\"asOf\"` mode\n * requires a timestamp, and any supplied timestamp must be a canonical\n * fixed-width UTC ISO-8601 string (`YYYY-MM-DDTHH:mm:ss.sssZ`). The latter\n * is load-bearing — temporal filters compare `asOf` against `valid_from` /\n * `valid_to` as text on SQLite, so a non-canonical value (date-only, an\n * offset, natural language, or variable-width / missing milliseconds like\n * `.1Z`) would sort and compare wrong rather than error. Reached only through\n * {@link resolveReadCoordinate}, which every temporal read entry point routes\n * through (direct reads, queries, subgraphs, algorithms, and StoreView), so\n * they all fail identically.\n *\n * @param mode - The resolved temporal mode.\n * @param asOf - The supplied timestamp (may be `undefined`).\n * @param options.suggestion - A caller-specific remediation hint for the\n * missing-timestamp case.\n *\n * @throws {ValidationError} when `mode` is `\"asOf\"` and `asOf` is missing, or\n * when any supplied `asOf` is not a canonical UTC ISO-8601 timestamp. The\n * canonical check runs for *every* mode that consumes `asOf`, so a\n * non-canonical value can never reach a text comparison.\n */\nfunction assertValidAsOf(\n mode: TemporalMode,\n asOf: string | undefined,\n options?: Readonly<{ suggestion?: string }>,\n): void {\n if (mode === \"asOf\" && asOf === undefined) {\n throw new ValidationError(\n 'Temporal mode \"asOf\" requires a timestamp',\n {\n issues: [\n { path: \"asOf\", message: \"Timestamp is required for asOf mode\" },\n ],\n },\n {\n suggestion:\n options?.suggestion ??\n 'Provide an ISO-8601 timestamp for asOf mode, e.g. \"2026-01-01T00:00:00.000Z\".',\n },\n );\n }\n if (asOf !== undefined) {\n validateCanonicalIsoDate(asOf, \"asOf\");\n }\n}\n\n/**\n * A human-readable description of a coordinate for error messages, e.g.\n * `mode \"current\"` or `mode \"asOf\" asOf 2026-01-01T00:00:00.000Z`. Shared by\n * every refusal path (the `StoreView` read-only / current-only / search facades\n * and the sealed-query builder) so they describe a coordinate identically — and\n * a future axis (recorded time) is reflected everywhere from one place.\n */\nexport function describeCoordinate(coordinate: ReadCoordinate): string {\n const { mode, asOf } = coordinate.valid;\n const valid =\n asOf === undefined ? `mode \"${mode}\"` : `mode \"${mode}\" asOf ${asOf}`;\n return coordinate.recorded === undefined ?\n valid\n : `${valid}, recorded asOf ${coordinate.recorded.asOf}`;\n}\n\n/**\n * The structured error-context fields describing a coordinate, shared by the\n * same refusal paths as {@link describeCoordinate}.\n */\nexport function coordinateContext(\n coordinate: ReadCoordinate,\n): Record<string, unknown> {\n const { mode, asOf } = coordinate.valid;\n return {\n temporalMode: mode,\n ...(asOf !== undefined && { asOf }),\n ...(coordinate.recorded === undefined ?\n {}\n : { recordedAsOf: coordinate.recorded.asOf }),\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkHAQVISUF_cjs = require('./chunk-HAQVISUF.cjs');
|
|
4
4
|
|
|
5
5
|
// src/indexes/system.ts
|
|
6
6
|
var SYSTEM_INDEX_DECLARATIONS = [
|
|
@@ -175,7 +175,7 @@ var MAX_SQL_IDENTIFIER_LENGTH = 63;
|
|
|
175
175
|
function systemIndexName(physicalTableName, suffix) {
|
|
176
176
|
const full = `${physicalTableName}_${suffix}`;
|
|
177
177
|
if (full.length <= MAX_SQL_IDENTIFIER_LENGTH) return full;
|
|
178
|
-
const hash =
|
|
178
|
+
const hash = chunkHAQVISUF_cjs.shortHash(JSON.stringify([physicalTableName, suffix]));
|
|
179
179
|
return `${full.slice(0, MAX_SQL_IDENTIFIER_LENGTH - 1 - hash.length)}_${hash}`;
|
|
180
180
|
}
|
|
181
181
|
function resolveSystemIndexNames(overrides) {
|
|
@@ -200,11 +200,11 @@ function assertNoSystemIndexNameCollision(indexes, overrides) {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
function generateSystemIndexDDL(declaration, physicalTableName, options) {
|
|
203
|
-
const name =
|
|
203
|
+
const name = chunkHAQVISUF_cjs.quoteIdentifier(
|
|
204
204
|
systemIndexName(physicalTableName, declaration.suffix)
|
|
205
205
|
);
|
|
206
|
-
const table =
|
|
207
|
-
const columns = declaration.columns.map((column) =>
|
|
206
|
+
const table = chunkHAQVISUF_cjs.quoteIdentifier(physicalTableName);
|
|
207
|
+
const columns = declaration.columns.map((column) => chunkHAQVISUF_cjs.quoteIdentifier(column)).join(", ");
|
|
208
208
|
const concurrently = options.concurrent ? "CONCURRENTLY " : "";
|
|
209
209
|
return `CREATE INDEX ${concurrently}IF NOT EXISTS ${name} ON ${table} (${columns});`;
|
|
210
210
|
}
|
|
@@ -215,5 +215,5 @@ exports.generateSystemIndexDDL = generateSystemIndexDDL;
|
|
|
215
215
|
exports.resolveSystemIndexNames = resolveSystemIndexNames;
|
|
216
216
|
exports.resolveSystemIndexTableName = resolveSystemIndexTableName;
|
|
217
217
|
exports.systemIndexName = systemIndexName;
|
|
218
|
-
//# sourceMappingURL=chunk-
|
|
219
|
-
//# sourceMappingURL=chunk-
|
|
218
|
+
//# sourceMappingURL=chunk-LLE25NRD.cjs.map
|
|
219
|
+
//# sourceMappingURL=chunk-LLE25NRD.cjs.map
|