@nicia-ai/typegraph 0.28.1 → 0.30.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 (178) hide show
  1. package/dist/backend/postgres/index.cjs +24 -762
  2. package/dist/backend/postgres/index.cjs.map +1 -1
  3. package/dist/backend/postgres/index.d.cts +24 -5
  4. package/dist/backend/postgres/index.d.ts +24 -5
  5. package/dist/backend/postgres/index.js +11 -753
  6. package/dist/backend/postgres/index.js.map +1 -1
  7. package/dist/backend/postgres/pglite.cjs +52 -0
  8. package/dist/backend/postgres/pglite.cjs.map +1 -0
  9. package/dist/backend/postgres/pglite.d.cts +116 -0
  10. package/dist/backend/postgres/pglite.d.ts +116 -0
  11. package/dist/backend/postgres/pglite.js +50 -0
  12. package/dist/backend/postgres/pglite.js.map +1 -0
  13. package/dist/backend/sqlite/index.cjs +23 -27
  14. package/dist/backend/sqlite/index.d.cts +22 -15
  15. package/dist/backend/sqlite/index.d.ts +22 -15
  16. package/dist/backend/sqlite/index.js +10 -10
  17. package/dist/backend/sqlite/libsql.cjs +18 -14
  18. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  19. package/dist/backend/sqlite/libsql.d.cts +3 -3
  20. package/dist/backend/sqlite/libsql.d.ts +3 -3
  21. package/dist/backend/sqlite/libsql.js +17 -13
  22. package/dist/backend/sqlite/libsql.js.map +1 -1
  23. package/dist/backend/sqlite/local.cjs +19 -17
  24. package/dist/backend/sqlite/local.cjs.map +1 -1
  25. package/dist/backend/sqlite/local.d.cts +9 -3
  26. package/dist/backend/sqlite/local.d.ts +9 -3
  27. package/dist/backend/sqlite/local.js +17 -15
  28. package/dist/backend/sqlite/local.js.map +1 -1
  29. package/dist/chunk-26HWIIVS.cjs +740 -0
  30. package/dist/chunk-26HWIIVS.cjs.map +1 -0
  31. package/dist/chunk-2QA5EHEN.js +181 -0
  32. package/dist/chunk-2QA5EHEN.js.map +1 -0
  33. package/dist/chunk-3IRMLJEK.js +206 -0
  34. package/dist/chunk-3IRMLJEK.js.map +1 -0
  35. package/dist/{chunk-5MTOKWDA.js → chunk-3JLRHQ67.js} +9 -9
  36. package/dist/{chunk-5MTOKWDA.js.map → chunk-3JLRHQ67.js.map} +1 -1
  37. package/dist/{chunk-WVQXAFP3.js → chunk-454I6GDF.js} +46 -5
  38. package/dist/chunk-454I6GDF.js.map +1 -0
  39. package/dist/{chunk-CTHNVU6K.cjs → chunk-4BXHVEFB.cjs} +16 -16
  40. package/dist/{chunk-CTHNVU6K.cjs.map → chunk-4BXHVEFB.cjs.map} +1 -1
  41. package/dist/{chunk-NMOE2ZEU.cjs → chunk-4LBO6KIF.cjs} +139 -128
  42. package/dist/chunk-4LBO6KIF.cjs.map +1 -0
  43. package/dist/chunk-633N7DSE.js +258 -0
  44. package/dist/chunk-633N7DSE.js.map +1 -0
  45. package/dist/{chunk-WFUN6DCM.cjs → chunk-7JGLPAFV.cjs} +11 -11
  46. package/dist/chunk-7JGLPAFV.cjs.map +1 -0
  47. package/dist/{chunk-ZTREJOGB.js → chunk-AI3RNREM.js} +140 -69
  48. package/dist/chunk-AI3RNREM.js.map +1 -0
  49. package/dist/{chunk-TSGBRPNE.js → chunk-ENDUY2CD.js} +46 -46
  50. package/dist/chunk-ENDUY2CD.js.map +1 -0
  51. package/dist/{chunk-7V335GHG.cjs → chunk-FLRCVI2G.cjs} +12 -2
  52. package/dist/chunk-FLRCVI2G.cjs.map +1 -0
  53. package/dist/chunk-FVIGJTS7.js +305 -0
  54. package/dist/chunk-FVIGJTS7.js.map +1 -0
  55. package/dist/chunk-FWBVPATK.cjs +208 -0
  56. package/dist/chunk-FWBVPATK.cjs.map +1 -0
  57. package/dist/chunk-IE6GN7L3.cjs +319 -0
  58. package/dist/chunk-IE6GN7L3.cjs.map +1 -0
  59. package/dist/{chunk-PGU2XKMA.js → chunk-IUIJJYPI.js} +117 -106
  60. package/dist/chunk-IUIJJYPI.js.map +1 -0
  61. package/dist/{chunk-E5ROA3MN.js → chunk-IX7RE7CG.js} +3 -3
  62. package/dist/{chunk-E5ROA3MN.js.map → chunk-IX7RE7CG.js.map} +1 -1
  63. package/dist/{chunk-YEDQLNVE.cjs → chunk-JIEJCTDS.cjs} +30 -2
  64. package/dist/chunk-JIEJCTDS.cjs.map +1 -0
  65. package/dist/{chunk-WZH2MKHW.cjs → chunk-K4N35E7B.cjs} +101 -101
  66. package/dist/{chunk-WZH2MKHW.cjs.map → chunk-K4N35E7B.cjs.map} +1 -1
  67. package/dist/{chunk-NZ5PMBTG.js → chunk-K5P5OZXS.js} +12 -3
  68. package/dist/chunk-K5P5OZXS.js.map +1 -0
  69. package/dist/chunk-K5VREXMZ.js +738 -0
  70. package/dist/chunk-K5VREXMZ.js.map +1 -0
  71. package/dist/chunk-LUHU4T2F.cjs +12 -0
  72. package/dist/{chunk-4FJVSF3K.cjs.map → chunk-LUHU4T2F.cjs.map} +1 -1
  73. package/dist/{chunk-O57GYGYK.js → chunk-M6OC455F.js} +32 -18
  74. package/dist/chunk-M6OC455F.js.map +1 -0
  75. package/dist/{chunk-OYLF3IC7.js → chunk-MAQJYNJR.js} +4 -4
  76. package/dist/chunk-MAQJYNJR.js.map +1 -0
  77. package/dist/{chunk-OOS2RKRH.js → chunk-MXE2U3EX.js} +4 -4
  78. package/dist/{chunk-OOS2RKRH.js.map → chunk-MXE2U3EX.js.map} +1 -1
  79. package/dist/{chunk-TKM2WDT4.js → chunk-N2OEOGBB.js} +386 -1093
  80. package/dist/chunk-N2OEOGBB.js.map +1 -0
  81. package/dist/{chunk-EJCDOA37.js → chunk-R4JOBEJU.js} +5 -5
  82. package/dist/{chunk-EJCDOA37.js.map → chunk-R4JOBEJU.js.map} +1 -1
  83. package/dist/{chunk-FFHW2JEK.cjs → chunk-RP7YITHX.cjs} +32 -17
  84. package/dist/chunk-RP7YITHX.cjs.map +1 -0
  85. package/dist/{chunk-PYJOBZR3.cjs → chunk-SGPXKJ4A.cjs} +60 -60
  86. package/dist/chunk-SGPXKJ4A.cjs.map +1 -0
  87. package/dist/{chunk-U5ROKVRF.js → chunk-TQOYM4LN.js} +29 -3
  88. package/dist/chunk-TQOYM4LN.js.map +1 -0
  89. package/dist/{chunk-PN37HVAV.cjs → chunk-UESTHN47.cjs} +153 -71
  90. package/dist/chunk-UESTHN47.cjs.map +1 -0
  91. package/dist/chunk-VFX3LC76.cjs +183 -0
  92. package/dist/chunk-VFX3LC76.cjs.map +1 -0
  93. package/dist/chunk-WEMZM7J7.cjs +270 -0
  94. package/dist/chunk-WEMZM7J7.cjs.map +1 -0
  95. package/dist/{chunk-NYQFPGYP.cjs → chunk-WFCECD6Q.cjs} +423 -1139
  96. package/dist/chunk-WFCECD6Q.cjs.map +1 -0
  97. package/dist/{chunk-EK6RJ373.cjs → chunk-YQGLVWB2.cjs} +7 -7
  98. package/dist/{chunk-EK6RJ373.cjs.map → chunk-YQGLVWB2.cjs.map} +1 -1
  99. package/dist/{chunk-X3244EKP.cjs → chunk-ZFWNO3GE.cjs} +48 -4
  100. package/dist/chunk-ZFWNO3GE.cjs.map +1 -0
  101. package/dist/ddl-BSFlbGQF.d.cts +38 -0
  102. package/dist/ddl-EdkIiFVU.d.ts +38 -0
  103. package/dist/{extension-types-B78CZfA5.d.cts → extension-types-CwHV-Uk4.d.cts} +4 -4
  104. package/dist/{extension-types-B78CZfA5.d.ts → extension-types-CwHV-Uk4.d.ts} +4 -4
  105. package/dist/graph-extension/index.cjs +19 -19
  106. package/dist/graph-extension/index.d.cts +4 -4
  107. package/dist/graph-extension/index.d.ts +4 -4
  108. package/dist/graph-extension/index.js +4 -4
  109. package/dist/{index-CWdBFWbI.d.ts → index-DzeIiMO3.d.ts} +30 -3
  110. package/dist/{index-Bilw0pYm.d.cts → index-Ln_KHTGA.d.cts} +30 -3
  111. package/dist/index.cjs +1542 -1011
  112. package/dist/index.cjs.map +1 -1
  113. package/dist/index.d.cts +142 -12
  114. package/dist/index.d.ts +142 -12
  115. package/dist/index.js +1138 -643
  116. package/dist/index.js.map +1 -1
  117. package/dist/indexes/index.cjs +19 -19
  118. package/dist/indexes/index.d.cts +9 -9
  119. package/dist/indexes/index.d.ts +9 -9
  120. package/dist/indexes/index.js +5 -5
  121. package/dist/interchange/index.cjs +8 -14
  122. package/dist/interchange/index.cjs.map +1 -1
  123. package/dist/interchange/index.d.cts +5 -16
  124. package/dist/interchange/index.d.ts +5 -16
  125. package/dist/interchange/index.js +3 -9
  126. package/dist/interchange/index.js.map +1 -1
  127. package/dist/{manager-ehLTTNq0.d.ts → manager-BbdyNhkv.d.ts} +2 -2
  128. package/dist/{manager-c1MGaVVR.d.cts → manager-wTDgjoXG.d.cts} +2 -2
  129. package/dist/{materialize-indexes-DFavFQah.d.ts → materialize-indexes-lkawaDor.d.ts} +1 -1
  130. package/dist/{materialize-indexes-BQfaAZKA.d.cts → materialize-indexes-oanE3RU0.d.cts} +1 -1
  131. package/dist/{ddl-0Ooc2dpL.d.ts → postgres-CK2ByP1q.d.cts} +2 -471
  132. package/dist/{ddl-Dza3kDrI.d.cts → postgres-ymXYC6Rr.d.ts} +2 -471
  133. package/dist/profiler/index.cjs +10 -10
  134. package/dist/profiler/index.d.cts +7 -7
  135. package/dist/profiler/index.d.ts +7 -7
  136. package/dist/profiler/index.js +3 -3
  137. package/dist/schema/index.cjs +33 -33
  138. package/dist/schema/index.d.cts +7 -7
  139. package/dist/schema/index.d.ts +7 -7
  140. package/dist/schema/index.js +10 -10
  141. package/dist/{sqlite-BxZUPbyD.d.ts → sqlite-DxH1lrwD.d.cts} +2 -468
  142. package/dist/{sqlite-mvpXjEeB.d.cts → sqlite-R8YGOqVQ.d.ts} +2 -468
  143. package/dist/{store-Ufc1Eoey.d.ts → store--z1Tmk7U.d.cts} +124 -5
  144. package/dist/{store-D7YEMg2v.d.cts → store-CNKM334w.d.ts} +124 -5
  145. package/dist/{types-CMQymcwk.d.cts → types-BBiDqJCU.d.ts} +252 -46
  146. package/dist/{types-B-sJJ4GQ.d.ts → types-CMvxx2kd.d.ts} +2 -2
  147. package/dist/{types-CmUA9sal.d.cts → types-D5B6Be5c.d.cts} +2 -2
  148. package/dist/{types-CQ7xXJMP.d.ts → types-dL-clxO3.d.cts} +252 -46
  149. package/dist/{where-CtrLu1Zf.d.ts → where-CAo6wsBZ.d.ts} +2 -2
  150. package/dist/{where-5zf15aFZ.d.cts → where-bJjuOCeV.d.cts} +2 -2
  151. package/package.json +20 -5
  152. package/dist/chunk-3EUKJEQ3.js +0 -77
  153. package/dist/chunk-3EUKJEQ3.js.map +0 -1
  154. package/dist/chunk-4FJVSF3K.cjs +0 -12
  155. package/dist/chunk-7V335GHG.cjs.map +0 -1
  156. package/dist/chunk-FFHW2JEK.cjs.map +0 -1
  157. package/dist/chunk-HTGDWIDE.cjs +0 -89
  158. package/dist/chunk-HTGDWIDE.cjs.map +0 -1
  159. package/dist/chunk-LYRUNG6E.cjs +0 -52
  160. package/dist/chunk-LYRUNG6E.cjs.map +0 -1
  161. package/dist/chunk-NMOE2ZEU.cjs.map +0 -1
  162. package/dist/chunk-NYQFPGYP.cjs.map +0 -1
  163. package/dist/chunk-NZ5PMBTG.js.map +0 -1
  164. package/dist/chunk-O57GYGYK.js.map +0 -1
  165. package/dist/chunk-OYLF3IC7.js.map +0 -1
  166. package/dist/chunk-PCHTTG42.js +0 -47
  167. package/dist/chunk-PCHTTG42.js.map +0 -1
  168. package/dist/chunk-PGU2XKMA.js.map +0 -1
  169. package/dist/chunk-PN37HVAV.cjs.map +0 -1
  170. package/dist/chunk-PYJOBZR3.cjs.map +0 -1
  171. package/dist/chunk-TKM2WDT4.js.map +0 -1
  172. package/dist/chunk-TSGBRPNE.js.map +0 -1
  173. package/dist/chunk-U5ROKVRF.js.map +0 -1
  174. package/dist/chunk-WFUN6DCM.cjs.map +0 -1
  175. package/dist/chunk-WVQXAFP3.js.map +0 -1
  176. package/dist/chunk-X3244EKP.cjs.map +0 -1
  177. package/dist/chunk-YEDQLNVE.cjs.map +0 -1
  178. package/dist/chunk-ZTREJOGB.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,25 +1,28 @@
