@nicia-ai/typegraph 0.39.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.
Files changed (247) hide show
  1. package/dist/backend/drizzle/indexes.cjs +8 -10
  2. package/dist/backend/drizzle/indexes.d.cts +2 -2
  3. package/dist/backend/drizzle/indexes.d.ts +2 -2
  4. package/dist/backend/drizzle/indexes.js +4 -6
  5. package/dist/backend/index.cjs +60 -39
  6. package/dist/backend/index.d.cts +60 -1
  7. package/dist/backend/index.d.ts +60 -1
  8. package/dist/backend/index.js +12 -3
  9. package/dist/backend/postgres/index.cjs +24 -26
  10. package/dist/backend/postgres/index.d.cts +6 -6
  11. package/dist/backend/postgres/index.d.ts +6 -6
  12. package/dist/backend/postgres/index.js +11 -13
  13. package/dist/backend/postgres/pglite-store.cjs +25 -26
  14. package/dist/backend/postgres/pglite-store.cjs.map +1 -1
  15. package/dist/backend/postgres/pglite-store.d.cts +6 -5
  16. package/dist/backend/postgres/pglite-store.d.ts +6 -5
  17. package/dist/backend/postgres/pglite-store.js +21 -22
  18. package/dist/backend/postgres/pglite-store.js.map +1 -1
  19. package/dist/backend/postgres/pglite.cjs +13 -15
  20. package/dist/backend/postgres/pglite.d.cts +3 -3
  21. package/dist/backend/postgres/pglite.d.ts +3 -3
  22. package/dist/backend/postgres/pglite.js +12 -14
  23. package/dist/backend/sqlite/index.cjs +25 -27
  24. package/dist/backend/sqlite/index.d.cts +6 -6
  25. package/dist/backend/sqlite/index.d.ts +6 -6
  26. package/dist/backend/sqlite/index.js +9 -11
  27. package/dist/backend/sqlite/libsql.cjs +15 -17
  28. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  29. package/dist/backend/sqlite/libsql.d.cts +3 -3
  30. package/dist/backend/sqlite/libsql.d.ts +3 -3
  31. package/dist/backend/sqlite/libsql.js +14 -16
  32. package/dist/backend/sqlite/libsql.js.map +1 -1
  33. package/dist/backend/sqlite/local-store.cjs +26 -27
  34. package/dist/backend/sqlite/local-store.cjs.map +1 -1
  35. package/dist/backend/sqlite/local-store.d.cts +6 -5
  36. package/dist/backend/sqlite/local-store.d.ts +6 -5
  37. package/dist/backend/sqlite/local-store.js +22 -23
  38. package/dist/backend/sqlite/local-store.js.map +1 -1
  39. package/dist/backend/sqlite/local.cjs +14 -16
  40. package/dist/backend/sqlite/local.d.cts +3 -3
  41. package/dist/backend/sqlite/local.d.ts +3 -3
  42. package/dist/backend/sqlite/local.js +12 -14
  43. package/dist/{chunk-U4JDJKPD.js → chunk-2I3DNNBU.js} +4 -4
  44. package/dist/{chunk-U4JDJKPD.js.map → chunk-2I3DNNBU.js.map} +1 -1
  45. package/dist/{chunk-NPWACFQJ.cjs → chunk-2J5NMMVR.cjs} +43 -43
  46. package/dist/{chunk-NPWACFQJ.cjs.map → chunk-2J5NMMVR.cjs.map} +1 -1
  47. package/dist/{chunk-3YFDFOYB.cjs → chunk-2X73QTIC.cjs} +12 -13
  48. package/dist/chunk-2X73QTIC.cjs.map +1 -0
  49. package/dist/{chunk-CBK2IVI2.js → chunk-3BL3JFHL.js} +40 -30
  50. package/dist/chunk-3BL3JFHL.js.map +1 -0
  51. package/dist/chunk-3SHAUJRB.js +79 -0
  52. package/dist/chunk-3SHAUJRB.js.map +1 -0
  53. package/dist/{chunk-3SK4SVTW.js → chunk-53BSOG3O.js} +8 -7
  54. package/dist/chunk-53BSOG3O.js.map +1 -0
  55. package/dist/chunk-5J4VNCUD.js +856 -0
  56. package/dist/chunk-5J4VNCUD.js.map +1 -0
  57. package/dist/chunk-5YBDB7UG.cjs +12 -0
  58. package/dist/{chunk-FMNUSGZ4.cjs.map → chunk-5YBDB7UG.cjs.map} +1 -1
  59. package/dist/{chunk-6XDBRDZE.js → chunk-6N7QBIWN.js} +7 -3
  60. package/dist/chunk-6N7QBIWN.js.map +1 -0
  61. package/dist/{chunk-EZH7FNUS.js → chunk-6QP4QXBR.js} +3 -3
  62. package/dist/{chunk-EZH7FNUS.js.map → chunk-6QP4QXBR.js.map} +1 -1
  63. package/dist/{chunk-E6TXEISH.cjs → chunk-7UTUKH4E.cjs} +4 -4
  64. package/dist/{chunk-E6TXEISH.cjs.map → chunk-7UTUKH4E.cjs.map} +1 -1
  65. package/dist/chunk-7WLEQIHA.cjs +605 -0
  66. package/dist/chunk-7WLEQIHA.cjs.map +1 -0
  67. package/dist/{chunk-BQITNFQJ.js → chunk-AQVDAKXH.js} +3 -3
  68. package/dist/{chunk-BQITNFQJ.js.map → chunk-AQVDAKXH.js.map} +1 -1
  69. package/dist/{chunk-X6CNEA32.js → chunk-BUZWMDNL.js} +5 -5
  70. package/dist/{chunk-X6CNEA32.js.map → chunk-BUZWMDNL.js.map} +1 -1
  71. package/dist/{chunk-7M3NACL3.cjs → chunk-CKFBZ4LV.cjs} +4 -4
  72. package/dist/{chunk-7M3NACL3.cjs.map → chunk-CKFBZ4LV.cjs.map} +1 -1
  73. package/dist/{chunk-SU7VQOJ3.js → chunk-CU3LPYNB.js} +4 -4
  74. package/dist/{chunk-SU7VQOJ3.js.map → chunk-CU3LPYNB.js.map} +1 -1
  75. package/dist/{chunk-IFRPHG7O.js → chunk-EFZ4S22A.js} +10 -9
  76. package/dist/chunk-EFZ4S22A.js.map +1 -0
  77. package/dist/chunk-ELA3V6UN.js +601 -0
  78. package/dist/chunk-ELA3V6UN.js.map +1 -0
  79. package/dist/{chunk-6SRLCSAV.cjs → chunk-H6I36MGT.cjs} +883 -873
  80. package/dist/chunk-H6I36MGT.cjs.map +1 -0
  81. package/dist/chunk-HAQVISUF.cjs +1098 -0
  82. package/dist/chunk-HAQVISUF.cjs.map +1 -0
  83. package/dist/{chunk-BKAKAVRW.cjs → chunk-HQRZEYYB.cjs} +44 -44
  84. package/dist/{chunk-BKAKAVRW.cjs.map → chunk-HQRZEYYB.cjs.map} +1 -1
  85. package/dist/{chunk-KAFXPB2L.js → chunk-I5CRUPKO.js} +9 -10
  86. package/dist/{chunk-KAFXPB2L.js.map → chunk-I5CRUPKO.js.map} +1 -1
  87. package/dist/{chunk-IFDXG2YJ.js → chunk-JHK6NPFV.js} +217 -305
  88. package/dist/chunk-JHK6NPFV.js.map +1 -0
  89. package/dist/chunk-JZYMOHHM.cjs +226 -0
  90. package/dist/chunk-JZYMOHHM.cjs.map +1 -0
  91. package/dist/{chunk-VXAFOF6Z.cjs → chunk-K4FB2RMO.cjs} +7 -7
  92. package/dist/{chunk-VXAFOF6Z.cjs.map → chunk-K4FB2RMO.cjs.map} +1 -1
  93. package/dist/{chunk-ERZ4QPQX.js → chunk-K6CD6W5J.js} +5 -5
  94. package/dist/{chunk-ERZ4QPQX.js.map → chunk-K6CD6W5J.js.map} +1 -1
  95. package/dist/{chunk-JD2YC62H.cjs → chunk-KHNKYSGP.cjs} +34 -34
  96. package/dist/{chunk-JD2YC62H.cjs.map → chunk-KHNKYSGP.cjs.map} +1 -1
  97. package/dist/{chunk-CWX77JB4.cjs → chunk-KLR77R5A.cjs} +13 -13
  98. package/dist/{chunk-CWX77JB4.cjs.map → chunk-KLR77R5A.cjs.map} +1 -1
  99. package/dist/{chunk-AOL64O4Z.js → chunk-L3DDZUZP.js} +3 -3
  100. package/dist/{chunk-AOL64O4Z.js.map → chunk-L3DDZUZP.js.map} +1 -1
  101. package/dist/{chunk-PZHC5GCD.js → chunk-L5ET7FYQ.js} +3 -3
  102. package/dist/{chunk-PZHC5GCD.js.map → chunk-L5ET7FYQ.js.map} +1 -1
  103. package/dist/{chunk-B63IFHXR.cjs → chunk-LFFVD5ZR.cjs} +41 -41
  104. package/dist/{chunk-B63IFHXR.cjs.map → chunk-LFFVD5ZR.cjs.map} +1 -1
  105. package/dist/chunk-LL5D5T5W.cjs +157 -0
  106. package/dist/chunk-LL5D5T5W.cjs.map +1 -0
  107. package/dist/{chunk-GUUWKPTK.cjs → chunk-LLE25NRD.cjs} +7 -7
  108. package/dist/{chunk-GUUWKPTK.cjs.map → chunk-LLE25NRD.cjs.map} +1 -1
  109. package/dist/chunk-LLHMAHG4.cjs +886 -0
  110. package/dist/chunk-LLHMAHG4.cjs.map +1 -0
  111. package/dist/{chunk-KIZSHRUI.cjs → chunk-M2RPZS7J.cjs} +10 -10
  112. package/dist/{chunk-KIZSHRUI.cjs.map → chunk-M2RPZS7J.cjs.map} +1 -1
  113. package/dist/chunk-MNURF4RF.cjs +85 -0
  114. package/dist/chunk-MNURF4RF.cjs.map +1 -0
  115. package/dist/chunk-QOHTVDHU.js +144 -0
  116. package/dist/chunk-QOHTVDHU.js.map +1 -0
  117. package/dist/{chunk-HTQOBY75.cjs → chunk-QXKVUJLI.cjs} +110 -109
  118. package/dist/chunk-QXKVUJLI.cjs.map +1 -0
  119. package/dist/{chunk-GNPGGLAE.cjs → chunk-QYDUCWD2.cjs} +4 -4
  120. package/dist/{chunk-GNPGGLAE.cjs.map → chunk-QYDUCWD2.cjs.map} +1 -1
  121. package/dist/{chunk-DOKUXLFH.js → chunk-QZYGZVUI.js} +34 -34
  122. package/dist/chunk-QZYGZVUI.js.map +1 -0
  123. package/dist/{chunk-GKQU44SQ.cjs → chunk-SAMJLDGG.cjs} +103 -103
  124. package/dist/{chunk-GKQU44SQ.cjs.map → chunk-SAMJLDGG.cjs.map} +1 -1
  125. package/dist/{chunk-DOVMTPKE.cjs → chunk-SE422RES.cjs} +27 -27
  126. package/dist/{chunk-DOVMTPKE.cjs.map → chunk-SE422RES.cjs.map} +1 -1
  127. package/dist/{chunk-5ELKD2FQ.cjs → chunk-UCHW2MGP.cjs} +330 -431
  128. package/dist/chunk-UCHW2MGP.cjs.map +1 -0
  129. package/dist/{chunk-Y6UA55YS.cjs → chunk-UDS5DZNY.cjs} +495 -1095
  130. package/dist/chunk-UDS5DZNY.cjs.map +1 -0
  131. package/dist/{chunk-VDYA2HMS.js → chunk-VWEFXG73.js} +3 -3
  132. package/dist/{chunk-VDYA2HMS.js.map → chunk-VWEFXG73.js.map} +1 -1
  133. package/dist/{chunk-KXFUQNF2.js → chunk-W66YCXWT.js} +463 -1047
  134. package/dist/chunk-W66YCXWT.js.map +1 -0
  135. package/dist/{chunk-NQBYTLPW.js → chunk-XMEYZYGE.js} +6 -6
  136. package/dist/{chunk-NQBYTLPW.js.map → chunk-XMEYZYGE.js.map} +1 -1
  137. package/dist/{chunk-G3CSQLLT.js → chunk-Y5UC3IXF.js} +461 -6
  138. package/dist/chunk-Y5UC3IXF.js.map +1 -0
  139. package/dist/{chunk-SDHV2MWU.js → chunk-YGX4PMG6.js} +5 -5
  140. package/dist/{chunk-SDHV2MWU.js.map → chunk-YGX4PMG6.js.map} +1 -1
  141. package/dist/{chunk-E2Q7SP2K.cjs → chunk-YIX3BEBR.cjs} +86 -85
  142. package/dist/chunk-YIX3BEBR.cjs.map +1 -0
  143. package/dist/{chunk-X6RDQ5NB.cjs → chunk-YX3H63VV.cjs} +8 -2
  144. package/dist/chunk-YX3H63VV.cjs.map +1 -0
  145. package/dist/chunk-YYLMXERH.js +211 -0
  146. package/dist/chunk-YYLMXERH.js.map +1 -0
  147. package/dist/{chunk-YPUNPG2T.js → chunk-ZE7E46IZ.js} +5 -5
  148. package/dist/{chunk-YPUNPG2T.js.map → chunk-ZE7E46IZ.js.map} +1 -1
  149. package/dist/{chunk-Z2PPIVOO.js → chunk-ZVME6OSV.js} +5 -5
  150. package/dist/{chunk-Z2PPIVOO.js.map → chunk-ZVME6OSV.js.map} +1 -1
  151. package/dist/core/index.cjs +15 -3
  152. package/dist/core/index.d.cts +4 -3
  153. package/dist/core/index.d.ts +4 -3
  154. package/dist/core/index.js +2 -2
  155. package/dist/{ddl-Dx3Z0_WC.d.ts → ddl-BLEzHw6j.d.ts} +3 -3
  156. package/dist/{ddl-J6sDyABg.d.cts → ddl-KnCdF_le.d.cts} +3 -3
  157. package/dist/{define-graph-CzEvA_8F.d.cts → define-graph-Cv3CFwKm.d.cts} +1 -1
  158. package/dist/{define-graph-DRo9xpYN.d.ts → define-graph-DQnj3fNH.d.ts} +1 -1
  159. package/dist/graph-merge/index.cjs +37 -38
  160. package/dist/graph-merge/index.cjs.map +1 -1
  161. package/dist/graph-merge/index.d.cts +6 -5
  162. package/dist/graph-merge/index.d.ts +6 -5
  163. package/dist/graph-merge/index.js +15 -16
  164. package/dist/graph-merge/index.js.map +1 -1
  165. package/dist/index.cjs +141 -117
  166. package/dist/index.d.cts +12 -10
  167. package/dist/index.d.ts +12 -10
  168. package/dist/index.js +22 -22
  169. package/dist/indexes/index.cjs +12 -14
  170. package/dist/indexes/index.d.cts +5 -5
  171. package/dist/indexes/index.d.ts +5 -5
  172. package/dist/indexes/index.js +5 -7
  173. package/dist/interchange/index.cjs +28 -29
  174. package/dist/interchange/index.cjs.map +1 -1
  175. package/dist/interchange/index.d.cts +6 -5
  176. package/dist/interchange/index.d.ts +6 -5
  177. package/dist/interchange/index.js +9 -10
  178. package/dist/interchange/index.js.map +1 -1
  179. package/dist/{manager-CASfhmzV.d.ts → manager-DjE6Mhag.d.ts} +2 -2
  180. package/dist/{manager-nCEJiYBb.d.cts → manager-mqee5MVB.d.cts} +2 -2
  181. package/dist/{postgres-DMgIKQU-.d.cts → postgres-Bm4DyFQU.d.cts} +100 -49
  182. package/dist/{postgres-Cl1ZAN1G.d.ts → postgres-DtaVALOZ.d.ts} +100 -49
  183. package/dist/profiler/index.d.cts +8 -7
  184. package/dist/profiler/index.d.ts +8 -7
  185. package/dist/provenance/index.cjs +19 -19
  186. package/dist/provenance/index.d.cts +6 -5
  187. package/dist/provenance/index.d.ts +6 -5
  188. package/dist/provenance/index.js +6 -6
  189. package/dist/schema/index.cjs +25 -27
  190. package/dist/schema/index.cjs.map +1 -1
  191. package/dist/schema/index.d.cts +5 -5
  192. package/dist/schema/index.d.ts +5 -5
  193. package/dist/schema/index.js +6 -8
  194. package/dist/schema/index.js.map +1 -1
  195. package/dist/{temporal-DqtOEo_B.d.ts → searchable-BxlJQVFw.d.cts} +3 -58
  196. package/dist/{temporal-BC_NQV5Y.d.cts → searchable-ChJ29MCd.d.ts} +3 -58
  197. package/dist/{sqlite-BDkW39aa.d.cts → sqlite-DT6tTHOG.d.cts} +124 -97
  198. package/dist/{sqlite-CYfhvESj.d.ts → sqlite-m9Izphk_.d.ts} +124 -97
  199. package/dist/{store-view-BJd6Vwpt.d.cts → store-view-C-buB8Q8.d.cts} +7 -14
  200. package/dist/{store-view-CLIhwMMX.d.ts → store-view-CagdeyNn.d.ts} +7 -14
  201. package/dist/temporal-CyFsSPe8.d.ts +73 -0
  202. package/dist/temporal-Dn_JADWY.d.cts +73 -0
  203. package/dist/{types-CUevi_D1.d.ts → types-CYdXzZef.d.ts} +1 -1
  204. package/dist/{types-COq3-vMC.d.cts → types-CqSfMRW3.d.cts} +1 -1
  205. package/dist/{where-C92TXCzT.d.cts → where-C3-HRgUq.d.cts} +1 -1
  206. package/dist/{where-BdE_cYtx.d.ts → where-sQL4u5h-.d.ts} +1 -1
  207. package/package.json +1 -1
  208. package/dist/chunk-3SK4SVTW.js.map +0 -1
  209. package/dist/chunk-3YFDFOYB.cjs.map +0 -1
  210. package/dist/chunk-5ELKD2FQ.cjs.map +0 -1
  211. package/dist/chunk-6SRLCSAV.cjs.map +0 -1
  212. package/dist/chunk-6XDBRDZE.js.map +0 -1
  213. package/dist/chunk-CBK2IVI2.js.map +0 -1
  214. package/dist/chunk-DDCIXXOO.js +0 -9
  215. package/dist/chunk-DDCIXXOO.js.map +0 -1
  216. package/dist/chunk-DDCYVIVV.cjs +0 -44
  217. package/dist/chunk-DDCYVIVV.cjs.map +0 -1
  218. package/dist/chunk-DOKUXLFH.js.map +0 -1
  219. package/dist/chunk-E2Q7SP2K.cjs.map +0 -1
  220. package/dist/chunk-EOJFGECD.cjs +0 -284
  221. package/dist/chunk-EOJFGECD.cjs.map +0 -1
  222. package/dist/chunk-FMNUSGZ4.cjs +0 -12
  223. package/dist/chunk-G3CSQLLT.js.map +0 -1
  224. package/dist/chunk-HTQOBY75.cjs.map +0 -1
  225. package/dist/chunk-I6FX7AAG.js +0 -39
  226. package/dist/chunk-I6FX7AAG.js.map +0 -1
  227. package/dist/chunk-IFDXG2YJ.js.map +0 -1
  228. package/dist/chunk-IFRPHG7O.js.map +0 -1
  229. package/dist/chunk-J6IJARLG.js +0 -94
  230. package/dist/chunk-J6IJARLG.js.map +0 -1
  231. package/dist/chunk-KXFUQNF2.js.map +0 -1
  232. package/dist/chunk-MTNEGGM2.js +0 -273
  233. package/dist/chunk-MTNEGGM2.js.map +0 -1
  234. package/dist/chunk-SVUKGWSN.cjs +0 -102
  235. package/dist/chunk-SVUKGWSN.cjs.map +0 -1
  236. package/dist/chunk-UH2USOMG.cjs +0 -627
  237. package/dist/chunk-UH2USOMG.cjs.map +0 -1
  238. package/dist/chunk-X6RDQ5NB.cjs.map +0 -1
  239. package/dist/chunk-Y6UA55YS.cjs.map +0 -1
  240. package/dist/chunk-Y7M44XEK.js +0 -462
  241. package/dist/chunk-Y7M44XEK.js.map +0 -1
  242. package/dist/chunk-Z5QHVL5U.cjs +0 -12
  243. package/dist/chunk-Z5QHVL5U.cjs.map +0 -1
  244. package/dist/chunk-ZKZAIX42.cjs +0 -479
  245. package/dist/chunk-ZKZAIX42.cjs.map +0 -1
  246. package/dist/{index-CrFL_ENI.d.cts → types-C5pZeKTl.d.cts} +1 -1
  247. package/dist/{index-Bq7vSPHy.d.ts → types-D8szWDUo.d.ts} +1 -1
