@nicia-ai/typegraph 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/postgres/index.cjs +23 -761
- package/dist/backend/postgres/index.cjs.map +1 -1
- package/dist/backend/postgres/index.d.cts +24 -5
- package/dist/backend/postgres/index.d.ts +24 -5
- package/dist/backend/postgres/index.js +10 -752
- package/dist/backend/postgres/index.js.map +1 -1
- package/dist/backend/postgres/pglite.cjs +52 -0
- package/dist/backend/postgres/pglite.cjs.map +1 -0
- package/dist/backend/postgres/pglite.d.cts +116 -0
- package/dist/backend/postgres/pglite.d.ts +116 -0
- package/dist/backend/postgres/pglite.js +50 -0
- package/dist/backend/postgres/pglite.js.map +1 -0
- package/dist/backend/sqlite/index.cjs +22 -26
- package/dist/backend/sqlite/index.d.cts +17 -15
- package/dist/backend/sqlite/index.d.ts +17 -15
- package/dist/backend/sqlite/index.js +9 -9
- package/dist/backend/sqlite/libsql.cjs +17 -13
- package/dist/backend/sqlite/libsql.cjs.map +1 -1
- package/dist/backend/sqlite/libsql.d.cts +3 -3
- package/dist/backend/sqlite/libsql.d.ts +3 -3
- package/dist/backend/sqlite/libsql.js +16 -12
- package/dist/backend/sqlite/libsql.js.map +1 -1
- package/dist/backend/sqlite/local.cjs +17 -16
- package/dist/backend/sqlite/local.cjs.map +1 -1
- package/dist/backend/sqlite/local.d.cts +3 -3
- package/dist/backend/sqlite/local.d.ts +3 -3
- package/dist/backend/sqlite/local.js +15 -14
- package/dist/backend/sqlite/local.js.map +1 -1
- package/dist/{chunk-DFHLG75V.js → chunk-3DTLDGIM.js} +386 -1093
- package/dist/chunk-3DTLDGIM.js.map +1 -0
- package/dist/{chunk-WVQXAFP3.js → chunk-454I6GDF.js} +46 -5
- package/dist/chunk-454I6GDF.js.map +1 -0
- package/dist/chunk-4K6IHUW6.cjs +183 -0
- package/dist/chunk-4K6IHUW6.cjs.map +1 -0
- package/dist/{chunk-ZTREJOGB.js → chunk-7KLVFWXR.js} +113 -68
- package/dist/chunk-7KLVFWXR.js.map +1 -0
- package/dist/{chunk-UKG7XHZ3.js → chunk-A4H6QMV4.js} +110 -102
- package/dist/chunk-A4H6QMV4.js.map +1 -0
- package/dist/{chunk-E5ROA3MN.js → chunk-BMDF2S7S.js} +3 -3
- package/dist/{chunk-E5ROA3MN.js.map → chunk-BMDF2S7S.js.map} +1 -1
- package/dist/{chunk-PN37HVAV.cjs → chunk-C2RWFIYP.cjs} +121 -67
- package/dist/chunk-C2RWFIYP.cjs.map +1 -0
- package/dist/chunk-CUZGBWFT.js +206 -0
- package/dist/chunk-CUZGBWFT.js.map +1 -0
- package/dist/chunk-F2Q76CQ4.cjs +266 -0
- package/dist/chunk-F2Q76CQ4.cjs.map +1 -0
- package/dist/{chunk-YEDQLNVE.cjs → chunk-G6P3OVDY.cjs} +14 -2
- package/dist/chunk-G6P3OVDY.cjs.map +1 -0
- package/dist/chunk-GPUNAJFH.js +181 -0
- package/dist/chunk-GPUNAJFH.js.map +1 -0
- package/dist/chunk-HKN622O4.js +254 -0
- package/dist/chunk-HKN622O4.js.map +1 -0
- package/dist/{chunk-PYJOBZR3.cjs → chunk-HM6XMR3E.cjs} +52 -52
- package/dist/chunk-HM6XMR3E.cjs.map +1 -0
- package/dist/chunk-IE2TPFBT.js +305 -0
- package/dist/chunk-IE2TPFBT.js.map +1 -0
- package/dist/chunk-KGAJ5HFO.cjs +319 -0
- package/dist/chunk-KGAJ5HFO.cjs.map +1 -0
- package/dist/chunk-M6OC455F.js +65 -0
- package/dist/chunk-M6OC455F.js.map +1 -0
- package/dist/{chunk-U5ROKVRF.js → chunk-MB363HT5.js} +14 -3
- package/dist/chunk-MB363HT5.js.map +1 -0
- package/dist/{chunk-X53YKGHR.js → chunk-MRMD7S7E.js} +9 -9
- package/dist/{chunk-X53YKGHR.js.map → chunk-MRMD7S7E.js.map} +1 -1
- package/dist/{chunk-OOS2RKRH.js → chunk-N3VVQDMA.js} +3 -3
- package/dist/{chunk-OOS2RKRH.js.map → chunk-N3VVQDMA.js.map} +1 -1
- package/dist/{chunk-EJCDOA37.js → chunk-OGUH56BB.js} +4 -4
- package/dist/{chunk-EJCDOA37.js.map → chunk-OGUH56BB.js.map} +1 -1
- package/dist/chunk-Q3ZZLU3O.cjs +12 -0
- package/dist/{chunk-4FJVSF3K.cjs.map → chunk-Q3ZZLU3O.cjs.map} +1 -1
- package/dist/chunk-Q5ASTPM4.cjs +208 -0
- package/dist/chunk-Q5ASTPM4.cjs.map +1 -0
- package/dist/{chunk-WFUN6DCM.cjs → chunk-R2LA6MKR.cjs} +11 -11
- package/dist/chunk-R2LA6MKR.cjs.map +1 -0
- package/dist/chunk-RP7YITHX.cjs +70 -0
- package/dist/chunk-RP7YITHX.cjs.map +1 -0
- package/dist/{chunk-33K3ZYFG.cjs → chunk-RU5BBUU2.cjs} +132 -124
- package/dist/chunk-RU5BBUU2.cjs.map +1 -0
- package/dist/{chunk-TSGBRPNE.js → chunk-SFNUHFON.js} +45 -45
- package/dist/chunk-SFNUHFON.js.map +1 -0
- package/dist/chunk-UP4QAJND.cjs +740 -0
- package/dist/chunk-UP4QAJND.cjs.map +1 -0
- package/dist/{chunk-CTHNVU6K.cjs → chunk-UPBXUOW7.cjs} +8 -8
- package/dist/{chunk-CTHNVU6K.cjs.map → chunk-UPBXUOW7.cjs.map} +1 -1
- package/dist/{chunk-EK6RJ373.cjs → chunk-VGU26WIU.cjs} +5 -5
- package/dist/{chunk-EK6RJ373.cjs.map → chunk-VGU26WIU.cjs.map} +1 -1
- package/dist/{chunk-ZGEMI7MJ.cjs → chunk-XTQHSOIC.cjs} +101 -101
- package/dist/{chunk-ZGEMI7MJ.cjs.map → chunk-XTQHSOIC.cjs.map} +1 -1
- package/dist/chunk-Y52UNT66.js +738 -0
- package/dist/chunk-Y52UNT66.js.map +1 -0
- package/dist/{chunk-OYLF3IC7.js → chunk-Z36W5WUM.js} +4 -4
- package/dist/chunk-Z36W5WUM.js.map +1 -0
- package/dist/{chunk-X3244EKP.cjs → chunk-ZFWNO3GE.cjs} +48 -4
- package/dist/chunk-ZFWNO3GE.cjs.map +1 -0
- package/dist/{chunk-2E4VTD2E.cjs → chunk-ZYQEXGYC.cjs} +423 -1139
- package/dist/chunk-ZYQEXGYC.cjs.map +1 -0
- package/dist/ddl-BwH00BB6.d.ts +38 -0
- package/dist/ddl-D3o-RmsV.d.cts +38 -0
- package/dist/{extension-types-B78CZfA5.d.ts → extension-types-CwHV-Uk4.d.cts} +4 -4
- package/dist/{extension-types-B78CZfA5.d.cts → extension-types-CwHV-Uk4.d.ts} +4 -4
- package/dist/graph-extension/index.cjs +18 -18
- package/dist/graph-extension/index.d.cts +4 -4
- package/dist/graph-extension/index.d.ts +4 -4
- package/dist/graph-extension/index.js +3 -3
- package/dist/{index-CWdBFWbI.d.ts → index-CapHwi1a.d.ts} +22 -3
- package/dist/{index-Bilw0pYm.d.cts → index-jPPexxM5.d.cts} +22 -3
- package/dist/index.cjs +1211 -945
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -12
- package/dist/index.d.ts +142 -12
- package/dist/index.js +778 -544
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +18 -18
- package/dist/indexes/index.d.cts +9 -9
- package/dist/indexes/index.d.ts +9 -9
- package/dist/indexes/index.js +4 -4
- package/dist/interchange/index.cjs +8 -14
- package/dist/interchange/index.cjs.map +1 -1
- package/dist/interchange/index.d.cts +5 -16
- package/dist/interchange/index.d.ts +5 -16
- package/dist/interchange/index.js +3 -9
- package/dist/interchange/index.js.map +1 -1
- package/dist/{manager-ehLTTNq0.d.ts → manager-BUugwCYz.d.ts} +2 -2
- package/dist/{manager-c1MGaVVR.d.cts → manager-DpIpn1HQ.d.cts} +2 -2
- package/dist/{materialize-indexes-DFavFQah.d.ts → materialize-indexes-lkawaDor.d.ts} +1 -1
- package/dist/{materialize-indexes-BQfaAZKA.d.cts → materialize-indexes-oanE3RU0.d.cts} +1 -1
- package/dist/{ddl-0Ooc2dpL.d.ts → postgres-CQL9UIn2.d.cts} +2 -471
- package/dist/{ddl-Dza3kDrI.d.cts → postgres-CcRLaxz0.d.ts} +2 -471
- package/dist/profiler/index.cjs +4 -4
- package/dist/profiler/index.d.cts +7 -7
- package/dist/profiler/index.d.ts +7 -7
- package/dist/profiler/index.js +2 -2
- package/dist/schema/index.cjs +32 -32
- package/dist/schema/index.d.cts +7 -7
- package/dist/schema/index.d.ts +7 -7
- package/dist/schema/index.js +9 -9
- package/dist/{sqlite-BxZUPbyD.d.ts → sqlite-CZDFUfHS.d.ts} +2 -468
- package/dist/{sqlite-mvpXjEeB.d.cts → sqlite-Rj3xu4It.d.cts} +2 -468
- package/dist/{store-Ufc1Eoey.d.ts → store-B43FpOVX.d.cts} +84 -5
- package/dist/{store-D7YEMg2v.d.cts → store-De0Y33wP.d.ts} +84 -5
- package/dist/{types-B-sJJ4GQ.d.ts → types-B5GSeE3t.d.ts} +2 -2
- package/dist/{types-CmUA9sal.d.cts → types-Bwlp_yvu.d.cts} +2 -2
- package/dist/{types-CMQymcwk.d.cts → types-CmAT-Z47.d.ts} +250 -46
- package/dist/{types-CQ7xXJMP.d.ts → types-DXCSyxac.d.cts} +250 -46
- package/dist/{where-5zf15aFZ.d.cts → where-2dsyYt3d.d.cts} +2 -2
- package/dist/{where-CtrLu1Zf.d.ts → where-CP4qGIHd.d.ts} +2 -2
- package/package.json +20 -5
- package/dist/chunk-2E4VTD2E.cjs.map +0 -1
- package/dist/chunk-33K3ZYFG.cjs.map +0 -1
- package/dist/chunk-3EUKJEQ3.js +0 -77
- package/dist/chunk-3EUKJEQ3.js.map +0 -1
- package/dist/chunk-4FJVSF3K.cjs +0 -12
- package/dist/chunk-5H3BAMTB.js +0 -32
- package/dist/chunk-5H3BAMTB.js.map +0 -1
- package/dist/chunk-DFHLG75V.js.map +0 -1
- package/dist/chunk-HTGDWIDE.cjs +0 -89
- package/dist/chunk-HTGDWIDE.cjs.map +0 -1
- package/dist/chunk-IUIWCFG3.cjs +0 -36
- package/dist/chunk-IUIWCFG3.cjs.map +0 -1
- package/dist/chunk-LYRUNG6E.cjs +0 -52
- package/dist/chunk-LYRUNG6E.cjs.map +0 -1
- package/dist/chunk-OYLF3IC7.js.map +0 -1
- package/dist/chunk-PCHTTG42.js +0 -47
- package/dist/chunk-PCHTTG42.js.map +0 -1
- package/dist/chunk-PN37HVAV.cjs.map +0 -1
- package/dist/chunk-PYJOBZR3.cjs.map +0 -1
- package/dist/chunk-TSGBRPNE.js.map +0 -1
- package/dist/chunk-U5ROKVRF.js.map +0 -1
- package/dist/chunk-UKG7XHZ3.js.map +0 -1
- package/dist/chunk-WFUN6DCM.cjs.map +0 -1
- package/dist/chunk-WVQXAFP3.js.map +0 -1
- package/dist/chunk-X3244EKP.cjs.map +0 -1
- package/dist/chunk-YEDQLNVE.cjs.map +0 -1
- package/dist/chunk-ZTREJOGB.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
4
|
-
import {
|
|
5
|
-
export {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
export { libsqlVectorStrategy } from './chunk-CUZGBWFT.js';
|
|
2
|
+
import { quoteIdentifier, EMPTY_REQUIRED_COLUMNS, addRequiredColumn, markSelectiveFieldAsRequired, markFieldRefAsRequired, NODE_COLUMNS, shouldProjectColumn, mapSelectiveSystemFieldToColumn, isIdFieldRef, isAggregateExpr, EDGE_COLUMNS } from './chunk-IE2TPFBT.js';
|
|
3
|
+
export { pgvectorStrategy } from './chunk-IE2TPFBT.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-MRMD7S7E.js';
|
|
5
|
+
export { broader, core, defineEdge, defineNode, differentFrom, disjointWith, equivalentTo, hasPart, implies, inverseOf, isMetaEdge, narrower, partOf, relatedTo, sameAs, subClassOf } from './chunk-MRMD7S7E.js';
|
|
6
|
+
import { nowIso, isKnownKind, validateOptionalIsoDate, getNodeKinds, getEdgeKinds } from './chunk-Z36W5WUM.js';
|
|
7
|
+
export { defineGraph, getEdgeKinds, getNodeKinds, isEdgeType, isEdgeTypeWithEndpoints, isGraphDef, isNodeType } from './chunk-Z36W5WUM.js';
|
|
8
|
+
export { defineGraphExtension } from './chunk-BMDF2S7S.js';
|
|
9
|
+
import { IncompatibleChangeError, filterReservedKeys, RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS, RemoveCompileTimeKindError, KindHasReferentsError, validateProjectionField } from './chunk-SFNUHFON.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-SFNUHFON.js';
|
|
11
|
+
export { sqliteVecStrategy } from './chunk-GPUNAJFH.js';
|
|
12
|
+
import { LEGACY_EMBEDDINGS_TABLE_NAME, runOptionallyInTransaction } from './chunk-HKN622O4.js';
|
|
13
|
+
import { isMissingTableError, sortedReplacer, canonicalEqual } from './chunk-M6OC455F.js';
|
|
14
|
+
import { quotedTableName, getDialect, assertVectorMinScore, generateIndexDDL, vectorScoreExpression, vectorMinScoreCondition } from './chunk-7KLVFWXR.js';
|
|
15
|
+
export { andWhere, buildVectorCapabilities, fts5Strategy, notWhere, orWhere, tsvectorStrategy } from './chunk-7KLVFWXR.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-OGUH56BB.js';
|
|
17
|
+
export { defineEdgeIndex, defineNodeIndex } from './chunk-OGUH56BB.js';
|
|
18
|
+
import { createSchemaIntrospector, resolveFieldTypeInfoAtJsonPointer, getSearchableMetadata, DEFAULT_SEARCHABLE_LANGUAGE } from './chunk-N3VVQDMA.js';
|
|
19
|
+
export { DEFAULT_SEARCHABLE_LANGUAGE, getSearchableMetadata, isSearchableSchema, searchable } from './chunk-N3VVQDMA.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, NodeConstraintNotFoundError, RestrictedDeleteError, NodeNotFoundError, EndpointNotFoundError, UniquenessError, CardinalityError, DisjointError } from './chunk-MB363HT5.js';
|
|
23
|
+
export { BackendDisposedError, CardinalityError, CompilerInvariantError, ConfigurationError, DatabaseOperationError, DisjointError, EagerMaterializationError, EdgeNotFoundError, EmbeddingDimensionChangedError, EndpointError, EndpointNotFoundError, KindNotFoundError, MigrationError, NodeConstraintNotFoundError, NodeNotFoundError, RestrictedDeleteError, SchemaContentConflictError, SchemaMismatchError, StaleVersionError, StoreNotInitializedError, TypeGraphError, UniquenessError, UnsupportedPredicateError, ValidationError, VersionConflictError, getErrorSuggestion, isConstraintError, isSystemError, isTypeGraphError, isUserRecoverable } from './chunk-MB363HT5.js';
|
|
21
24
|
import { jsonPointer, parseJsonPointer, normalizeJsonPointer, joinJsonPointers } from './chunk-NZ5PMBTG.js';
|
|
22
25
|
export { MAX_JSON_POINTER_DEPTH, joinJsonPointers, jsonPointer, normalizeJsonPointer, parseJsonPointer } from './chunk-NZ5PMBTG.js';
|
|
23
26
|
import { z } from 'zod';
|
|
@@ -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
|
-
|
|
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
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
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
|
|
2531
|
-
if (
|
|
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 (
|
|
2537
|
-
|
|
2538
|
-
|
|
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
|
|
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,
|
|
4532
|
-
const passState = runSetOperationPassPipeline(
|
|
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
|
|
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,361 +4724,28 @@ function compileSetOperationStandard(op, graphId, dialect, logicalPlan, compileQ
|
|
|
4554
4724
|
...suffixClauses.length === 0 ? {} : { suffixClauses }
|
|
4555
4725
|
});
|
|
4556
4726
|
}
|
|
4557
|
-
function
|
|
4558
|
-
const left =
|
|
4559
|
-
|
|
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
|
-
|
|
4568
|
-
|
|
4732
|
+
compileQuery2,
|
|
4733
|
+
dialect
|
|
4569
4734
|
);
|
|
4570
4735
|
const opSql = sql.raw(OPERATOR_MAP[op.operator]);
|
|
4571
|
-
return sql
|
|
4736
|
+
return sql`${dialect.wrapSetOperationOperand(left)} ${opSql} ${dialect.wrapSetOperationOperand(right)}`;
|
|
4572
4737
|
}
|
|
4573
|
-
function
|
|
4738
|
+
function compileComposableQuery(query, graphId, compileQuery2, dialect) {
|
|
4574
4739
|
if ("__type" in query) {
|
|
4575
|
-
return
|
|
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
|
|
4585
|
-
const
|
|
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
|
|
4616
|
-
|
|
4617
|
-
...allCtes.length === 0 ? {} : { ctes: allCtes },
|
|
4618
|
-
logicalPlan,
|
|
4619
|
-
...suffixClauses.length === 0 ? {} : { suffixClauses }
|
|
4620
|
-
});
|
|
4621
|
-
}
|
|
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");
|
|
4632
|
-
}
|
|
4633
|
-
if (hasFulltextMatchPredicates(ast)) {
|
|
4634
|
-
unsupported.push("fulltext match predicates");
|
|
4635
|
-
}
|
|
4636
|
-
if (ast.groupBy !== void 0) {
|
|
4637
|
-
unsupported.push("GROUP BY");
|
|
4638
|
-
}
|
|
4639
|
-
if (ast.having !== void 0) {
|
|
4640
|
-
unsupported.push("HAVING");
|
|
4641
|
-
}
|
|
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
|
-
);
|
|
4646
|
-
}
|
|
4647
|
-
if (ast.limit !== void 0) {
|
|
4648
|
-
unsupported.push("per-query LIMIT (use set operation's limit instead)");
|
|
4649
|
-
}
|
|
4650
|
-
if (ast.offset !== void 0) {
|
|
4651
|
-
unsupported.push("per-query OFFSET (use set operation's offset instead)");
|
|
4652
|
-
}
|
|
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
|
-
);
|
|
4657
|
-
}
|
|
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}`;
|
|
4747
|
+
if (suffixClauses.length === 0) return core2;
|
|
4748
|
+
return sql.join([core2, ...suffixClauses], sql` `);
|
|
4912
4749
|
}
|
|
4913
4750
|
function getLeftmostProjection(op) {
|
|
4914
4751
|
let current = op.left;
|
|
@@ -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(
|
|
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,9 @@ 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
|
+
...options_.vectorSlots === void 0 ? {} : { vectorSlots: options_.vectorSlots }
|
|
5362
5205
|
};
|
|
5363
5206
|
if (hasVariableLengthTraversal(ast)) {
|
|
5364
5207
|
const lowered = tryLowerSingleHopRecursiveTraversal(ast);
|
|
@@ -5393,14 +5236,13 @@ function tryLowerSingleHopRecursiveTraversal(ast) {
|
|
|
5393
5236
|
function compileSetOperation2(op, graphId, options = "sqlite") {
|
|
5394
5237
|
const options_ = typeof options === "string" ? { dialect: options } : options;
|
|
5395
5238
|
const dialect = options_.dialect ?? "sqlite";
|
|
5396
|
-
const schema = options_.schema ?? DEFAULT_SQL_SCHEMA;
|
|
5397
5239
|
const adapter = resolveDialectAdapter(dialect, options_.fulltextStrategy);
|
|
5398
5240
|
return compileSetOperation(
|
|
5399
5241
|
op,
|
|
5400
5242
|
graphId,
|
|
5401
5243
|
adapter,
|
|
5402
|
-
|
|
5403
|
-
|
|
5244
|
+
(ast, gid) => compileQuery(ast, gid, propagateOptions(options_)),
|
|
5245
|
+
options_.vectorStrategy
|
|
5404
5246
|
);
|
|
5405
5247
|
}
|
|
5406
5248
|
function resolveDialectAdapter(dialect, fulltextStrategy) {
|
|
@@ -5414,7 +5256,9 @@ function propagateOptions(options_) {
|
|
|
5414
5256
|
return {
|
|
5415
5257
|
dialect: options_.dialect ?? "sqlite",
|
|
5416
5258
|
...options_.schema === void 0 ? {} : { schema: options_.schema },
|
|
5417
|
-
...options_.fulltextStrategy === void 0 ? {} : { fulltextStrategy: options_.fulltextStrategy }
|
|
5259
|
+
...options_.fulltextStrategy === void 0 ? {} : { fulltextStrategy: options_.fulltextStrategy },
|
|
5260
|
+
...options_.vectorStrategy === void 0 ? {} : { vectorStrategy: options_.vectorStrategy },
|
|
5261
|
+
...options_.vectorSlots === void 0 ? {} : { vectorSlots: options_.vectorSlots }
|
|
5418
5262
|
};
|
|
5419
5263
|
}
|
|
5420
5264
|
function resolveCountAggregateFastPath(ast) {
|
|
@@ -7005,12 +6849,31 @@ function buildQueryAst(config, state) {
|
|
|
7005
6849
|
// src/query/builder/compile-options.ts
|
|
7006
6850
|
function buildCompileOptions(config) {
|
|
7007
6851
|
const fulltextStrategy = config.backend?.fulltextStrategy;
|
|
6852
|
+
const vectorStrategy = config.backend?.vectorStrategy;
|
|
7008
6853
|
return {
|
|
7009
6854
|
dialect: config.dialect ?? "sqlite",
|
|
7010
6855
|
schema: config.schema,
|
|
7011
|
-
...fulltextStrategy === void 0 ? {} : { fulltextStrategy }
|
|
6856
|
+
...fulltextStrategy === void 0 ? {} : { fulltextStrategy },
|
|
6857
|
+
...vectorStrategy === void 0 ? {} : { vectorStrategy, vectorSlots: buildVectorSlots(config.registry) }
|
|
7012
6858
|
};
|
|
7013
6859
|
}
|
|
6860
|
+
var vectorSlotsCache = /* @__PURE__ */ new WeakMap();
|
|
6861
|
+
function buildVectorSlots(registry) {
|
|
6862
|
+
const cached = vectorSlotsCache.get(registry);
|
|
6863
|
+
if (cached !== void 0) return cached;
|
|
6864
|
+
const slots = /* @__PURE__ */ new Map();
|
|
6865
|
+
for (const [nodeKind, nodeType] of registry.nodeKinds) {
|
|
6866
|
+
for (const field2 of resolveEmbeddingFields(nodeType.schema)) {
|
|
6867
|
+
slots.set(vectorSlotKey(nodeKind, field2.fieldPath), {
|
|
6868
|
+
dimensions: field2.dimensions,
|
|
6869
|
+
metric: field2.metric,
|
|
6870
|
+
indexType: field2.indexType
|
|
6871
|
+
});
|
|
6872
|
+
}
|
|
6873
|
+
}
|
|
6874
|
+
vectorSlotsCache.set(registry, slots);
|
|
6875
|
+
return slots;
|
|
6876
|
+
}
|
|
7014
6877
|
function toLiteral(value) {
|
|
7015
6878
|
if (value === null) {
|
|
7016
6879
|
throw new ConfigurationError(
|
|
@@ -11212,7 +11075,7 @@ async function materializeVectorIndex(declaration, backend, graphId, schemaVersi
|
|
|
11212
11075
|
);
|
|
11213
11076
|
}
|
|
11214
11077
|
const vectorCapability = backend.capabilities.vector;
|
|
11215
|
-
if (vectorCapability?.supported !== true || backend.createVectorIndex === void 0) {
|
|
11078
|
+
if (vectorCapability?.supported !== true || backend.createVectorIndex === void 0 || backend.vectorStrategy === void 0) {
|
|
11216
11079
|
return skippedEntry(
|
|
11217
11080
|
declaration,
|
|
11218
11081
|
`Backend (${backend.dialect}) does not support vector indexes in its current configuration`
|
|
@@ -11224,7 +11087,11 @@ async function materializeVectorIndex(declaration, backend, graphId, schemaVersi
|
|
|
11224
11087
|
`Backend (${backend.dialect}) does not support index type "${declaration.indexType}" for vector indexes; supported: ${vectorCapability.indexTypes.join(", ") || "(none)"}`
|
|
11225
11088
|
);
|
|
11226
11089
|
}
|
|
11227
|
-
const embeddingsTable = backend.
|
|
11090
|
+
const embeddingsTable = backend.vectorStrategy.tableName(
|
|
11091
|
+
graphId,
|
|
11092
|
+
declaration.kind,
|
|
11093
|
+
declaration.fieldPath
|
|
11094
|
+
);
|
|
11228
11095
|
const signature = await computeIndexSignature(
|
|
11229
11096
|
backend.dialect,
|
|
11230
11097
|
embeddingsTable,
|
|
@@ -11387,16 +11254,16 @@ async function materializeRemovals(context, options = {}) {
|
|
|
11387
11254
|
}
|
|
11388
11255
|
await ensureFocusedStatusTable(backend, backend.ensureKindRemovalsTable);
|
|
11389
11256
|
await reconcilePendingRemovals(context);
|
|
11257
|
+
const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(context);
|
|
11390
11258
|
const pending = await backend.getPendingKindRemovals(graphId);
|
|
11391
11259
|
const kindFilter = options.kinds === void 0 ? void 0 : new Set(options.kinds);
|
|
11392
11260
|
const candidates = pending.filter(
|
|
11393
11261
|
(row) => kindFilter === void 0 ? true : kindFilter.has(row.kindName)
|
|
11394
11262
|
);
|
|
11395
|
-
if (candidates.length === 0) return { results: [] };
|
|
11263
|
+
if (candidates.length === 0) return { results: [], reclaimedVectorFields };
|
|
11396
11264
|
const tableNames = backend.tableNames;
|
|
11397
11265
|
const nodesTable = tableNames?.nodes ?? "typegraph_nodes";
|
|
11398
11266
|
const edgesTable = tableNames?.edges ?? "typegraph_edges";
|
|
11399
|
-
const embeddingsTable = tableNames?.embeddings ?? "typegraph_node_embeddings";
|
|
11400
11267
|
const fulltextTable = tableNames?.fulltext ?? "typegraph_node_fulltext";
|
|
11401
11268
|
const uniquesTable = tableNames?.uniques ?? "typegraph_node_uniques";
|
|
11402
11269
|
const ctx = {
|
|
@@ -11404,7 +11271,6 @@ async function materializeRemovals(context, options = {}) {
|
|
|
11404
11271
|
graphId,
|
|
11405
11272
|
nodesTable,
|
|
11406
11273
|
edgesTable,
|
|
11407
|
-
embeddingsTable,
|
|
11408
11274
|
fulltextTable,
|
|
11409
11275
|
uniquesTable
|
|
11410
11276
|
};
|
|
@@ -11413,7 +11279,8 @@ async function materializeRemovals(context, options = {}) {
|
|
|
11413
11279
|
candidates,
|
|
11414
11280
|
options,
|
|
11415
11281
|
(removal) => materializeOne2(removal, ctx)
|
|
11416
|
-
)
|
|
11282
|
+
),
|
|
11283
|
+
reclaimedVectorFields
|
|
11417
11284
|
};
|
|
11418
11285
|
}
|
|
11419
11286
|
async function reconcilePendingRemovals(context) {
|
|
@@ -11500,15 +11367,13 @@ async function materializeOne2(row, ctx) {
|
|
|
11500
11367
|
executeDdl(
|
|
11501
11368
|
`DELETE FROM ${quote(ctx.edgesTable)} WHERE graph_id = ${graphLit} AND (from_kind = ${kindLit} OR to_kind = ${kindLit})`
|
|
11502
11369
|
),
|
|
11503
|
-
executeDdl(
|
|
11504
|
-
`DELETE FROM ${quote(ctx.embeddingsTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
|
|
11505
|
-
),
|
|
11506
11370
|
executeDdl(
|
|
11507
11371
|
`DELETE FROM ${quote(ctx.fulltextTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
|
|
11508
11372
|
),
|
|
11509
11373
|
executeDdl(
|
|
11510
11374
|
`DELETE FROM ${quote(ctx.uniquesTable)} WHERE graph_id = ${graphLit} AND node_kind = ${kindLit}`
|
|
11511
|
-
)
|
|
11375
|
+
),
|
|
11376
|
+
...buildEmbeddingTableCleanup(ctx, row)
|
|
11512
11377
|
);
|
|
11513
11378
|
} else {
|
|
11514
11379
|
deletes.push(
|
|
@@ -11552,6 +11417,128 @@ async function materializeOne2(row, ctx) {
|
|
|
11552
11417
|
};
|
|
11553
11418
|
}
|
|
11554
11419
|
}
|
|
11420
|
+
function buildEmbeddingTableCleanup(ctx, row) {
|
|
11421
|
+
const vectorStrategy = ctx.backend.vectorStrategy;
|
|
11422
|
+
if (vectorStrategy === void 0) return [];
|
|
11423
|
+
const executeDdl = ctx.backend.executeDdl;
|
|
11424
|
+
const cleanup = (async () => {
|
|
11425
|
+
const slots = await resolveRemovedKindEmbeddingSlots(ctx.backend, row);
|
|
11426
|
+
await Promise.all(
|
|
11427
|
+
slots.map(
|
|
11428
|
+
(slot) => dropVectorSlotStorage(vectorStrategy, executeDdl, slot)
|
|
11429
|
+
)
|
|
11430
|
+
);
|
|
11431
|
+
})();
|
|
11432
|
+
return [cleanup];
|
|
11433
|
+
}
|
|
11434
|
+
async function dropVectorSlotStorage(strategy, executeDdl, slot) {
|
|
11435
|
+
try {
|
|
11436
|
+
for (const ddl of strategy.buildDropStorage(slot)) {
|
|
11437
|
+
await executeDdl(ddl);
|
|
11438
|
+
}
|
|
11439
|
+
} catch (error) {
|
|
11440
|
+
if (!isMissingTableError(error)) throw error;
|
|
11441
|
+
}
|
|
11442
|
+
}
|
|
11443
|
+
async function resolveRemovedKindEmbeddingSlots(backend, row) {
|
|
11444
|
+
const priorVersion = row.schemaVersion - 1;
|
|
11445
|
+
if (priorVersion < 1) return [];
|
|
11446
|
+
const priorRow = await backend.getSchemaVersion(row.graphId, priorVersion);
|
|
11447
|
+
if (priorRow === void 0) return [];
|
|
11448
|
+
const priorSchema = parseSerializedSchema(priorRow.schema_doc);
|
|
11449
|
+
const slots = /* @__PURE__ */ new Map();
|
|
11450
|
+
for (const declaration of priorSchema.indexes ?? []) {
|
|
11451
|
+
if (declaration.entity === "vector" && declaration.kind === row.kindName) {
|
|
11452
|
+
slots.set(declaration.fieldPath, {
|
|
11453
|
+
graphId: row.graphId,
|
|
11454
|
+
nodeKind: row.kindName,
|
|
11455
|
+
fieldPath: declaration.fieldPath,
|
|
11456
|
+
dimensions: declaration.dimensions,
|
|
11457
|
+
metric: declaration.metric,
|
|
11458
|
+
indexType: declaration.indexType
|
|
11459
|
+
});
|
|
11460
|
+
}
|
|
11461
|
+
}
|
|
11462
|
+
return [...slots.values()];
|
|
11463
|
+
}
|
|
11464
|
+
function vectorFieldKey(kind, fieldPath) {
|
|
11465
|
+
return `${kind}\0${fieldPath}`;
|
|
11466
|
+
}
|
|
11467
|
+
async function reclaimRemovedVectorFieldTables(context) {
|
|
11468
|
+
const { backend, graphId } = context;
|
|
11469
|
+
const vectorStrategy = backend.vectorStrategy;
|
|
11470
|
+
const executeDdl = backend.executeDdl;
|
|
11471
|
+
if (vectorStrategy === void 0 || executeDdl === void 0) return [];
|
|
11472
|
+
const activeRow = await backend.getActiveSchema(graphId);
|
|
11473
|
+
if (activeRow === void 0) return [];
|
|
11474
|
+
const cacheKey = `${graphId}\0${activeRow.version}`;
|
|
11475
|
+
let perBackend = reclaimCache.get(backend);
|
|
11476
|
+
const cached = perBackend?.get(cacheKey);
|
|
11477
|
+
if (cached !== void 0) return cached;
|
|
11478
|
+
const activeSchema = parseSerializedSchema(activeRow.schema_doc);
|
|
11479
|
+
const activeVectorFields = /* @__PURE__ */ new Set();
|
|
11480
|
+
for (const declaration of activeSchema.indexes ?? []) {
|
|
11481
|
+
if (declaration.entity === "vector") {
|
|
11482
|
+
activeVectorFields.add(
|
|
11483
|
+
vectorFieldKey(declaration.kind, declaration.fieldPath)
|
|
11484
|
+
);
|
|
11485
|
+
}
|
|
11486
|
+
}
|
|
11487
|
+
const survivingKinds = new Set(Object.keys(activeSchema.nodes));
|
|
11488
|
+
const historical = /* @__PURE__ */ new Map();
|
|
11489
|
+
for (let version = activeRow.version - 1; version >= 1; version -= 1) {
|
|
11490
|
+
const priorRow = await backend.getSchemaVersion(graphId, version);
|
|
11491
|
+
if (priorRow === void 0) continue;
|
|
11492
|
+
const priorSchema = parseSerializedSchema(priorRow.schema_doc);
|
|
11493
|
+
for (const declaration of priorSchema.indexes ?? []) {
|
|
11494
|
+
if (declaration.entity !== "vector") continue;
|
|
11495
|
+
const key = vectorFieldKey(declaration.kind, declaration.fieldPath);
|
|
11496
|
+
if (historical.has(key)) continue;
|
|
11497
|
+
historical.set(key, {
|
|
11498
|
+
kind: declaration.kind,
|
|
11499
|
+
fieldPath: declaration.fieldPath,
|
|
11500
|
+
slot: {
|
|
11501
|
+
graphId,
|
|
11502
|
+
nodeKind: declaration.kind,
|
|
11503
|
+
fieldPath: declaration.fieldPath,
|
|
11504
|
+
dimensions: declaration.dimensions,
|
|
11505
|
+
metric: declaration.metric,
|
|
11506
|
+
indexType: declaration.indexType
|
|
11507
|
+
}
|
|
11508
|
+
});
|
|
11509
|
+
}
|
|
11510
|
+
}
|
|
11511
|
+
const orphans = [...historical.values()].filter(
|
|
11512
|
+
(field2) => !activeVectorFields.has(vectorFieldKey(field2.kind, field2.fieldPath)) && survivingKinds.has(field2.kind)
|
|
11513
|
+
);
|
|
11514
|
+
const results = [];
|
|
11515
|
+
for (const field2 of orphans) {
|
|
11516
|
+
try {
|
|
11517
|
+
await dropVectorSlotStorage(vectorStrategy, executeDdl, field2.slot);
|
|
11518
|
+
results.push({
|
|
11519
|
+
kind: field2.kind,
|
|
11520
|
+
fieldPath: field2.fieldPath,
|
|
11521
|
+
status: "reclaimed"
|
|
11522
|
+
});
|
|
11523
|
+
} catch (error) {
|
|
11524
|
+
results.push({
|
|
11525
|
+
kind: field2.kind,
|
|
11526
|
+
fieldPath: field2.fieldPath,
|
|
11527
|
+
status: "failed",
|
|
11528
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
11529
|
+
});
|
|
11530
|
+
}
|
|
11531
|
+
}
|
|
11532
|
+
if (results.every((entry2) => entry2.status === "reclaimed")) {
|
|
11533
|
+
if (perBackend === void 0) {
|
|
11534
|
+
perBackend = /* @__PURE__ */ new Map();
|
|
11535
|
+
reclaimCache.set(backend, perBackend);
|
|
11536
|
+
}
|
|
11537
|
+
perBackend.set(cacheKey, results);
|
|
11538
|
+
}
|
|
11539
|
+
return results;
|
|
11540
|
+
}
|
|
11541
|
+
var reclaimCache = /* @__PURE__ */ new WeakMap();
|
|
11555
11542
|
function quote(identifier) {
|
|
11556
11543
|
return `"${identifier.replaceAll('"', '""')}"`;
|
|
11557
11544
|
}
|
|
@@ -12536,46 +12523,10 @@ var embeddingFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
|
12536
12523
|
function getEmbeddingFields(schema) {
|
|
12537
12524
|
const cached = embeddingFieldsCache.get(schema);
|
|
12538
12525
|
if (cached) return cached;
|
|
12539
|
-
const fields =
|
|
12526
|
+
const fields = resolveEmbeddingFields(schema);
|
|
12540
12527
|
embeddingFieldsCache.set(schema, fields);
|
|
12541
12528
|
return fields;
|
|
12542
12529
|
}
|
|
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
12530
|
async function syncEmbeddings(ctx, schema, props) {
|
|
12580
12531
|
const { backend } = ctx;
|
|
12581
12532
|
if (!backend.upsertEmbedding || !backend.deleteEmbedding) {
|
|
@@ -12594,14 +12545,19 @@ async function syncEmbeddings(ctx, schema, props) {
|
|
|
12594
12545
|
nodeId: ctx.nodeId,
|
|
12595
12546
|
fieldPath: field2.fieldPath,
|
|
12596
12547
|
embedding: value,
|
|
12597
|
-
dimensions: field2.dimensions
|
|
12548
|
+
dimensions: field2.dimensions,
|
|
12549
|
+
metric: field2.metric,
|
|
12550
|
+
indexType: field2.indexType
|
|
12598
12551
|
});
|
|
12599
12552
|
} else if (value === void 0) {
|
|
12600
12553
|
await backend.deleteEmbedding({
|
|
12601
12554
|
graphId: ctx.graphId,
|
|
12602
12555
|
nodeKind: ctx.nodeKind,
|
|
12603
12556
|
nodeId: ctx.nodeId,
|
|
12604
|
-
fieldPath: field2.fieldPath
|
|
12557
|
+
fieldPath: field2.fieldPath,
|
|
12558
|
+
dimensions: field2.dimensions,
|
|
12559
|
+
metric: field2.metric,
|
|
12560
|
+
indexType: field2.indexType
|
|
12605
12561
|
});
|
|
12606
12562
|
}
|
|
12607
12563
|
}
|
|
@@ -12620,7 +12576,10 @@ async function deleteNodeEmbeddings(ctx, schema) {
|
|
|
12620
12576
|
graphId: ctx.graphId,
|
|
12621
12577
|
nodeKind: ctx.nodeKind,
|
|
12622
12578
|
nodeId: ctx.nodeId,
|
|
12623
|
-
fieldPath: field2.fieldPath
|
|
12579
|
+
fieldPath: field2.fieldPath,
|
|
12580
|
+
dimensions: field2.dimensions,
|
|
12581
|
+
metric: field2.metric,
|
|
12582
|
+
indexType: field2.indexType
|
|
12624
12583
|
});
|
|
12625
12584
|
}
|
|
12626
12585
|
}
|
|
@@ -13360,6 +13319,10 @@ async function executeNodeHardDelete(ctx, kind, id, backend) {
|
|
|
13360
13319
|
await enforceDeleteBehavior(ctx, kind, id, "hard", backend, registration);
|
|
13361
13320
|
const hardDelete = async (target) => {
|
|
13362
13321
|
await target.hardDeleteNode({ graphId: ctx.graphId, kind, id });
|
|
13322
|
+
await deleteNodeEmbeddings(
|
|
13323
|
+
createEmbeddingSyncContext(ctx.graphId, kind, id, target),
|
|
13324
|
+
registration.type.schema
|
|
13325
|
+
);
|
|
13363
13326
|
};
|
|
13364
13327
|
await ("transaction" in backend && backend.capabilities.transactions ? backend.transaction(async (tx) => hardDelete(tx)) : hardDelete(backend));
|
|
13365
13328
|
});
|
|
@@ -13829,6 +13792,24 @@ function processPage(schema, rows) {
|
|
|
13829
13792
|
}
|
|
13830
13793
|
|
|
13831
13794
|
// src/store/search.ts
|
|
13795
|
+
function resolveSearchSlot(ctx, nodeKind, fieldPath) {
|
|
13796
|
+
const nodeType = ctx.registry.getNodeType(nodeKind);
|
|
13797
|
+
if (nodeType !== void 0) {
|
|
13798
|
+
const fields = getEmbeddingFields(nodeType.schema);
|
|
13799
|
+
const field2 = fields.find((entry2) => entry2.fieldPath === fieldPath);
|
|
13800
|
+
if (field2 !== void 0) {
|
|
13801
|
+
return {
|
|
13802
|
+
dimensions: field2.dimensions,
|
|
13803
|
+
metric: field2.metric,
|
|
13804
|
+
indexType: field2.indexType
|
|
13805
|
+
};
|
|
13806
|
+
}
|
|
13807
|
+
}
|
|
13808
|
+
throw new ConfigurationError(
|
|
13809
|
+
`Node kind "${nodeKind}" has no embedding field "${fieldPath}". Declare it with embedding(dimensions) on the node schema.`,
|
|
13810
|
+
{ capability: "vector", graphId: ctx.graphId }
|
|
13811
|
+
);
|
|
13812
|
+
}
|
|
13832
13813
|
async function executeFulltextSearch(ctx, nodeKind, options) {
|
|
13833
13814
|
const { backend, graphId } = ctx;
|
|
13834
13815
|
if (!backend.fulltextSearch) {
|
|
@@ -13890,12 +13871,29 @@ async function executeVectorSearch(ctx, nodeKind, options) {
|
|
|
13890
13871
|
);
|
|
13891
13872
|
}
|
|
13892
13873
|
assertEfSearch(options.efSearch, "vectorSearch.efSearch");
|
|
13874
|
+
const slot = resolveSearchSlot(ctx, nodeKind, options.fieldPath);
|
|
13875
|
+
assertVectorQueryCompatible(
|
|
13876
|
+
backend,
|
|
13877
|
+
slot,
|
|
13878
|
+
{ metric: options.metric, queryEmbedding: options.queryEmbedding },
|
|
13879
|
+
"vectorSearch"
|
|
13880
|
+
);
|
|
13881
|
+
assertMinScore(
|
|
13882
|
+
options.minScore,
|
|
13883
|
+
options.metric ?? slot.metric,
|
|
13884
|
+
"vectorSearch.minScore"
|
|
13885
|
+
);
|
|
13893
13886
|
const rows = await backend.vectorSearch({
|
|
13894
13887
|
graphId,
|
|
13895
13888
|
nodeKind,
|
|
13896
13889
|
fieldPath: options.fieldPath,
|
|
13897
13890
|
queryEmbedding: options.queryEmbedding,
|
|
13898
|
-
metric
|
|
13891
|
+
// Default to the field's DECLARED metric (the metric its index was built
|
|
13892
|
+
// for); only an explicit caller override changes it. Defaulting to cosine
|
|
13893
|
+
// here would mis-rank l2 / inner_product fields and bypass their ANN index.
|
|
13894
|
+
metric: options.metric ?? slot.metric,
|
|
13895
|
+
dimensions: slot.dimensions,
|
|
13896
|
+
indexType: slot.indexType,
|
|
13899
13897
|
limit: options.limit,
|
|
13900
13898
|
...options.minScore === void 0 ? {} : { minScore: options.minScore },
|
|
13901
13899
|
...options.efSearch === void 0 ? {} : { efSearch: options.efSearch }
|
|
@@ -13947,12 +13945,30 @@ async function executeHybridSearch(ctx, nodeKind, options) {
|
|
|
13947
13945
|
const overFetchMultiplier = 4;
|
|
13948
13946
|
const vectorK = options.vector.k ?? options.limit * overFetchMultiplier;
|
|
13949
13947
|
const fulltextK = options.fulltext.k ?? options.limit * overFetchMultiplier;
|
|
13948
|
+
const vectorSlot = resolveSearchSlot(ctx, nodeKind, options.vector.fieldPath);
|
|
13949
|
+
assertVectorQueryCompatible(
|
|
13950
|
+
backend,
|
|
13951
|
+
vectorSlot,
|
|
13952
|
+
{
|
|
13953
|
+
metric: options.vector.metric,
|
|
13954
|
+
queryEmbedding: options.vector.queryEmbedding
|
|
13955
|
+
},
|
|
13956
|
+
"hybridSearch.vector"
|
|
13957
|
+
);
|
|
13958
|
+
assertMinScore(
|
|
13959
|
+
options.vector.minScore,
|
|
13960
|
+
options.vector.metric ?? vectorSlot.metric,
|
|
13961
|
+
"hybridSearch.vector.minScore"
|
|
13962
|
+
);
|
|
13950
13963
|
const vectorPromise = backend.vectorSearch({
|
|
13951
13964
|
graphId,
|
|
13952
13965
|
nodeKind,
|
|
13953
13966
|
fieldPath: options.vector.fieldPath,
|
|
13954
13967
|
queryEmbedding: options.vector.queryEmbedding,
|
|
13955
|
-
|
|
13968
|
+
// Default to the field's declared metric (see executeVectorSearch).
|
|
13969
|
+
metric: options.vector.metric ?? vectorSlot.metric,
|
|
13970
|
+
dimensions: vectorSlot.dimensions,
|
|
13971
|
+
indexType: vectorSlot.indexType,
|
|
13956
13972
|
limit: vectorK,
|
|
13957
13973
|
...options.vector.minScore === void 0 ? {} : { minScore: options.vector.minScore },
|
|
13958
13974
|
...options.vector.efSearch === void 0 ? {} : { efSearch: options.vector.efSearch }
|
|
@@ -14043,6 +14059,30 @@ function assertEfSearch(efSearch, label) {
|
|
|
14043
14059
|
);
|
|
14044
14060
|
}
|
|
14045
14061
|
}
|
|
14062
|
+
function assertMinScore(minScore, metric, label) {
|
|
14063
|
+
if (minScore === void 0) return;
|
|
14064
|
+
assertVectorMinScore(minScore, metric, label);
|
|
14065
|
+
}
|
|
14066
|
+
function assertVectorQueryCompatible(backend, slot, options, label) {
|
|
14067
|
+
if (options.metric !== void 0 && options.metric !== slot.metric) {
|
|
14068
|
+
throw new ConfigurationError(
|
|
14069
|
+
`${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}".`,
|
|
14070
|
+
{ backend: backend.dialect, capability: "vector" }
|
|
14071
|
+
);
|
|
14072
|
+
}
|
|
14073
|
+
const supported = backend.capabilities.vector?.metrics;
|
|
14074
|
+
if (supported !== void 0 && !supported.includes(slot.metric)) {
|
|
14075
|
+
throw new ConfigurationError(
|
|
14076
|
+
`${label}: backend "${backend.dialect}" does not support the "${slot.metric}" metric (supported: ${supported.join(", ")}).`,
|
|
14077
|
+
{ backend: backend.dialect, capability: "vector" }
|
|
14078
|
+
);
|
|
14079
|
+
}
|
|
14080
|
+
if (options.queryEmbedding.length !== slot.dimensions) {
|
|
14081
|
+
throw new RangeError(
|
|
14082
|
+
`${label}: queryEmbedding has ${options.queryEmbedding.length} dimensions, but "${slot.dimensions}" are declared for this field.`
|
|
14083
|
+
);
|
|
14084
|
+
}
|
|
14085
|
+
}
|
|
14046
14086
|
function validateFulltextCallOptions(backend, options) {
|
|
14047
14087
|
const strategy = backend.fulltextStrategy;
|
|
14048
14088
|
const capabilities = backend.capabilities.fulltext;
|
|
@@ -14149,7 +14189,11 @@ var StoreSearch = class {
|
|
|
14149
14189
|
async fulltext(nodeKind, options) {
|
|
14150
14190
|
this.#assertKindRegistered(nodeKind);
|
|
14151
14191
|
return executeFulltextSearch(
|
|
14152
|
-
{
|
|
14192
|
+
{
|
|
14193
|
+
graphId: this.#context.graphId,
|
|
14194
|
+
backend: this.#context.backend,
|
|
14195
|
+
registry: this.#context.registry
|
|
14196
|
+
},
|
|
14153
14197
|
nodeKind,
|
|
14154
14198
|
options
|
|
14155
14199
|
);
|
|
@@ -14168,7 +14212,11 @@ var StoreSearch = class {
|
|
|
14168
14212
|
async vector(nodeKind, options) {
|
|
14169
14213
|
this.#assertKindRegistered(nodeKind);
|
|
14170
14214
|
return executeVectorSearch(
|
|
14171
|
-
{
|
|
14215
|
+
{
|
|
14216
|
+
graphId: this.#context.graphId,
|
|
14217
|
+
backend: this.#context.backend,
|
|
14218
|
+
registry: this.#context.registry
|
|
14219
|
+
},
|
|
14172
14220
|
nodeKind,
|
|
14173
14221
|
options
|
|
14174
14222
|
);
|
|
@@ -14185,7 +14233,11 @@ var StoreSearch = class {
|
|
|
14185
14233
|
async hybrid(nodeKind, options) {
|
|
14186
14234
|
this.#assertKindRegistered(nodeKind);
|
|
14187
14235
|
return executeHybridSearch(
|
|
14188
|
-
{
|
|
14236
|
+
{
|
|
14237
|
+
graphId: this.#context.graphId,
|
|
14238
|
+
backend: this.#context.backend,
|
|
14239
|
+
registry: this.#context.registry
|
|
14240
|
+
},
|
|
14189
14241
|
nodeKind,
|
|
14190
14242
|
options
|
|
14191
14243
|
);
|
|
@@ -14234,6 +14286,7 @@ var UNKNOWN_SCHEMA_METADATA = Object.freeze({
|
|
|
14234
14286
|
schemaVersion: void 0,
|
|
14235
14287
|
schemaHash: void 0
|
|
14236
14288
|
});
|
|
14289
|
+
var DEFAULT_REEMBED_BATCH_SIZE = 200;
|
|
14237
14290
|
var CAUGHT_UP_VERB_DETAILS = {
|
|
14238
14291
|
evolve: { phrase: "evolve", code: "EVOLVE_BEFORE_INITIALIZE" },
|
|
14239
14292
|
materialize: {
|
|
@@ -14248,6 +14301,10 @@ var CAUGHT_UP_VERB_DETAILS = {
|
|
|
14248
14301
|
undeprecate: {
|
|
14249
14302
|
phrase: "undeprecate kinds on",
|
|
14250
14303
|
code: "DEPRECATE_BEFORE_INITIALIZE"
|
|
14304
|
+
},
|
|
14305
|
+
reembed: {
|
|
14306
|
+
phrase: "re-embed a vector field on",
|
|
14307
|
+
code: "REEMBED_BEFORE_INITIALIZE"
|
|
14251
14308
|
}
|
|
14252
14309
|
};
|
|
14253
14310
|
var Store = class _Store {
|
|
@@ -14799,7 +14856,7 @@ var Store = class _Store {
|
|
|
14799
14856
|
return fn({ nodes: this.nodes, edges: this.edges });
|
|
14800
14857
|
}
|
|
14801
14858
|
return this.#backend.transaction(
|
|
14802
|
-
async (txBackend,
|
|
14859
|
+
async (txBackend, sql18) => fn(this.#buildTransactionContext(txBackend, sql18))
|
|
14803
14860
|
);
|
|
14804
14861
|
}
|
|
14805
14862
|
/**
|
|
@@ -14876,7 +14933,7 @@ var Store = class _Store {
|
|
|
14876
14933
|
* raw Drizzle handle bound to the same transaction (#140);
|
|
14877
14934
|
* `undefined` only on the non-transactional fallback.
|
|
14878
14935
|
*/
|
|
14879
|
-
#buildTransactionContext(txBackend,
|
|
14936
|
+
#buildTransactionContext(txBackend, sql18) {
|
|
14880
14937
|
const txNodeOperations = {
|
|
14881
14938
|
...this.#nodeOperations,
|
|
14882
14939
|
createQuery: () => this.#createQueryForBackend(txBackend)
|
|
@@ -14899,7 +14956,7 @@ var Store = class _Store {
|
|
|
14899
14956
|
txBackend,
|
|
14900
14957
|
txEdgeOperations
|
|
14901
14958
|
);
|
|
14902
|
-
return
|
|
14959
|
+
return sql18 === void 0 ? { nodes, edges } : { nodes, edges, sql: sql18 };
|
|
14903
14960
|
}
|
|
14904
14961
|
// === Graph Lifecycle ===
|
|
14905
14962
|
/**
|
|
@@ -14916,11 +14973,44 @@ var Store = class _Store {
|
|
|
14916
14973
|
await target.clearGraph(this.graphId);
|
|
14917
14974
|
};
|
|
14918
14975
|
await (this.#backend.capabilities.transactions ? this.#backend.transaction(async (tx) => doClear(tx)) : doClear(this.#backend));
|
|
14976
|
+
await this.#clearVectorStorage();
|
|
14919
14977
|
this.#nodeCollections = void 0;
|
|
14920
14978
|
this.#edgeCollections = void 0;
|
|
14921
14979
|
this.#algorithms = void 0;
|
|
14922
14980
|
this.#search = void 0;
|
|
14923
14981
|
}
|
|
14982
|
+
/**
|
|
14983
|
+
* Resets every declared embedding field's per-field storage for this graph by
|
|
14984
|
+
* dropping and recreating it empty. Drop+recreate (rather than DELETE) mirrors
|
|
14985
|
+
* `reembedVectorField` and keeps the backend's storage-ensure latch valid: the
|
|
14986
|
+
* table still exists after clear, so a later write finds it. Enumerated from
|
|
14987
|
+
* the in-memory registry (not the DB schema, which `clearGraph` just wiped).
|
|
14988
|
+
*/
|
|
14989
|
+
async #clearVectorStorage() {
|
|
14990
|
+
const backend = this.#backend;
|
|
14991
|
+
const strategy = backend.vectorStrategy;
|
|
14992
|
+
if (strategy === void 0 || backend.executeDdl === void 0) return;
|
|
14993
|
+
for (const [nodeKind, nodeType] of this.#registry.nodeKinds) {
|
|
14994
|
+
for (const field2 of resolveEmbeddingFields(nodeType.schema)) {
|
|
14995
|
+
const slot = {
|
|
14996
|
+
graphId: this.graphId,
|
|
14997
|
+
nodeKind,
|
|
14998
|
+
fieldPath: field2.fieldPath,
|
|
14999
|
+
dimensions: field2.dimensions,
|
|
15000
|
+
metric: field2.metric,
|
|
15001
|
+
indexType: field2.indexType
|
|
15002
|
+
};
|
|
15003
|
+
for (const ddl of strategy.buildDropStorage(slot)) {
|
|
15004
|
+
await backend.executeDdl(ddl);
|
|
15005
|
+
}
|
|
15006
|
+
for (const contribution of strategy.ownedTables(slot)) {
|
|
15007
|
+
for (const ddl of contribution.createDdl) {
|
|
15008
|
+
await backend.executeDdl(ddl);
|
|
15009
|
+
}
|
|
15010
|
+
}
|
|
15011
|
+
}
|
|
15012
|
+
}
|
|
15013
|
+
}
|
|
14924
15014
|
// === Lifecycle ===
|
|
14925
15015
|
/**
|
|
14926
15016
|
* Refreshes the backend's query-planner statistics.
|
|
@@ -15144,6 +15234,150 @@ var Store = class _Store {
|
|
|
15144
15234
|
options ?? {}
|
|
15145
15235
|
);
|
|
15146
15236
|
}
|
|
15237
|
+
/**
|
|
15238
|
+
* Recreate a vector field's per-field storage at its current declared
|
|
15239
|
+
* dimension, then optionally re-embed existing rows.
|
|
15240
|
+
*
|
|
15241
|
+
* Use this after changing a field's `embedding(N)` to `embedding(M)` (e.g. a
|
|
15242
|
+
* new embedding model): the stored N-dim vectors are invalid under the new
|
|
15243
|
+
* dimension and must be recomputed, not converted. This drops and recreates
|
|
15244
|
+
* the per-`(graphId, kind, field)` table at the new dimension — a brief
|
|
15245
|
+
* window where the field returns no vector hits — resets its materialization
|
|
15246
|
+
* marker, then, when `options.embed` is supplied, pages the kind's nodes,
|
|
15247
|
+
* calls `embed(batch)`, and upserts the returned vectors. Without `embed`,
|
|
15248
|
+
* storage is recreated empty and the caller re-embeds via normal
|
|
15249
|
+
* `update()` / `upsertEmbedding` writes.
|
|
15250
|
+
*
|
|
15251
|
+
* @throws {ConfigurationError} when the backend has no vector strategy or
|
|
15252
|
+
* cannot execute DDL, or `(kind, fieldPath)` is not a declared embedding.
|
|
15253
|
+
*/
|
|
15254
|
+
async reembedVectorField(kind, fieldPath, options) {
|
|
15255
|
+
if (options?.batchSize !== void 0 && (!Number.isInteger(options.batchSize) || options.batchSize <= 0)) {
|
|
15256
|
+
throw new RangeError(
|
|
15257
|
+
`reembedVectorField batchSize must be a positive integer, got: ${options.batchSize}`
|
|
15258
|
+
);
|
|
15259
|
+
}
|
|
15260
|
+
const { activeRow, baseline } = await this.#loadCaughtUp("reembed");
|
|
15261
|
+
const backend = this.#backend;
|
|
15262
|
+
const strategy = backend.vectorStrategy;
|
|
15263
|
+
if (strategy === void 0 || backend.executeDdl === void 0) {
|
|
15264
|
+
throw new ConfigurationError(
|
|
15265
|
+
"reembedVectorField requires a backend with a vector strategy and executeDdl.",
|
|
15266
|
+
{
|
|
15267
|
+
backend: backend.dialect,
|
|
15268
|
+
capability: "vector",
|
|
15269
|
+
operation: "reembed"
|
|
15270
|
+
}
|
|
15271
|
+
);
|
|
15272
|
+
}
|
|
15273
|
+
const declaration = (baseline.indexes ?? []).find(
|
|
15274
|
+
(candidate) => candidate.entity === "vector" && candidate.kind === kind && candidate.fieldPath === fieldPath
|
|
15275
|
+
);
|
|
15276
|
+
if (declaration === void 0) {
|
|
15277
|
+
throw new ConfigurationError(
|
|
15278
|
+
`No embedding field "${kind}.${fieldPath}" is declared in the active schema.`,
|
|
15279
|
+
{ kind, fieldPath, operation: "reembed" }
|
|
15280
|
+
);
|
|
15281
|
+
}
|
|
15282
|
+
const slot = {
|
|
15283
|
+
graphId: this.graphId,
|
|
15284
|
+
nodeKind: kind,
|
|
15285
|
+
fieldPath,
|
|
15286
|
+
dimensions: declaration.dimensions,
|
|
15287
|
+
metric: declaration.metric,
|
|
15288
|
+
indexType: declaration.indexType
|
|
15289
|
+
};
|
|
15290
|
+
for (const ddl of strategy.buildDropStorage(slot)) {
|
|
15291
|
+
await backend.executeDdl(ddl);
|
|
15292
|
+
}
|
|
15293
|
+
for (const contribution of strategy.ownedTables(slot)) {
|
|
15294
|
+
for (const ddl of contribution.createDdl) {
|
|
15295
|
+
await backend.executeDdl(ddl);
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15298
|
+
const declaredIndexMaterializes = declaration.indexType !== "none" && backend.capabilities.vector?.indexTypes.includes(
|
|
15299
|
+
declaration.indexType
|
|
15300
|
+
) === true;
|
|
15301
|
+
if (declaredIndexMaterializes && backend.createVectorIndex !== void 0) {
|
|
15302
|
+
await backend.createVectorIndex({
|
|
15303
|
+
graphId: this.graphId,
|
|
15304
|
+
nodeKind: kind,
|
|
15305
|
+
fieldPath,
|
|
15306
|
+
dimensions: declaration.dimensions,
|
|
15307
|
+
metric: declaration.metric,
|
|
15308
|
+
indexType: declaration.indexType,
|
|
15309
|
+
indexParams: {
|
|
15310
|
+
m: declaration.indexParams.m,
|
|
15311
|
+
efConstruction: declaration.indexParams.efConstruction,
|
|
15312
|
+
...declaration.indexParams.lists === void 0 ? {} : { lists: declaration.indexParams.lists }
|
|
15313
|
+
}
|
|
15314
|
+
});
|
|
15315
|
+
}
|
|
15316
|
+
if (declaredIndexMaterializes && backend.recordIndexMaterialization !== void 0) {
|
|
15317
|
+
const tableName = strategy.tableName(this.graphId, kind, fieldPath);
|
|
15318
|
+
const signature = await computeIndexSignature(
|
|
15319
|
+
backend.dialect,
|
|
15320
|
+
tableName,
|
|
15321
|
+
declaration
|
|
15322
|
+
);
|
|
15323
|
+
const now = nowIso();
|
|
15324
|
+
await backend.recordIndexMaterialization({
|
|
15325
|
+
indexName: vectorStatusKey(this.graphId, declaration.name),
|
|
15326
|
+
graphId: this.graphId,
|
|
15327
|
+
entity: "vector",
|
|
15328
|
+
kind,
|
|
15329
|
+
signature,
|
|
15330
|
+
schemaVersion: activeRow.version,
|
|
15331
|
+
attemptedAt: now,
|
|
15332
|
+
materializedAt: now,
|
|
15333
|
+
error: void 0
|
|
15334
|
+
});
|
|
15335
|
+
}
|
|
15336
|
+
if (options?.embed === void 0) {
|
|
15337
|
+
return { recreated: true, reembedded: 0 };
|
|
15338
|
+
}
|
|
15339
|
+
if (backend.upsertEmbedding === void 0) {
|
|
15340
|
+
throw new ConfigurationError(
|
|
15341
|
+
"reembedVectorField with an `embed` callback requires a backend that supports upsertEmbedding.",
|
|
15342
|
+
{
|
|
15343
|
+
backend: backend.dialect,
|
|
15344
|
+
capability: "vector",
|
|
15345
|
+
operation: "reembed"
|
|
15346
|
+
}
|
|
15347
|
+
);
|
|
15348
|
+
}
|
|
15349
|
+
const upsertEmbedding = backend.upsertEmbedding;
|
|
15350
|
+
const batchSize = options.batchSize ?? DEFAULT_REEMBED_BATCH_SIZE;
|
|
15351
|
+
const collection = this.getNodeCollectionOrThrow(kind);
|
|
15352
|
+
let reembedded = 0;
|
|
15353
|
+
let offset = 0;
|
|
15354
|
+
for (; ; ) {
|
|
15355
|
+
const batch = await collection.find({
|
|
15356
|
+
limit: batchSize,
|
|
15357
|
+
offset
|
|
15358
|
+
});
|
|
15359
|
+
if (batch.length === 0) break;
|
|
15360
|
+
const vectors = await options.embed(batch);
|
|
15361
|
+
for (const node of batch) {
|
|
15362
|
+
const embedding2 = vectors.get(node.id);
|
|
15363
|
+
if (embedding2 === void 0) continue;
|
|
15364
|
+
await upsertEmbedding({
|
|
15365
|
+
graphId: this.graphId,
|
|
15366
|
+
nodeKind: kind,
|
|
15367
|
+
nodeId: node.id,
|
|
15368
|
+
fieldPath,
|
|
15369
|
+
embedding: embedding2,
|
|
15370
|
+
dimensions: declaration.dimensions,
|
|
15371
|
+
metric: declaration.metric,
|
|
15372
|
+
indexType: declaration.indexType
|
|
15373
|
+
});
|
|
15374
|
+
reembedded += 1;
|
|
15375
|
+
}
|
|
15376
|
+
offset += batch.length;
|
|
15377
|
+
if (batch.length < batchSize) break;
|
|
15378
|
+
}
|
|
15379
|
+
return { recreated: true, reembedded };
|
|
15380
|
+
}
|
|
15147
15381
|
/**
|
|
15148
15382
|
* Removes extension kinds from the schema with cascading edge and
|
|
15149
15383
|
* ontology cleanup. Two-phase by design:
|
|
@@ -15521,6 +15755,6 @@ async function createVerifiedStore(graph, backend, options) {
|
|
|
15521
15755
|
return [store, result];
|
|
15522
15756
|
}
|
|
15523
15757
|
|
|
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 };
|
|
15758
|
+
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
15759
|
//# sourceMappingURL=index.js.map
|
|
15526
15760
|
//# sourceMappingURL=index.js.map
|