1
- import { quoteIdentifier, EMPTY_REQUIRED_COLUMNS, addRequiredColumn, markSelectiveFieldAsRequired, markFieldRefAsRequired, NODE_COLUMNS, shouldProjectColumn, mapSelectiveSystemFieldToColumn, isIdFieldRef, isAggregateExpr, EDGE_COLUMNS } from './chunk-3EUKJEQ3.js';
2
- import { META_EDGE_BRAND, loadAndMergeGraphExtensionDocument, ensureSchema, loadAndVerifyGraph, mergeGraphExtension, commitNewSchemaVersion, applyDeprecatedKinds, loadActiveSchemaWithBootstrap, parseSerializedSchema, computeClosuresFromOntology, createEmptyClosures, KindRegistry, extensionKindNames, serializeSchemaProperties, buildGraphExtensionOntologyKeySet, compileTimeOntologyKey, getTypeName, validateNodeProps, validateEdgeProps } from './chunk-5MTOKWDA.js';
3
- export { broader, core, defineEdge, defineNode, differentFrom, disjointWith, equivalentTo, hasPart, implies, inverseOf, isMetaEdge, narrower, partOf, relatedTo, sameAs, subClassOf } from './chunk-5MTOKWDA.js';
4
- import { nowIso, isKnownKind, validateOptionalIsoDate, getNodeKinds, getEdgeKinds } from './chunk-OYLF3IC7.js';
5
- export { defineGraph, getEdgeKinds, getNodeKinds, isEdgeType, isEdgeTypeWithEndpoints, isGraphDef, isNodeType } from './chunk-OYLF3IC7.js';
6
- export { defineGraphExtension } from './chunk-E5ROA3MN.js';
7
- import { IncompatibleChangeError, filterReservedKeys, RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS, RemoveCompileTimeKindError, KindHasReferentsError, validateProjectionField } from './chunk-TSGBRPNE.js';
8
- export { CURRENT_GRAPH_EXTENSION_VERSION, GraphExtensionError, GraphExtensionUnresolvedEndpointError, GraphExtensionValidationError, GraphExtensionVersionUnsupportedError, IncompatibleChangeError, KindCollisionError, KindHasReferentsError, LEGACY_GRAPH_EXTENSION_VERSION, RemoveCompileTimeKindError, validateGraphExtension } from './chunk-TSGBRPNE.js';
9
- import { runOptionallyInTransaction } from './chunk-PCHTTG42.js';
10
- import { canonicalEqual, sortedReplacer } from './chunk-O57GYGYK.js';
11
- import { getDialect, generateIndexDDL } from './chunk-ZTREJOGB.js';
12
- export { andWhere, fts5Strategy, notWhere, orWhere, tsvectorStrategy } from './chunk-ZTREJOGB.js';
13
- import { MAX_PG_IDENTIFIER_LENGTH, DEFAULT_PAGINATION_LIMIT, DEFAULT_STREAM_BATCH_SIZE, NODE_META_KEYS, EDGE_META_KEYS, SQLITE_PATH_DELIMITER, PG_ARRAY_START, PG_ARRAY_END, PG_PATH_ELEMENT_SEPARATOR, fnv1aBase36, sha256Hex } from './chunk-EJCDOA37.js';
14
- export { defineEdgeIndex, defineNodeIndex } from './chunk-EJCDOA37.js';
15
- import { createSchemaIntrospector, resolveFieldTypeInfoAtJsonPointer, getSearchableMetadata, DEFAULT_SEARCHABLE_LANGUAGE } from './chunk-OOS2RKRH.js';
16
- export { DEFAULT_SEARCHABLE_LANGUAGE, getSearchableMetadata, isSearchableSchema, searchable } from './chunk-OOS2RKRH.js';
17
- import { getEmbeddingDimensions, isEmbeddingSchema } from './chunk-WVQXAFP3.js';
18
- export { embedding, getEmbeddingDimensions, isEmbeddingSchema } from './chunk-WVQXAFP3.js';
19
- import { ConfigurationError, UnsupportedPredicateError, ValidationError, KindNotFoundError, EndpointError, EagerMaterializationError, CompilerInvariantError, DatabaseOperationError, EdgeNotFoundError, NodeConstraintNotFoundError, RestrictedDeleteError, NodeNotFoundError, EndpointNotFoundError, UniquenessError, CardinalityError, DisjointError } from './chunk-U5ROKVRF.js';
20
- export { BackendDisposedError, CardinalityError, CompilerInvariantError, ConfigurationError, DatabaseOperationError, DisjointError, EagerMaterializationError, EdgeNotFoundError, EndpointError, EndpointNotFoundError, KindNotFoundError, MigrationError, NodeConstraintNotFoundError, NodeNotFoundError, RestrictedDeleteError, SchemaContentConflictError, SchemaMismatchError, StaleVersionError, StoreNotInitializedError, TypeGraphError, UniquenessError, UnsupportedPredicateError, ValidationError, VersionConflictError, getErrorSuggestion, isConstraintError, isSystemError, isTypeGraphError, isUserRecoverable } from './chunk-U5ROKVRF.js';
21
- import { jsonPointer, parseJsonPointer, normalizeJsonPointer, joinJsonPointers } from './chunk-NZ5PMBTG.js';
22
- export { MAX_JSON_POINTER_DEPTH, joinJsonPointers, jsonPointer, normalizeJsonPointer, parseJsonPointer } from './chunk-NZ5PMBTG.js';
1
+ export { libsqlVectorStrategy } from './chunk-3IRMLJEK.js';
2
+ import { quoteIdentifier, EMPTY_REQUIRED_COLUMNS, addRequiredColumn, markSelectiveFieldAsRequired, markFieldRefAsRequired, NODE_COLUMNS, shouldProjectColumn, mapSelectiveSystemFieldToColumn, isIdFieldRef, isAggregateExpr, EDGE_COLUMNS } from './chunk-FVIGJTS7.js';
3
+ export { pgvectorStrategy } from './chunk-FVIGJTS7.js';
4
+ import { META_EDGE_BRAND, loadAndMergeGraphExtensionDocument, ensureSchema, loadAndVerifyGraph, mergeGraphExtension, commitNewSchemaVersion, applyDeprecatedKinds, loadActiveSchemaWithBootstrap, parseSerializedSchema, computeClosuresFromOntology, createEmptyClosures, KindRegistry, extensionKindNames, serializeSchemaProperties, buildGraphExtensionOntologyKeySet, compileTimeOntologyKey, getTypeName, validateNodeProps, validateEdgeProps } from './chunk-3JLRHQ67.js';
5
+ export { broader, core, defineEdge, defineNode, differentFrom, disjointWith, equivalentTo, hasPart, implies, inverseOf, isMetaEdge, narrower, partOf, relatedTo, sameAs, subClassOf } from './chunk-3JLRHQ67.js';
6
+ import { nowIso, isKnownKind, validateOptionalIsoDate, getNodeKinds, getEdgeKinds } from './chunk-MAQJYNJR.js';
7
+ export { defineGraph, getEdgeKinds, getNodeKinds, isEdgeType, isEdgeTypeWithEndpoints, isGraphDef, isNodeType } from './chunk-MAQJYNJR.js';
8
+ export { defineGraphExtension } from './chunk-IX7RE7CG.js';
9
+ import { IncompatibleChangeError, filterReservedKeys, RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS, RemoveCompileTimeKindError, KindHasReferentsError, validateProjectionField } from './chunk-ENDUY2CD.js';
10
+ export { CURRENT_GRAPH_EXTENSION_VERSION, GraphExtensionError, GraphExtensionUnresolvedEndpointError, GraphExtensionValidationError, GraphExtensionVersionUnsupportedError, IncompatibleChangeError, KindCollisionError, KindHasReferentsError, LEGACY_GRAPH_EXTENSION_VERSION, RemoveCompileTimeKindError, computeTransitiveClosure, invertClosure, isReachable, validateGraphExtension } from './chunk-ENDUY2CD.js';
11
+ export { sqliteVecStrategy } from './chunk-2QA5EHEN.js';
12
+ import { LEGACY_EMBEDDINGS_TABLE_NAME, runOptionallyInTransaction } from './chunk-633N7DSE.js';
13
+ import { isMissingTableError, sortedReplacer, canonicalEqual } from './chunk-M6OC455F.js';
14
+ import { quotedTableName, getDialect, assertVectorMinScore, compileNodeIndexFieldKeys, compileIndexWhere, generateIndexDDL, vectorScoreExpression, vectorMinScoreCondition } from './chunk-AI3RNREM.js';
15
+ export { andWhere, buildVectorCapabilities, fts5Strategy, notWhere, orWhere, tsvectorStrategy } from './chunk-AI3RNREM.js';
16
+ import { MAX_PG_IDENTIFIER_LENGTH, DEFAULT_PAGINATION_LIMIT, DEFAULT_STREAM_BATCH_SIZE, NODE_META_KEYS, EDGE_META_KEYS, sha256Hex, SQLITE_PATH_DELIMITER, PG_ARRAY_START, PG_ARRAY_END, PG_PATH_ELEMENT_SEPARATOR, fnv1aBase36 } from './chunk-R4JOBEJU.js';
17
+ export { defineEdgeIndex, defineNodeIndex } from './chunk-R4JOBEJU.js';
18
+ import { createSchemaIntrospector, resolveFieldTypeInfoAtJsonPointer, getSearchableMetadata, DEFAULT_SEARCHABLE_LANGUAGE } from './chunk-MXE2U3EX.js';
19
+ export { DEFAULT_SEARCHABLE_LANGUAGE, getSearchableMetadata, isSearchableSchema, searchable } from './chunk-MXE2U3EX.js';
20
+ import { DEFAULT_EMBEDDING_INDEX_TYPE, DEFAULT_EMBEDDING_METRIC, resolveEmbeddingFields } from './chunk-454I6GDF.js';
21
+ export { embedding, getEmbeddingDimensions, isEmbeddingSchema } from './chunk-454I6GDF.js';
22
+ import { ConfigurationError, EmbeddingDimensionChangedError, UnsupportedPredicateError, ValidationError, KindNotFoundError, EndpointError, EagerMaterializationError, CompilerInvariantError, DatabaseOperationError, EdgeNotFoundError, NodeIndexNotFoundError, NodeConstraintNotFoundError, RestrictedDeleteError, NodeNotFoundError, EndpointNotFoundError, UniquenessError, CardinalityError, DisjointError } from './chunk-TQOYM4LN.js';
23
+ export { BackendDisposedError, CardinalityError, CompilerInvariantError, ConfigurationError, DatabaseOperationError, DisjointError, EagerMaterializationError, EdgeNotFoundError, EmbeddingDimensionChangedError, EndpointError, EndpointNotFoundError, KindNotFoundError, MigrationError, NodeConstraintNotFoundError, NodeIndexNotFoundError, NodeNotFoundError, RestrictedDeleteError, SchemaContentConflictError, SchemaMismatchError, StaleVersionError, StoreNotInitializedError, TypeGraphError, UniquenessError, UnsupportedPredicateError, ValidationError, VersionConflictError, getErrorSuggestion, isConstraintError, isSystemError, isTypeGraphError, isUserRecoverable } from './chunk-TQOYM4LN.js';
24
+ import { jsonPointer, parseJsonPointer, resolveJsonPointer, normalizeJsonPointer, joinJsonPointers } from './chunk-K5P5OZXS.js';
25
+ export { MAX_JSON_POINTER_DEPTH, joinJsonPointers, jsonPointer, normalizeJsonPointer, parseJsonPointer } from './chunk-K5P5OZXS.js';
23
26
  import { z } from 'zod';
24
27
  import { sql, Placeholder } from 'drizzle-orm';
25
28
  import { nanoid } from 'nanoid';