@@ -1,462 +0,0 @@
1
- import { sql } from './chunk-6XDBRDZE.js';
2
- import { requireDefined } from './chunk-QMQLUA66.js';
3
-
4
- // src/backend/table-contribution.ts
5
- var FULLTEXT_CONTRIBUTION_NAME = "fulltext";
6
- var BASE_CONTRIBUTION_OWNER = "base";
7
-
8
- // src/query/dialect/fulltext-strategy.ts
9
- var ALL_FULLTEXT_MODES = [
10
- "websearch",
11
- "phrase",
12
- "plain",
13
- "raw"
14
- ];
15
- function buildFulltextCapabilities(strategy) {
16
- return {
17
- supported: true,
18
- languages: strategy.languages,
19
- phraseQueries: strategy.supportedModes.includes("phrase"),
20
- prefixQueries: strategy.supportsPrefix,
21
- highlighting: strategy.supportsSnippets
22
- };
23
- }
24
- function quoteIdentifier(name) {
25
- return `"${name.replaceAll('"', '""')}"`;
26
- }
27
- function tsvectorColumn(tableName) {
28
- return sql`${sql.identifier(tableName)}."tsv"`;
29
- }
30
- function dedupeFulltextBatchRows(rows) {
31
- const seen = /* @__PURE__ */ new Map();
32
- for (const row of rows) seen.set(row.nodeId, row);
33
- return [...seen.values()];
34
- }
35
- function buildPkScopedDelete(tableName, params) {
36
- const table = sql.identifier(tableName);
37
- return sql`
38
- DELETE FROM ${table}
39
- WHERE "graph_id" = ${params.graphId}
40
- AND "node_kind" = ${params.nodeKind}
41
- AND "node_id" = ${params.nodeId}
42
- `;
43
- }
44
- function buildPkScopedBatchDelete(tableName, params) {
45
- if (params.nodeIds.length === 0) return void 0;
46
- const unique = [...new Set(params.nodeIds)];
47
- const table = sql.identifier(tableName);
48
- return sql`
49
- DELETE FROM ${table}
50
- WHERE "graph_id" = ${params.graphId}
51
- AND "node_kind" = ${params.nodeKind}
52
- AND "node_id" IN (${sql.join(
53
- unique.map((id) => sql`${id}`),
54
- sql`, `
55
- )})
56
- `;
57
- }
58
- function postgresTsquery(mode, query, language) {
59
- const langExpr = language === void 0 ? sql`"language"` : sql`${language}::regconfig`;
60
- switch (mode) {
61
- case "websearch": {
62
- return sql`websearch_to_tsquery(${langExpr}, ${query})`;
63
- }
64
- case "phrase": {
65
- return sql`phraseto_tsquery(${langExpr}, ${query})`;
66
- }
67
- case "plain": {
68
- return sql`plainto_tsquery(${langExpr}, ${query})`;
69
- }
70
- case "raw": {
71
- return sql`to_tsquery(${langExpr}, ${query})`;
72
- }
73
- default: {
74
- const _exhaustive = mode;
75
- throw new Error(`Unsupported fulltext mode: ${String(_exhaustive)}`);
76
- }
77
- }
78
- }
79
- var tsvectorStrategy = {
80
- name: "tsvector",
81
- supportedModes: ALL_FULLTEXT_MODES,
82
- supportsSnippets: true,
83
- // `raw` mode exposes `foo:*` prefix-match syntax to callers.
84
- supportsPrefix: true,
85
- supportsLanguageOverride: true,
86
- // Canonical Postgres stemmers; every stock install ships these plus a
87
- // few others. Runtime `to_tsvector` accepts any installed regconfig
88
- // name — this list is advisory for capability discovery.
89
- languages: [
90
- "simple",
91
- "english",
92
- "french",
93
- "german",
94
- "italian",
95
- "portuguese",
96
- "russian",
97
- "spanish",
98
- "swedish"
99
- ],
100
- matchCondition(tableName, query, mode, language) {
101
- const q = postgresTsquery(mode, query, language);
102
- return sql`${tsvectorColumn(tableName)} @@ ${q}`;
103
- },
104
- rankExpression(tableName, query, mode, language) {
105
- const q = postgresTsquery(mode, query, language);
106
- return sql`ts_rank_cd(${tsvectorColumn(tableName)}, ${q})`;
107
- },
108
- snippetExpression(_tableName, query, mode, language) {
109
- const langExpr = language === void 0 ? sql`"language"` : sql`${language}::regconfig`;
110
- const q = postgresTsquery(mode, query, language);
111
- return sql`ts_headline(${langExpr}, "content", ${q}, 'StartSel=<mark>,StopSel=</mark>,MaxFragments=1,MinWords=5,MaxWords=30,ShortWord=3')`;
112
- },
113
- ownedTables(primaryTableName) {
114
- const name = quoteIdentifier(primaryTableName);
115
- const gin = quoteIdentifier(`${primaryTableName}_tsv_idx`);
116
- const kind = quoteIdentifier(`${primaryTableName}_kind_idx`);
117
- const createDdl = [
118
- `CREATE TABLE IF NOT EXISTS ${name} (
119
- "graph_id" TEXT NOT NULL,
120
- "node_kind" TEXT NOT NULL,
121
- "node_id" TEXT NOT NULL,
122
- "content" TEXT NOT NULL,
123
- "language" regconfig NOT NULL,
124
- "tsv" tsvector NOT NULL
125
- GENERATED ALWAYS AS (to_tsvector("language", "content")) STORED,
126
- "updated_at" TIMESTAMPTZ NOT NULL,
127
- PRIMARY KEY ("graph_id", "node_kind", "node_id")
128
- );`,
129
- `CREATE INDEX IF NOT EXISTS ${gin} ON ${name} USING GIN ("tsv");`,
130
- `CREATE INDEX IF NOT EXISTS ${kind} ON ${name} ("graph_id", "node_kind");`
131
- ];
132
- return [
133
- {
134
- logicalName: FULLTEXT_CONTRIBUTION_NAME,
135
- owner: "tsvector",
136
- tableName: primaryTableName,
137
- createDdl,
138
- runtimeEnsure: true
139
- }
140
- ];
141
- },
142
- buildUpsert(tableName, params, timestamp) {
143
- const table = sql.identifier(tableName);
144
- return [
145
- sql`
146
- INSERT INTO ${table} ("graph_id", "node_kind", "node_id", "content", "language", "updated_at")
147
- VALUES (
148
- ${params.graphId}, ${params.nodeKind}, ${params.nodeId},
149
- ${params.content}, ${params.language}::regconfig,
150
- ${timestamp}
151
- )
152
- ON CONFLICT ("graph_id", "node_kind", "node_id")
153
- DO UPDATE SET
154
- "content" = EXCLUDED."content",
155
- "language" = EXCLUDED."language",
156
- "updated_at" = EXCLUDED."updated_at"
157
- `
158
- ];
159
- },
160
- buildBatchUpsert(tableName, params, timestamp) {
161
- const rows = dedupeFulltextBatchRows(params.rows);
162
- if (rows.length === 0) return [];
163
- const table = sql.identifier(tableName);
164
- const valueTuples = rows.map(
165
- (row) => sql`
166
- (
167
- ${params.graphId}, ${params.nodeKind}, ${row.nodeId},
168
- ${row.content}, ${row.language}::regconfig,
169
- ${timestamp}
170
- )
171
- `
172
- );
173
- return [
174
- sql`
175
- INSERT INTO ${table} ("graph_id", "node_kind", "node_id", "content", "language", "updated_at")
176
- VALUES ${sql.join(valueTuples, sql`, `)}
177
- ON CONFLICT ("graph_id", "node_kind", "node_id")
178
- DO UPDATE SET
179
- "content" = EXCLUDED."content",
180
- "language" = EXCLUDED."language",
181
- "updated_at" = EXCLUDED."updated_at"
182
- `
183
- ];
184
- },
185
- buildDelete(tableName, params) {
186
- return [buildPkScopedDelete(tableName, params)];
187
- },
188
- buildBatchDelete(tableName, params) {
189
- const stmt = buildPkScopedBatchDelete(tableName, params);
190
- return stmt === void 0 ? [] : [stmt];
191
- }
192
- };
193
- function translateToFts5Query(query, mode) {
194
- switch (mode) {
195
- case "phrase": {
196
- return `"${query.replaceAll('"', '""')}"`;
197
- }
198
- case "plain": {
199
- return query.trim().split(/\s+/u).filter((token) => token.length > 0).map((token) => `"${token.replaceAll('"', '""')}"`).join(" ");
200
- }
201
- case "websearch": {
202
- return translateWebsearchToFts5(query);
203
- }
204
- case "raw": {
205
- return query;
206
- }
207
- default: {
208
- const _exhaustive = mode;
209
- throw new Error(`Unsupported fulltext mode: ${String(_exhaustive)}`);
210
- }
211
- }
212
- }
213
- function translateWebsearchToFts5(query) {
214
- const tokens = [];
215
- let index = 0;
216
- function skipWhitespace() {
217
- while (index < query.length && /\s/u.test(query[index] ?? "")) {
218
- index += 1;
219
- }
220
- }
221
- function readPhrase() {
222
- index += 1;
223
- let content = "";
224
- while (index < query.length && query[index] !== '"') {
225
- content += query[index] ?? "";
226
- index += 1;
227
- }
228
- if (query[index] === '"') index += 1;
229
- return `"${content.replaceAll('"', '""')}"`;
230
- }
231
- function readBareTerm() {
232
- let term = "";
233
- while (index < query.length && !/\s/u.test(query[index] ?? "")) {
234
- term += query[index] ?? "";
235
- index += 1;
236
- }
237
- return term;
238
- }
239
- while (index < query.length) {
240
- skipWhitespace();
241
- if (index >= query.length) break;
242
- const ch = query[index];
243
- if (ch === '"') {
244
- tokens.push(readPhrase());
245
- continue;
246
- }
247
- if (ch === "-") {
248
- index += 1;
249
- const term = query[index] === '"' ? readPhrase() : `"${readBareTerm().replaceAll('"', '""')}"`;
250
- tokens.push(`NOT ${term}`);
251
- continue;
252
- }
253
- if (ch === "+") {
254
- index += 1;
255
- continue;
256
- }
257
- const bare = readBareTerm();
258
- if (bare.length === 0) continue;
259
- if (bare.toUpperCase() === "OR") {
260
- tokens.push("OR");
261
- continue;
262
- }
263
- tokens.push(`"${bare.replaceAll('"', '""')}"`);
264
- }
265
- if (tokens.length > 0 && tokens[0]?.startsWith("NOT ")) {
266
- tokens.shift();
267
- }
268
- return tokens.join(" ");
269
- }
270
- var fts5Strategy = {
271
- name: "fts5",
272
- supportedModes: ALL_FULLTEXT_MODES,
273
- supportsSnippets: true,
274
- // FTS5 supports `foo*` prefix matching natively.
275
- supportsPrefix: true,
276
- // FTS5 tokenizer is fixed at table-create time; per-row / per-query
277
- // language metadata is stored but not consulted.
278
- supportsLanguageOverride: false,
279
- // The built-in tokenizer is `porter unicode61 remove_diacritics 2`; the
280
- // `language` field on searchable() is recorded for future use but not
281
- // applied at query time.
282
- languages: ["porter", "unicode61", "trigram"],
283
- matchCondition(tableName, query, mode, _language) {
284
- const matchExpression = translateToFts5Query(query, mode);
285
- return sql`${sql.identifier(tableName)} MATCH ${matchExpression}`;
286
- },
287
- rankExpression(tableName, _query, _mode, _language) {
288
- return sql`-bm25(${sql.identifier(tableName)})`;
289
- },
290
- snippetExpression(tableName, _query, _mode, _language) {
291
- return sql`snippet(${sql.identifier(tableName)}, -1, '<mark>', '</mark>', '…', 20)`;
292
- },
293
- ownedTables(primaryTableName) {
294
- const name = quoteIdentifier(primaryTableName);
295
- return [
296
- {
297
- logicalName: FULLTEXT_CONTRIBUTION_NAME,
298
- owner: "fts5",
299
- tableName: primaryTableName,
300
- createDdl: [
301
- `CREATE VIRTUAL TABLE IF NOT EXISTS ${name} USING fts5(
302
- graph_id UNINDEXED,
303
- node_kind UNINDEXED,
304
- node_id UNINDEXED,
305
- language UNINDEXED,
306
- updated_at UNINDEXED,
307
- content,
308
- tokenize='porter unicode61 remove_diacritics 2'
309
- );`
310
- ],
311
- runtimeEnsure: true
312
- }
313
- ];
314
- },
315
- buildUpsert(tableName, params, timestamp) {
316
- const table = sql.identifier(tableName);
317
- return [
318
- sql`
319
- DELETE FROM ${table}
320
- WHERE "graph_id" = ${params.graphId}
321
- AND "node_kind" = ${params.nodeKind}
322
- AND "node_id" = ${params.nodeId}
323
- `,
324
- sql`
325
- INSERT INTO ${table} (graph_id, node_kind, node_id, content, language, updated_at)
326
- VALUES (${params.graphId}, ${params.nodeKind}, ${params.nodeId}, ${params.content}, ${params.language}, ${timestamp})
327
- `
328
- ];
329
- },
330
- buildBatchUpsert(tableName, params, timestamp) {
331
- const rows = dedupeFulltextBatchRows(params.rows);
332
- if (rows.length === 0) return [];
333
- const table = sql.identifier(tableName);
334
- const nodeIds = rows.map((row) => row.nodeId);
335
- const deleteStmt = sql`
336
- DELETE FROM ${table}
337
- WHERE "graph_id" = ${params.graphId}
338
- AND "node_kind" = ${params.nodeKind}
339
- AND "node_id" IN (${sql.join(
340
- nodeIds.map((id) => sql`${id}`),
341
- sql`, `
342
- )})
343
- `;
344
- const valueTuples = rows.map(
345
- (row) => sql`
346
- (
347
- ${params.graphId}, ${params.nodeKind}, ${row.nodeId},
348
- ${row.content}, ${row.language}, ${timestamp}
349
- )
350
- `
351
- );
352
- const insertStmt = sql`
353
- INSERT INTO ${table} (graph_id, node_kind, node_id, content, language, updated_at)
354
- VALUES ${sql.join(valueTuples, sql`, `)}
355
- `;
356
- return [deleteStmt, insertStmt];
357
- },
358
- buildDelete(tableName, params) {
359
- return [buildPkScopedDelete(tableName, params)];
360
- },
361
- buildBatchDelete(tableName, params) {
362
- const stmt = buildPkScopedBatchDelete(tableName, params);
363
- return stmt === void 0 ? [] : [stmt];
364
- }
365
- };
366
-
367
- // src/query/dialect/vector-strategy.ts
368
- var VECTOR_CONTRIBUTION_PREFIX = "vector";
369
- function buildVectorCapabilities(strategy) {
370
- return strategy.capabilities;
371
- }
372
- function vectorScoreExpression(distanceExpression, metric) {
373
- switch (metric) {
374
- case "cosine": {
375
- return sql`(1 - (${distanceExpression}))`;
376
- }
377
- case "l2":
378
- case "inner_product": {
379
- return distanceExpression;
380
- }
381
- default: {
382
- const _exhaustive = metric;
383
- throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);
384
- }
385
- }
386
- }
387
- function vectorMinScoreCondition(distanceExpression, metric, minScore) {
388
- assertVectorMinScore(minScore, metric);
389
- switch (metric) {
390
- case "cosine": {
391
- return sql`${distanceExpression} <= ${1 - minScore}`;
392
- }
393
- case "l2": {
394
- return sql`${distanceExpression} <= ${minScore}`;
395
- }
396
- case "inner_product": {
397
- return sql`${distanceExpression} <= ${-minScore}`;
398
- }
399
- default: {
400
- const _exhaustive = metric;
401
- throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);
402
- }
403
- }
404
- }
405
- function assertFiniteEmbedding(embedding, name) {
406
- for (const [index, value] of embedding.entries()) {
407
- if (typeof value !== "number" || !Number.isFinite(value)) {
408
- throw new TypeError(
409
- `${name}[${index}] must be a finite number, got: ${value}`
410
- );
411
- }
412
- }
413
- }
414
- function assertVectorSearchLimit(limit) {
415
- if (!Number.isInteger(limit) || limit <= 0) {
416
- throw new RangeError(
417
- `vectorSearch limit must be a positive integer, got: ${limit}`
418
- );
419
- }
420
- }
421
- function assertVectorMinScore(minScore, metric, label = "minScore") {
422
- if (!Number.isFinite(minScore)) {
423
- throw new RangeError(`${label} must be a finite number, got: ${minScore}`);
424
- }
425
- if (metric === "cosine" && Math.abs(minScore) > 1) {
426
- throw new RangeError(
427
- `${label} for the cosine metric must be between -1 and 1, got: ${minScore}`
428
- );
429
- }
430
- }
431
- var MAX_VECTOR_IDENTIFIER_LENGTH = 63;
432
- function sanitizeIdentifierPart(value) {
433
- return value.toLowerCase().replaceAll(/[^a-z0-9_]/g, "_");
434
- }
435
- function shortHash(input) {
436
- let h1 = 3735928559;
437
- let h2 = 1103547991;
438
- for (let index = 0; index < input.length; index++) {
439
- const ch = requireDefined(input.codePointAt(index));
440
- h1 = Math.imul(h1 ^ ch, 2654435761);
441
- h2 = Math.imul(h2 ^ ch, 1597334677);
442
- }
443
- h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
444
- h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
445
- const hi = (h2 >>> 0).toString(16).padStart(8, "0");
446
- const lo = (h1 >>> 0).toString(16).padStart(8, "0");
447
- return `${hi}${lo}`.slice(0, 8);
448
- }
449
- function vectorPhysicalName(prefix, graphId, nodeKind, fieldPath) {
450
- const readable = `${prefix}_${sanitizeIdentifierPart(graphId)}_${sanitizeIdentifierPart(nodeKind)}_${sanitizeIdentifierPart(fieldPath)}`;
451
- const hash = shortHash(JSON.stringify([graphId, nodeKind, fieldPath]));
452
- const full = `${readable}_${hash}`;
453
- if (full.length <= MAX_VECTOR_IDENTIFIER_LENGTH) return full;
454
- return `${readable.slice(0, MAX_VECTOR_IDENTIFIER_LENGTH - 1 - hash.length)}_${hash}`;
455
- }
456
- function quoteIdentifier2(name) {
457
- return `"${name.replaceAll('"', '""')}"`;
458
- }
459
-
460
- export { ALL_FULLTEXT_MODES, BASE_CONTRIBUTION_OWNER, FULLTEXT_CONTRIBUTION_NAME, VECTOR_CONTRIBUTION_PREFIX, assertFiniteEmbedding, assertVectorMinScore, assertVectorSearchLimit, buildFulltextCapabilities, buildVectorCapabilities, fts5Strategy, quoteIdentifier2 as quoteIdentifier, shortHash, tsvectorStrategy, vectorMinScoreCondition, vectorPhysicalName, vectorScoreExpression };
461
- //# sourceMappingURL=chunk-Y7M44XEK.js.map
462
- //# sourceMappingURL=chunk-Y7M44XEK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/backend/table-contribution.ts","../src/query/dialect/fulltext-strategy.ts","../src/query/dialect/vector-strategy.ts"],"names":["quoteIdentifier"],"mappings":"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","file":"chunk-Y7M44XEK.js","sourcesContent":["/**\n * Unified table-contribution contract (#129).\n *\n * Every table TypeGraph owns — whether modeled as a Drizzle table or\n * emitted as strategy-owned raw DDL — is described by a single\n * {@link TableContribution} shape. This is the one place that answers\n * \"what tables does this backend/strategy own?\", replacing the\n * previously split surfaces (Drizzle named exports, tables-factory\n * recursion, strategy raw DDL, per-table `ensureXTable` methods).\n *\n * Lives in the neutral `backend/` layer (sibling of `backend/types.ts`,\n * which `query/dialect` already depends on) and is deliberately\n * Drizzle-free, so declaring contributions does not pull the concrete\n * Drizzle backend runtime into the query/dialect layer.\n *\n * ## Identity vs. signature (prerequisite for #135)\n *\n * #135 (durable fulltext/contribution materialization) needs to make\n * \"not materialized\" vs. \"materialized but stale\" a decidable, durable\n * fact instead of an in-memory per-backend latch. That requires two\n * conceptually separate things, and #129's job is only to make both\n * *derivable* from the contract:\n *\n * - **Materialization identity** — `owner` + `logicalName` +\n * resolved physical `tableName`. Keying on `logicalName` alone is\n * insufficient: custom per-deployment table names must be\n * distinguishable, otherwise two deployments with different physical\n * names would collide on one durable marker. (#135 additionally\n * scopes this by `graphId` at persistence time.)\n * - **Drift signature** — a hash of the strategy identity/version,\n * the resolved table name(s), and the normalized `createDdl`. #129\n * guarantees `createDdl` is deterministic for a given resolved\n * configuration so the hash #135 computes is meaningful.\n *\n * The signature is intentionally **not** eagerly carried on the\n * contribution: hashing is async (Web Crypto, see `utils/hash`) and\n * #135 already owns signature persistence the same way\n * `materializeIndexes` does for declared indexes.\n */\n\n/**\n * `logicalName` of the strategy-owned fulltext slot. Used as a logic\n * discriminant (latch routing, runtime-ensure) across the strategies\n * and both backends — a shared constant so a strategy declaring a\n * different name fails loudly at the call site instead of silently\n * skipping the latched fulltext path.\n */\nexport const FULLTEXT_CONTRIBUTION_NAME = \"fulltext\";\n\n/** `owner` of core/base schema tables (not strategy-owned). */\nexport const BASE_CONTRIBUTION_OWNER = \"base\";\n\n/**\n * A single table TypeGraph owns.\n */\nexport type TableContribution = Readonly<{\n /**\n * Stable, graph- and deployment-independent identity for the logical\n * slot this contribution fills (e.g. `\"fulltext\"`). NOT the physical\n * table name. Stable across table-name overrides and across strategy\n * swaps of the *same* logical slot, so #135's durable marker can\n * survive both.\n */\n logicalName: string;\n /**\n * Identifies the producer of this contribution (e.g. a strategy id\n * like `\"tsvector\"` / `\"fts5\"`, or `\"base\"` for core schema tables).\n * Part of the #135 materialization identity and an input to the\n * drift signature — a strategy swap on the same `logicalName` is a\n * legitimate, detectable drift, not a silent reuse.\n */\n owner: string;\n /**\n * Resolved physical table name after any per-deployment name\n * override. Part of the #135 materialization identity (custom names\n * must be distinguishable) and used by diagnostics / the focused\n * bootstrap ensure.\n */\n tableName: string;\n /**\n * Idempotent (`CREATE ... IF NOT EXISTS`) statements that\n * materialize this contribution's table **and its supporting\n * indexes**. Running the full list is how the runtime ensure\n * self-heals partial states (table present, index missing) — it is\n * not a probe-and-skip. Deterministic for a given resolved\n * configuration: the canonical normalized input to #135's drift\n * signature.\n */\n createDdl: readonly string[];\n /**\n * When `true`, the post-schema-load focused ensure\n * (`loadActiveSchemaWithBootstrap`) materializes this contribution\n * on every successful schema load.\n *\n * **Invariant: only strategy-declared contributions may set this.**\n * Core/base tables are always `false` — they are created by\n * drizzle-kit / `bootstrapTables`. This is what lets the boot path\n * derive runtime contributions straight from the strategy\n * (`fulltextStrategy.ownedTables`) without walking — and generating\n * DDL for — every base table.\n */\n runtimeEnsure: boolean;\n}>;\n\n/**\n * A table a {@link FulltextStrategy} declares it owns. An alias, not a\n * distinct shape: a strategy's declaration is already authoritative\n * (no resolution step). The name documents the producer role.\n */\nexport type StrategyTableContribution = TableContribution;\n","/**\n * Fulltext Strategy — pluggable DDL + SQL generation for a dialect's\n * fulltext stack. A strategy owns every SQL statement that touches its\n * backing table: DDL, upsert (single + batch), delete (single + batch),\n * MATCH condition, rank expression, and snippet expression.\n *\n * A dialect picks one as its default; `createPostgresBackend` /\n * `createSqliteBackend` accept an override for alternate Postgres stacks\n * (pg_trgm, ParadeDB/pg_search, pgroonga) to swap the entire fulltext\n * pipeline without forking TypeGraph.\n */\nimport {\n FULLTEXT_CONTRIBUTION_NAME,\n type StrategyTableContribution,\n} from \"../../backend/table-contribution\";\nimport {\n type DeleteFulltextBatchParams,\n type DeleteFulltextParams,\n type FulltextBatchRow,\n type FulltextCapabilities,\n type FulltextQueryMode,\n type UpsertFulltextBatchParams,\n type UpsertFulltextParams,\n} from \"../../backend/types\";\nimport { sql, type SqlFragment } from \"../sql-fragment\";\n\n/**\n * Every `FulltextQueryMode` both shipped strategies accept.\n */\nexport const ALL_FULLTEXT_MODES: readonly FulltextQueryMode[] = [\n \"websearch\",\n \"phrase\",\n \"plain\",\n \"raw\",\n] as const;\n\n/**\n * Derives the `FulltextCapabilities` backends advertise from the active\n * strategy, so the two never drift.\n */\nexport function buildFulltextCapabilities(\n strategy: FulltextStrategy,\n): FulltextCapabilities {\n return {\n supported: true,\n languages: strategy.languages,\n phraseQueries: strategy.supportedModes.includes(\"phrase\"),\n prefixQueries: strategy.supportsPrefix,\n highlighting: strategy.supportsSnippets,\n };\n}\n\n/**\n * A pluggable fulltext implementation. Each strategy is expected to be\n * self-contained: given a table name, a query string, and a parse mode,\n * it emits every SQL statement the compiler and backend need — DDL,\n * reads, and writes. No out-of-band conventions across layers.\n */\nexport type FulltextStrategy = Readonly<{\n /** Human-readable identifier used in error messages and telemetry. */\n name: string;\n\n /**\n * Parse modes this strategy can translate. Callers validate against\n * this list before emitting SQL; a mode outside the set means the\n * strategy rejects the query at compile time.\n */\n supportedModes: readonly FulltextQueryMode[];\n\n /**\n * Whether the strategy can emit a per-row highlighted snippet. When\n * false, `snippetExpression` returns a literal `NULL` so callers can\n * leave the `snippet` column in place without a branch.\n */\n supportsSnippets: boolean;\n\n /**\n * Whether the strategy supports prefix queries (`foo*`). Used to\n * populate `BackendCapabilities.fulltext.prefixQueries`. A strategy\n * may support prefix queries via dedicated syntax without advertising\n * \"raw\" mode (and vice-versa).\n */\n supportsPrefix: boolean;\n\n /**\n * Whether a per-query `language` override is honored. Postgres' tsvector\n * accepts any installed regconfig at query time; SQLite FTS5's tokenizer\n * is fixed at table-create time, so the override is silently ignored.\n * Callers may surface a warning when the user passes `language` to a\n * strategy that doesn't honor it.\n */\n supportsLanguageOverride: boolean;\n\n /**\n * Languages / tokenizer names understood by the strategy. Advisory — a\n * runtime backend like Postgres may accept other installed regconfigs.\n * Used to populate `BackendCapabilities.fulltext.languages`.\n */\n languages: readonly string[];\n\n /**\n * Emits the WHERE-side MATCH expression.\n *\n * @example\n * tsvector: `\"typegraph_node_fulltext\".\"tsv\" @@ websearch_to_tsquery('english', 'cats')`\n * fts5: `\"typegraph_node_fulltext\" MATCH '\"cats\"'`\n */\n matchCondition: (\n this: void,\n tableName: string,\n query: string,\n mode: FulltextQueryMode,\n language?: string,\n ) => SqlFragment;\n\n /**\n * Emits the relevance expression. Higher values = more relevant. The\n * compiler orders by this expression DESC, and both builder and\n * backend-direct paths use the same form so their top-k results agree.\n */\n rankExpression: (\n this: void,\n tableName: string,\n query: string,\n mode: FulltextQueryMode,\n language?: string,\n ) => SqlFragment;\n\n /**\n * Emits a per-row highlighted snippet expression, or `NULL` when\n * `supportsSnippets` is false. Snippet markup is `<mark>…</mark>` in\n * both shipped strategies so consumers can apply one stylesheet.\n */\n snippetExpression: (\n this: void,\n tableName: string,\n query: string,\n mode: FulltextQueryMode,\n language?: string,\n ) => SqlFragment;\n\n /**\n * The tables this strategy owns, as Drizzle-free, already\n * authoritative `TableContribution`s (`logicalName`, `owner`,\n * resolved `tableName`, idempotent `createDdl` for the table **and\n * its supporting indexes**, `runtimeEnsure`). A strategy never\n * constructs a Drizzle table itself; drizzle-kit visibility, when\n * applicable, is the schema barrel's responsibility (the default\n * Postgres strategy's `schema/postgres.ts` exports a matching\n * `tables.fulltext` — a non-default strategy must export its own).\n *\n * Replaces the former `generateDdl(tableName)`: DDL is now one field\n * of a contribution rather than the strategy's whole storage\n * surface. (Public API change — see #129.)\n */\n ownedTables: (\n this: void,\n primaryTableName: string,\n ) => readonly StrategyTableContribution[];\n\n /**\n * Emits the statements that upsert a single fulltext row. Returns one\n * or more statements — some backends (SQLite FTS5) cannot emulate\n * upsert in a single statement and need DELETE + INSERT.\n */\n buildUpsert: (\n this: void,\n tableName: string,\n params: UpsertFulltextParams,\n timestamp: string,\n ) => readonly SqlFragment[];\n\n /**\n * Emits the statements that upsert many fulltext rows at once. Input\n * rows are expected to be de-duplicated last-write-wins by the\n * strategy if the underlying SQL statement cannot tolerate duplicate\n * conflict keys. Returns `[]` when `params.rows` is empty.\n */\n buildBatchUpsert: (\n this: void,\n tableName: string,\n params: UpsertFulltextBatchParams,\n timestamp: string,\n ) => readonly SqlFragment[];\n\n /**\n * Emits the statements that delete a single fulltext row. Normally a\n * single PK-scoped DELETE, but strategies that maintain auxiliary\n * indexes (delete-triggered external stores, ParadeDB-style secondary\n * structures) may need more.\n */\n buildDelete: (\n this: void,\n tableName: string,\n params: DeleteFulltextParams,\n ) => readonly SqlFragment[];\n\n /**\n * Emits the statements that delete many fulltext rows at once. Returns\n * `[]` when `params.nodeIds` is empty.\n */\n buildBatchDelete: (\n this: void,\n tableName: string,\n params: DeleteFulltextBatchParams,\n ) => readonly SqlFragment[];\n}>;\n\n// ============================================================\n// Internal helpers\n// ============================================================\n\nfunction quoteIdentifier(name: string): string {\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction tsvectorColumn(tableName: string): SqlFragment {\n return sql`${sql.identifier(tableName)}.\"tsv\"`;\n}\n\n/**\n * Dedupes batch rows last-write-wins by nodeId. Returns a plain array\n * in insertion order of the last occurrence of each id. Shared by both\n * shipped strategies.\n */\nfunction dedupeFulltextBatchRows(\n rows: readonly FulltextBatchRow[],\n): FulltextBatchRow[] {\n const seen = new Map<string, FulltextBatchRow>();\n for (const row of rows) seen.set(row.nodeId, row);\n return [...seen.values()];\n}\n\nfunction buildPkScopedDelete(\n tableName: string,\n params: DeleteFulltextParams,\n): SqlFragment {\n const table = sql.identifier(tableName);\n return sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId}\n AND \"node_kind\" = ${params.nodeKind}\n AND \"node_id\" = ${params.nodeId}\n `;\n}\n\nfunction buildPkScopedBatchDelete(\n tableName: string,\n params: DeleteFulltextBatchParams,\n): SqlFragment | undefined {\n if (params.nodeIds.length === 0) return undefined;\n const unique = [...new Set(params.nodeIds)];\n const table = sql.identifier(tableName);\n return sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId}\n AND \"node_kind\" = ${params.nodeKind}\n AND \"node_id\" IN (${sql.join(\n unique.map((id) => sql`${id}`),\n sql`, `,\n )})\n `;\n}\n\n// ============================================================\n// tsvector strategy (PostgreSQL built-in)\n// ============================================================\n\nfunction postgresTsquery(\n mode: FulltextQueryMode,\n query: string,\n language: string | undefined,\n): SqlFragment {\n // The `language` column is already `regconfig`, so the non-override\n // path references the column directly. The per-query override path\n // still arrives as a bound text parameter and needs the cast.\n const langExpr: SqlFragment =\n language === undefined ? sql`\"language\"` : sql`${language}::regconfig`;\n switch (mode) {\n case \"websearch\": {\n return sql`websearch_to_tsquery(${langExpr}, ${query})`;\n }\n case \"phrase\": {\n return sql`phraseto_tsquery(${langExpr}, ${query})`;\n }\n case \"plain\": {\n return sql`plainto_tsquery(${langExpr}, ${query})`;\n }\n case \"raw\": {\n return sql`to_tsquery(${langExpr}, ${query})`;\n }\n default: {\n const _exhaustive: never = mode;\n throw new Error(`Unsupported fulltext mode: ${String(_exhaustive)}`);\n }\n }\n}\n\nexport const tsvectorStrategy: FulltextStrategy = {\n name: \"tsvector\",\n supportedModes: ALL_FULLTEXT_MODES,\n supportsSnippets: true,\n // `raw` mode exposes `foo:*` prefix-match syntax to callers.\n supportsPrefix: true,\n supportsLanguageOverride: true,\n // Canonical Postgres stemmers; every stock install ships these plus a\n // few others. Runtime `to_tsvector` accepts any installed regconfig\n // name — this list is advisory for capability discovery.\n languages: [\n \"simple\",\n \"english\",\n \"french\",\n \"german\",\n \"italian\",\n \"portuguese\",\n \"russian\",\n \"spanish\",\n \"swedish\",\n ] as const,\n\n matchCondition(tableName, query, mode, language) {\n const q = postgresTsquery(mode, query, language);\n return sql`${tsvectorColumn(tableName)} @@ ${q}`;\n },\n\n rankExpression(tableName, query, mode, language) {\n const q = postgresTsquery(mode, query, language);\n return sql`ts_rank_cd(${tsvectorColumn(tableName)}, ${q})`;\n },\n\n snippetExpression(_tableName, query, mode, language) {\n const langExpr: SqlFragment =\n language === undefined ? sql`\"language\"` : sql`${language}::regconfig`;\n const q = postgresTsquery(mode, query, language);\n return sql`ts_headline(${langExpr}, \"content\", ${q}, 'StartSel=<mark>,StopSel=</mark>,MaxFragments=1,MinWords=5,MaxWords=30,ShortWord=3')`;\n },\n\n ownedTables(primaryTableName) {\n const name = quoteIdentifier(primaryTableName);\n const gin = quoteIdentifier(`${primaryTableName}_tsv_idx`);\n const kind = quoteIdentifier(`${primaryTableName}_kind_idx`);\n // `language` is `regconfig` so `to_tsvector(\"language\", \"content\")`\n // is an immutable expression — Postgres can then compute `tsv` as a\n // GENERATED STORED column and own the `content → tsv` invariant.\n // (The text→regconfig cast happens once at INSERT time against the\n // bound parameter, which is fine because it's not inside the\n // generated expression.)\n const createDdl = [\n `CREATE TABLE IF NOT EXISTS ${name} (\n \"graph_id\" TEXT NOT NULL,\n \"node_kind\" TEXT NOT NULL,\n \"node_id\" TEXT NOT NULL,\n \"content\" TEXT NOT NULL,\n \"language\" regconfig NOT NULL,\n \"tsv\" tsvector NOT NULL\n GENERATED ALWAYS AS (to_tsvector(\"language\", \"content\")) STORED,\n \"updated_at\" TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (\"graph_id\", \"node_kind\", \"node_id\")\n);`,\n `CREATE INDEX IF NOT EXISTS ${gin} ON ${name} USING GIN (\"tsv\");`,\n `CREATE INDEX IF NOT EXISTS ${kind} ON ${name} (\"graph_id\", \"node_kind\");`,\n ];\n // drizzle-kit visibility for this default strategy comes from\n // `schema/postgres.ts` exporting the matching `tables.fulltext`\n // pgTable through the barrel — one object, not two. `runtimeEnsure`\n // because drizzle-kit-managed setups create every base table except\n // this strategy-owned one.\n return [\n {\n logicalName: FULLTEXT_CONTRIBUTION_NAME,\n owner: \"tsvector\",\n tableName: primaryTableName,\n createDdl,\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(tableName, params, timestamp) {\n const table = sql.identifier(tableName);\n // `tsv` is a GENERATED STORED column — Postgres computes it from\n // `content` + `language`, so it must not appear in the column list\n // or the ON CONFLICT update set.\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_kind\", \"node_id\", \"content\", \"language\", \"updated_at\")\n VALUES (\n ${params.graphId}, ${params.nodeKind}, ${params.nodeId},\n ${params.content}, ${params.language}::regconfig,\n ${timestamp}\n )\n ON CONFLICT (\"graph_id\", \"node_kind\", \"node_id\")\n DO UPDATE SET\n \"content\" = EXCLUDED.\"content\",\n \"language\" = EXCLUDED.\"language\",\n \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildBatchUpsert(tableName, params, timestamp) {\n const rows = dedupeFulltextBatchRows(params.rows);\n if (rows.length === 0) return [];\n\n const table = sql.identifier(tableName);\n const valueTuples = rows.map(\n (row) => sql`\n (\n ${params.graphId}, ${params.nodeKind}, ${row.nodeId},\n ${row.content}, ${row.language}::regconfig,\n ${timestamp}\n )\n `,\n );\n\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_kind\", \"node_id\", \"content\", \"language\", \"updated_at\")\n VALUES ${sql.join(valueTuples, sql`, `)}\n ON CONFLICT (\"graph_id\", \"node_kind\", \"node_id\")\n DO UPDATE SET\n \"content\" = EXCLUDED.\"content\",\n \"language\" = EXCLUDED.\"language\",\n \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildDelete(tableName, params) {\n return [buildPkScopedDelete(tableName, params)];\n },\n\n buildBatchDelete(tableName, params) {\n const stmt = buildPkScopedBatchDelete(tableName, params);\n return stmt === undefined ? [] : [stmt];\n },\n};\n\n// ============================================================\n// FTS5 strategy (SQLite)\n// ============================================================\n\nfunction translateToFts5Query(query: string, mode: FulltextQueryMode): string {\n switch (mode) {\n case \"phrase\": {\n return `\"${query.replaceAll('\"', '\"\"')}\"`;\n }\n case \"plain\": {\n return query\n .trim()\n .split(/\\s+/u)\n .filter((token) => token.length > 0)\n .map((token) => `\"${token.replaceAll('\"', '\"\"')}\"`)\n .join(\" \");\n }\n case \"websearch\": {\n return translateWebsearchToFts5(query);\n }\n case \"raw\": {\n return query;\n }\n default: {\n const _exhaustive: never = mode;\n throw new Error(`Unsupported fulltext mode: ${String(_exhaustive)}`);\n }\n }\n}\n\nfunction translateWebsearchToFts5(query: string): string {\n const tokens: string[] = [];\n let index = 0;\n\n function skipWhitespace(): void {\n while (index < query.length && /\\s/u.test(query[index] ?? \"\")) {\n index += 1;\n }\n }\n\n function readPhrase(): string {\n index += 1;\n let content = \"\";\n while (index < query.length && query[index] !== '\"') {\n content += query[index] ?? \"\";\n index += 1;\n }\n if (query[index] === '\"') index += 1;\n return `\"${content.replaceAll('\"', '\"\"')}\"`;\n }\n\n function readBareTerm(): string {\n let term = \"\";\n while (index < query.length && !/\\s/u.test(query[index] ?? \"\")) {\n term += query[index] ?? \"\";\n index += 1;\n }\n return term;\n }\n\n while (index < query.length) {\n skipWhitespace();\n if (index >= query.length) break;\n const ch = query[index];\n if (ch === '\"') {\n tokens.push(readPhrase());\n continue;\n }\n if (ch === \"-\") {\n index += 1;\n const term =\n query[index] === '\"' ?\n readPhrase()\n : `\"${readBareTerm().replaceAll('\"', '\"\"')}\"`;\n tokens.push(`NOT ${term}`);\n continue;\n }\n if (ch === \"+\") {\n index += 1;\n continue;\n }\n const bare = readBareTerm();\n if (bare.length === 0) continue;\n if (bare.toUpperCase() === \"OR\") {\n tokens.push(\"OR\");\n continue;\n }\n tokens.push(`\"${bare.replaceAll('\"', '\"\"')}\"`);\n }\n\n if (tokens.length > 0 && tokens[0]?.startsWith(\"NOT \")) {\n tokens.shift();\n }\n\n return tokens.join(\" \");\n}\n\nexport const fts5Strategy: FulltextStrategy = {\n name: \"fts5\",\n supportedModes: ALL_FULLTEXT_MODES,\n supportsSnippets: true,\n // FTS5 supports `foo*` prefix matching natively.\n supportsPrefix: true,\n // FTS5 tokenizer is fixed at table-create time; per-row / per-query\n // language metadata is stored but not consulted.\n supportsLanguageOverride: false,\n // The built-in tokenizer is `porter unicode61 remove_diacritics 2`; the\n // `language` field on searchable() is recorded for future use but not\n // applied at query time.\n languages: [\"porter\", \"unicode61\", \"trigram\"] as const,\n\n matchCondition(tableName, query, mode, _language) {\n const matchExpression = translateToFts5Query(query, mode);\n return sql`${sql.identifier(tableName)} MATCH ${matchExpression}`;\n },\n\n rankExpression(tableName, _query, _mode, _language) {\n // FTS5 bm25() returns a negative score where lower = more relevant.\n // Negate so callers see higher = better (uniform with tsvector).\n return sql`-bm25(${sql.identifier(tableName)})`;\n },\n\n snippetExpression(tableName, _query, _mode, _language) {\n return sql`snippet(${sql.identifier(tableName)}, -1, '<mark>', '</mark>', '…', 20)`;\n },\n\n ownedTables(primaryTableName) {\n const name = quoteIdentifier(primaryTableName);\n // FTS5 virtual tables cannot be modeled as a Drizzle table, so this\n // contribution is raw-ddl: emitted verbatim and invisible to\n // drizzle-kit. `runtimeEnsure` because no drizzle-kit-managed setup\n // can create it.\n return [\n {\n logicalName: FULLTEXT_CONTRIBUTION_NAME,\n owner: \"fts5\",\n tableName: primaryTableName,\n createDdl: [\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${name} USING fts5(\n graph_id UNINDEXED,\n node_kind UNINDEXED,\n node_id UNINDEXED,\n language UNINDEXED,\n updated_at UNINDEXED,\n content,\n tokenize='porter unicode61 remove_diacritics 2'\n);`,\n ],\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(tableName, params, timestamp) {\n const table = sql.identifier(tableName);\n // FTS5 virtual tables don't support ON CONFLICT — emulate with\n // DELETE + INSERT, atomic under the caller's outer transaction.\n return [\n sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId}\n AND \"node_kind\" = ${params.nodeKind}\n AND \"node_id\" = ${params.nodeId}\n `,\n sql`\n INSERT INTO ${table} (graph_id, node_kind, node_id, content, language, updated_at)\n VALUES (${params.graphId}, ${params.nodeKind}, ${params.nodeId}, ${params.content}, ${params.language}, ${timestamp})\n `,\n ];\n },\n\n buildBatchUpsert(tableName, params, timestamp) {\n const rows = dedupeFulltextBatchRows(params.rows);\n if (rows.length === 0) return [];\n\n const table = sql.identifier(tableName);\n const nodeIds = rows.map((row) => row.nodeId);\n\n const deleteStmt = sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId}\n AND \"node_kind\" = ${params.nodeKind}\n AND \"node_id\" IN (${sql.join(\n nodeIds.map((id) => sql`${id}`),\n sql`, `,\n )})\n `;\n\n const valueTuples = rows.map(\n (row) => sql`\n (\n ${params.graphId}, ${params.nodeKind}, ${row.nodeId},\n ${row.content}, ${row.language}, ${timestamp}\n )\n `,\n );\n\n const insertStmt = sql`\n INSERT INTO ${table} (graph_id, node_kind, node_id, content, language, updated_at)\n VALUES ${sql.join(valueTuples, sql`, `)}\n `;\n\n return [deleteStmt, insertStmt];\n },\n\n buildDelete(tableName, params) {\n return [buildPkScopedDelete(tableName, params)];\n },\n\n buildBatchDelete(tableName, params) {\n const stmt = buildPkScopedBatchDelete(tableName, params);\n return stmt === undefined ? [] : [stmt];\n },\n};\n","/**\n * Vector Strategy — pluggable storage + SQL generation for a backend's\n * vector stack. The sibling of {@link FulltextStrategy}: a strategy owns\n * every statement that touches its embedding storage — the per-field DDL,\n * upsert, delete, similarity search, and (optional) ANN index lifecycle —\n * plus the capability advertisement and the distance/score expressions the\n * query compiler splices into its relevance CTE.\n *\n * ## Why a strategy, and why per-(kind, field) storage\n *\n * The spike behind #157 established that \"real\" ANN on every engine we\n * support converges on a\n * **typed, fixed-dimension structure per `(nodeKind, fieldPath)`**:\n *\n * - pgvector: a `vector(N)` column + HNSW/IVFFlat;\n * - libSQL native: an `F32_BLOB(N)` column + `libsql_vector_idx` +\n * `vector_top_k` (a plain `BLOB` or dimensionless `F32_BLOB` is rejected\n * by the index — the dimension must live in the column type);\n * - sqlite-vec: a `vec0(embedding float[N])` virtual table.\n *\n * The legacy single shared `typegraph_node_embeddings` table (one generic\n * column holding mixed-dimension vectors) can only ever be brute-forced;\n * pgvector was the sole engine that hid this, because its index supplies the\n * dimension via a `::vector(N)` cast expression. So storage is the\n * strategy's to own, slot by slot, rather than a fixed global table.\n *\n * Brute force remains a legitimate, capability-advertised mode (libSQL's\n * `vector_distance_cos` over a column with no index, sqlite-vec's\n * `vec_distance_cosine`): a strategy whose `capabilities.indexTypes` is\n * `[\"none\"]` simply never emits an ANN index and `buildSearch` always scans.\n */\nimport { type StrategyTableContribution } from \"../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingBatchParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorIndexType,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../backend/types\";\nimport { requireDefined } from \"../../utils/presence\";\nimport { sql, type SqlFragment } from \"../sql-fragment\";\n\n/**\n * `logicalName` prefix of a strategy-owned vector slot. Each\n * `(nodeKind, fieldPath)` pair fills one logical vector slot; the full\n * logical name is `${VECTOR_CONTRIBUTION_PREFIX}:${nodeKind}.${fieldPath}`,\n * stable across table-name overrides and strategy swaps so #135's durable\n * materialization marker survives both.\n */\nexport const VECTOR_CONTRIBUTION_PREFIX = \"vector\";\n\n/**\n * The resolved identity of one embedding field's storage in a graph —\n * everything a strategy needs to DDL, address, and index it.\n *\n * Graph-scoped: each `(graphId, nodeKind, fieldPath)` gets its own physical\n * table. TypeGraph supports many graphs per physical database, and the same\n * `(kind, field)` can carry different embedding dimensions across graphs — a\n * shared per-`(kind, field)` table would collide on the fixed column type\n * (`vector(N)` / `F32_BLOB(N)`). Graph-scoping also makes libSQL's\n * table-global `vector_top_k` per-graph-exact (no cross-graph recall bleed).\n */\nexport type VectorSlot = Readonly<{\n /** Graph the embedding belongs to — scopes the physical table. */\n graphId: string;\n /** Node kind owning the embedding field (e.g. `\"Document\"`). */\n nodeKind: string;\n /** Dot-path of the embedding field within the node props (e.g. `\"embedding\"`). */\n fieldPath: string;\n /** Fixed vector dimension `N` for this field — carried into the column type. */\n dimensions: number;\n /** Distance metric the field's index is built for. */\n metric: VectorMetric;\n /**\n * Index type to materialize. `\"none\"` means brute-force only (no ANN\n * index emitted); the strategy still stores and searches the field.\n */\n indexType: VectorIndexType;\n /**\n * Optional ANN index tuning carried into the index DDL (pgvector\n * `m`/`ef_construction`/`lists`). Present on the create-index / re-embed\n * paths (resolved from the field's `embedding()` declaration); omitted on\n * the write/search ensure paths, where the strategy falls back to defaults.\n */\n indexParams?: Readonly<{\n m?: number;\n efConstruction?: number;\n lists?: number;\n }>;\n}>;\n\n/**\n * Derives the `VectorCapabilities` a backend advertises from its active\n * strategy, so the two never drift (mirrors `buildFulltextCapabilities`).\n * The strategy is the single source of truth; there are no per-call-site\n * `SQLITE_VECTOR_*` constants.\n */\nexport function buildVectorCapabilities(\n strategy: VectorStrategy,\n): VectorCapabilities {\n return strategy.capabilities;\n}\n\n/**\n * A pluggable vector implementation. Each strategy is self-contained:\n * given a {@link VectorSlot}, it emits every statement the backend and\n * compiler need — per-field storage DDL, writes, similarity search, ANN\n * index lifecycle — and advertises exactly the metrics and index types it\n * can honor. Adding the Nth backend is one of these objects; no core edits.\n */\nexport type VectorStrategy = Readonly<{\n /** Human-readable identifier used in error messages and telemetry. */\n name: string;\n\n /**\n * The metrics, index types, and dimension ceiling this strategy honors —\n * advertised verbatim as `backend.capabilities.vector`. Asymmetry across\n * engines is legitimate and explicit here (pgvector has `inner_product`;\n * libSQL/sqlite-vec do not), never a silent runtime failure.\n */\n capabilities: VectorCapabilities;\n\n /**\n * Deterministic physical table (or virtual-table) name backing a field in\n * a graph. The compiler references this to scan the right per-field storage,\n * and the backend uses it to route upserts/deletes. Must be a stable,\n * collision-safe SQL identifier derived from `(graphId, nodeKind, fieldPath)`.\n */\n tableName: (\n this: void,\n graphId: string,\n nodeKind: string,\n fieldPath: string,\n ) => string;\n\n /**\n * The per-field storage this strategy owns for `slot`, as Drizzle-free\n * `StrategyTableContribution`s (resolved `tableName`, deterministic\n * idempotent `createDdl` for the table **and** its ANN index when the\n * slot's `indexType` warrants one, `runtimeEnsure`). Rides the #129/#135\n * table-contribution + durable-materialization machinery exactly as the\n * FTS5 / tsvector virtual tables do — these are materialized per graph by\n * `materializeIndexes()`, not by global `bootstrapTables`.\n */\n ownedTables: (\n this: void,\n slot: VectorSlot,\n ) => readonly StrategyTableContribution[];\n\n /**\n * Emits the statement(s) that upsert a single embedding into the slot's\n * storage. Multiple statements are allowed for engines that cannot upsert\n * a vector in one statement (e.g. a `vec0` virtual table → DELETE+INSERT).\n */\n buildUpsert: (\n this: void,\n slot: VectorSlot,\n params: UpsertEmbeddingParams,\n timestamp: string,\n ) => readonly SqlFragment[];\n\n /**\n * Emits the statement(s) that upsert MANY embeddings into the slot's\n * storage in multi-row form. Optional — the backend falls back to one\n * {@link buildUpsert} per row when unset. The backend guarantees the\n * rows carry distinct `nodeId`s and fit the connection's bound-parameter\n * budget (it chunks before calling).\n */\n buildUpsertBatch?: (\n this: void,\n slot: VectorSlot,\n params: UpsertEmbeddingBatchParams,\n timestamp: string,\n ) => readonly SqlFragment[];\n\n /** Emits the statement(s) that delete a single embedding from the slot. */\n buildDelete: (\n this: void,\n slot: VectorSlot,\n params: DeleteEmbeddingParams,\n ) => readonly SqlFragment[];\n\n /**\n * Raw DDL statement(s) that drop the slot's entire physical storage\n * (table + ANN index, and any engine-managed shadow tables). Used by the\n * destructive `store.reembedVectorField()` path to recreate a field's\n * storage at a new dimension. Returned as raw strings (like\n * `ownedTables(...).createDdl`) for `backend.executeDdl`; must be idempotent\n * (`IF EXISTS`).\n */\n buildDropStorage: (this: void, slot: VectorSlot) => readonly string[];\n\n /**\n * Emits the similarity-search query for the `backend.vectorSearch` path,\n * returning rows shaped `{ node_id, score }` ordered best-first. The\n * strategy picks brute-force vs ANN based on whether `slot.indexType`\n * materialized an index — the caller never branches. `score` follows the\n * shared convention (cosine → similarity `1 - distance`; l2 /\n * inner_product → raw distance), so `coerceVectorScore` / fusion stay\n * dialect-neutral.\n *\n * `candidates`, when provided, is a subquery yielding the node ids\n * eligible to appear in results (the backend passes its live-node-ids\n * subquery so top-k is computed over live rows in SQL — see\n * `liveNodeIdsSubquery`). Strategies whose ANN form cannot take the\n * filter directly must over-fetch and post-filter, documenting the\n * recall bound. A custom strategy that ignores the argument keeps the\n * pre-pushdown behavior: tombstoned ids are dropped after top-k during\n * hydration, so results can shrink below `limit` under index drift.\n */\n buildSearch: (\n this: void,\n slot: VectorSlot,\n params: VectorSearchParams,\n candidates?: SqlFragment,\n ) => SqlFragment;\n\n /**\n * True when {@link buildSearch} returns EXACT rankings — a brute-force\n * engine form, not an approximate index (sqlite-vec's vec0 KNN scans\n * every row in C). The query compiler then routes the NON-approximate\n * `.similarTo()` branch through `buildSearch` too: same results as the\n * SQL distance scan, at engine speed (measured 489ms -> 113ms at 50k\n * on the SQLite lane). Leave false/absent when the engine form is or\n * can be approximate (pgvector planner rewrites, libSQL DiskANN):\n * exactness of the default path is a semantic guarantee.\n */\n searchIsExact?: boolean;\n\n /**\n * The distance expression over the slot's embedding column, used by the\n * **query compiler** to splice vector relevance into its CTE. This is the\n * one genuinely engine-specific fragment (`vec_distance_cosine` vs\n * `<=>` vs `vector_distance_cos`); the surrounding score / minScore /\n * ORDER BY math is shared (see {@link vectorScoreExpression} etc.).\n *\n * `embeddingColumn` is the already-qualified column SQL; `queryEmbedding`\n * is formatted by the strategy into its engine's literal form.\n */\n distanceExpression: (\n this: void,\n embeddingColumn: SqlFragment,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n ) => SqlFragment;\n\n /**\n * Emits the ANN index creation statement for a slot, or `undefined` when\n * indexing is inline (vec0) or unsupported (brute-force-only strategies).\n * Invoked through `backend.createVectorIndex` during `materializeIndexes`.\n */\n buildCreateIndex?: (\n this: void,\n slot: VectorSlot,\n options?: Readonly<{ concurrent?: boolean }>,\n ) => SqlFragment | undefined;\n\n /** Emits the ANN index drop statement, or `undefined` when not applicable. */\n buildDropIndex?: (this: void, slot: VectorSlot) => SqlFragment | undefined;\n}>;\n\n// ============================================================\n// Shared, dialect-neutral expression math\n// ============================================================\n//\n// These transforms are identical across pgvector / sqlite-vec / libSQL —\n// only `distanceExpression` differs — so they live once here and are reused\n// by both `buildSearch` implementations and the compiler CTE builder.\n\n/**\n * Converts a distance expression into a score expression (higher = better).\n * Cosine distance is mapped to similarity (`1 - d`); l2 and inner_product\n * are returned as-is (lower distance already ranks better, ordered ASC).\n */\nexport function vectorScoreExpression(\n distanceExpression: SqlFragment,\n metric: VectorMetric,\n): SqlFragment {\n switch (metric) {\n case \"cosine\": {\n return sql`(1 - (${distanceExpression}))`;\n }\n case \"l2\":\n case \"inner_product\": {\n return distanceExpression;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Builds the `minScore` WHERE condition against a distance expression,\n * translating the score threshold back into the metric's distance space.\n */\nexport function vectorMinScoreCondition(\n distanceExpression: SqlFragment,\n metric: VectorMetric,\n minScore: number,\n): SqlFragment {\n // Validate against the RESOLVED metric — both the compiler's relevance CTE\n // and the backend search path funnel here, so an out-of-range floor (e.g. a\n // cosine minScore of 5 → `distance <= 1 - 5`, which matches nothing) is\n // rejected loudly instead of silently returning zero rows.\n assertVectorMinScore(minScore, metric);\n switch (metric) {\n case \"cosine\": {\n return sql`${distanceExpression} <= ${1 - minScore}`;\n }\n case \"l2\": {\n return sql`${distanceExpression} <= ${minScore}`;\n }\n case \"inner_product\": {\n return sql`${distanceExpression} <= ${-minScore}`;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Validates that every value in an embedding is a finite number. Shared by\n * strategies so a NaN/Infinity is reported with the offending index before\n * it reaches engine-specific literal formatting (which would mask it).\n */\nexport function assertFiniteEmbedding(\n embedding: readonly number[],\n name: string,\n): void {\n for (const [index, value] of embedding.entries()) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new TypeError(\n `${name}[${index}] must be a finite number, got: ${value}`,\n );\n }\n }\n}\n\n/**\n * Validates a vector-search `limit` is a positive integer. Enforced by the\n * backend's `vectorSearch` (defense in depth — the store boundary also\n * checks) so a direct backend call with `limit: 0` fails loudly instead of\n * silently scanning nothing.\n */\nexport function assertVectorSearchLimit(limit: number): void {\n if (!Number.isInteger(limit) || limit <= 0) {\n throw new RangeError(\n `vectorSearch limit must be a positive integer, got: ${limit}`,\n );\n }\n}\n\n/**\n * Validates a `minScore` floor against its (resolved) metric: it must be finite,\n * and for cosine it must lie in [-1, 1] (a cosine score is the `1 - distance`\n * similarity). Shared by the store facade, the compiler's relevance CTE\n * ({@link vectorMinScoreCondition}), and the backend search path so every entry\n * point rejects the same out-of-range floor instead of silently returning none.\n */\nexport function assertVectorMinScore(\n minScore: number,\n metric: VectorMetric,\n label = \"minScore\",\n): void {\n if (!Number.isFinite(minScore)) {\n throw new RangeError(`${label} must be a finite number, got: ${minScore}`);\n }\n if (metric === \"cosine\" && Math.abs(minScore) > 1) {\n throw new RangeError(\n `${label} for the cosine metric must be between -1 and 1, got: ${minScore}`,\n );\n }\n}\n\n// ============================================================\n// Shared physical naming\n// ============================================================\n\n/**\n * pgvector inherits Postgres' 63-byte identifier ceiling; SQLite/libSQL are\n * far more generous, so the smallest common cap keeps one naming scheme\n * across every strategy.\n */\nconst MAX_VECTOR_IDENTIFIER_LENGTH = 63;\n\nfunction sanitizeIdentifierPart(value: string): string {\n return value.toLowerCase().replaceAll(/[^a-z0-9_]/g, \"_\");\n}\n\n/**\n * Deterministic 8-char hash for collision-safe truncation of over-long\n * identifiers. Self-contained so the strategy layer has no backend-runtime\n * dependency.\n */\nexport function shortHash(input: string): string {\n let h1 = 0xde_ad_be_ef;\n let h2 = 0x41_c6_ce_57;\n for (let index = 0; index < input.length; index++) {\n const ch = requireDefined(input.codePointAt(index));\n h1 = Math.imul(h1 ^ ch, 0x9e_37_79_b1);\n h2 = Math.imul(h2 ^ ch, 0x5f_35_64_95);\n }\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 0x85_eb_ca_6b) ^\n Math.imul(h2 ^ (h2 >>> 13), 0xc2_b2_ae_35);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 0x85_eb_ca_6b) ^\n Math.imul(h1 ^ (h1 >>> 13), 0xc2_b2_ae_35);\n const hi = (h2 >>> 0).toString(16).padStart(8, \"0\");\n const lo = (h1 >>> 0).toString(16).padStart(8, \"0\");\n return `${hi}${lo}`.slice(0, 8);\n}\n\n/**\n * Deterministic per-`(graphId, nodeKind, fieldPath)` physical name. Shared by\n * every strategy's `tableName`, by index naming, and by the compiler's\n * per-field table resolution so all three agree on which physical object backs\n * a field in a graph. Truncated with a hash suffix past the 63-char ceiling;\n * the hash covers all three parts, so truncation stays collision-safe even\n * when long graph ids dominate the prefix.\n *\n * @example `vectorPhysicalName(\"tg_vec\", \"g1\", \"Document\", \"embedding\")`\n * → `\"tg_vec_g1_document_embedding_<hash8>\"`\n */\nexport function vectorPhysicalName(\n prefix: string,\n graphId: string,\n nodeKind: string,\n fieldPath: string,\n): string {\n const readable = `${prefix}_${sanitizeIdentifierPart(graphId)}_${sanitizeIdentifierPart(nodeKind)}_${sanitizeIdentifierPart(fieldPath)}`;\n // Always suffix a hash of the EXACT (graphId, nodeKind, fieldPath) tuple.\n // Sanitization is lossy (case-folding, every non-`[a-z0-9_]` char → `_`) and\n // the `_` join is ambiguous, so distinct fields can share a readable part —\n // e.g. (\"a_b\",\"c\") vs (\"a\",\"b_c\"), or \"Doc-A\" vs \"Doc_A\" vs \"doc\". The hash\n // keeps their physical tables distinct so writes/searches never cross fields.\n const hash = shortHash(JSON.stringify([graphId, nodeKind, fieldPath]));\n const full = `${readable}_${hash}`;\n if (full.length <= MAX_VECTOR_IDENTIFIER_LENGTH) return full;\n // Over the ceiling: truncate the readable part, always keep the hash.\n return `${readable.slice(0, MAX_VECTOR_IDENTIFIER_LENGTH - 1 - hash.length)}_${hash}`;\n}\n\n/**\n * Double-quote a SQL identifier, escaping embedded quotes. Dialect-neutral\n * (both SQLite and Postgres use `\"...\"`), so the three vector strategies share\n * one implementation for quoting their per-field table / index names.\n */\nexport function quoteIdentifier(name: string): string {\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n"]}
@@ -1,12 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkX6RDQ5NB_cjs = require('./chunk-X6RDQ5NB.cjs');
4
-
5
- // src/query/dialect/like-escape.ts
6
- var LIKE_ESCAPE_CHARACTER = "\\";
7
- var likeEscapeClause = chunkX6RDQ5NB_cjs.sql`ESCAPE '\\'`;
8
-
9
- exports.LIKE_ESCAPE_CHARACTER = LIKE_ESCAPE_CHARACTER;
10
- exports.likeEscapeClause = likeEscapeClause;
11
- //# sourceMappingURL=chunk-Z5QHVL5U.cjs.map
12
- //# sourceMappingURL=chunk-Z5QHVL5U.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/query/dialect/like-escape.ts"],"names":["sql"],"mappings":";;;;;AAsBO,IAAM,qBAAA,GAAwB;AAQ9B,IAAM,gBAAA,GAAgCA,qBAAA,CAAA,WAAA","file":"chunk-Z5QHVL5U.cjs","sourcesContent":["/**\n * Shared LIKE-escape clause for the query compiler.\n *\n * The compiler builds `contains` / `startsWith` / `endsWith` patterns by\n * escaping the literal `%`, `_`, and `\\` in user input with a backslash (see\n * the pattern builders in `compiler/predicates.ts`). For that escaping to take\n * effect the emitted `LIKE` / `ILIKE` must declare backslash as its escape\n * character. PostgreSQL's default LIKE escape is already backslash, so this\n * clause is a no-op there; SQLite has *no* default escape character, so without\n * it an escaped `\\%` matches a literal backslash followed by any character —\n * silently diverging from Postgres. Emitting it on every compiled predicate\n * makes the two backends match by construction.\n */\nimport { sql, type SqlFragment } from \"../sql-fragment\";\n\n/**\n * The backslash escape character used by the JS pattern builder\n * (`compileStringPattern` in `compiler/predicates.ts`) to prefix the literal\n * `%`, `_`, and `\\` in user input. It must match the character declared by\n * {@link likeEscapeClause}: the builder prefixes wildcards with this character,\n * and the clause tells SQL to treat it as the escape. Both are backslash.\n */\nexport const LIKE_ESCAPE_CHARACTER = \"\\\\\";\n\n/**\n * `ESCAPE '\\'` clause appended to every compiled `LIKE` / `ILIKE` predicate,\n * declaring {@link LIKE_ESCAPE_CHARACTER} as the escape character. The single\n * backslash inside the quotes is a literal in both PostgreSQL (with\n * `standard_conforming_strings`, the default) and SQLite.\n */\nexport const likeEscapeClause: SqlFragment = sql`ESCAPE '\\\\'`;\n"]}