@@ -67,6 +70,184 @@ function getExternalRefTable(schema) {
67
70
  function createExternalRef(table) {
68
71
  return (id) => ({ table, id });
69
72
  }
73
+ var DEFAULT_BATCH_SIZE = 500;
74
+ var DEFAULT_SLOT_METRIC = DEFAULT_EMBEDDING_METRIC;
75
+ var DEFAULT_SLOT_INDEX_TYPE = DEFAULT_EMBEDDING_INDEX_TYPE;
76
+ async function migrateLegacyEmbeddings(options) {
77
+ const {
78
+ backend,
79
+ graphId,
80
+ resolveSlotConfig,
81
+ batchSize = DEFAULT_BATCH_SIZE,
82
+ legacyTableName = LEGACY_EMBEDDINGS_TABLE_NAME
83
+ } = options;
84
+ if (backend.vectorStrategy === void 0 || backend.upsertEmbedding === void 0) {
85
+ throw new Error(
86
+ "migrateLegacyEmbeddings requires a backend wired with a vectorStrategy (the destination per-field storage). Pass the post-cutover backend."
87
+ );
88
+ }
89
+ if (!Number.isInteger(batchSize) || batchSize <= 0) {
90
+ throw new RangeError(
91
+ `batchSize must be a positive integer, got: ${batchSize}`
92
+ );
93
+ }
94
+ const upsertEmbedding = backend.upsertEmbedding;
95
+ const perField = {};
96
+ const skippedDimensionMismatch = {};
97
+ const skippedDecodeError = {};
98
+ let migrated = 0;
99
+ let cursor;
100
+ for (; ; ) {
101
+ let batch;
102
+ try {
103
+ batch = await readLegacyBatch(backend, {
104
+ legacyTableName,
105
+ graphId,
106
+ batchSize,
107
+ after: cursor
108
+ });
109
+ } catch (error) {
110
+ if (cursor === void 0 && isMissingTableError(error)) {
111
+ return {
112
+ migrated: 0,
113
+ perField: {},
114
+ skippedDimensionMismatch: {},
115
+ skippedDecodeError: {},
116
+ legacyTablePresent: false
117
+ };
118
+ }
119
+ throw error;
120
+ }
121
+ if (batch.length === 0) break;
122
+ for (const row of batch) {
123
+ const slotKey = `${row.node_kind}.${row.field_path}`;
124
+ let embedding2;
125
+ try {
126
+ embedding2 = decodeEmbeddingJson(row);
127
+ } catch {
128
+ skippedDecodeError[slotKey] = (skippedDecodeError[slotKey] ?? 0) + 1;
129
+ continue;
130
+ }
131
+ const config = resolveSlotConfig?.(row.node_kind, row.field_path);
132
+ try {
133
+ await upsertEmbedding({
134
+ graphId: row.graph_id,
135
+ nodeKind: row.node_kind,
136
+ nodeId: row.node_id,
137
+ fieldPath: row.field_path,
138
+ embedding: embedding2,
139
+ // The decoded length is the authoritative fixed dimension — the
140
+ // strategy provisions its column type (e.g. `F32_BLOB(N)`) from it.
141
+ dimensions: embedding2.length,
142
+ metric: config?.metric ?? DEFAULT_SLOT_METRIC,
143
+ indexType: config?.indexType ?? DEFAULT_SLOT_INDEX_TYPE
144
+ });
145
+ } catch (error) {
146
+ if (error instanceof EmbeddingDimensionChangedError) {
147
+ skippedDimensionMismatch[slotKey] = (skippedDimensionMismatch[slotKey] ?? 0) + 1;
148
+ continue;
149
+ }
150
+ throw error;
151
+ }
152
+ migrated += 1;
153
+ perField[slotKey] = (perField[slotKey] ?? 0) + 1;
154
+ }
155
+ if (batch.length < batchSize) break;
156
+ const last = batch.at(-1);
157
+ cursor = {
158
+ graphId: last.graph_id,
159
+ nodeKind: last.node_kind,
160
+ nodeId: last.node_id,
161
+ fieldPath: last.field_path
162
+ };
163
+ }
164
+ return {
165
+ migrated,
166
+ perField,
167
+ skippedDimensionMismatch,
168
+ skippedDecodeError,
169
+ legacyTablePresent: true
170
+ };
171
+ }
172
+ async function readLegacyBatch(backend, params) {
173
+ const table = quotedTableName(params.legacyTableName);
174
+ const embeddingJson = legacyEmbeddingDecodeExpression(backend);
175
+ const conditions = [];
176
+ if (params.graphId !== void 0) {
177
+ conditions.push(sql`"graph_id" = ${params.graphId}`);
178
+ }
179
+ if (params.after !== void 0) {
180
+ conditions.push(keysetAfterCondition(params.after));
181
+ }
182
+ const whereClause = conditions.length === 0 ? sql`` : sql` WHERE ${sql.join(conditions, sql` AND `)}`;
183
+ const query = sql`
184
+ SELECT
185
+ "graph_id" AS graph_id,
186
+ "node_kind" AS node_kind,
187
+ "node_id" AS node_id,
188
+ "field_path" AS field_path,
189
+ ${embeddingJson} AS embedding_json
190
+ FROM ${table}${whereClause}
191
+ ORDER BY "graph_id" ASC, "node_kind" ASC, "node_id" ASC, "field_path" ASC
192
+ LIMIT ${params.batchSize}
193
+ `;
194
+ return backend.execute(query);
195
+ }
196
+ function keysetAfterCondition(after) {
197
+ return sql`
198
+ (
199
+ "graph_id" > ${after.graphId}
200
+ OR ("graph_id" = ${after.graphId} AND "node_kind" > ${after.nodeKind})
201
+ OR ("graph_id" = ${after.graphId} AND "node_kind" = ${after.nodeKind} AND "node_id" > ${after.nodeId})
202
+ OR (
203
+ "graph_id" = ${after.graphId}
204
+ AND "node_kind" = ${after.nodeKind}
205
+ AND "node_id" = ${after.nodeId}
206
+ AND "field_path" > ${after.fieldPath}
207
+ )
208
+ )
209
+ `;
210
+ }
211
+ function legacyEmbeddingDecodeExpression(backend) {
212
+ switch (backend.dialect) {
213
+ case "sqlite": {
214
+ return sql`vec_to_json("embedding")`;
215
+ }
216
+ case "postgres": {
217
+ return sql`"embedding"::text`;
218
+ }
219
+ default: {
220
+ const _exhaustive = backend.dialect;
221
+ throw new Error(
222
+ `migrateLegacyEmbeddings does not support dialect: ${String(_exhaustive)}`
223
+ );
224
+ }
225
+ }
226
+ }
227
+ function decodeEmbeddingJson(row) {
228
+ let parsed;
229
+ try {
230
+ parsed = JSON.parse(row.embedding_json);
231
+ } catch (error) {
232
+ throw new Error(
233
+ `Failed to decode legacy embedding for ${row.node_kind}.${row.field_path} (graph ${row.graph_id}, node ${row.node_id}): not valid JSON.`,
234
+ { cause: error }
235
+ );
236
+ }
237
+ if (!Array.isArray(parsed) || parsed.length === 0) {
238
+ throw new Error(
239
+ `Legacy embedding for ${row.node_kind}.${row.field_path} (graph ${row.graph_id}, node ${row.node_id}) decoded to a non-array or empty value.`
240
+ );
241
+ }
242
+ for (const [index, value] of parsed.entries()) {
243
+ if (typeof value !== "number" || !Number.isFinite(value)) {
244
+ throw new TypeError(
245
+ `Legacy embedding for ${row.node_kind}.${row.field_path} (graph ${row.graph_id}, node ${row.node_id}) has a non-finite value at index ${index}: ${String(value)}.`
246
+ );
247
+ }
248
+ }
249
+ return parsed;
250
+ }
70
251
 
71
252
  // src/query/subquery-utils.ts
72
253
  function normalizeValueType(valueType) {
@@ -371,7 +552,10 @@ function vectorSimilarity(field2, queryEmbedding, limit, options) {
371
552
  __type: "vector_similarity",
372
553
  field: field2,
373
554
  queryEmbedding,
374
- metric: options?.metric ?? "cosine",
555
+ // Leave metric unset when the caller didn't specify one, so the compiler
556
+ // resolves the field's declared metric per kind. Defaulting to "cosine"
557
+ // here would mis-rank l2/inner_product fields and bypass their ANN index.
558
+ ...options?.metric !== void 0 && { metric: options.metric },
375
559
  limit,
376
560
  ...options?.minScore !== void 0 && { minScore: options.minScore }
377
561
  };
@@ -1614,7 +1798,6 @@ function mergeEdgeKinds(traversal) {
1614
1798
  var DEFAULT_TABLE_NAMES = {
1615
1799
  nodes: "typegraph_nodes",
1616
1800
  edges: "typegraph_edges",
1617
- embeddings: "typegraph_node_embeddings",
1618
1801
  fulltext: "typegraph_node_fulltext",
1619
1802
  uniques: "typegraph_node_uniques"
1620
1803
  };
@@ -1641,18 +1824,19 @@ function createSqlSchema(names = {}) {
1641
1824
  const tables = { ...DEFAULT_TABLE_NAMES, ...names };
1642
1825
  validateTableName(tables.nodes, "nodes");
1643
1826
  validateTableName(tables.edges, "edges");
1644
- validateTableName(tables.embeddings, "embeddings");
1645
1827
  validateTableName(tables.fulltext, "fulltext");
1646
1828
  validateTableName(tables.uniques, "uniques");
1647
1829
  return {
1648
1830
  tables,
1649
1831
  nodesTable: sql.raw(quoteIdentifier2(tables.nodes)),
1650
1832
  edgesTable: sql.raw(quoteIdentifier2(tables.edges)),
1651
- embeddingsTable: sql.raw(quoteIdentifier2(tables.embeddings)),
1652
1833
  fulltextTable: sql.raw(quoteIdentifier2(tables.fulltext))
1653
1834
  };
1654
1835
  }
1655
1836
  var DEFAULT_SQL_SCHEMA = createSqlSchema();
1837
+ function vectorSlotKey(nodeKind, fieldPath) {
1838
+ return `${nodeKind}\0${fieldPath}`;
1839
+ }
1656
1840
  var ALIAS_CTE_PREFIX = "cte_";
1657
1841
  var EMBEDDINGS_CTE_ALIAS = "cte_embeddings";
1658
1842
  var FULLTEXT_CTE_ALIAS = "cte_fulltext";
@@ -2159,35 +2343,61 @@ function buildStandardHaving(input) {
2159
2343
  }
2160
2344
  function buildStandardEmbeddingsCte(input) {
2161
2345
  const { ctx, graphId, nodeKinds, vectorPredicate } = input;
2162
- const { dialect } = ctx;
2163
2346
  const { field: field2, metric, minScore, queryEmbedding } = vectorPredicate;
2164
- const embeddingsTableName = ctx.schema.tables.embeddings;
2165
2347
  if (nodeKinds.length === 0) {
2166
2348
  throw new UnsupportedPredicateError(
2167
2349
  "Vector predicate must resolve to at least one node kind"
2168
2350
  );
2169
2351
  }
2170
- const fieldPath = resolveEmbeddingFieldPath(field2);
2171
- const distanceExpr = dialect.vectorDistance(
2172
- qualifyColumn(embeddingsTableName, "embedding"),
2173
- queryEmbedding,
2174
- metric
2175
- );
2176
- const scopedNodes = buildScopedNodeIdsSubquery(field2.alias);
2177
- const conditions = [
2178
- sql`${qualifyColumn(embeddingsTableName, "graph_id")} = ${graphId}`,
2179
- compileKindFilter(
2180
- qualifyColumn(embeddingsTableName, "node_kind"),
2181
- nodeKinds
2182
- ),
2183
- sql`${qualifyColumn(embeddingsTableName, "field_path")} = ${fieldPath}`
2184
- ];
2185
- if (minScore !== void 0) {
2186
- conditions.push(
2187
- compileVectorMinScoreCondition(distanceExpr, metric, minScore)
2352
+ const { vectorStrategy } = ctx;
2353
+ if (vectorStrategy === void 0) {
2354
+ throw new UnsupportedPredicateError(
2355
+ "Vector similarity predicate requires a backend with a vector strategy"
2188
2356
  );
2189
2357
  }
2190
- const scoreExpr = compileVectorScoreExpression(distanceExpr, metric);
2358
+ const fieldPath = resolveEmbeddingFieldPath(field2);
2359
+ const vectorSlots = ctx.vectorSlots;
2360
+ const scopedNodes = buildScopedNodeIdsSubquery(field2.alias);
2361
+ const declaringKinds = nodeKinds.filter(
2362
+ (kind) => vectorSlots?.has(vectorSlotKey(kind, fieldPath))
2363
+ );
2364
+ const branches = declaringKinds.map((kind) => {
2365
+ const tableName = vectorStrategy.tableName(graphId, kind, fieldPath);
2366
+ const branchMetric = metric ?? vectorSlots?.get(vectorSlotKey(kind, fieldPath))?.metric ?? "cosine";
2367
+ const distanceExpr = vectorStrategy.distanceExpression(
2368
+ qualifyColumn(tableName, "embedding"),
2369
+ queryEmbedding,
2370
+ branchMetric
2371
+ );
2372
+ const scoreExpr = vectorScoreExpression(distanceExpr, branchMetric);
2373
+ const conditions = [
2374
+ sql`${qualifyColumn(tableName, "graph_id")} = ${graphId}`
2375
+ ];
2376
+ if (minScore !== void 0) {
2377
+ conditions.push(
2378
+ vectorMinScoreCondition(distanceExpr, branchMetric, minScore)
2379
+ );
2380
+ }
2381
+ return sql`
2382
+ SELECT
2383
+ ${qualifyColumn(tableName, "node_id")} AS node_id,
2384
+ ${kind} AS node_kind,
2385
+ ${distanceExpr} AS distance,
2386
+ ${scoreExpr} AS score
2387
+ FROM ${quoteIdentifier(tableName)}
2388
+ INNER JOIN ${scopedNodes}
2389
+ ON ${sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_id`)} =
2390
+ ${qualifyColumn(tableName, "node_id")}
2391
+ AND ${sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_kind`)} = ${kind}
2392
+ WHERE ${sql.join(conditions, sql` AND `)}
2393
+ `;
2394
+ });
2395
+ const unionBody = branches.length === 0 ? emptyEmbeddingsBody() : sql.join(
2396
+ branches,
2397
+ sql`
2398
+ UNION ALL
2399
+ `
2400
+ );
2191
2401
  return sql`
2192
2402
  ${sql.raw(EMBEDDINGS_CTE_ALIAS)} AS (
2193
2403
  SELECT
@@ -2197,49 +2407,22 @@ function buildStandardEmbeddingsCte(input) {
2197
2407
  score,
2198
2408
  ROW_NUMBER() OVER (ORDER BY distance ASC) AS ord
2199
2409
  FROM (
2200
- SELECT
2201
- ${qualifyColumn(embeddingsTableName, "node_id")} AS node_id,
2202
- ${qualifyColumn(embeddingsTableName, "node_kind")} AS node_kind,
2203
- ${distanceExpr} AS distance,
2204
- ${scoreExpr} AS score
2205
- FROM ${ctx.schema.embeddingsTable}
2206
- INNER JOIN ${scopedNodes}
2207
- ON ${sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_id`)} =
2208
- ${qualifyColumn(embeddingsTableName, "node_id")}
2209
- AND ${sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_kind`)} =
2210
- ${qualifyColumn(embeddingsTableName, "node_kind")}
2211
- WHERE ${sql.join(conditions, sql` AND `)}
2410
+ ${unionBody}
2212
2411
  ORDER BY distance ASC
2213
2412
  LIMIT ${vectorPredicate.limit}
2214
2413
  ) AS vec_inner
2215
2414
  )
2216
2415
  `;
2217
2416
  }
2218
- function compileVectorScoreExpression(distanceExpr, metric) {
2219
- switch (metric) {
2220
- case "cosine": {
2221
- return sql`(1.0 - ${distanceExpr})`;
2222
- }
2223
- case "l2":
2224
- case "inner_product": {
2225
- return distanceExpr;
2226
- }
2227
- }
2228
- }
2229
- function compileVectorMinScoreCondition(distanceExpr, metric, minScore) {
2230
- switch (metric) {
2231
- case "cosine": {
2232
- const threshold = 1 - minScore;
2233
- return sql`${distanceExpr} <= ${threshold}`;
2234
- }
2235
- case "l2": {
2236
- return sql`${distanceExpr} <= ${minScore}`;
2237
- }
2238
- case "inner_product": {
2239
- const negativeThreshold = -minScore;
2240
- return sql`${distanceExpr} <= ${negativeThreshold}`;
2241
- }
2242
- }
2417
+ function emptyEmbeddingsBody() {
2418
+ return sql`
2419
+ SELECT
2420
+ CAST(NULL AS TEXT) AS node_id,
2421
+ CAST(NULL AS TEXT) AS node_kind,
2422
+ CAST(NULL AS REAL) AS distance,
2423
+ CAST(NULL AS REAL) AS score
2424
+ WHERE 1 = 0
2425
+ `;
2243
2426
  }
2244
2427
  function buildStandardFulltextCte(input) {
2245
2428
  const { ctx, fulltextPredicate, graphId, nodeKinds } = input;
@@ -2406,6 +2589,11 @@ function runFulltextPredicatePass(ast, dialect) {
2406
2589
  `Fulltext query mode "${fulltextPredicate.mode}" is not supported by the "${strategy.name}" strategy. Supported modes: ${strategy.supportedModes.join(", ")}.`
2407
2590
  );
2408
2591
  }
2592
+ if (fulltextPredicate.language !== void 0 && !strategy.supportsLanguageOverride) {
2593
+ throw new UnsupportedPredicateError(
2594
+ `Fulltext strategy "${strategy.name}" does not honor a per-query \`language\` override (its tokenizer is fixed at table-create time). Drop the option, or use a strategy that advertises \`supportsLanguageOverride: true\`.`
2595
+ );
2596
+ }
2409
2597
  if (!Number.isFinite(fulltextPredicate.limit) || fulltextPredicate.limit <= 0) {
2410
2598
  throw new UnsupportedPredicateError(
2411
2599
  `Fulltext match limit must be a positive finite number, got ${String(fulltextPredicate.limit)}`
@@ -2516,7 +2704,7 @@ function createTemporalFilterPass(ast, currentTimestamp) {
2516
2704
  }
2517
2705
 
2518
2706
  // src/query/compiler/passes/vector.ts
2519
- function runVectorPredicatePass(ast, dialect) {
2707
+ function runVectorPredicatePass(ast, dialect, vectorStrategy) {
2520
2708
  const vectorPredicates = extractVectorSimilarityPredicates(ast.predicates);
2521
2709
  if (vectorPredicates.length > 1) {
2522
2710
  throw new UnsupportedPredicateError(
@@ -2527,16 +2715,19 @@ function runVectorPredicatePass(ast, dialect) {
2527
2715
  if (vectorPredicate === void 0) {
2528
2716
  return { vectorPredicate: void 0 };
2529
2717
  }
2530
- const vectorStrategy = dialect.capabilities.vectorPredicateStrategy;
2531
- if (vectorStrategy === "unsupported" || !dialect.supportsVectors) {
2718
+ const predicateStrategy = dialect.capabilities.vectorPredicateStrategy;
2719
+ if (predicateStrategy === "unsupported" || !dialect.supportsVectors) {
2532
2720
  throw new UnsupportedPredicateError(
2533
2721
  `Vector similarity predicates are not supported for dialect "${dialect.name}"`
2534
2722
  );
2535
2723
  }
2536
- if (!dialect.capabilities.vectorMetrics.includes(vectorPredicate.metric)) {
2537
- throw new UnsupportedPredicateError(
2538
- `Vector metric "${vectorPredicate.metric}" is not supported for dialect "${dialect.name}"`
2539
- );
2724
+ if (vectorPredicate.metric !== void 0) {
2725
+ const supportedMetrics = vectorStrategy?.capabilities.metrics ?? dialect.capabilities.vectorMetrics;
2726
+ if (!supportedMetrics.includes(vectorPredicate.metric)) {
2727
+ throw new UnsupportedPredicateError(
2728
+ vectorStrategy === void 0 ? `Vector metric "${vectorPredicate.metric}" is not supported for dialect "${dialect.name}"` : `Vector metric "${vectorPredicate.metric}" is not supported by vector strategy "${vectorStrategy.name}" (supported: ${supportedMetrics.join(", ")})`
2729
+ );
2730
+ }
2540
2731
  }
2541
2732
  if (!Number.isFinite(vectorPredicate.limit) || vectorPredicate.limit <= 0) {
2542
2733
  throw new UnsupportedPredicateError(
@@ -2781,13 +2972,14 @@ function lowerRecursiveQueryToLogicalPlanNode(input) {
2781
2972
  ast.limit
2782
2973
  );
2783
2974
  }
2784
- function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlanNodeId) {
2975
+ function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlanNodeId, vectorStrategy) {
2785
2976
  if ("__type" in query) {
2786
2977
  return lowerSetOperationToLogicalPlanNode(
2787
2978
  query,
2788
2979
  graphId,
2789
2980
  dialect,
2790
- nextPlanNodeId
2981
+ nextPlanNodeId,
2982
+ vectorStrategy
2791
2983
  );
2792
2984
  }
2793
2985
  const hasVariableLengthTraversal2 = query.traversals.some(
@@ -2803,7 +2995,8 @@ function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlan
2803
2995
  const dialectAdapter = getDialect(dialect);
2804
2996
  const vectorPredicate = runVectorPredicatePass(
2805
2997
  query,
2806
- dialectAdapter
2998
+ dialectAdapter,
2999
+ vectorStrategy
2807
3000
  ).vectorPredicate;
2808
3001
  const fulltextPredicate = runFulltextPredicatePass(
2809
3002
  query,
@@ -2827,14 +3020,15 @@ function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlan
2827
3020
  };
2828
3021
  return lowerStandardQueryToLogicalPlanNode(loweringInput);
2829
3022
  }
2830
- function lowerSetOperationToLogicalPlanNode(op, graphId, dialect, nextPlanNodeId) {
3023
+ function lowerSetOperationToLogicalPlanNode(op, graphId, dialect, nextPlanNodeId, vectorStrategy) {
2831
3024
  let currentNode = {
2832
3025
  id: nextPlanNodeId(),
2833
3026
  left: lowerComposableQueryToLogicalPlanNode(
2834
3027
  op.left,
2835
3028
  dialect,
2836
3029
  graphId,
2837
- nextPlanNodeId
3030
+ nextPlanNodeId,
3031
+ vectorStrategy
2838
3032
  ),
2839
3033
  op: "set_op",
2840
3034
  operator: op.operator,
@@ -2842,7 +3036,8 @@ function lowerSetOperationToLogicalPlanNode(op, graphId, dialect, nextPlanNodeId
2842
3036
  op.right,
2843
3037
  dialect,
2844
3038
  graphId,
2845
- nextPlanNodeId
3039
+ nextPlanNodeId,
3040
+ vectorStrategy
2846
3041
  )
2847
3042
  };
2848
3043
  if (op.orderBy !== void 0 && op.orderBy.length > 0) {
@@ -2906,7 +3101,8 @@ function lowerSetOperationToLogicalPlan(input) {
2906
3101
  input.op,
2907
3102
  input.graphId,
2908
3103
  input.dialect,
2909
- nextPlanNodeId
3104
+ nextPlanNodeId,
3105
+ input.vectorStrategy
2910
3106
  )
2911
3107
  };
2912
3108
  }
@@ -4480,29 +4676,7 @@ var OPERATOR_MAP = {
4480
4676
  intersect: "INTERSECT",
4481
4677
  except: "EXCEPT"
4482
4678
  };
4483
- function compileSetOperationWithStandardParenthesizedStrategy(op, graphId, dialect, logicalPlan, _schema, compileQuery2) {
4484
- return compileSetOperationStandard(
4485
- op,
4486
- graphId,
4487
- dialect,
4488
- logicalPlan,
4489
- compileQuery2
4490
- );
4491
- }
4492
- function compileSetOperationWithSqliteCompoundStrategy(op, graphId, dialect, logicalPlan, schema, _compileQuery) {
4493
- return compileSetOperationForSqlite(
4494
- op,
4495
- graphId,
4496
- dialect,
4497
- logicalPlan,
4498
- schema
4499
- );
4500
- }
4501
- var SET_OPERATION_STRATEGY_HANDLERS = {
4502
- standard_parenthesized: compileSetOperationWithStandardParenthesizedStrategy,
4503
- sqlite_compound: compileSetOperationWithSqliteCompoundStrategy
4504
- };
4505
- function runSetOperationPassPipeline(op, graphId, dialect) {
4679
+ function runSetOperationPassPipeline(op, graphId, dialect, vectorStrategy) {
4506
4680
  let state = {
4507
4681
  dialect,
4508
4682
  graphId,
@@ -4515,7 +4689,8 @@ function runSetOperationPassPipeline(op, graphId, dialect) {
4515
4689
  return lowerSetOperationToLogicalPlan({
4516
4690
  dialect: currentState.dialect.name,
4517
4691
  graphId: currentState.graphId,
4518
- op: currentState.op
4692
+ op: currentState.op,
4693
+ ...vectorStrategy === void 0 ? {} : { vectorStrategy }
4519
4694
  });
4520
4695
  },
4521
4696
  update(currentState, logicalPlan) {
@@ -4528,25 +4703,20 @@ function runSetOperationPassPipeline(op, graphId, dialect) {
4528
4703
  state = logicalPlanPass.state;
4529
4704
  return state;
4530
4705
  }
4531
- function compileSetOperation(op, graphId, dialect, schema, compileQuery2) {
4532
- const passState = runSetOperationPassPipeline(op, graphId, dialect);
4706
+ function compileSetOperation(op, graphId, dialect, compileQuery2, vectorStrategy) {
4707
+ const passState = runSetOperationPassPipeline(
4708
+ op,
4709
+ graphId,
4710
+ dialect,
4711
+ vectorStrategy
4712
+ );
4533
4713
  const { logicalPlan } = passState;
4534
4714
  if (logicalPlan === void 0) {
4535
4715
  throw new CompilerInvariantError(
4536
4716
  "Logical plan pass did not initialize plan state"
4537
4717
  );
4538
4718
  }
4539
- const strategy = dialect.capabilities.setOperationStrategy;
4540
- const handler = SET_OPERATION_STRATEGY_HANDLERS[strategy];
4541
- return handler(op, graphId, dialect, logicalPlan, schema, compileQuery2);
4542
- }
4543
- function compileSetOperationStandard(op, graphId, dialect, logicalPlan, compileQuery2) {
4544
- const coreSql = compileSetOperationCoreStandard(
4545
- op,
4546
- graphId,
4547
- dialect,
4548
- compileQuery2
4549
- );
4719
+ const coreSql = compileSetOperationCore(op, graphId, compileQuery2, dialect);
4550
4720
  const suffixClauses = buildSetOperationSuffixClauses(op, dialect);
4551
4721
  return emitSetOperationQuerySql({
4552
4722
  baseQuery: coreSql,
@@ -4554,439 +4724,106 @@ function compileSetOperationStandard(op, graphId, dialect, logicalPlan, compileQ
4554
4724
  ...suffixClauses.length === 0 ? {} : { suffixClauses }
4555
4725
  });
4556
4726
  }
4557
- function compileSetOperationCoreStandard(op, graphId, dialect, compileQuery2) {
4558
- const left = compileComposableQueryStandard(
4559
- op.left,
4560
- graphId,
4561
- dialect,
4562
- compileQuery2
4563
- );
4564
- const right = compileComposableQueryStandard(
4727
+ function compileSetOperationCore(op, graphId, compileQuery2, dialect) {
4728
+ const left = compileComposableQuery(op.left, graphId, compileQuery2, dialect);
4729
+ const right = compileComposableQuery(
4565
4730
  op.right,
4566
4731
  graphId,
4567
- dialect,
4568
- compileQuery2
4732
+ compileQuery2,
4733
+ dialect
4569
4734
  );
4570
4735
  const opSql = sql.raw(OPERATOR_MAP[op.operator]);
4571
- return sql`(${left}) ${opSql} (${right})`;
4736
+ return sql`${dialect.wrapSetOperationOperand(left)} ${opSql} ${dialect.wrapSetOperationOperand(right)}`;
4572
4737
  }
4573
- function compileComposableQueryStandard(query, graphId, dialect, compileQuery2) {
4738
+ function compileComposableQuery(query, graphId, compileQuery2, dialect) {
4574
4739
  if ("__type" in query) {
4575
- return compileSetOperationCoreStandard(
4576
- query,
4577
- graphId,
4578
- dialect,
4579
- compileQuery2
4580
- );
4740
+ return compileSetOperationCompound(query, graphId, compileQuery2, dialect);
4581
4741
  }
4582
4742
  return compileQuery2(query, graphId);
4583
4743
  }
4584
- function runSqliteSetOperationValidationPass(op) {
4585
- const leaves = [];
4586
- collectLeafQueries(op, leaves, "q");
4587
- for (const leaf of leaves) {
4588
- validateSqliteSetOpLeaf(leaf.ast);
4589
- }
4590
- return { leaves };
4591
- }
4592
- function compileSetOperationForSqlite(op, graphId, dialect, logicalPlan, schema) {
4593
- const { leaves } = runSqliteSetOperationValidationPass(op);
4594
- const allCtes = [];
4595
- const ctx = {
4596
- dialect,
4597
- schema,
4598
- compileQuery: () => {
4599
- throw new CompilerInvariantError(
4600
- "compileQuery is not available in set-operation CTE compilation"
4601
- );
4602
- }
4603
- };
4604
- for (const leaf of leaves) {
4605
- const cte = compilePrefixedStartCte(leaf.ast, leaf.prefix, graphId, ctx);
4606
- allCtes.push(cte);
4607
- }
4608
- const selectStatements = [];
4609
- for (const leaf of leaves) {
4610
- const select = compilePrefixedSelect(leaf.ast, leaf.prefix, dialect);
4611
- selectStatements.push(select);
4612
- }
4613
- const compoundSelect = buildCompoundSelect(op, leaves, selectStatements);
4744
+ function compileSetOperationCompound(op, graphId, compileQuery2, dialect) {
4745
+ const core2 = compileSetOperationCore(op, graphId, compileQuery2, dialect);
4614
4746
  const suffixClauses = buildSetOperationSuffixClauses(op, dialect);
4615
- return emitSetOperationQuerySql({
4616
- baseQuery: compoundSelect,
4617
- ...allCtes.length === 0 ? {} : { ctes: allCtes },
4618
- logicalPlan,
4619
- ...suffixClauses.length === 0 ? {} : { suffixClauses }
4620
- });
4747
+ if (suffixClauses.length === 0) return core2;
4748
+ return sql.join([core2, ...suffixClauses], sql` `);
4621
4749
  }
4622
- function validateSqliteSetOpLeaf(ast) {
4623
- const unsupported = [];
4624
- if (ast.traversals.length > 0) {
4625
- unsupported.push("traversals");
4626
- }
4627
- if (hasSubqueryPredicates(ast)) {
4628
- unsupported.push("EXISTS/IN subqueries");
4629
- }
4630
- if (hasVectorSimilarityPredicates(ast)) {
4631
- unsupported.push("vector similarity predicates");
4750
+ function getLeftmostProjection(op) {
4751
+ let current = op.left;
4752
+ while ("__type" in current) {
4753
+ current = current.left;
4632
4754
  }
4633
- if (hasFulltextMatchPredicates(ast)) {
4634
- unsupported.push("fulltext match predicates");
4755
+ return current.projection;
4756
+ }
4757
+ function normalizeFieldRefKey(field2) {
4758
+ let pointer = field2.jsonPointer;
4759
+ if (pointer === void 0 && field2.path.length > 1 && field2.path[0] === "props") {
4760
+ pointer = jsonPointer(field2.path.slice(1));
4635
4761
  }
4636
- if (ast.groupBy !== void 0) {
4637
- unsupported.push("GROUP BY");
4762
+ const basePath = field2.path.length > 0 && field2.path[0] === "props" ? "props" : field2.path.join(".");
4763
+ return `${field2.alias}:${basePath}:${pointer ?? ""}`;
4764
+ }
4765
+ function matchFieldToProjection(field2, projection) {
4766
+ const targetKey = normalizeFieldRefKey(field2);
4767
+ for (const projected of projection.fields) {
4768
+ const source = projected.source;
4769
+ if (!("__type" in source) || source.__type !== "field_ref") continue;
4770
+ if (normalizeFieldRefKey(source) === targetKey) {
4771
+ return projected;
4772
+ }
4638
4773
  }
4639
- if (ast.having !== void 0) {
4640
- unsupported.push("HAVING");
4774
+ return void 0;
4775
+ }
4776
+ function buildSetOperationSuffixClauses(op, dialect) {
4777
+ const clauses = [];
4778
+ if (op.orderBy && op.orderBy.length > 0) {
4779
+ const projection = getLeftmostProjection(op);
4780
+ if (projection.fields.length === 0) {
4781
+ throw new UnsupportedPredicateError(
4782
+ "Set operation ORDER BY requires explicit field projection. SELECT * does not provide stable output column names for ordering. Use .select() to specify which fields to project."
4783
+ );
4784
+ }
4785
+ const orderParts = [];
4786
+ for (const orderSpec of op.orderBy) {
4787
+ const projected = matchFieldToProjection(orderSpec.field, projection);
4788
+ if (!projected) {
4789
+ const fieldDesc = orderSpec.field.jsonPointer ? `${orderSpec.field.alias}.props${orderSpec.field.jsonPointer}` : `${orderSpec.field.alias}.${orderSpec.field.path.join(".")}`;
4790
+ const availableFields = projection.fields.map((f) => f.outputName).join(", ");
4791
+ throw new UnsupportedPredicateError(
4792
+ `Set operation ORDER BY field "${fieldDesc}" is not in the projection. ORDER BY for UNION/INTERSECT/EXCEPT must reference projected columns. Available columns: ${availableFields}`
4793
+ );
4794
+ }
4795
+ const columnRef = sql.raw(dialect.quoteIdentifier(projected.outputName));
4796
+ const dir = sql.raw(orderSpec.direction.toUpperCase());
4797
+ const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
4798
+ const nullsDir = sql.raw(nulls === "first" ? "DESC" : "ASC");
4799
+ orderParts.push(
4800
+ sql`(${columnRef} IS NULL) ${nullsDir}`,
4801
+ sql`${columnRef} ${dir}`
4802
+ );
4803
+ }
4804
+ clauses.push(sql`ORDER BY ${sql.join(orderParts, sql`, `)}`);
4641
4805
  }
4642
- if (ast.orderBy !== void 0 && ast.orderBy.length > 0) {
4643
- unsupported.push(
4644
- "per-query ORDER BY (use set operation's orderBy instead)"
4645
- );
4806
+ if (op.limit !== void 0) {
4807
+ clauses.push(sql`LIMIT ${op.limit}`);
4646
4808
  }
4647
- if (ast.limit !== void 0) {
4648
- unsupported.push("per-query LIMIT (use set operation's limit instead)");
4809
+ if (op.offset !== void 0) {
4810
+ clauses.push(sql`OFFSET ${op.offset}`);
4649
4811
  }
4650
- if (ast.offset !== void 0) {
4651
- unsupported.push("per-query OFFSET (use set operation's offset instead)");
4812
+ return clauses;
4813
+ }
4814
+
4815
+ // src/query/compiler/standard-pass-pipeline.ts
4816
+ var TRAVERSAL_LIMIT_PUSHDOWN_MULTIPLIER = 8;
4817
+ var TRAVERSAL_LIMIT_PUSHDOWN_MAX = 1e4;
4818
+ function isColumnPruningEnabled(ast) {
4819
+ if (ast.selectiveFields && ast.selectiveFields.length > 0) {
4820
+ return true;
4652
4821
  }
4653
- if (unsupported.length > 0) {
4654
- throw new UnsupportedPredicateError(
4655
- `SQLite set operations (UNION/INTERSECT/EXCEPT) do not support: ${unsupported.join(", ")}. Use PostgreSQL for complex set operations, or refactor to separate queries.`
4656
- );
4822
+ if (ast.groupBy || ast.having) {
4823
+ return true;
4657
4824
  }
4658
- }
4659
- function hasVectorSimilarityPredicates(ast) {
4660
- return ast.predicates.some(
4661
- (predicate2) => hasVectorSimilarityInExpression(predicate2.expression)
4662
- );
4663
- }
4664
- function hasVectorSimilarityInExpression(expr) {
4665
- if ("__type" in expr) {
4666
- switch (expr.__type) {
4667
- case "and":
4668
- case "or": {
4669
- return expr.predicates.some((p) => hasVectorSimilarityInExpression(p));
4670
- }
4671
- case "not": {
4672
- return hasVectorSimilarityInExpression(expr.predicate);
4673
- }
4674
- case "vector_similarity": {
4675
- return true;
4676
- }
4677
- case "exists":
4678
- case "in_subquery":
4679
- case "comparison":
4680
- case "string_op":
4681
- case "null_check":
4682
- case "between":
4683
- case "array_op":
4684
- case "object_op":
4685
- case "aggregate_comparison":
4686
- case "fulltext_match": {
4687
- return false;
4688
- }
4689
- }
4690
- }
4691
- return false;
4692
- }
4693
- function hasFulltextMatchPredicates(ast) {
4694
- return ast.predicates.some(
4695
- (predicate2) => hasFulltextMatchInExpression(predicate2.expression)
4696
- );
4697
- }
4698
- function hasFulltextMatchInExpression(expr) {
4699
- if ("__type" in expr) {
4700
- switch (expr.__type) {
4701
- case "and":
4702
- case "or": {
4703
- return expr.predicates.some((p) => hasFulltextMatchInExpression(p));
4704
- }
4705
- case "not": {
4706
- return hasFulltextMatchInExpression(expr.predicate);
4707
- }
4708
- case "fulltext_match": {
4709
- return true;
4710
- }
4711
- case "exists":
4712
- case "in_subquery":
4713
- case "comparison":
4714
- case "string_op":
4715
- case "null_check":
4716
- case "between":
4717
- case "array_op":
4718
- case "object_op":
4719
- case "aggregate_comparison":
4720
- case "vector_similarity": {
4721
- return false;
4722
- }
4723
- }
4724
- }
4725
- return false;
4726
- }
4727
- function hasSubqueryPredicates(ast) {
4728
- return ast.predicates.some(
4729
- (predicate2) => hasSubqueryInExpression(predicate2.expression)
4730
- );
4731
- }
4732
- function hasSubqueryInExpression(expr) {
4733
- if ("__type" in expr) {
4734
- switch (expr.__type) {
4735
- case "and":
4736
- case "or": {
4737
- return expr.predicates.some((p) => hasSubqueryInExpression(p));
4738
- }
4739
- case "not": {
4740
- return hasSubqueryInExpression(expr.predicate);
4741
- }
4742
- case "exists": {
4743
- return true;
4744
- }
4745
- case "in_subquery": {
4746
- return true;
4747
- }
4748
- // These expression types don't contain subqueries
4749
- case "comparison":
4750
- case "string_op":
4751
- case "null_check":
4752
- case "between":
4753
- case "array_op":
4754
- case "object_op":
4755
- case "aggregate_comparison":
4756
- case "vector_similarity":
4757
- case "fulltext_match": {
4758
- return false;
4759
- }
4760
- }
4761
- }
4762
- return false;
4763
- }
4764
- function collectLeafQueries(query, leaves, basePrefix) {
4765
- if ("__type" in query) {
4766
- collectLeafQueries(query.left, leaves, basePrefix);
4767
- collectLeafQueries(query.right, leaves, basePrefix);
4768
- } else {
4769
- const index = leaves.length;
4770
- leaves.push({ ast: query, prefix: `${basePrefix}${index}` });
4771
- }
4772
- }
4773
- function compilePrefixedStartCte(ast, prefix, graphId, ctx) {
4774
- const temporalFilterPass = createTemporalFilterPass(
4775
- ast,
4776
- ctx.dialect.currentTimestamp()
4777
- );
4778
- const alias = ast.start.alias;
4779
- const kinds = ast.start.kinds;
4780
- const kindFilter = kinds.length === 1 ? sql`kind = ${kinds[0]}` : sql`kind IN (${sql.join(
4781
- kinds.map((k) => sql`${k}`),
4782
- sql`, `
4783
- )})`;
4784
- const temporalFilter = temporalFilterPass.forAlias();
4785
- const cteContext = { ...ctx, cteColumnPrefix: "" };
4786
- const predicateClauses = ast.predicates.filter((p) => p.targetAlias === alias).map((p) => compilePredicateExpression(p.expression, cteContext));
4787
- const whereClauses = [
4788
- sql`graph_id = ${graphId}`,
4789
- kindFilter,
4790
- temporalFilter,
4791
- ...predicateClauses
4792
- ];
4793
- const cteName = `cte_${prefix}_${alias}`;
4794
- return sql`
4795
- ${sql.raw(cteName)} AS (
4796
- SELECT
4797
- id AS ${sql.raw(alias)}_id,
4798
- kind AS ${sql.raw(alias)}_kind,
4799
- props AS ${sql.raw(alias)}_props,
4800
- version AS ${sql.raw(alias)}_version,
4801
- valid_from AS ${sql.raw(alias)}_valid_from,
4802
- valid_to AS ${sql.raw(alias)}_valid_to,
4803
- created_at AS ${sql.raw(alias)}_created_at,
4804
- updated_at AS ${sql.raw(alias)}_updated_at,
4805
- deleted_at AS ${sql.raw(alias)}_deleted_at
4806
- FROM ${ctx.schema.nodesTable}
4807
- WHERE ${sql.join(whereClauses, sql` AND `)}
4808
- )
4809
- `;
4810
- }
4811
- function compilePrefixedSelect(ast, prefix, dialect) {
4812
- const alias = ast.start.alias;
4813
- const cteName = `cte_${prefix}_${alias}`;
4814
- const fields = ast.projection.fields;
4815
- const projection = fields.length === 0 ? sql.raw("*") : sql.join(
4816
- fields.map((f) => {
4817
- const source = compileFieldValueForSetOp(
4818
- f.source,
4819
- prefix,
4820
- alias,
4821
- dialect
4822
- );
4823
- return sql`${source} AS ${sql.raw(dialect.quoteIdentifier(f.outputName))}`;
4824
- }),
4825
- sql`, `
4826
- );
4827
- return sql`SELECT ${projection} FROM ${sql.raw(cteName)}`;
4828
- }
4829
- function compileFieldValueForSetOp(source, prefix, alias, dialect) {
4830
- if ("__type" in source && source.__type === "aggregate") {
4831
- const { field: field2, function: fn } = source;
4832
- switch (fn) {
4833
- case "count":
4834
- case "countDistinct":
4835
- case "sum":
4836
- case "avg":
4837
- case "min":
4838
- case "max": {
4839
- const column = compileFieldColumnForSetOp(field2, prefix, dialect);
4840
- if (fn === "countDistinct") {
4841
- return sql`COUNT(DISTINCT ${column})`;
4842
- }
4843
- return sql`${sql.raw(fn.toUpperCase())}(${column})`;
4844
- }
4845
- default: {
4846
- throw new CompilerInvariantError(
4847
- `Unknown aggregate function: ${String(fn)}`
4848
- );
4849
- }
4850
- }
4851
- }
4852
- return compileFieldColumnForSetOp(source, prefix, dialect);
4853
- }
4854
- function compileFieldColumnForSetOp(field2, prefix, dialect) {
4855
- const cteName = `cte_${prefix}_${field2.alias}`;
4856
- const alias = field2.alias;
4857
- if (field2.path.length === 1) {
4858
- const columnName = field2.path[0];
4859
- const columnMap = {
4860
- id: "_id",
4861
- kind: "_kind",
4862
- props: "_props",
4863
- version: "_version",
4864
- valid_from: "_valid_from",
4865
- valid_to: "_valid_to",
4866
- created_at: "_created_at",
4867
- updated_at: "_updated_at",
4868
- deleted_at: "_deleted_at"
4869
- };
4870
- if (columnName === void 0) return sql.raw(`${cteName}.${alias}_props`);
4871
- const suffix = columnMap[columnName];
4872
- if (suffix) {
4873
- return sql.raw(`${cteName}.${alias}${suffix}`);
4874
- }
4875
- }
4876
- const column = sql.raw(`${cteName}.${alias}_props`);
4877
- const pointer = field2.jsonPointer;
4878
- if (!pointer) {
4879
- return column;
4880
- }
4881
- return compileTypedJsonExtract({
4882
- column,
4883
- dialect,
4884
- fallback: "text",
4885
- pointer,
4886
- valueType: field2.valueType
4887
- });
4888
- }
4889
- function buildCompoundSelect(op, leaves, selectStatements) {
4890
- const prefixToSelect = /* @__PURE__ */ new Map();
4891
- for (const [index, leaf] of leaves.entries()) {
4892
- prefixToSelect.set(leaf.prefix, selectStatements[index]);
4893
- }
4894
- return buildCompoundSelectRecursive(op, leaves, prefixToSelect);
4895
- }
4896
- function buildCompoundSelectRecursive(query, leaves, prefixToSelect) {
4897
- if (!("__type" in query)) {
4898
- const leaf = leaves.find((l) => l.ast === query);
4899
- if (!leaf) {
4900
- throw new CompilerInvariantError("Leaf query not found in leaves array");
4901
- }
4902
- return prefixToSelect.get(leaf.prefix);
4903
- }
4904
- const left = buildCompoundSelectRecursive(query.left, leaves, prefixToSelect);
4905
- const right = buildCompoundSelectRecursive(
4906
- query.right,
4907
- leaves,
4908
- prefixToSelect
4909
- );
4910
- const opSql = sql.raw(OPERATOR_MAP[query.operator]);
4911
- return sql`${left} ${opSql} ${right}`;
4912
- }
4913
- function getLeftmostProjection(op) {
4914
- let current = op.left;
4915
- while ("__type" in current) {
4916
- current = current.left;
4917
- }
4918
- return current.projection;
4919
- }
4920
- function normalizeFieldRefKey(field2) {
4921
- let pointer = field2.jsonPointer;
4922
- if (pointer === void 0 && field2.path.length > 1 && field2.path[0] === "props") {
4923
- pointer = jsonPointer(field2.path.slice(1));
4924
- }
4925
- const basePath = field2.path.length > 0 && field2.path[0] === "props" ? "props" : field2.path.join(".");
4926
- return `${field2.alias}:${basePath}:${pointer ?? ""}`;
4927
- }
4928
- function matchFieldToProjection(field2, projection) {
4929
- const targetKey = normalizeFieldRefKey(field2);
4930
- for (const projected of projection.fields) {
4931
- const source = projected.source;
4932
- if (!("__type" in source) || source.__type !== "field_ref") continue;
4933
- if (normalizeFieldRefKey(source) === targetKey) {
4934
- return projected;
4935
- }
4936
- }
4937
- return void 0;
4938
- }
4939
- function buildSetOperationSuffixClauses(op, dialect) {
4940
- const clauses = [];
4941
- if (op.orderBy && op.orderBy.length > 0) {
4942
- const projection = getLeftmostProjection(op);
4943
- if (projection.fields.length === 0) {
4944
- throw new UnsupportedPredicateError(
4945
- "Set operation ORDER BY requires explicit field projection. SELECT * does not provide stable output column names for ordering. Use .select() to specify which fields to project."
4946
- );
4947
- }
4948
- const orderParts = [];
4949
- for (const orderSpec of op.orderBy) {
4950
- const projected = matchFieldToProjection(orderSpec.field, projection);
4951
- if (!projected) {
4952
- const fieldDesc = orderSpec.field.jsonPointer ? `${orderSpec.field.alias}.props${orderSpec.field.jsonPointer}` : `${orderSpec.field.alias}.${orderSpec.field.path.join(".")}`;
4953
- const availableFields = projection.fields.map((f) => f.outputName).join(", ");
4954
- throw new UnsupportedPredicateError(
4955
- `Set operation ORDER BY field "${fieldDesc}" is not in the projection. ORDER BY for UNION/INTERSECT/EXCEPT must reference projected columns. Available columns: ${availableFields}`
4956
- );
4957
- }
4958
- const columnRef = sql.raw(dialect.quoteIdentifier(projected.outputName));
4959
- const dir = sql.raw(orderSpec.direction.toUpperCase());
4960
- const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
4961
- const nullsDir = sql.raw(nulls === "first" ? "DESC" : "ASC");
4962
- orderParts.push(
4963
- sql`(${columnRef} IS NULL) ${nullsDir}`,
4964
- sql`${columnRef} ${dir}`
4965
- );
4966
- }
4967
- clauses.push(sql`ORDER BY ${sql.join(orderParts, sql`, `)}`);
4968
- }
4969
- if (op.limit !== void 0) {
4970
- clauses.push(sql`LIMIT ${op.limit}`);
4971
- }
4972
- if (op.offset !== void 0) {
4973
- clauses.push(sql`OFFSET ${op.offset}`);
4974
- }
4975
- return clauses;
4976
- }
4977
-
4978
- // src/query/compiler/standard-pass-pipeline.ts
4979
- var TRAVERSAL_LIMIT_PUSHDOWN_MULTIPLIER = 8;
4980
- var TRAVERSAL_LIMIT_PUSHDOWN_MAX = 1e4;
4981
- function isColumnPruningEnabled(ast) {
4982
- if (ast.selectiveFields && ast.selectiveFields.length > 0) {
4983
- return true;
4984
- }
4985
- if (ast.groupBy || ast.having) {
4986
- return true;
4987
- }
4988
- return ast.projection.fields.some(
4989
- (field2) => field2.source.__type === "aggregate"
4825
+ return ast.projection.fields.some(
4826
+ (field2) => field2.source.__type === "aggregate"
4990
4827
  );
4991
4828
  }
4992
4829
  function markPredicateFieldsAsRequired(requiredColumnsByAlias, expression) {
@@ -5201,7 +5038,11 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
5201
5038
  const vectorPass = runCompilerPass(state, {
5202
5039
  name: "vector_predicate",
5203
5040
  execute(currentState) {
5204
- return runVectorPredicatePass(currentState.ast, currentState.ctx.dialect).vectorPredicate;
5041
+ return runVectorPredicatePass(
5042
+ currentState.ast,
5043
+ currentState.ctx.dialect,
5044
+ currentState.ctx.vectorStrategy
5045
+ ).vectorPredicate;
5205
5046
  },
5206
5047
  update(currentState, vectorPredicate) {
5207
5048
  return {
@@ -5358,7 +5199,10 @@ function compileQuery(ast, graphId, options = "sqlite") {
5358
5199
  const ctx = {
5359
5200
  dialect: adapter,
5360
5201
  schema,
5361
- compileQuery: (subAst, subGraphId) => compileQuery(subAst, subGraphId, propagateOptions(options_))
5202
+ compileQuery: (subAst, subGraphId) => compileQuery(subAst, subGraphId, propagateOptions(options_)),
5203
+ ...options_.vectorStrategy === void 0 ? {} : { vectorStrategy: options_.vectorStrategy },
5204
+ windowFunctions: options_.windowFunctions ?? true,
5205
+ ...options_.vectorSlots === void 0 ? {} : { vectorSlots: options_.vectorSlots }
5362
5206
  };
5363
5207
  if (hasVariableLengthTraversal(ast)) {
5364
5208
  const lowered = tryLowerSingleHopRecursiveTraversal(ast);
@@ -5393,14 +5237,13 @@ function tryLowerSingleHopRecursiveTraversal(ast) {
5393
5237
  function compileSetOperation2(op, graphId, options = "sqlite") {
5394
5238
  const options_ = typeof options === "string" ? { dialect: options } : options;
5395
5239
  const dialect = options_.dialect ?? "sqlite";
5396
- const schema = options_.schema ?? DEFAULT_SQL_SCHEMA;
5397
5240
  const adapter = resolveDialectAdapter(dialect, options_.fulltextStrategy);
5398
5241
  return compileSetOperation(
5399
5242
  op,
5400
5243
  graphId,
5401
5244
  adapter,
5402
- schema,
5403
- (ast, gid) => compileQuery(ast, gid, propagateOptions(options_))
5245
+ (ast, gid) => compileQuery(ast, gid, propagateOptions(options_)),
5246
+ options_.vectorStrategy
5404
5247
  );
5405
5248
  }
5406
5249
  function resolveDialectAdapter(dialect, fulltextStrategy) {
@@ -5414,7 +5257,10 @@ function propagateOptions(options_) {
5414
5257
  return {
5415
5258
  dialect: options_.dialect ?? "sqlite",
5416
5259
  ...options_.schema === void 0 ? {} : { schema: options_.schema },
5417
- ...options_.fulltextStrategy === void 0 ? {} : { fulltextStrategy: options_.fulltextStrategy }
5260
+ ...options_.fulltextStrategy === void 0 ? {} : { fulltextStrategy: options_.fulltextStrategy },
5261
+ ...options_.vectorStrategy === void 0 ? {} : { vectorStrategy: options_.vectorStrategy },
5262
+ windowFunctions: options_.windowFunctions ?? true,
5263
+ ...options_.vectorSlots === void 0 ? {} : { vectorSlots: options_.vectorSlots }
5418
5264
  };
5419
5265
  }
5420
5266
  function resolveCountAggregateFastPath(ast) {
@@ -5694,6 +5540,27 @@ function selectStandardOrderBy(input) {
5694
5540
  dialect
5695
5541
  });
5696
5542
  }
5543
+ function selectWindowFunctionOperation(vectorPredicate, fulltextPredicate) {
5544
+ if (vectorPredicate !== void 0 && fulltextPredicate !== void 0) {
5545
+ return "hybrid relevance ranking";
5546
+ }
5547
+ if (vectorPredicate !== void 0) return "vector relevance ranking";
5548
+ return "fulltext relevance ranking";
5549
+ }
5550
+ function assertWindowFunctionsSupported(ctx, operation) {
5551
+ if (ctx.windowFunctions) return;
5552
+ throw new ConfigurationError(
5553
+ `${operation} requires SQL window functions, but this backend profile declares windowFunctions: false.`,
5554
+ {
5555
+ capability: "windowFunctions",
5556
+ operation,
5557
+ windowFunctions: false
5558
+ },
5559
+ {
5560
+ suggestion: "Use a backend profile that supports SQL window functions, or avoid this query shape."
5561
+ }
5562
+ );
5563
+ }
5697
5564
  function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
5698
5565
  const { dialect } = ctx;
5699
5566
  const {
@@ -5721,6 +5588,12 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
5721
5588
  { phase: "standard-pass-pipeline" }
5722
5589
  );
5723
5590
  }
5591
+ if (vectorPredicate !== void 0 || fulltextPredicate !== void 0) {
5592
+ assertWindowFunctionsSupported(
5593
+ ctx,
5594
+ selectWindowFunctionOperation(vectorPredicate, fulltextPredicate)
5595
+ );
5596
+ }
5724
5597
  if (!vectorPredicate && !fulltextPredicate) {
5725
5598
  const fastPathSql = compileCountAggregateFastPath(
5726
5599
  ast,
@@ -5932,12 +5805,7 @@ function extractCursorValue(row, spec) {
5932
5805
  current = record[segment];
5933
5806
  }
5934
5807
  if (jsonPointer2) {
5935
- const segments = parseJsonPointer(jsonPointer2);
5936
- for (const segment of segments) {
5937
- if (current === null || current === void 0) return void 0;
5938
- if (typeof current !== "object") return void 0;
5939
- current = current[segment];
5940
- }
5808
+ return resolveJsonPointer(current, jsonPointer2);
5941
5809
  }
5942
5810
  return current;
5943
5811
  }
@@ -7005,12 +6873,32 @@ function buildQueryAst(config, state) {
7005
6873
  // src/query/builder/compile-options.ts
7006
6874
  function buildCompileOptions(config) {
7007
6875
  const fulltextStrategy = config.backend?.fulltextStrategy;
6876
+ const vectorStrategy = config.backend?.vectorStrategy;
7008
6877
  return {
7009
6878
  dialect: config.dialect ?? "sqlite",
7010
6879
  schema: config.schema,
7011
- ...fulltextStrategy === void 0 ? {} : { fulltextStrategy }
6880
+ windowFunctions: config.backend?.capabilities.windowFunctions ?? true,
6881
+ ...fulltextStrategy === void 0 ? {} : { fulltextStrategy },
6882
+ ...vectorStrategy === void 0 ? {} : { vectorStrategy, vectorSlots: buildVectorSlots(config.registry) }
7012
6883
  };
7013
6884
  }
6885
+ var vectorSlotsCache = /* @__PURE__ */ new WeakMap();
6886
+ function buildVectorSlots(registry) {
6887
+ const cached = vectorSlotsCache.get(registry);
6888
+ if (cached !== void 0) return cached;
6889
+ const slots = /* @__PURE__ */ new Map();
6890
+ for (const [nodeKind, nodeType] of registry.nodeKinds) {
6891
+ for (const field2 of resolveEmbeddingFields(nodeType.schema)) {
6892
+ slots.set(vectorSlotKey(nodeKind, field2.fieldPath), {
6893
+ dimensions: field2.dimensions,
6894
+ metric: field2.metric,
6895
+ indexType: field2.indexType
6896
+ });
6897
+ }
6898
+ }
6899
+ vectorSlotsCache.set(registry, slots);
6900
+ return slots;
6901
+ }
7014
6902
  function toLiteral(value) {
7015
6903
  if (value === null) {
7016
6904
  throw new ConfigurationError(
@@ -10630,6 +10518,27 @@ function createEdgeCollection(config) {
10630
10518
  };
10631
10519
  }
10632
10520
 
10521
+ // src/store/node-fetch.ts
10522
+ async function getNodeRowsByIds(backend, graphId, kind, ids) {
10523
+ const rowsById = /* @__PURE__ */ new Map();
10524
+ if (ids.length === 0) return rowsById;
10525
+ if (backend.getNodes !== void 0) {
10526
+ const rows2 = await backend.getNodes(graphId, kind, ids);
10527
+ for (const row of rows2) {
10528
+ rowsById.set(row.id, row);
10529
+ }
10530
+ return rowsById;
10531
+ }
10532
+ const uniqueIds = [...new Set(ids)];
10533
+ const rows = await Promise.all(
10534
+ uniqueIds.map((id) => backend.getNode(graphId, kind, id))
10535
+ );
10536
+ for (const row of rows) {
10537
+ if (row !== void 0) rowsById.set(row.id, row);
10538
+ }
10539
+ return rowsById;
10540
+ }
10541
+
10633
10542
  // src/store/collections/node-collection.ts
10634
10543
  function narrowNode(node) {
10635
10544
  return node;
@@ -10671,7 +10580,8 @@ function createNodeCollection(config) {
10671
10580
  executeGetOrCreateByConstraint,
10672
10581
  executeBulkGetOrCreateByConstraint,
10673
10582
  executeFindByConstraint,
10674
- executeBulkFindByConstraint
10583
+ executeBulkFindByConstraint,
10584
+ executeBulkFindByIndex
10675
10585
  } = config;
10676
10586
  return {
10677
10587
  async create(props, options) {
@@ -10692,27 +10602,13 @@ function createNodeCollection(config) {
10692
10602
  },
10693
10603
  async getByIds(ids, options) {
10694
10604
  if (ids.length === 0) return [];
10695
- if (backend.getNodes !== void 0) {
10696
- const rows = await backend.getNodes(graphId, kind, ids);
10697
- const rowMap = /* @__PURE__ */ new Map();
10698
- for (const row of rows) {
10699
- rowMap.set(row.id, row);
10700
- }
10701
- return ids.map((id) => {
10702
- const row = rowMap.get(id);
10703
- if (!row) return;
10704
- if (!matchesTemporalMode(row, options)) return;
10705
- return narrowNode(rowToNode2(row));
10706
- });
10707
- }
10708
- return Promise.all(
10709
- ids.map(async (id) => {
10710
- const row = await backend.getNode(graphId, kind, id);
10711
- if (!row) return;
10712
- if (!matchesTemporalMode(row, options)) return;
10713
- return narrowNode(rowToNode2(row));
10714
- })
10715
- );
10605
+ const rowsById = await getNodeRowsByIds(backend, graphId, kind, ids);
10606
+ return ids.map((id) => {
10607
+ const row = rowsById.get(id);
10608
+ if (!row) return;
10609
+ if (!matchesTemporalMode(row, options)) return;
10610
+ return narrowNode(rowToNode2(row));
10611
+ });
10716
10612
  },
10717
10613
  async update(id, props, options) {
10718
10614
  const result = await executeNodeUpdate2(
@@ -10909,6 +10805,20 @@ function createNodeCollection(config) {
10909
10805
  (result) => result === void 0 ? void 0 : narrowNode(result)
10910
10806
  );
10911
10807
  },
10808
+ async bulkFindByIndex(indexName, items, options) {
10809
+ if (items.length === 0) return [];
10810
+ const mappedItems = items.map((item) => ({
10811
+ props: item.props
10812
+ }));
10813
+ const results = await executeBulkFindByIndex(
10814
+ kind,
10815
+ indexName,
10816
+ mappedItems,
10817
+ backend,
10818
+ options
10819
+ );
10820
+ return results.map((bucket) => narrowNodes(bucket));
10821
+ },
10912
10822
  async getOrCreateByConstraint(constraintName, props, options) {
10913
10823
  const execute = async (target) => {
10914
10824
  const result = await executeGetOrCreateByConstraint(
@@ -11212,7 +11122,7 @@ async function materializeVectorIndex(declaration, backend, graphId, schemaVersi
11212
11122
  );
11213
11123
  }
11214
11124
  const vectorCapability = backend.capabilities.vector;
11215
- if (vectorCapability?.supported !== true || backend.createVectorIndex === void 0) {
11125
+ if (vectorCapability?.supported !== true || backend.createVectorIndex === void 0 || backend.vectorStrategy === void 0) {
11216
11126
  return skippedEntry(
11217
11127
  declaration,
11218
11128
  `Backend (${backend.dialect}) does not support vector indexes in its current configuration`
@@ -11224,7 +11134,11 @@ async function materializeVectorIndex(declaration, backend, graphId, schemaVersi
11224
11134
  `Backend (${backend.dialect}) does not support index type "${declaration.indexType}" for vector indexes; supported: ${vectorCapability.indexTypes.join(", ") || "(none)"}`
11225
11135
  );
11226
11136
  }
11227
- const embeddingsTable = backend.tableNames?.embeddings ?? "typegraph_node_embeddings";
11137
+ const embeddingsTable = backend.vectorStrategy.tableName(
11138
+ graphId,
11139
+ declaration.kind,
11140
+ declaration.fieldPath
11141
+ );
11228
11142
  const signature = await computeIndexSignature(
11229
11143
  backend.dialect,
11230
11144
  embeddingsTable,
@@ -11387,16 +11301,16 @@ async function materializeRemovals(context, options = {}) {
11387
11301
  }
11388
11302
  await ensureFocusedStatusTable(backend, backend.ensureKindRemovalsTable);
11389
11303
  await reconcilePendingRemovals(context);
11304
+ const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(context);
11390
11305
  const pending = await backend.getPendingKindRemovals(graphId);
11391
11306
  const kindFilter = options.kinds === void 0 ? void 0 : new Set(options.kinds);
11392
11307
  const candidates = pending.filter(
11393
11308
  (row) => kindFilter === void 0 ? true : kindFilter.has(row.kindName)
11394
11309
  );
11395
- if (candidates.length === 0) return { results: [] };
11310
+ if (candidates.length === 0) return { results: [], reclaimedVectorFields };
11396
11311
  const tableNames = backend.tableNames;
11397
11312
  const nodesTable = tableNames?.nodes ?? "typegraph_nodes";
11398
11313
  const edgesTable = tableNames?.edges ?? "typegraph_edges";
11399
- const embeddingsTable = tableNames?.embeddings ?? "typegraph_node_embeddings";
11400
11314
  const fulltextTable = tableNames?.fulltext ?? "typegraph_node_fulltext";
11401
11315
  const uniquesTable = tableNames?.uniques ?? "typegraph_node_uniques";
11402
11316
  const ctx = {
@@ -11404,7 +11318,6 @@ async function materializeRemovals(context, options = {}) {
11404
11318
  graphId,
11405
11319
  nodesTable,
11406
11320
  edgesTable,
11407
- embeddingsTable,
11408
11321
  fulltextTable,
11409
11322
  uniquesTable
11410
11323
  };
@@ -11413,7 +11326,8 @@ async function materializeRemovals(context, options = {}) {
11413
11326
  candidates,
11414
11327
  options,
11415
11328
  (removal) => materializeOne2(removal, ctx)
11416
- )
11329
+ ),
11330
+ reclaimedVectorFields
11417
11331
  };
11418
11332
  }
11419
11333
  async function reconcilePendingRemovals(context) {
@@ -11500,15 +11414,13 @@ async function materializeOne2(row, ctx) {
11500
11414
  executeDdl(
11501
11415
  `DELETE FROM ${quote(ctx.edgesTable)} WHERE graph_id = ${graphLit} AND (from_kind = ${kindLit} OR to_kind = ${kindLit})`
11502
11416
  ),
11503
- executeDdl(
11504
- `DELETE FROM ${quote(ctx.embeddingsTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
11505
- ),
11506
11417
  executeDdl(
11507
11418
  `DELETE FROM ${quote(ctx.fulltextTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
11508
11419
  ),
11509
11420
  executeDdl(
11510
11421
  `DELETE FROM ${quote(ctx.uniquesTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
11511
- )
11422
+ ),
11423
+ ...buildEmbeddingTableCleanup(ctx, row)
11512
11424
  );
11513
11425
  } else {
11514
11426
  deletes.push(
@@ -11552,6 +11464,128 @@ async function materializeOne2(row, ctx) {
11552
11464
  };
11553
11465
  }
11554
11466
  }
11467
+ function buildEmbeddingTableCleanup(ctx, row) {
11468
+ const vectorStrategy = ctx.backend.vectorStrategy;
11469
+ if (vectorStrategy === void 0) return [];
11470
+ const executeDdl = ctx.backend.executeDdl;
11471
+ const cleanup = (async () => {
11472
+ const slots = await resolveRemovedKindEmbeddingSlots(ctx.backend, row);
11473
+ await Promise.all(
11474
+ slots.map(
11475
+ (slot) => dropVectorSlotStorage(vectorStrategy, executeDdl, slot)
11476
+ )
11477
+ );
11478
+ })();
11479
+ return [cleanup];
11480
+ }
11481
+ async function dropVectorSlotStorage(strategy, executeDdl, slot) {
11482
+ try {
11483
+ for (const ddl of strategy.buildDropStorage(slot)) {
11484
+ await executeDdl(ddl);
11485
+ }
11486
+ } catch (error) {
11487
+ if (!isMissingTableError(error)) throw error;
11488
+ }
11489
+ }
11490
+ async function resolveRemovedKindEmbeddingSlots(backend, row) {
11491
+ const priorVersion = row.schemaVersion - 1;
11492
+ if (priorVersion < 1) return [];
11493
+ const priorRow = await backend.getSchemaVersion(row.graphId, priorVersion);
11494
+ if (priorRow === void 0) return [];
11495
+ const priorSchema = parseSerializedSchema(priorRow.schema_doc);
11496
+ const slots = /* @__PURE__ */ new Map();
11497
+ for (const declaration of priorSchema.indexes ?? []) {
11498
+ if (declaration.entity === "vector" && declaration.kind === row.kindName) {
11499
+ slots.set(declaration.fieldPath, {
11500
+ graphId: row.graphId,
11501
+ nodeKind: row.kindName,
11502
+ fieldPath: declaration.fieldPath,
11503
+ dimensions: declaration.dimensions,
11504
+ metric: declaration.metric,
11505
+ indexType: declaration.indexType
11506
+ });
11507
+ }
11508
+ }
11509
+ return [...slots.values()];
11510
+ }
11511
+ function vectorFieldKey(kind, fieldPath) {
11512
+ return `${kind}\0${fieldPath}`;
11513
+ }
11514
+ async function reclaimRemovedVectorFieldTables(context) {
11515
+ const { backend, graphId } = context;
11516
+ const vectorStrategy = backend.vectorStrategy;
11517
+ const executeDdl = backend.executeDdl;
11518
+ if (vectorStrategy === void 0 || executeDdl === void 0) return [];
11519
+ const activeRow = await backend.getActiveSchema(graphId);
11520
+ if (activeRow === void 0) return [];
11521
+ const cacheKey = `${graphId}\0${activeRow.version}`;
11522
+ let perBackend = reclaimCache.get(backend);
11523
+ const cached = perBackend?.get(cacheKey);
11524
+ if (cached !== void 0) return cached;
11525
+ const activeSchema = parseSerializedSchema(activeRow.schema_doc);
11526
+ const activeVectorFields = /* @__PURE__ */ new Set();
11527
+ for (const declaration of activeSchema.indexes ?? []) {
11528
+ if (declaration.entity === "vector") {
11529
+ activeVectorFields.add(
11530
+ vectorFieldKey(declaration.kind, declaration.fieldPath)
11531
+ );
11532
+ }
11533
+ }
11534
+ const survivingKinds = new Set(Object.keys(activeSchema.nodes));
11535
+ const historical = /* @__PURE__ */ new Map();
11536
+ for (let version = activeRow.version - 1; version >= 1; version -= 1) {
11537
+ const priorRow = await backend.getSchemaVersion(graphId, version);
11538
+ if (priorRow === void 0) continue;
11539
+ const priorSchema = parseSerializedSchema(priorRow.schema_doc);
11540
+ for (const declaration of priorSchema.indexes ?? []) {
11541
+ if (declaration.entity !== "vector") continue;
11542
+ const key = vectorFieldKey(declaration.kind, declaration.fieldPath);
11543
+ if (historical.has(key)) continue;
11544
+ historical.set(key, {
11545
+ kind: declaration.kind,
11546
+ fieldPath: declaration.fieldPath,
11547
+ slot: {
11548
+ graphId,
11549
+ nodeKind: declaration.kind,
11550
+ fieldPath: declaration.fieldPath,
11551
+ dimensions: declaration.dimensions,
11552
+ metric: declaration.metric,
11553
+ indexType: declaration.indexType
11554
+ }
11555
+ });
11556
+ }
11557
+ }
11558
+ const orphans = [...historical.values()].filter(
11559
+ (field2) => !activeVectorFields.has(vectorFieldKey(field2.kind, field2.fieldPath)) && survivingKinds.has(field2.kind)
11560
+ );
11561
+ const results = [];
11562
+ for (const field2 of orphans) {
11563
+ try {
11564
+ await dropVectorSlotStorage(vectorStrategy, executeDdl, field2.slot);
11565
+ results.push({
11566
+ kind: field2.kind,
11567
+ fieldPath: field2.fieldPath,
11568
+ status: "reclaimed"
11569
+ });
11570
+ } catch (error) {
11571
+ results.push({
11572
+ kind: field2.kind,
11573
+ fieldPath: field2.fieldPath,
11574
+ status: "failed",
11575
+ error: error instanceof Error ? error : new Error(String(error))
11576
+ });
11577
+ }
11578
+ }
11579
+ if (results.every((entry2) => entry2.status === "reclaimed")) {
11580
+ if (perBackend === void 0) {
11581
+ perBackend = /* @__PURE__ */ new Map();
11582
+ reclaimCache.set(backend, perBackend);
11583
+ }
11584
+ perBackend.set(cacheKey, results);
11585
+ }
11586
+ return results;
11587
+ }
11588
+ var reclaimCache = /* @__PURE__ */ new WeakMap();
11555
11589
  function quote(identifier) {
11556
11590
  return `"${identifier.replaceAll('"', '""')}"`;
11557
11591
  }
@@ -12536,46 +12570,10 @@ var embeddingFieldsCache = /* @__PURE__ */ new WeakMap();
12536
12570
  function getEmbeddingFields(schema) {
12537
12571
  const cached = embeddingFieldsCache.get(schema);
12538
12572
  if (cached) return cached;
12539
- const fields = computeEmbeddingFields(schema);
12573
+ const fields = resolveEmbeddingFields(schema);
12540
12574
  embeddingFieldsCache.set(schema, fields);
12541
12575
  return fields;
12542
12576
  }
12543
- function computeEmbeddingFields(schema) {
12544
- if (schema.type !== "object") return [];
12545
- const def = schema.def;
12546
- const shape = def.shape;
12547
- if (!shape) return [];
12548
- const fields = [];
12549
- for (const [fieldPath, fieldSchema] of Object.entries(shape)) {
12550
- const dimensions = getEmbeddingDimensionsFromField(fieldSchema);
12551
- if (dimensions !== void 0) {
12552
- fields.push({ fieldPath, dimensions });
12553
- }
12554
- }
12555
- return fields;
12556
- }
12557
- function getEmbeddingDimensionsFromField(schema) {
12558
- const directDimensions = getEmbeddingDimensions(schema);
12559
- if (directDimensions !== void 0) {
12560
- return directDimensions;
12561
- }
12562
- const unwrapped = unwrapToEmbedding(schema);
12563
- if (unwrapped) {
12564
- return getEmbeddingDimensions(unwrapped);
12565
- }
12566
- return void 0;
12567
- }
12568
- function unwrapToEmbedding(schema) {
12569
- const type = schema.type;
12570
- const def = schema.def;
12571
- if ((type === "optional" || type === "nullable" || type === "default" || type === "readonly") && def.innerType) {
12572
- if (isEmbeddingSchema(def.innerType)) {
12573
- return def.innerType;
12574
- }
12575
- return unwrapToEmbedding(def.innerType);
12576
- }
12577
- return void 0;
12578
- }
12579
12577
  async function syncEmbeddings(ctx, schema, props) {
12580
12578
  const { backend } = ctx;
12581
12579
  if (!backend.upsertEmbedding || !backend.deleteEmbedding) {
@@ -12594,14 +12592,19 @@ async function syncEmbeddings(ctx, schema, props) {
12594
12592
  nodeId: ctx.nodeId,
12595
12593
  fieldPath: field2.fieldPath,
12596
12594
  embedding: value,
12597
- dimensions: field2.dimensions
12595
+ dimensions: field2.dimensions,
12596
+ metric: field2.metric,
12597
+ indexType: field2.indexType
12598
12598
  });
12599
12599
  } else if (value === void 0) {
12600
12600
  await backend.deleteEmbedding({
12601
12601
  graphId: ctx.graphId,
12602
12602
  nodeKind: ctx.nodeKind,
12603
12603
  nodeId: ctx.nodeId,
12604
- fieldPath: field2.fieldPath
12604
+ fieldPath: field2.fieldPath,
12605
+ dimensions: field2.dimensions,
12606
+ metric: field2.metric,
12607
+ indexType: field2.indexType
12605
12608
  });
12606
12609
  }
12607
12610
  }
@@ -12620,7 +12623,10 @@ async function deleteNodeEmbeddings(ctx, schema) {
12620
12623
  graphId: ctx.graphId,
12621
12624
  nodeKind: ctx.nodeKind,
12622
12625
  nodeId: ctx.nodeId,
12623
- fieldPath: field2.fieldPath
12626
+ fieldPath: field2.fieldPath,
12627
+ dimensions: field2.dimensions,
12628
+ metric: field2.metric,
12629
+ indexType: field2.indexType
12624
12630
  });
12625
12631
  }
12626
12632
  }
@@ -13360,6 +13366,10 @@ async function executeNodeHardDelete(ctx, kind, id, backend) {
13360
13366
  await enforceDeleteBehavior(ctx, kind, id, "hard", backend, registration);
13361
13367
  const hardDelete = async (target) => {
13362
13368
  await target.hardDeleteNode({ graphId: ctx.graphId, kind, id });
13369
+ await deleteNodeEmbeddings(
13370
+ createEmbeddingSyncContext(ctx.graphId, kind, id, target),
13371
+ registration.type.schema
13372
+ );
13363
13373
  };
13364
13374
  await ("transaction" in backend && backend.capabilities.transactions ? backend.transaction(async (tx) => hardDelete(tx)) : hardDelete(backend));
13365
13375
  });
@@ -13549,6 +13559,212 @@ async function executeNodeBulkFindByConstraint(ctx, kind, constraintName, items,
13549
13559
  }
13550
13560
  return results;
13551
13561
  }
13562
+ function resolveNodeIndex(graph, kind, indexName) {
13563
+ getNodeRegistration(graph, kind);
13564
+ const declaration = graph.indexes?.find(
13565
+ (candidate) => candidate.entity === "node" && candidate.kind === kind && candidate.name === indexName
13566
+ );
13567
+ if (declaration?.entity !== "node") {
13568
+ throw new NodeIndexNotFoundError(indexName, kind);
13569
+ }
13570
+ return declaration;
13571
+ }
13572
+ var INDEX_PROBE_EXPECTED_TYPEOF = {
13573
+ string: "string",
13574
+ number: "number",
13575
+ boolean: "boolean"
13576
+ };
13577
+ function validateIndexProbeValue(value, valueType, pointer, kind) {
13578
+ if (value === void 0 || value === null) return;
13579
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && !(value instanceof Date)) {
13580
+ throw indexProbeTypeError(
13581
+ pointer,
13582
+ kind,
13583
+ "a scalar (string, number, boolean, or Date)",
13584
+ value
13585
+ );
13586
+ }
13587
+ if (valueType === "date") {
13588
+ if (value instanceof Date || typeof value === "string") return;
13589
+ throw indexProbeTypeError(
13590
+ pointer,
13591
+ kind,
13592
+ "date (Date or ISO string)",
13593
+ value
13594
+ );
13595
+ }
13596
+ const expected = INDEX_PROBE_EXPECTED_TYPEOF[valueType ?? "unknown"];
13597
+ if (expected === void 0) return;
13598
+ if (typeof value !== expected) {
13599
+ throw indexProbeTypeError(pointer, kind, expected, value);
13600
+ }
13601
+ }
13602
+ function indexProbeTypeError(pointer, kind, expected, value) {
13603
+ return new ValidationError(
13604
+ `Index probe value for "${pointer}" on node kind "${kind}" has an incompatible type`,
13605
+ {
13606
+ entityType: "node",
13607
+ kind,
13608
+ issues: [
13609
+ {
13610
+ path: pointer,
13611
+ message: `Expected ${expected}, received ${typeof value}`,
13612
+ code: "invalid_type"
13613
+ }
13614
+ ]
13615
+ }
13616
+ );
13617
+ }
13618
+ function coerceIndexProbeBind(value, adapter) {
13619
+ return adapter.bindValue(normalizeProbeScalar(value));
13620
+ }
13621
+ function normalizeProbeScalar(value) {
13622
+ return value instanceof Date ? value.toISOString() : value;
13623
+ }
13624
+ var PROBE_NULL_TAG = 0;
13625
+ var PROBE_VALUE_TAG = 1;
13626
+ function canonicalIndexProbeKey(probe) {
13627
+ return JSON.stringify(
13628
+ probe.map(
13629
+ (value) => value === void 0 || value === null ? [PROBE_NULL_TAG] : [PROBE_VALUE_TAG, normalizeProbeScalar(value)]
13630
+ )
13631
+ );
13632
+ }
13633
+ async function executeNodeBulkFindByIndex(ctx, kind, indexName, items, backend, options) {
13634
+ if (items.length === 0) return [];
13635
+ const index = resolveNodeIndex(ctx.graph, kind, indexName);
13636
+ if (index.fieldValueTypes.includes("date")) {
13637
+ throw new ConfigurationError(
13638
+ `bulkFindByIndex does not support date-typed key fields on index "${indexName}" (node kind "${kind}")`,
13639
+ { indexName, kind },
13640
+ {
13641
+ suggestion: "Date index keys compare differently across SQLite and PostgreSQL. Use a string-encoded key field, or query date predicates via store.query(...).where(...)."
13642
+ }
13643
+ );
13644
+ }
13645
+ const limitPerInput = options?.limitPerInput;
13646
+ if (limitPerInput !== void 0 && (!Number.isInteger(limitPerInput) || limitPerInput <= 0)) {
13647
+ throw new ValidationError(
13648
+ "bulkFindByIndex limitPerInput must be a positive integer",
13649
+ {
13650
+ entityType: "node",
13651
+ kind,
13652
+ issues: [
13653
+ {
13654
+ path: "limitPerInput",
13655
+ message: `Expected a positive integer, received ${String(limitPerInput)}`,
13656
+ code: "invalid_value"
13657
+ }
13658
+ ]
13659
+ }
13660
+ );
13661
+ }
13662
+ const adapter = getDialect(backend.dialect);
13663
+ const probes = items.map(
13664
+ (item) => index.fields.map((pointer, position) => {
13665
+ const value = resolveJsonPointer(item.props, pointer);
13666
+ validateIndexProbeValue(
13667
+ value,
13668
+ index.fieldValueTypes[position],
13669
+ pointer,
13670
+ kind
13671
+ );
13672
+ return value;
13673
+ })
13674
+ );
13675
+ const groupByKey = /* @__PURE__ */ new Map();
13676
+ const groupProbes = [];
13677
+ const groupToInputs = [];
13678
+ for (const [inputIndex, probe] of probes.entries()) {
13679
+ const key = canonicalIndexProbeKey(probe);
13680
+ const existing = groupByKey.get(key);
13681
+ if (existing === void 0) {
13682
+ groupByKey.set(key, groupProbes.length);
13683
+ groupProbes.push(probe);
13684
+ groupToInputs.push([inputIndex]);
13685
+ continue;
13686
+ }
13687
+ groupToInputs[existing]?.push(inputIndex);
13688
+ }
13689
+ const schema = backend.tableNames ? createSqlSchema(backend.tableNames) : DEFAULT_SQL_SCHEMA;
13690
+ const compileContext = {
13691
+ dialect: backend.dialect,
13692
+ propsColumn: sql.raw(`"props"`),
13693
+ systemColumn: (column) => sql.raw(`"${column}"`)
13694
+ };
13695
+ const fieldKeys = compileNodeIndexFieldKeys(index, compileContext);
13696
+ const groupPredicates = groupProbes.map(
13697
+ (probe) => sql`(${sql.join(
13698
+ fieldKeys.map((fieldKey, position) => {
13699
+ const value = probe[position];
13700
+ if (value === void 0 || value === null) {
13701
+ return sql`${fieldKey} IS NULL`;
13702
+ }
13703
+ return adapter.nullSafeEquals(
13704
+ fieldKey,
13705
+ sql`${coerceIndexProbeBind(value, adapter)}`
13706
+ );
13707
+ }),
13708
+ sql` AND `
13709
+ )})`
13710
+ );
13711
+ const caseBranches = groupPredicates.map(
13712
+ (predicate2, group) => sql`WHEN ${predicate2} THEN ${sql.raw(String(group))}`
13713
+ );
13714
+ const probeIndexExpr = sql`CASE ${sql.join(caseBranches, sql` `)} ELSE NULL END`;
13715
+ const conditions = [
13716
+ sql`"graph_id" = ${ctx.graphId}`,
13717
+ sql`"kind" = ${kind}`,
13718
+ sql`"deleted_at" IS NULL`
13719
+ ];
13720
+ if (index.where !== void 0) {
13721
+ conditions.push(compileIndexWhere(compileContext, index.where));
13722
+ }
13723
+ conditions.push(sql`(${sql.join(groupPredicates, sql` OR `)})`);
13724
+ const whereClause = sql.join(conditions, sql` AND `);
13725
+ const probedSelect = sql`SELECT "id", ${probeIndexExpr} AS probe_idx FROM ${schema.nodesTable} WHERE ${whereClause}`;
13726
+ const capInSql = limitPerInput !== void 0 && backend.capabilities.windowFunctions;
13727
+ const query = capInSql ? sql`SELECT "id", probe_idx FROM (SELECT "id", probe_idx, ROW_NUMBER() OVER (PARTITION BY probe_idx ORDER BY "id") AS probe_rank FROM (${probedSelect}) AS probed) AS ranked WHERE probe_rank <= ${limitPerInput} ORDER BY probe_idx, "id"` : sql`${probedSelect} ORDER BY probe_idx, "id"`;
13728
+ const rawMatches = await backend.execute(query);
13729
+ const matches = limitPerInput !== void 0 && !capInSql ? capMatchesPerGroup(rawMatches, limitPerInput) : rawMatches;
13730
+ const nodesById = await hydrateNodesById(
13731
+ backend,
13732
+ ctx.graphId,
13733
+ kind,
13734
+ matches.map((match) => match.id)
13735
+ );
13736
+ const results = Array.from({ length: items.length }, () => []);
13737
+ for (const match of matches) {
13738
+ const node = nodesById.get(match.id);
13739
+ if (node === void 0) continue;
13740
+ const inputs = groupToInputs[match.probe_idx];
13741
+ if (inputs === void 0) continue;
13742
+ for (const inputIndex of inputs) {
13743
+ results[inputIndex]?.push(node);
13744
+ }
13745
+ }
13746
+ return results;
13747
+ }
13748
+ function capMatchesPerGroup(matches, limitPerInput) {
13749
+ const perGroupCount = /* @__PURE__ */ new Map();
13750
+ const capped = [];
13751
+ for (const match of matches) {
13752
+ const count2 = perGroupCount.get(match.probe_idx) ?? 0;
13753
+ if (count2 >= limitPerInput) continue;
13754
+ perGroupCount.set(match.probe_idx, count2 + 1);
13755
+ capped.push(match);
13756
+ }
13757
+ return capped;
13758
+ }
13759
+ async function hydrateNodesById(backend, graphId, kind, ids) {
13760
+ const rowsById = await getNodeRowsByIds(backend, graphId, kind, ids);
13761
+ const nodesById = /* @__PURE__ */ new Map();
13762
+ for (const [id, row] of rowsById) {
13763
+ if (row.deleted_at !== void 0) continue;
13764
+ nodesById.set(id, rowToNode(row));
13765
+ }
13766
+ return nodesById;
13767
+ }
13552
13768
  async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName, items, backend, options) {
13553
13769
  if (items.length === 0) return [];
13554
13770
  const ifExists = options?.ifExists ?? "return";
@@ -13829,6 +14045,24 @@ function processPage(schema, rows) {
13829
14045
  }
13830
14046
 
13831
14047
  // src/store/search.ts
14048
+ function resolveSearchSlot(ctx, nodeKind, fieldPath) {
14049
+ const nodeType = ctx.registry.getNodeType(nodeKind);
14050
+ if (nodeType !== void 0) {
14051
+ const fields = getEmbeddingFields(nodeType.schema);
14052
+ const field2 = fields.find((entry2) => entry2.fieldPath === fieldPath);
14053
+ if (field2 !== void 0) {
14054
+ return {
14055
+ dimensions: field2.dimensions,
14056
+ metric: field2.metric,
14057
+ indexType: field2.indexType
14058
+ };
14059
+ }
14060
+ }
14061
+ throw new ConfigurationError(
14062
+ `Node kind "${nodeKind}" has no embedding field "${fieldPath}". Declare it with embedding(dimensions) on the node schema.`,
14063
+ { capability: "vector", graphId: ctx.graphId }
14064
+ );
14065
+ }
13832
14066
  async function executeFulltextSearch(ctx, nodeKind, options) {
13833
14067
  const { backend, graphId } = ctx;
13834
14068
  if (!backend.fulltextSearch) {
@@ -13890,12 +14124,29 @@ async function executeVectorSearch(ctx, nodeKind, options) {
13890
14124
  );
13891
14125
  }
13892
14126
  assertEfSearch(options.efSearch, "vectorSearch.efSearch");
14127
+ const slot = resolveSearchSlot(ctx, nodeKind, options.fieldPath);
14128
+ assertVectorQueryCompatible(
14129
+ backend,
14130
+ slot,
14131
+ { metric: options.metric, queryEmbedding: options.queryEmbedding },
14132
+ "vectorSearch"
14133
+ );
14134
+ assertMinScore(
14135
+ options.minScore,
14136
+ options.metric ?? slot.metric,
14137
+ "vectorSearch.minScore"
14138
+ );
13893
14139
  const rows = await backend.vectorSearch({
13894
14140
  graphId,
13895
14141
  nodeKind,
13896
14142
  fieldPath: options.fieldPath,
13897
14143
  queryEmbedding: options.queryEmbedding,
13898
- metric: options.metric ?? "cosine",
14144
+ // Default to the field's DECLARED metric (the metric its index was built
14145
+ // for); only an explicit caller override changes it. Defaulting to cosine
14146
+ // here would mis-rank l2 / inner_product fields and bypass their ANN index.
14147
+ metric: options.metric ?? slot.metric,
14148
+ dimensions: slot.dimensions,
14149
+ indexType: slot.indexType,
13899
14150
  limit: options.limit,
13900
14151
  ...options.minScore === void 0 ? {} : { minScore: options.minScore },
13901
14152
  ...options.efSearch === void 0 ? {} : { efSearch: options.efSearch }
@@ -13947,12 +14198,30 @@ async function executeHybridSearch(ctx, nodeKind, options) {
13947
14198
  const overFetchMultiplier = 4;
13948
14199
  const vectorK = options.vector.k ?? options.limit * overFetchMultiplier;
13949
14200
  const fulltextK = options.fulltext.k ?? options.limit * overFetchMultiplier;
14201
+ const vectorSlot = resolveSearchSlot(ctx, nodeKind, options.vector.fieldPath);
14202
+ assertVectorQueryCompatible(
14203
+ backend,
14204
+ vectorSlot,
14205
+ {
14206
+ metric: options.vector.metric,
14207
+ queryEmbedding: options.vector.queryEmbedding
14208
+ },
14209
+ "hybridSearch.vector"
14210
+ );
14211
+ assertMinScore(
14212
+ options.vector.minScore,
14213
+ options.vector.metric ?? vectorSlot.metric,
14214
+ "hybridSearch.vector.minScore"
14215
+ );
13950
14216
  const vectorPromise = backend.vectorSearch({
13951
14217
  graphId,
13952
14218
  nodeKind,
13953
14219
  fieldPath: options.vector.fieldPath,
13954
14220
  queryEmbedding: options.vector.queryEmbedding,
13955
- metric: options.vector.metric ?? "cosine",
14221
+ // Default to the field's declared metric (see executeVectorSearch).
14222
+ metric: options.vector.metric ?? vectorSlot.metric,
14223
+ dimensions: vectorSlot.dimensions,
14224
+ indexType: vectorSlot.indexType,
13956
14225
  limit: vectorK,
13957
14226
  ...options.vector.minScore === void 0 ? {} : { minScore: options.vector.minScore },
13958
14227
  ...options.vector.efSearch === void 0 ? {} : { efSearch: options.vector.efSearch }
@@ -14043,6 +14312,30 @@ function assertEfSearch(efSearch, label) {
14043
14312
  );
14044
14313
  }
14045
14314
  }
14315
+ function assertMinScore(minScore, metric, label) {
14316
+ if (minScore === void 0) return;
14317
+ assertVectorMinScore(minScore, metric, label);
14318
+ }
14319
+ function assertVectorQueryCompatible(backend, slot, options, label) {
14320
+ if (options.metric !== void 0 && options.metric !== slot.metric) {
14321
+ throw new ConfigurationError(
14322
+ `${label}: metric "${options.metric}" does not match the field's declared metric "${slot.metric}". Vector storage is built for the declared metric \u2014 omit metric or pass "${slot.metric}".`,
14323
+ { backend: backend.dialect, capability: "vector" }
14324
+ );
14325
+ }
14326
+ const supported = backend.capabilities.vector?.metrics;
14327
+ if (supported !== void 0 && !supported.includes(slot.metric)) {
14328
+ throw new ConfigurationError(
14329
+ `${label}: backend "${backend.dialect}" does not support the "${slot.metric}" metric (supported: ${supported.join(", ")}).`,
14330
+ { backend: backend.dialect, capability: "vector" }
14331
+ );
14332
+ }
14333
+ if (options.queryEmbedding.length !== slot.dimensions) {
14334
+ throw new RangeError(
14335
+ `${label}: queryEmbedding has ${options.queryEmbedding.length} dimensions, but "${slot.dimensions}" are declared for this field.`
14336
+ );
14337
+ }
14338
+ }
14046
14339
  function validateFulltextCallOptions(backend, options) {
14047
14340
  const strategy = backend.fulltextStrategy;
14048
14341
  const capabilities = backend.capabilities.fulltext;
@@ -14149,7 +14442,11 @@ var StoreSearch = class {
14149
14442
  async fulltext(nodeKind, options) {
14150
14443
  this.#assertKindRegistered(nodeKind);
14151
14444
  return executeFulltextSearch(
14152
- { graphId: this.#context.graphId, backend: this.#context.backend },
14445
+ {
14446
+ graphId: this.#context.graphId,
14447
+ backend: this.#context.backend,
14448
+ registry: this.#context.registry
14449
+ },
14153
14450
  nodeKind,
14154
14451
  options
14155
14452
  );
@@ -14168,7 +14465,11 @@ var StoreSearch = class {
14168
14465
  async vector(nodeKind, options) {
14169
14466
  this.#assertKindRegistered(nodeKind);
14170
14467
  return executeVectorSearch(
14171
- { graphId: this.#context.graphId, backend: this.#context.backend },
14468
+ {
14469
+ graphId: this.#context.graphId,
14470
+ backend: this.#context.backend,
14471
+ registry: this.#context.registry
14472
+ },
14172
14473
  nodeKind,
14173
14474
  options
14174
14475
  );
@@ -14185,7 +14486,11 @@ var StoreSearch = class {
14185
14486
  async hybrid(nodeKind, options) {
14186
14487
  this.#assertKindRegistered(nodeKind);
14187
14488
  return executeHybridSearch(
14188
- { graphId: this.#context.graphId, backend: this.#context.backend },
14489
+ {
14490
+ graphId: this.#context.graphId,
14491
+ backend: this.#context.backend,
14492
+ registry: this.#context.registry
14493
+ },
14189
14494
  nodeKind,
14190
14495
  options
14191
14496
  );
@@ -14234,6 +14539,7 @@ var UNKNOWN_SCHEMA_METADATA = Object.freeze({
14234
14539
  schemaVersion: void 0,
14235
14540
  schemaHash: void 0
14236
14541
  });
14542
+ var DEFAULT_REEMBED_BATCH_SIZE = 200;
14237
14543
  var CAUGHT_UP_VERB_DETAILS = {
14238
14544
  evolve: { phrase: "evolve", code: "EVOLVE_BEFORE_INITIALIZE" },
14239
14545
  materialize: {
@@ -14248,6 +14554,10 @@ var CAUGHT_UP_VERB_DETAILS = {
14248
14554
  undeprecate: {
14249
14555
  phrase: "undeprecate kinds on",
14250
14556
  code: "DEPRECATE_BEFORE_INITIALIZE"
14557
+ },
14558
+ reembed: {
14559
+ phrase: "re-embed a vector field on",
14560
+ code: "REEMBED_BEFORE_INITIALIZE"
14251
14561
  }
14252
14562
  };
14253
14563
  var Store = class _Store {
@@ -14553,6 +14863,14 @@ var Store = class _Store {
14553
14863
  constraintName,
14554
14864
  items,
14555
14865
  backend
14866
+ ),
14867
+ executeBulkFindByIndex: (kind, indexName, items, backend, options) => executeNodeBulkFindByIndex(
14868
+ ctx,
14869
+ kind,
14870
+ indexName,
14871
+ items,
14872
+ backend,
14873
+ options
14556
14874
  )
14557
14875
  };
14558
14876
  }
@@ -14799,7 +15117,7 @@ var Store = class _Store {
14799
15117
  return fn({ nodes: this.nodes, edges: this.edges });
14800
15118
  }
14801
15119
  return this.#backend.transaction(
14802
- async (txBackend, sql17) => fn(this.#buildTransactionContext(txBackend, sql17))
15120
+ async (txBackend, sql19) => fn(this.#buildTransactionContext(txBackend, sql19))
14803
15121
  );
14804
15122
  }
14805
15123
  /**
@@ -14876,7 +15194,7 @@ var Store = class _Store {
14876
15194
  * raw Drizzle handle bound to the same transaction (#140);
14877
15195
  * `undefined` only on the non-transactional fallback.
14878
15196
  */
14879
- #buildTransactionContext(txBackend, sql17) {
15197
+ #buildTransactionContext(txBackend, sql19) {
14880
15198
  const txNodeOperations = {
14881
15199
  ...this.#nodeOperations,
14882
15200
  createQuery: () => this.#createQueryForBackend(txBackend)
@@ -14899,7 +15217,7 @@ var Store = class _Store {
14899
15217
  txBackend,
14900
15218
  txEdgeOperations
14901
15219
  );
14902
- return sql17 === void 0 ? { nodes, edges } : { nodes, edges, sql: sql17 };
15220
+ return sql19 === void 0 ? { nodes, edges } : { nodes, edges, sql: sql19 };
14903
15221
  }
14904
15222
  // === Graph Lifecycle ===
14905
15223
  /**
@@ -14916,11 +15234,44 @@ var Store = class _Store {
14916
15234
  await target.clearGraph(this.graphId);
14917
15235
  };
14918
15236
  await (this.#backend.capabilities.transactions ? this.#backend.transaction(async (tx) => doClear(tx)) : doClear(this.#backend));
15237
+ await this.#clearVectorStorage();
14919
15238
  this.#nodeCollections = void 0;
14920
15239
  this.#edgeCollections = void 0;
14921
15240
  this.#algorithms = void 0;
14922
15241
  this.#search = void 0;
14923
15242
  }
15243
+ /**
15244
+ * Resets every declared embedding field's per-field storage for this graph by
15245
+ * dropping and recreating it empty. Drop+recreate (rather than DELETE) mirrors
15246
+ * `reembedVectorField` and keeps the backend's storage-ensure latch valid: the
15247
+ * table still exists after clear, so a later write finds it. Enumerated from
15248
+ * the in-memory registry (not the DB schema, which `clearGraph` just wiped).
15249
+ */
15250
+ async #clearVectorStorage() {
15251
+ const backend = this.#backend;
15252
+ const strategy = backend.vectorStrategy;
15253
+ if (strategy === void 0 || backend.executeDdl === void 0) return;
15254
+ for (const [nodeKind, nodeType] of this.#registry.nodeKinds) {
15255
+ for (const field2 of resolveEmbeddingFields(nodeType.schema)) {
15256
+ const slot = {
15257
+ graphId: this.graphId,
15258
+ nodeKind,
15259
+ fieldPath: field2.fieldPath,
15260
+ dimensions: field2.dimensions,
15261
+ metric: field2.metric,
15262
+ indexType: field2.indexType
15263
+ };
15264
+ for (const ddl of strategy.buildDropStorage(slot)) {
15265
+ await backend.executeDdl(ddl);
15266
+ }
15267
+ for (const contribution of strategy.ownedTables(slot)) {
15268
+ for (const ddl of contribution.createDdl) {
15269
+ await backend.executeDdl(ddl);
15270
+ }
15271
+ }
15272
+ }
15273
+ }
15274
+ }
14924
15275
  // === Lifecycle ===
14925
15276
  /**
14926
15277
  * Refreshes the backend's query-planner statistics.
@@ -15144,6 +15495,150 @@ var Store = class _Store {
15144
15495
  options ?? {}
15145
15496
  );
15146
15497
  }
15498
+ /**
15499
+ * Recreate a vector field's per-field storage at its current declared
15500
+ * dimension, then optionally re-embed existing rows.
15501
+ *
15502
+ * Use this after changing a field's `embedding(N)` to `embedding(M)` (e.g. a
15503
+ * new embedding model): the stored N-dim vectors are invalid under the new
15504
+ * dimension and must be recomputed, not converted. This drops and recreates
15505
+ * the per-`(graphId, kind, field)` table at the new dimension — a brief
15506
+ * window where the field returns no vector hits — resets its materialization
15507
+ * marker, then, when `options.embed` is supplied, pages the kind's nodes,
15508
+ * calls `embed(batch)`, and upserts the returned vectors. Without `embed`,
15509
+ * storage is recreated empty and the caller re-embeds via normal
15510
+ * `update()` / `upsertEmbedding` writes.
15511
+ *
15512
+ * @throws {ConfigurationError} when the backend has no vector strategy or
15513
+ * cannot execute DDL, or `(kind, fieldPath)` is not a declared embedding.
15514
+ */
15515
+ async reembedVectorField(kind, fieldPath, options) {
15516
+ if (options?.batchSize !== void 0 && (!Number.isInteger(options.batchSize) || options.batchSize <= 0)) {
15517
+ throw new RangeError(
15518
+ `reembedVectorField batchSize must be a positive integer, got: ${options.batchSize}`
15519
+ );
15520
+ }
15521
+ const { activeRow, baseline } = await this.#loadCaughtUp("reembed");
15522
+ const backend = this.#backend;
15523
+ const strategy = backend.vectorStrategy;
15524
+ if (strategy === void 0 || backend.executeDdl === void 0) {
15525
+ throw new ConfigurationError(
15526
+ "reembedVectorField requires a backend with a vector strategy and executeDdl.",
15527
+ {
15528
+ backend: backend.dialect,
15529
+ capability: "vector",
15530
+ operation: "reembed"
15531
+ }
15532
+ );
15533
+ }
15534
+ const declaration = (baseline.indexes ?? []).find(
15535
+ (candidate) => candidate.entity === "vector" && candidate.kind === kind && candidate.fieldPath === fieldPath
15536
+ );
15537
+ if (declaration === void 0) {
15538
+ throw new ConfigurationError(
15539
+ `No embedding field "${kind}.${fieldPath}" is declared in the active schema.`,
15540
+ { kind, fieldPath, operation: "reembed" }
15541
+ );
15542
+ }
15543
+ const slot = {
15544
+ graphId: this.graphId,
15545
+ nodeKind: kind,
15546
+ fieldPath,
15547
+ dimensions: declaration.dimensions,
15548
+ metric: declaration.metric,
15549
+ indexType: declaration.indexType
15550
+ };
15551
+ for (const ddl of strategy.buildDropStorage(slot)) {
15552
+ await backend.executeDdl(ddl);
15553
+ }
15554
+ for (const contribution of strategy.ownedTables(slot)) {
15555
+ for (const ddl of contribution.createDdl) {
15556
+ await backend.executeDdl(ddl);
15557
+ }
15558
+ }
15559
+ const declaredIndexMaterializes = declaration.indexType !== "none" && backend.capabilities.vector?.indexTypes.includes(
15560
+ declaration.indexType
15561
+ ) === true;
15562
+ if (declaredIndexMaterializes && backend.createVectorIndex !== void 0) {
15563
+ await backend.createVectorIndex({
15564
+ graphId: this.graphId,
15565
+ nodeKind: kind,
15566
+ fieldPath,
15567
+ dimensions: declaration.dimensions,
15568
+ metric: declaration.metric,
15569
+ indexType: declaration.indexType,
15570
+ indexParams: {
15571
+ m: declaration.indexParams.m,
15572
+ efConstruction: declaration.indexParams.efConstruction,
15573
+ ...declaration.indexParams.lists === void 0 ? {} : { lists: declaration.indexParams.lists }
15574
+ }
15575
+ });
15576
+ }
15577
+ if (declaredIndexMaterializes && backend.recordIndexMaterialization !== void 0) {
15578
+ const tableName = strategy.tableName(this.graphId, kind, fieldPath);
15579
+ const signature = await computeIndexSignature(
15580
+ backend.dialect,
15581
+ tableName,
15582
+ declaration
15583
+ );
15584
+ const now = nowIso();
15585
+ await backend.recordIndexMaterialization({
15586
+ indexName: vectorStatusKey(this.graphId, declaration.name),
15587
+ graphId: this.graphId,
15588
+ entity: "vector",
15589
+ kind,
15590
+ signature,
15591
+ schemaVersion: activeRow.version,
15592
+ attemptedAt: now,
15593
+ materializedAt: now,
15594
+ error: void 0
15595
+ });
15596
+ }
15597
+ if (options?.embed === void 0) {
15598
+ return { recreated: true, reembedded: 0 };
15599
+ }
15600
+ if (backend.upsertEmbedding === void 0) {
15601
+ throw new ConfigurationError(
15602
+ "reembedVectorField with an `embed` callback requires a backend that supports upsertEmbedding.",
15603
+ {
15604
+ backend: backend.dialect,
15605
+ capability: "vector",
15606
+ operation: "reembed"
15607
+ }
15608
+ );
15609
+ }
15610
+ const upsertEmbedding = backend.upsertEmbedding;
15611
+ const batchSize = options.batchSize ?? DEFAULT_REEMBED_BATCH_SIZE;
15612
+ const collection = this.getNodeCollectionOrThrow(kind);
15613
+ let reembedded = 0;
15614
+ let offset = 0;
15615
+ for (; ; ) {
15616
+ const batch = await collection.find({
15617
+ limit: batchSize,
15618
+ offset
15619
+ });
15620
+ if (batch.length === 0) break;
15621
+ const vectors = await options.embed(batch);
15622
+ for (const node of batch) {
15623
+ const embedding2 = vectors.get(node.id);
15624
+ if (embedding2 === void 0) continue;
15625
+ await upsertEmbedding({
15626
+ graphId: this.graphId,
15627
+ nodeKind: kind,
15628
+ nodeId: node.id,
15629
+ fieldPath,
15630
+ embedding: embedding2,
15631
+ dimensions: declaration.dimensions,
15632
+ metric: declaration.metric,
15633
+ indexType: declaration.indexType
15634
+ });
15635
+ reembedded += 1;
15636
+ }
15637
+ offset += batch.length;
15638
+ if (batch.length < batchSize) break;
15639
+ }
15640
+ return { recreated: true, reembedded };
15641
+ }
15147
15642
  /**
15148
15643
  * Removes extension kinds from the schema with cascading edge and
15149
15644
  * ontology cleanup. Two-phase by design:
@@ -15521,6 +16016,6 @@ async function createVerifiedStore(graph, backend, options) {
15521
16016
  return [store, result];
15522
16017
  }
15523
16018
 
15524
- export { DEFAULT_SQL_SCHEMA, ExecutableAggregateQuery, ExecutableQuery, MAX_EXPLICIT_RECURSIVE_DEPTH, MAX_RECURSIVE_DEPTH, PreparedQuery, QueryBuilder, StoreSearch, UnionableQuery, avg, composeFragments, count, countDistinct, countDistinctEdges, countEdges, createExternalRef, createFragment, createQueryBuilder, createSqlSchema, createStore, createStoreWithSchema, createVerifiedStore, defineSubgraphProject, exists, externalRef, field, fieldRef, generateId, getExternalRefTable, having, havingEq, havingGt, havingGte, havingLt, havingLte, inSubquery, isExternalRefSchema, isParameterRef, limitFragment, max, metaEdge, min, notExists, notInSubquery, offsetFragment, orderByFragment, param, sum };
16019
+ export { DEFAULT_SQL_SCHEMA, ExecutableAggregateQuery, ExecutableQuery, MAX_EXPLICIT_RECURSIVE_DEPTH, MAX_RECURSIVE_DEPTH, PreparedQuery, QueryBuilder, StoreSearch, UnionableQuery, avg, composeFragments, count, countDistinct, countDistinctEdges, countEdges, createExternalRef, createFragment, createQueryBuilder, createSqlSchema, createStore, createStoreWithSchema, createVerifiedStore, defineSubgraphProject, exists, externalRef, field, fieldRef, generateId, getExternalRefTable, having, havingEq, havingGt, havingGte, havingLt, havingLte, inSubquery, isExternalRefSchema, isParameterRef, limitFragment, max, metaEdge, migrateLegacyEmbeddings, min, notExists, notInSubquery, offsetFragment, orderByFragment, param, sum };
15525
16020
  //# sourceMappingURL=index.js.map
15526
16021
  //# sourceMappingURL=index.js.map