@nicia-ai/typegraph 0.20.0 → 0.21.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/{ast-Bh2NDeaK.d.cts → ast-CSLbPIOC.d.ts} +56 -3
- package/dist/{ast-COMyNeMn.d.ts → ast-DogwbBqA.d.cts} +56 -3
- package/dist/backend/postgres/index.cjs +123 -45
- package/dist/backend/postgres/index.cjs.map +1 -1
- package/dist/backend/postgres/index.d.cts +15 -7
- package/dist/backend/postgres/index.d.ts +15 -7
- package/dist/backend/postgres/index.js +101 -23
- package/dist/backend/postgres/index.js.map +1 -1
- package/dist/backend/sqlite/index.cjs +15 -15
- package/dist/backend/sqlite/index.d.cts +11 -7
- package/dist/backend/sqlite/index.d.ts +11 -7
- package/dist/backend/sqlite/index.js +5 -5
- package/dist/backend/sqlite/libsql.cjs +8 -8
- package/dist/backend/sqlite/libsql.d.cts +4 -5
- package/dist/backend/sqlite/libsql.d.ts +4 -5
- package/dist/backend/sqlite/libsql.js +5 -5
- package/dist/backend/sqlite/local.cjs +9 -9
- package/dist/backend/sqlite/local.d.cts +4 -5
- package/dist/backend/sqlite/local.d.ts +4 -5
- package/dist/backend/sqlite/local.js +5 -5
- package/dist/{chunk-LELLOHJK.cjs → chunk-2X7P7AD5.cjs} +35 -35
- package/dist/{chunk-LELLOHJK.cjs.map → chunk-2X7P7AD5.cjs.map} +1 -1
- package/dist/{chunk-GNIYZKBI.js → chunk-4XNE2JG3.js} +376 -8
- package/dist/chunk-4XNE2JG3.js.map +1 -0
- package/dist/{chunk-HXJXTOXR.cjs → chunk-CQL6FOTT.cjs} +82 -21
- package/dist/chunk-CQL6FOTT.cjs.map +1 -0
- package/dist/{chunk-K7SQ3SWP.js → chunk-EYELZHKY.js} +120 -12
- package/dist/chunk-EYELZHKY.js.map +1 -0
- package/dist/{chunk-MME3H4ZF.cjs → chunk-FQCQM3KG.cjs} +385 -9
- package/dist/chunk-FQCQM3KG.cjs.map +1 -0
- package/dist/{chunk-X33WV2UF.cjs → chunk-HRNQ3DVJ.cjs} +24 -21
- package/dist/chunk-HRNQ3DVJ.cjs.map +1 -0
- package/dist/{chunk-W6M7XWKX.js → chunk-JYUQA77I.js} +21 -18
- package/dist/chunk-JYUQA77I.js.map +1 -0
- package/dist/{chunk-LLHFS53Q.js → chunk-NRNJ52AA.js} +72 -11
- package/dist/chunk-NRNJ52AA.js.map +1 -0
- package/dist/{chunk-IYWWXOVK.cjs → chunk-Q73OWTJY.cjs} +204 -89
- package/dist/chunk-Q73OWTJY.cjs.map +1 -0
- package/dist/{chunk-G5CYWKRF.js → chunk-RS5OLGEW.js} +2 -2
- package/dist/{chunk-G5CYWKRF.js.map → chunk-RS5OLGEW.js.map} +1 -1
- package/dist/{chunk-6GWJH6AR.js → chunk-SMMOAVJ5.js} +4 -4
- package/dist/{chunk-6GWJH6AR.js.map → chunk-SMMOAVJ5.js.map} +1 -1
- package/dist/{chunk-QFZQGEQ3.js → chunk-UQVBVBVG.js} +151 -36
- package/dist/chunk-UQVBVBVG.js.map +1 -0
- package/dist/{chunk-P5CNM325.cjs → chunk-UVZHTBZ5.cjs} +123 -11
- package/dist/chunk-UVZHTBZ5.cjs.map +1 -0
- package/dist/{chunk-5GZMPJOP.cjs → chunk-WRWVWKQL.cjs} +2 -2
- package/dist/{chunk-5GZMPJOP.cjs.map → chunk-WRWVWKQL.cjs.map} +1 -1
- package/dist/{ddl-BBo2EcFc.d.cts → ddl-BqkTShcR.d.ts} +28 -6
- package/dist/{ddl-D4jlcOH_.d.ts → ddl-Dk1NDN3M.d.cts} +28 -6
- package/dist/index.cjs +1705 -490
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -10
- package/dist/index.d.ts +8 -10
- package/dist/index.js +1552 -361
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +17 -17
- package/dist/indexes/index.d.cts +5 -5
- package/dist/indexes/index.d.ts +5 -5
- package/dist/indexes/index.js +3 -3
- package/dist/interchange/index.cjs +6 -6
- package/dist/interchange/index.d.cts +4 -5
- package/dist/interchange/index.d.ts +4 -5
- package/dist/interchange/index.js +1 -1
- package/dist/{manager-Chhrq1vl.d.ts → manager-0jVZtiE8.d.ts} +1 -2
- package/dist/{manager-Bj1UEnhE.d.cts → manager-BPK-2PUI.d.cts} +1 -2
- package/dist/profiler/index.cjs +15 -8
- package/dist/profiler/index.cjs.map +1 -1
- package/dist/profiler/index.d.cts +7 -8
- package/dist/profiler/index.d.ts +7 -8
- package/dist/profiler/index.js +8 -1
- package/dist/profiler/index.js.map +1 -1
- package/dist/schema/index.cjs +21 -21
- package/dist/schema/index.d.cts +4 -5
- package/dist/schema/index.d.ts +4 -5
- package/dist/schema/index.js +3 -3
- package/dist/{sqlite-DE-6NWtC.d.cts → sqlite-D1rrwcir.d.cts} +14 -1
- package/dist/{sqlite-Blq-AhmK.d.ts → sqlite-W3rmJMlc.d.ts} +14 -1
- package/dist/{store-BMrRi_mY.d.ts → store-2QW2SIRk.d.cts} +404 -5
- package/dist/{store-DRRvALu8.d.cts → store-C0q13mtJ.d.ts} +404 -5
- package/dist/{types-B3mmOMJV.d.cts → types-CQF88McG.d.cts} +475 -2
- package/dist/{types-ThB4cFLp.d.ts → types-CQF88McG.d.ts} +475 -2
- package/dist/{types-COPePE8_.d.ts → types-CglvhPKz.d.ts} +1 -1
- package/dist/{types-CVtGFpB9.d.cts → types-D23slCOA.d.cts} +1 -1
- package/dist/{types-Ceb01czq.d.ts → types-IMQCuser.d.ts} +2 -2
- package/dist/{types-CZd2PEOc.d.cts → types-vgjar7Ch.d.cts} +2 -2
- package/package.json +9 -9
- package/dist/chunk-GNIYZKBI.js.map +0 -1
- package/dist/chunk-HXJXTOXR.cjs.map +0 -1
- package/dist/chunk-IYWWXOVK.cjs.map +0 -1
- package/dist/chunk-K7SQ3SWP.js.map +0 -1
- package/dist/chunk-LLHFS53Q.js.map +0 -1
- package/dist/chunk-MME3H4ZF.cjs.map +0 -1
- package/dist/chunk-P5CNM325.cjs.map +0 -1
- package/dist/chunk-QFZQGEQ3.js.map +0 -1
- package/dist/chunk-W6M7XWKX.js.map +0 -1
- package/dist/chunk-X33WV2UF.cjs.map +0 -1
- package/dist/types-DMzKq0d5.d.cts +0 -181
- package/dist/types-DMzKq0d5.d.ts +0 -181
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkHRNQ3DVJ_cjs = require('./chunk-HRNQ3DVJ.cjs');
|
|
4
|
+
var chunkWRWVWKQL_cjs = require('./chunk-WRWVWKQL.cjs');
|
|
5
5
|
var chunkO5PST6TB_cjs = require('./chunk-O5PST6TB.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var chunkFQCQM3KG_cjs = require('./chunk-FQCQM3KG.cjs');
|
|
7
|
+
var chunkUVZHTBZ5_cjs = require('./chunk-UVZHTBZ5.cjs');
|
|
8
8
|
var zod = require('zod');
|
|
9
9
|
var drizzleOrm = require('drizzle-orm');
|
|
10
10
|
var nanoid = require('nanoid');
|
|
@@ -29,6 +29,44 @@ var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
|
29
29
|
"constructor",
|
|
30
30
|
"prototype"
|
|
31
31
|
]);
|
|
32
|
+
var RESERVED_PROPERTY_PREFIX = "$";
|
|
33
|
+
function isReservedPropertyName(name) {
|
|
34
|
+
return name.startsWith(RESERVED_PROPERTY_PREFIX);
|
|
35
|
+
}
|
|
36
|
+
function assertSchemaKeysAreFree(entityKind, name, keys, reservedStructuralKeys) {
|
|
37
|
+
const structuralConflicts = keys.filter(
|
|
38
|
+
(key) => reservedStructuralKeys.has(key)
|
|
39
|
+
);
|
|
40
|
+
if (structuralConflicts.length > 0) {
|
|
41
|
+
const label = entityKind.toLowerCase();
|
|
42
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
43
|
+
`${entityKind} "${name}" schema contains reserved property names: ${structuralConflicts.join(", ")}`,
|
|
44
|
+
{
|
|
45
|
+
[`${label}Type`]: name,
|
|
46
|
+
conflicts: structuralConflicts,
|
|
47
|
+
reservedKeys: [...reservedStructuralKeys]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
suggestion: `Rename the conflicting properties. Reserved names (${[...reservedStructuralKeys].join(", ")}) are added automatically to all ${label}s.`
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const prefixConflicts = keys.filter((key) => isReservedPropertyName(key));
|
|
55
|
+
if (prefixConflicts.length > 0) {
|
|
56
|
+
const label = entityKind.toLowerCase();
|
|
57
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
58
|
+
`${entityKind} "${name}" schema uses the reserved "${RESERVED_PROPERTY_PREFIX}" prefix on: ${prefixConflicts.join(", ")}`,
|
|
59
|
+
{
|
|
60
|
+
[`${label}Type`]: name,
|
|
61
|
+
conflicts: prefixConflicts,
|
|
62
|
+
reservedPrefix: RESERVED_PROPERTY_PREFIX
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
suggestion: `Property names starting with "${RESERVED_PROPERTY_PREFIX}" are reserved for TypeGraph accessors (e.g. $fulltext). Rename each field.`
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
32
70
|
function validateProjectionField(field2, entityType, kind) {
|
|
33
71
|
const reserved = entityType === "node" ? RESERVED_NODE_KEYS : RESERVED_EDGE_KEYS;
|
|
34
72
|
if (reserved.has(field2)) {
|
|
@@ -62,24 +100,17 @@ function filterReservedKeys(props, reservedKeys) {
|
|
|
62
100
|
|
|
63
101
|
// src/core/node.ts
|
|
64
102
|
function validateSchemaKeys(schema, name) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
103
|
+
assertSchemaKeysAreFree(
|
|
104
|
+
"Node",
|
|
105
|
+
name,
|
|
106
|
+
Object.keys(schema.shape),
|
|
107
|
+
RESERVED_NODE_KEYS
|
|
68
108
|
);
|
|
69
|
-
if (conflicts.length > 0) {
|
|
70
|
-
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
71
|
-
`Node "${name}" schema contains reserved property names: ${conflicts.join(", ")}`,
|
|
72
|
-
{ nodeType: name, conflicts, reservedKeys: [...RESERVED_NODE_KEYS] },
|
|
73
|
-
{
|
|
74
|
-
suggestion: `Rename the conflicting properties. Reserved names (id, kind, meta) are added automatically to all nodes.`
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
109
|
}
|
|
79
110
|
function defineNode(name, options) {
|
|
80
111
|
validateSchemaKeys(options.schema, name);
|
|
81
112
|
return Object.freeze({
|
|
82
|
-
[
|
|
113
|
+
[chunkWRWVWKQL_cjs.NODE_TYPE_BRAND]: true,
|
|
83
114
|
kind: name,
|
|
84
115
|
schema: options.schema,
|
|
85
116
|
description: options.description
|
|
@@ -87,25 +118,18 @@ function defineNode(name, options) {
|
|
|
87
118
|
}
|
|
88
119
|
var EMPTY_SCHEMA = zod.z.object({});
|
|
89
120
|
function validateSchemaKeys2(schema, name) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
assertSchemaKeysAreFree(
|
|
122
|
+
"Edge",
|
|
123
|
+
name,
|
|
124
|
+
Object.keys(schema.shape),
|
|
125
|
+
RESERVED_EDGE_KEYS
|
|
93
126
|
);
|
|
94
|
-
if (conflicts.length > 0) {
|
|
95
|
-
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
96
|
-
`Edge "${name}" schema contains reserved property names: ${conflicts.join(", ")}`,
|
|
97
|
-
{ edgeType: name, conflicts, reservedKeys: [...RESERVED_EDGE_KEYS] },
|
|
98
|
-
{
|
|
99
|
-
suggestion: `Rename the conflicting properties. Reserved names are added automatically to all edges.`
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
127
|
}
|
|
104
128
|
function defineEdge(name, options) {
|
|
105
129
|
const schema = options?.schema ?? EMPTY_SCHEMA;
|
|
106
130
|
validateSchemaKeys2(schema, name);
|
|
107
131
|
return Object.freeze({
|
|
108
|
-
[
|
|
132
|
+
[chunkWRWVWKQL_cjs.EDGE_TYPE_BRAND]: true,
|
|
109
133
|
kind: name,
|
|
110
134
|
schema,
|
|
111
135
|
description: options?.description,
|
|
@@ -125,7 +149,7 @@ function metaEdge(name, options = {}) {
|
|
|
125
149
|
description: options.description
|
|
126
150
|
};
|
|
127
151
|
return Object.freeze({
|
|
128
|
-
[
|
|
152
|
+
[chunkHRNQ3DVJ_cjs.META_EDGE_BRAND]: true,
|
|
129
153
|
name,
|
|
130
154
|
properties
|
|
131
155
|
});
|
|
@@ -161,7 +185,7 @@ function createExternalRef(table) {
|
|
|
161
185
|
// src/ontology/core-meta-edges.ts
|
|
162
186
|
function createMetaEdge(name, properties) {
|
|
163
187
|
return Object.freeze({
|
|
164
|
-
[
|
|
188
|
+
[chunkHRNQ3DVJ_cjs.META_EDGE_BRAND]: true,
|
|
165
189
|
name,
|
|
166
190
|
properties: {
|
|
167
191
|
transitive: properties.transitive ?? false,
|
|
@@ -173,7 +197,7 @@ function createMetaEdge(name, properties) {
|
|
|
173
197
|
}
|
|
174
198
|
});
|
|
175
199
|
}
|
|
176
|
-
var subClassOfMetaEdge = createMetaEdge(
|
|
200
|
+
var subClassOfMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_SUB_CLASS_OF, {
|
|
177
201
|
transitive: true,
|
|
178
202
|
inference: "subsumption",
|
|
179
203
|
description: "Type inheritance (Podcast subClassOf Media)"
|
|
@@ -185,9 +209,9 @@ function subClassOf(child, parent) {
|
|
|
185
209
|
to: parent
|
|
186
210
|
};
|
|
187
211
|
}
|
|
188
|
-
var broaderMetaEdge = createMetaEdge(
|
|
212
|
+
var broaderMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_BROADER, {
|
|
189
213
|
transitive: true,
|
|
190
|
-
inverse:
|
|
214
|
+
inverse: chunkHRNQ3DVJ_cjs.META_EDGE_NARROWER,
|
|
191
215
|
inference: "hierarchy",
|
|
192
216
|
description: "Broader concept (ML broader AI)"
|
|
193
217
|
});
|
|
@@ -198,9 +222,9 @@ function broader(narrowerConcept, broaderConcept) {
|
|
|
198
222
|
to: broaderConcept
|
|
199
223
|
};
|
|
200
224
|
}
|
|
201
|
-
var narrowerMetaEdge = createMetaEdge(
|
|
225
|
+
var narrowerMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_NARROWER, {
|
|
202
226
|
transitive: true,
|
|
203
|
-
inverse:
|
|
227
|
+
inverse: chunkHRNQ3DVJ_cjs.META_EDGE_BROADER,
|
|
204
228
|
inference: "hierarchy",
|
|
205
229
|
description: "Narrower concept (AI narrower ML)"
|
|
206
230
|
});
|
|
@@ -211,7 +235,7 @@ function narrower(broaderConcept, narrowerConcept) {
|
|
|
211
235
|
to: narrowerConcept
|
|
212
236
|
};
|
|
213
237
|
}
|
|
214
|
-
var relatedToMetaEdge = createMetaEdge(
|
|
238
|
+
var relatedToMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_RELATED_TO, {
|
|
215
239
|
symmetric: true,
|
|
216
240
|
inference: "association",
|
|
217
241
|
description: "Non-hierarchical association"
|
|
@@ -223,7 +247,7 @@ function relatedTo(conceptA, conceptB) {
|
|
|
223
247
|
to: conceptB
|
|
224
248
|
};
|
|
225
249
|
}
|
|
226
|
-
var equivalentToMetaEdge = createMetaEdge(
|
|
250
|
+
var equivalentToMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_EQUIVALENT_TO, {
|
|
227
251
|
symmetric: true,
|
|
228
252
|
transitive: true,
|
|
229
253
|
inference: "substitution",
|
|
@@ -236,7 +260,7 @@ function equivalentTo(kindA, kindBOrIri) {
|
|
|
236
260
|
to: kindBOrIri
|
|
237
261
|
};
|
|
238
262
|
}
|
|
239
|
-
var sameAsMetaEdge = createMetaEdge(
|
|
263
|
+
var sameAsMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_SAME_AS, {
|
|
240
264
|
symmetric: true,
|
|
241
265
|
transitive: true,
|
|
242
266
|
inference: "substitution",
|
|
@@ -249,7 +273,7 @@ function sameAs(kindA, kindBOrIri) {
|
|
|
249
273
|
to: kindBOrIri
|
|
250
274
|
};
|
|
251
275
|
}
|
|
252
|
-
var differentFromMetaEdge = createMetaEdge(
|
|
276
|
+
var differentFromMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_DIFFERENT_FROM, {
|
|
253
277
|
symmetric: true,
|
|
254
278
|
inference: "constraint",
|
|
255
279
|
description: "Explicitly different individuals"
|
|
@@ -261,7 +285,7 @@ function differentFrom(kindA, kindB) {
|
|
|
261
285
|
to: kindB
|
|
262
286
|
};
|
|
263
287
|
}
|
|
264
|
-
var disjointWithMetaEdge = createMetaEdge(
|
|
288
|
+
var disjointWithMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_DISJOINT_WITH, {
|
|
265
289
|
symmetric: true,
|
|
266
290
|
inference: "constraint",
|
|
267
291
|
description: "Mutually exclusive types"
|
|
@@ -273,9 +297,9 @@ function disjointWith(kindA, kindB) {
|
|
|
273
297
|
to: kindB
|
|
274
298
|
};
|
|
275
299
|
}
|
|
276
|
-
var partOfMetaEdge = createMetaEdge(
|
|
300
|
+
var partOfMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_PART_OF, {
|
|
277
301
|
transitive: true,
|
|
278
|
-
inverse:
|
|
302
|
+
inverse: chunkHRNQ3DVJ_cjs.META_EDGE_HAS_PART,
|
|
279
303
|
inference: "composition",
|
|
280
304
|
description: "X is part of Y"
|
|
281
305
|
});
|
|
@@ -286,9 +310,9 @@ function partOf(part, whole) {
|
|
|
286
310
|
to: whole
|
|
287
311
|
};
|
|
288
312
|
}
|
|
289
|
-
var hasPartMetaEdge = createMetaEdge(
|
|
313
|
+
var hasPartMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_HAS_PART, {
|
|
290
314
|
transitive: true,
|
|
291
|
-
inverse:
|
|
315
|
+
inverse: chunkHRNQ3DVJ_cjs.META_EDGE_PART_OF,
|
|
292
316
|
inference: "composition",
|
|
293
317
|
description: "Y has part X"
|
|
294
318
|
});
|
|
@@ -299,12 +323,12 @@ function hasPart(whole, part) {
|
|
|
299
323
|
to: part
|
|
300
324
|
};
|
|
301
325
|
}
|
|
302
|
-
var inverseOfMetaEdge = createMetaEdge(
|
|
326
|
+
var inverseOfMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_INVERSE_OF, {
|
|
303
327
|
symmetric: true,
|
|
304
328
|
inference: "none",
|
|
305
329
|
description: "Edge A is inverse of edge B"
|
|
306
330
|
});
|
|
307
|
-
var impliesMetaEdge = createMetaEdge(
|
|
331
|
+
var impliesMetaEdge = createMetaEdge(chunkHRNQ3DVJ_cjs.META_EDGE_IMPLIES, {
|
|
308
332
|
transitive: true,
|
|
309
333
|
inference: "none",
|
|
310
334
|
description: "Edge A implies edge B exists"
|
|
@@ -565,6 +589,41 @@ function stringField(field2) {
|
|
|
565
589
|
ilike: (pattern) => stringOp("ilike", field2, pattern)
|
|
566
590
|
};
|
|
567
591
|
}
|
|
592
|
+
var DEFAULT_FULLTEXT_MATCH_K = 50;
|
|
593
|
+
function createFulltextAccessor(alias, hasSearchableField) {
|
|
594
|
+
return {
|
|
595
|
+
matches: (query, k, options) => {
|
|
596
|
+
if (!hasSearchableField()) {
|
|
597
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
598
|
+
`Cannot call .$fulltext.matches() on alias "${alias}" \u2014 its node kind has no fields declared with searchable(). Add at least one: \`title: searchable({ language: "english" })\`.`
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
return fulltextMatch(
|
|
602
|
+
fieldRef(alias, ["$fulltext"]),
|
|
603
|
+
query,
|
|
604
|
+
k ?? DEFAULT_FULLTEXT_MATCH_K,
|
|
605
|
+
options
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function fulltextMatch(field2, query, limit, options) {
|
|
611
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
612
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
613
|
+
`matches() limit must be a positive finite number, got ${String(limit)}`
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
const expr = {
|
|
617
|
+
__type: "fulltext_match",
|
|
618
|
+
field: field2,
|
|
619
|
+
query,
|
|
620
|
+
mode: options?.mode ?? "websearch",
|
|
621
|
+
limit,
|
|
622
|
+
...options?.language === void 0 ? {} : { language: options.language },
|
|
623
|
+
...options?.minScore === void 0 ? {} : { minScore: options.minScore }
|
|
624
|
+
};
|
|
625
|
+
return predicate(expr);
|
|
626
|
+
}
|
|
568
627
|
function numberField(field2) {
|
|
569
628
|
return {
|
|
570
629
|
...baseFieldBuilder(field2),
|
|
@@ -664,7 +723,7 @@ function buildFieldBuilderForTypeInfo(field2, typeInfo) {
|
|
|
664
723
|
}
|
|
665
724
|
}
|
|
666
725
|
function resolvePointerTypeInfo(typeInfo, pointer) {
|
|
667
|
-
return
|
|
726
|
+
return chunkUVZHTBZ5_cjs.resolveFieldTypeInfoAtJsonPointer(typeInfo, pointer);
|
|
668
727
|
}
|
|
669
728
|
function objectOp(op, field2, pointer, value, options) {
|
|
670
729
|
const expr = {
|
|
@@ -687,8 +746,8 @@ function objectField(field2, options) {
|
|
|
687
746
|
return {
|
|
688
747
|
...baseFieldBuilder(field2),
|
|
689
748
|
get: (key) => {
|
|
690
|
-
const pointer =
|
|
691
|
-
const nestedPointer =
|
|
749
|
+
const pointer = chunkUVZHTBZ5_cjs.jsonPointer([key]);
|
|
750
|
+
const nestedPointer = chunkUVZHTBZ5_cjs.joinJsonPointers(basePointer, pointer);
|
|
692
751
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, pointer);
|
|
693
752
|
const nestedRef = fieldRef(field2.alias, field2.path, {
|
|
694
753
|
jsonPointer: nestedPointer,
|
|
@@ -702,17 +761,17 @@ function objectField(field2, options) {
|
|
|
702
761
|
return buildFieldBuilderForTypeInfo(nestedRef, resolved);
|
|
703
762
|
},
|
|
704
763
|
hasKey: (key) => {
|
|
705
|
-
const pointer =
|
|
764
|
+
const pointer = chunkUVZHTBZ5_cjs.jsonPointer([key]);
|
|
706
765
|
resolvePointerTypeInfo(options?.typeInfo, pointer);
|
|
707
766
|
return objectOp("hasKey", field2, pointer);
|
|
708
767
|
},
|
|
709
768
|
hasPath: (pointer) => {
|
|
710
|
-
const normalized =
|
|
769
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
711
770
|
resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
712
771
|
return objectOp("hasPath", field2, normalized);
|
|
713
772
|
},
|
|
714
773
|
pathEquals: (pointer, value) => {
|
|
715
|
-
const normalized =
|
|
774
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
716
775
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
717
776
|
if (resolved && (resolved.valueType === "array" || resolved.valueType === "object")) {
|
|
718
777
|
throw new Error("pathEquals is only supported for scalar JSON values");
|
|
@@ -721,7 +780,7 @@ function objectField(field2, options) {
|
|
|
721
780
|
return objectOp("pathEquals", field2, normalized, value, predicateOptions);
|
|
722
781
|
},
|
|
723
782
|
pathContains: (pointer, value) => {
|
|
724
|
-
const normalized =
|
|
783
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
725
784
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
726
785
|
if (resolved && resolved.valueType !== "array") {
|
|
727
786
|
throw new Error("pathContains is only supported for JSON array values");
|
|
@@ -736,7 +795,7 @@ function objectField(field2, options) {
|
|
|
736
795
|
);
|
|
737
796
|
},
|
|
738
797
|
pathIsNull: (pointer) => {
|
|
739
|
-
const normalized =
|
|
798
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
740
799
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
741
800
|
const predicateOptions = resolved?.valueType === void 0 ? void 0 : { valueType: resolved.valueType };
|
|
742
801
|
return objectOp(
|
|
@@ -748,7 +807,7 @@ function objectField(field2, options) {
|
|
|
748
807
|
);
|
|
749
808
|
},
|
|
750
809
|
pathIsNotNull: (pointer) => {
|
|
751
|
-
const normalized =
|
|
810
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
752
811
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
753
812
|
const predicateOptions = resolved?.valueType === void 0 ? void 0 : { valueType: resolved.valueType };
|
|
754
813
|
return objectOp(
|
|
@@ -760,8 +819,8 @@ function objectField(field2, options) {
|
|
|
760
819
|
);
|
|
761
820
|
},
|
|
762
821
|
field: (pointer) => {
|
|
763
|
-
const normalized =
|
|
764
|
-
const nestedPointer =
|
|
822
|
+
const normalized = chunkUVZHTBZ5_cjs.normalizeJsonPointer(pointer);
|
|
823
|
+
const nestedPointer = chunkUVZHTBZ5_cjs.joinJsonPointers(basePointer, normalized);
|
|
765
824
|
const resolved = resolvePointerTypeInfo(options?.typeInfo, normalized);
|
|
766
825
|
const nestedRef = fieldRef(field2.alias, field2.path, {
|
|
767
826
|
jsonPointer: nestedPointer,
|
|
@@ -891,7 +950,7 @@ function getFieldPointer(field2) {
|
|
|
891
950
|
return field2.jsonPointer;
|
|
892
951
|
}
|
|
893
952
|
if (field2.path.length > 1 && field2.path[0] === "props") {
|
|
894
|
-
return
|
|
953
|
+
return chunkUVZHTBZ5_cjs.jsonPointer(field2.path.slice(1));
|
|
895
954
|
}
|
|
896
955
|
return void 0;
|
|
897
956
|
}
|
|
@@ -1140,11 +1199,13 @@ function compilePredicateExpression(expr, ctx) {
|
|
|
1140
1199
|
case "in_subquery": {
|
|
1141
1200
|
return compileInSubquery(expr, ctx);
|
|
1142
1201
|
}
|
|
1143
|
-
case "vector_similarity":
|
|
1144
|
-
|
|
1202
|
+
case "vector_similarity":
|
|
1203
|
+
case "fulltext_match": {
|
|
1204
|
+
return STRUCTURAL_PREDICATE_NOOP;
|
|
1145
1205
|
}
|
|
1146
1206
|
}
|
|
1147
1207
|
}
|
|
1208
|
+
var STRUCTURAL_PREDICATE_NOOP = drizzleOrm.sql.raw("1=1");
|
|
1148
1209
|
function compileComparisonPredicate(expr, dialect, cteColumnPrefix) {
|
|
1149
1210
|
if (isParameterRef(expr.right)) {
|
|
1150
1211
|
const parameterValueType = normalizeValueType2(expr.right.valueType) ?? normalizeValueType2(expr.left.valueType);
|
|
@@ -1248,7 +1309,7 @@ function compileArrayPredicate(expr, dialect, cteColumnPrefix) {
|
|
|
1248
1309
|
}
|
|
1249
1310
|
function compileObjectPredicate(expr, dialect, cteColumnPrefix) {
|
|
1250
1311
|
const basePointer = getFieldPointer(expr.field);
|
|
1251
|
-
const pointer =
|
|
1312
|
+
const pointer = chunkUVZHTBZ5_cjs.joinJsonPointers(basePointer, expr.pointer);
|
|
1252
1313
|
const column = compileFieldColumn(expr.field, void 0, cteColumnPrefix);
|
|
1253
1314
|
switch (expr.op) {
|
|
1254
1315
|
case "hasKey":
|
|
@@ -1398,45 +1459,61 @@ function compileInSubquery(expr, ctx) {
|
|
|
1398
1459
|
const subSql = ctx.compileQuery(expr.subquery, expr.subquery.graphId);
|
|
1399
1460
|
return expr.negated ? drizzleOrm.sql`${fieldSql} NOT IN (${subSql})` : drizzleOrm.sql`${fieldSql} IN (${subSql})`;
|
|
1400
1461
|
}
|
|
1401
|
-
function
|
|
1402
|
-
return drizzleOrm.sql.raw("1=1");
|
|
1403
|
-
}
|
|
1404
|
-
function extractVectorSimilarityPredicates(predicates) {
|
|
1462
|
+
function extractStructuralPredicates(predicates, isMatch, rejectionMessage) {
|
|
1405
1463
|
const results = [];
|
|
1406
1464
|
function visit(expr, inDisallowedBranch) {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
1411
|
-
"Vector similarity predicates cannot be nested under OR or NOT. Use top-level AND combinations instead."
|
|
1412
|
-
);
|
|
1413
|
-
}
|
|
1414
|
-
results.push(expr);
|
|
1415
|
-
break;
|
|
1465
|
+
if (isMatch(expr)) {
|
|
1466
|
+
if (inDisallowedBranch) {
|
|
1467
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(rejectionMessage);
|
|
1416
1468
|
}
|
|
1469
|
+
results.push(expr);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
switch (expr.__type) {
|
|
1417
1473
|
case "and": {
|
|
1418
|
-
for (const
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
break;
|
|
1474
|
+
for (const child of expr.predicates) visit(child, inDisallowedBranch);
|
|
1475
|
+
return;
|
|
1422
1476
|
}
|
|
1423
1477
|
case "or": {
|
|
1424
|
-
for (const
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
break;
|
|
1478
|
+
for (const child of expr.predicates) visit(child, true);
|
|
1479
|
+
return;
|
|
1428
1480
|
}
|
|
1429
1481
|
case "not": {
|
|
1430
1482
|
visit(expr.predicate, true);
|
|
1431
|
-
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
case "comparison":
|
|
1486
|
+
case "string_op":
|
|
1487
|
+
case "null_check":
|
|
1488
|
+
case "between":
|
|
1489
|
+
case "array_op":
|
|
1490
|
+
case "object_op":
|
|
1491
|
+
case "aggregate_comparison":
|
|
1492
|
+
case "exists":
|
|
1493
|
+
case "in_subquery":
|
|
1494
|
+
case "vector_similarity":
|
|
1495
|
+
case "fulltext_match": {
|
|
1496
|
+
return;
|
|
1432
1497
|
}
|
|
1433
1498
|
}
|
|
1434
1499
|
}
|
|
1435
|
-
for (const pred of predicates)
|
|
1436
|
-
visit(pred.expression, false);
|
|
1437
|
-
}
|
|
1500
|
+
for (const pred of predicates) visit(pred.expression, false);
|
|
1438
1501
|
return results;
|
|
1439
1502
|
}
|
|
1503
|
+
function extractVectorSimilarityPredicates(predicates) {
|
|
1504
|
+
return extractStructuralPredicates(
|
|
1505
|
+
predicates,
|
|
1506
|
+
(expr) => expr.__type === "vector_similarity",
|
|
1507
|
+
"Vector similarity predicates cannot be nested under OR or NOT. Use top-level AND combinations instead."
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
function extractFulltextMatchPredicates(predicates) {
|
|
1511
|
+
return extractStructuralPredicates(
|
|
1512
|
+
predicates,
|
|
1513
|
+
(expr) => expr.__type === "fulltext_match",
|
|
1514
|
+
"Fulltext match predicates cannot be nested under OR or NOT. Use top-level AND combinations instead."
|
|
1515
|
+
);
|
|
1516
|
+
}
|
|
1440
1517
|
|
|
1441
1518
|
// src/query/compiler/predicate-utils.ts
|
|
1442
1519
|
var EMPTY_PREDICATES = [];
|
|
@@ -1495,6 +1572,10 @@ function getNodeKindsForAlias(ast, alias) {
|
|
|
1495
1572
|
}
|
|
1496
1573
|
throw new chunkO5PST6TB_cjs.CompilerInvariantError(`Unknown traversal source alias: ${alias}`);
|
|
1497
1574
|
}
|
|
1575
|
+
function getHybridTargetAlias(vectorPredicate, fulltextPredicate) {
|
|
1576
|
+
if (!vectorPredicate || !fulltextPredicate) return void 0;
|
|
1577
|
+
return vectorPredicate.field.alias === fulltextPredicate.field.alias ? vectorPredicate.field.alias : void 0;
|
|
1578
|
+
}
|
|
1498
1579
|
|
|
1499
1580
|
// src/query/compiler/emitter/plan-inspector.ts
|
|
1500
1581
|
function collectPlanOperations(node, ops) {
|
|
@@ -1502,6 +1583,7 @@ function collectPlanOperations(node, ops) {
|
|
|
1502
1583
|
switch (node.op) {
|
|
1503
1584
|
case "aggregate":
|
|
1504
1585
|
case "filter":
|
|
1586
|
+
case "fulltext_match":
|
|
1505
1587
|
case "join":
|
|
1506
1588
|
case "limit_offset":
|
|
1507
1589
|
case "project":
|
|
@@ -1530,6 +1612,7 @@ function findUnaryNodeInProjectChain(rootNode, op) {
|
|
|
1530
1612
|
switch (currentNode.op) {
|
|
1531
1613
|
case "aggregate":
|
|
1532
1614
|
case "filter":
|
|
1615
|
+
case "fulltext_match":
|
|
1533
1616
|
case "join":
|
|
1534
1617
|
case "limit_offset":
|
|
1535
1618
|
case "recursive_expand":
|
|
@@ -1565,6 +1648,7 @@ function inspectProjectPlan(logicalPlan) {
|
|
|
1565
1648
|
);
|
|
1566
1649
|
return {
|
|
1567
1650
|
hasAggregate: operations.has("aggregate"),
|
|
1651
|
+
hasFulltextMatch: operations.has("fulltext_match"),
|
|
1568
1652
|
hasLimitOffset: operations.has("limit_offset"),
|
|
1569
1653
|
hasRecursiveExpand: operations.has("recursive_expand"),
|
|
1570
1654
|
hasSetOperation: operations.has("set_op"),
|
|
@@ -1616,6 +1700,7 @@ function findTopLevelLimitOffsetNode(rootNode) {
|
|
|
1616
1700
|
switch (currentNode.op) {
|
|
1617
1701
|
case "aggregate":
|
|
1618
1702
|
case "filter":
|
|
1703
|
+
case "fulltext_match":
|
|
1619
1704
|
case "join":
|
|
1620
1705
|
case "project":
|
|
1621
1706
|
case "recursive_expand":
|
|
@@ -1640,6 +1725,7 @@ function findTopLevelSortNode(rootNode) {
|
|
|
1640
1725
|
switch (currentNode.op) {
|
|
1641
1726
|
case "aggregate":
|
|
1642
1727
|
case "filter":
|
|
1728
|
+
case "fulltext_match":
|
|
1643
1729
|
case "join":
|
|
1644
1730
|
case "limit_offset":
|
|
1645
1731
|
case "project":
|
|
@@ -1774,16 +1860,16 @@ function assertStandardEmitterClauseAlignment(logicalPlan, input) {
|
|
|
1774
1860
|
{ component: "standard-emitter" }
|
|
1775
1861
|
);
|
|
1776
1862
|
}
|
|
1777
|
-
const expectsOrderBy = planShape.hasSort || planShape.hasVectorKnn;
|
|
1863
|
+
const expectsOrderBy = planShape.hasSort || planShape.hasVectorKnn || planShape.hasFulltextMatch;
|
|
1778
1864
|
if (expectsOrderBy && input.orderBy === void 0) {
|
|
1779
1865
|
throw new chunkO5PST6TB_cjs.CompilerInvariantError(
|
|
1780
|
-
"Standard SQL emitter expected ORDER BY clause for plan containing a sort or
|
|
1866
|
+
"Standard SQL emitter expected ORDER BY clause for plan containing a sort, vector_knn, or fulltext_match node",
|
|
1781
1867
|
{ component: "standard-emitter" }
|
|
1782
1868
|
);
|
|
1783
1869
|
}
|
|
1784
1870
|
if (!expectsOrderBy && input.orderBy !== void 0) {
|
|
1785
1871
|
throw new chunkO5PST6TB_cjs.CompilerInvariantError(
|
|
1786
|
-
"Standard SQL emitter received ORDER BY clause for a plan without sort or
|
|
1872
|
+
"Standard SQL emitter received ORDER BY clause for a plan without sort, vector_knn, or fulltext_match nodes",
|
|
1787
1873
|
{ component: "standard-emitter" }
|
|
1788
1874
|
);
|
|
1789
1875
|
}
|
|
@@ -1822,6 +1908,62 @@ function emitStandardQuerySql(input) {
|
|
|
1822
1908
|
return drizzleOrm.sql.join(parts, drizzleOrm.sql` `);
|
|
1823
1909
|
}
|
|
1824
1910
|
|
|
1911
|
+
// src/query/ast.ts
|
|
1912
|
+
var DEFAULT_RRF_K = 60;
|
|
1913
|
+
var DEFAULT_RRF_WEIGHT = 1;
|
|
1914
|
+
function mergeEdgeKinds(traversal) {
|
|
1915
|
+
const inverse = traversal.inverseEdgeKinds;
|
|
1916
|
+
if (inverse === void 0 || inverse.length === 0) return traversal.edgeKinds;
|
|
1917
|
+
return [
|
|
1918
|
+
...traversal.edgeKinds,
|
|
1919
|
+
...inverse.filter((kind) => !traversal.edgeKinds.includes(kind))
|
|
1920
|
+
];
|
|
1921
|
+
}
|
|
1922
|
+
var DEFAULT_TABLE_NAMES = {
|
|
1923
|
+
nodes: "typegraph_nodes",
|
|
1924
|
+
edges: "typegraph_edges",
|
|
1925
|
+
embeddings: "typegraph_node_embeddings",
|
|
1926
|
+
fulltext: "typegraph_node_fulltext"
|
|
1927
|
+
};
|
|
1928
|
+
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
1929
|
+
function validateTableName(name, label) {
|
|
1930
|
+
if (!name || name.length === 0) {
|
|
1931
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(`${label} table name cannot be empty`);
|
|
1932
|
+
}
|
|
1933
|
+
if (name.length > chunkFQCQM3KG_cjs.MAX_PG_IDENTIFIER_LENGTH) {
|
|
1934
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
1935
|
+
`${label} table name exceeds maximum length of ${chunkFQCQM3KG_cjs.MAX_PG_IDENTIFIER_LENGTH} characters`
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
if (!VALID_IDENTIFIER_PATTERN.test(name)) {
|
|
1939
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
1940
|
+
`${label} table name "${name}" is not a valid SQL identifier. Table names must start with a letter or underscore and contain only letters, digits, underscores, or dollar signs.`
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
function quoteIdentifier(name) {
|
|
1945
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
1946
|
+
}
|
|
1947
|
+
function createSqlSchema(names = {}) {
|
|
1948
|
+
const tables = { ...DEFAULT_TABLE_NAMES, ...names };
|
|
1949
|
+
validateTableName(tables.nodes, "nodes");
|
|
1950
|
+
validateTableName(tables.edges, "edges");
|
|
1951
|
+
validateTableName(tables.embeddings, "embeddings");
|
|
1952
|
+
validateTableName(tables.fulltext, "fulltext");
|
|
1953
|
+
return {
|
|
1954
|
+
tables,
|
|
1955
|
+
nodesTable: drizzleOrm.sql.raw(quoteIdentifier(tables.nodes)),
|
|
1956
|
+
edgesTable: drizzleOrm.sql.raw(quoteIdentifier(tables.edges)),
|
|
1957
|
+
embeddingsTable: drizzleOrm.sql.raw(quoteIdentifier(tables.embeddings)),
|
|
1958
|
+
fulltextTable: drizzleOrm.sql.raw(quoteIdentifier(tables.fulltext))
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
var DEFAULT_SQL_SCHEMA = createSqlSchema();
|
|
1962
|
+
var ALIAS_CTE_PREFIX = "cte_";
|
|
1963
|
+
var EMBEDDINGS_CTE_ALIAS = "cte_embeddings";
|
|
1964
|
+
var FULLTEXT_CTE_ALIAS = "cte_fulltext";
|
|
1965
|
+
var HYBRID_CANDIDATES_CTE_ALIAS = "cte_relevance_candidates";
|
|
1966
|
+
|
|
1825
1967
|
// src/query/compiler/typed-json-extract.ts
|
|
1826
1968
|
function compileTypedJsonExtract(input) {
|
|
1827
1969
|
const { column, dialect, pointer, valueType } = input;
|
|
@@ -1875,7 +2017,7 @@ var EDGE_COLUMNS = [
|
|
|
1875
2017
|
"deleted_at"
|
|
1876
2018
|
];
|
|
1877
2019
|
var EMPTY_REQUIRED_COLUMNS = /* @__PURE__ */ new Set();
|
|
1878
|
-
function
|
|
2020
|
+
function quoteIdentifier2(identifier) {
|
|
1879
2021
|
return drizzleOrm.sql.raw(`"${identifier.replaceAll('"', '""')}"`);
|
|
1880
2022
|
}
|
|
1881
2023
|
function shouldProjectColumn(requiredColumns, column, alwaysRequiredColumns) {
|
|
@@ -1929,6 +2071,21 @@ function compileColumnReference(tableAlias, column) {
|
|
|
1929
2071
|
}
|
|
1930
2072
|
return drizzleOrm.sql`${drizzleOrm.sql.raw(tableAlias)}.${drizzleOrm.sql.raw(column)}`;
|
|
1931
2073
|
}
|
|
2074
|
+
function qualifyColumn(owner, name) {
|
|
2075
|
+
return drizzleOrm.sql`${quoteIdentifier2(owner)}.${quoteIdentifier2(name)}`;
|
|
2076
|
+
}
|
|
2077
|
+
var SCOPED_RELEVANCE_NODES_ALIAS = "scoped_relevance_nodes";
|
|
2078
|
+
function buildScopedNodeIdsSubquery(nodeAlias) {
|
|
2079
|
+
const cteAlias = `${ALIAS_CTE_PREFIX}${nodeAlias}`;
|
|
2080
|
+
return drizzleOrm.sql`
|
|
2081
|
+
(
|
|
2082
|
+
SELECT DISTINCT
|
|
2083
|
+
${qualifyColumn(cteAlias, `${nodeAlias}_id`)} AS node_id,
|
|
2084
|
+
${qualifyColumn(cteAlias, `${nodeAlias}_kind`)} AS node_kind
|
|
2085
|
+
FROM ${quoteIdentifier2(cteAlias)}
|
|
2086
|
+
) AS ${drizzleOrm.sql.raw(SCOPED_RELEVANCE_NODES_ALIAS)}
|
|
2087
|
+
`;
|
|
2088
|
+
}
|
|
1932
2089
|
function compileNodeSelectColumns(tableAlias, alias, requiredColumns) {
|
|
1933
2090
|
return NODE_COLUMNS.filter(
|
|
1934
2091
|
(column) => column === "id" || column === "kind" || shouldProjectColumn(requiredColumns, column)
|
|
@@ -2181,7 +2338,7 @@ function buildStandardProjection(input) {
|
|
|
2181
2338
|
}
|
|
2182
2339
|
const projectedFields = fields.map((field2) => {
|
|
2183
2340
|
const source = compileProjectedSource(field2, dialect);
|
|
2184
|
-
return drizzleOrm.sql`${source} AS ${
|
|
2341
|
+
return drizzleOrm.sql`${source} AS ${quoteIdentifier2(field2.outputName)}`;
|
|
2185
2342
|
});
|
|
2186
2343
|
return drizzleOrm.sql.join(projectedFields, drizzleOrm.sql`, `);
|
|
2187
2344
|
}
|
|
@@ -2201,23 +2358,67 @@ function compileSelectiveProjection(fields, dialect, ast, collapsedTraversalCteA
|
|
|
2201
2358
|
const cteAlias = collapsedTraversalCteAlias ?? aliasToCte.get(field2.alias) ?? `cte_${field2.alias}`;
|
|
2202
2359
|
if (field2.isSystemField) {
|
|
2203
2360
|
const dbColumn = mapSelectiveSystemFieldToColumn(field2.field);
|
|
2204
|
-
return drizzleOrm.sql`${drizzleOrm.sql.raw(cteAlias)}.${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${
|
|
2361
|
+
return drizzleOrm.sql`${drizzleOrm.sql.raw(cteAlias)}.${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${quoteIdentifier2(field2.outputName)}`;
|
|
2205
2362
|
}
|
|
2206
2363
|
const propsColumn = `${field2.alias}_props`;
|
|
2207
2364
|
const column = drizzleOrm.sql`${drizzleOrm.sql.raw(cteAlias)}.${drizzleOrm.sql.raw(propsColumn)}`;
|
|
2208
|
-
const pointer =
|
|
2365
|
+
const pointer = chunkUVZHTBZ5_cjs.jsonPointer([field2.field]);
|
|
2209
2366
|
const extracted = compileTypedJsonExtract({
|
|
2210
2367
|
column,
|
|
2211
2368
|
dialect,
|
|
2212
2369
|
pointer,
|
|
2213
2370
|
valueType: field2.valueType
|
|
2214
2371
|
});
|
|
2215
|
-
return drizzleOrm.sql`${extracted} AS ${
|
|
2372
|
+
return drizzleOrm.sql`${extracted} AS ${quoteIdentifier2(field2.outputName)}`;
|
|
2216
2373
|
});
|
|
2217
2374
|
return drizzleOrm.sql.join(columns, drizzleOrm.sql`, `);
|
|
2218
2375
|
}
|
|
2376
|
+
function buildRelevanceJoins(vectorPredicate, fulltextPredicate) {
|
|
2377
|
+
const hybridTargetAlias = getHybridTargetAlias(
|
|
2378
|
+
vectorPredicate,
|
|
2379
|
+
fulltextPredicate
|
|
2380
|
+
);
|
|
2381
|
+
if (hybridTargetAlias !== void 0) {
|
|
2382
|
+
return [
|
|
2383
|
+
buildHybridCandidateJoin(hybridTargetAlias),
|
|
2384
|
+
buildRelevanceJoin(EMBEDDINGS_CTE_ALIAS, hybridTargetAlias, "LEFT JOIN"),
|
|
2385
|
+
buildRelevanceJoin(FULLTEXT_CTE_ALIAS, hybridTargetAlias, "LEFT JOIN")
|
|
2386
|
+
];
|
|
2387
|
+
}
|
|
2388
|
+
const joins = [];
|
|
2389
|
+
if (vectorPredicate) {
|
|
2390
|
+
joins.push(
|
|
2391
|
+
buildRelevanceJoin(EMBEDDINGS_CTE_ALIAS, vectorPredicate.field.alias)
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
if (fulltextPredicate) {
|
|
2395
|
+
joins.push(
|
|
2396
|
+
buildRelevanceJoin(FULLTEXT_CTE_ALIAS, fulltextPredicate.field.alias)
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
2399
|
+
return joins;
|
|
2400
|
+
}
|
|
2401
|
+
function buildHybridCandidateJoin(nodeAlias) {
|
|
2402
|
+
const candidateCte = drizzleOrm.sql.raw(HYBRID_CANDIDATES_CTE_ALIAS);
|
|
2403
|
+
const node = drizzleOrm.sql.raw(`${ALIAS_CTE_PREFIX}${nodeAlias}`);
|
|
2404
|
+
const idColumn = drizzleOrm.sql.raw(`${nodeAlias}_id`);
|
|
2405
|
+
const kindColumn = drizzleOrm.sql.raw(`${nodeAlias}_kind`);
|
|
2406
|
+
return drizzleOrm.sql`INNER JOIN ${candidateCte} ON ${candidateCte}.node_id = ${node}.${idColumn} AND ${candidateCte}.node_kind = ${node}.${kindColumn}`;
|
|
2407
|
+
}
|
|
2408
|
+
function buildRelevanceJoin(cteAlias, nodeAlias, joinType = "INNER JOIN") {
|
|
2409
|
+
const cte = drizzleOrm.sql.raw(cteAlias);
|
|
2410
|
+
const node = drizzleOrm.sql.raw(`${ALIAS_CTE_PREFIX}${nodeAlias}`);
|
|
2411
|
+
const idColumn = drizzleOrm.sql.raw(`${nodeAlias}_id`);
|
|
2412
|
+
const kindColumn = drizzleOrm.sql.raw(`${nodeAlias}_kind`);
|
|
2413
|
+
return drizzleOrm.sql`${drizzleOrm.sql.raw(joinType)} ${cte} ON ${cte}.node_id = ${node}.${idColumn} AND ${cte}.node_kind = ${node}.${kindColumn}`;
|
|
2414
|
+
}
|
|
2219
2415
|
function buildStandardFromClause(input) {
|
|
2220
|
-
const {
|
|
2416
|
+
const {
|
|
2417
|
+
ast,
|
|
2418
|
+
collapsedTraversalCteAlias,
|
|
2419
|
+
fulltextPredicate,
|
|
2420
|
+
vectorPredicate
|
|
2421
|
+
} = input;
|
|
2221
2422
|
if (collapsedTraversalCteAlias !== void 0) {
|
|
2222
2423
|
return drizzleOrm.sql`FROM ${drizzleOrm.sql.raw(collapsedTraversalCteAlias)}`;
|
|
2223
2424
|
}
|
|
@@ -2232,11 +2433,8 @@ function buildStandardFromClause(input) {
|
|
|
2232
2433
|
drizzleOrm.sql`${drizzleOrm.sql.raw(joinType)} ${drizzleOrm.sql.raw(cteAlias)} ON ${drizzleOrm.sql.raw(cteAlias)}.${drizzleOrm.sql.raw(previousAlias)}_id = cte_${drizzleOrm.sql.raw(previousAlias)}.${drizzleOrm.sql.raw(previousAlias)}_id AND ${drizzleOrm.sql.raw(cteAlias)}.${drizzleOrm.sql.raw(previousAlias)}_kind = cte_${drizzleOrm.sql.raw(previousAlias)}.${drizzleOrm.sql.raw(previousAlias)}_kind`
|
|
2233
2434
|
);
|
|
2234
2435
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
joins.push(
|
|
2238
|
-
drizzleOrm.sql`INNER JOIN cte_embeddings ON cte_embeddings.node_id = cte_${drizzleOrm.sql.raw(nodeAlias)}.${drizzleOrm.sql.raw(nodeAlias)}_id`
|
|
2239
|
-
);
|
|
2436
|
+
for (const join of buildRelevanceJoins(vectorPredicate, fulltextPredicate)) {
|
|
2437
|
+
joins.push(join);
|
|
2240
2438
|
}
|
|
2241
2439
|
return joins.length === 0 ? fromClause : drizzleOrm.sql`${fromClause} ${drizzleOrm.sql.join(joins, drizzleOrm.sql` `)}`;
|
|
2242
2440
|
}
|
|
@@ -2275,6 +2473,15 @@ function fieldRefKey(field2) {
|
|
|
2275
2473
|
const pointer = field2.jsonPointer ?? "";
|
|
2276
2474
|
return `${field2.alias}:${field2.path.join(".")}:${pointer}`;
|
|
2277
2475
|
}
|
|
2476
|
+
function resolveEmbeddingFieldPath(field2) {
|
|
2477
|
+
if (field2.jsonPointer !== void 0 && field2.jsonPointer !== "" && field2.jsonPointer !== "/") {
|
|
2478
|
+
return field2.jsonPointer.replace(/^\//u, "").replaceAll("/", ".");
|
|
2479
|
+
}
|
|
2480
|
+
if (field2.path[0] === "props") {
|
|
2481
|
+
return field2.path.slice(1).join(".");
|
|
2482
|
+
}
|
|
2483
|
+
return field2.path.join(".");
|
|
2484
|
+
}
|
|
2278
2485
|
function buildStandardGroupBy(input) {
|
|
2279
2486
|
const { ast, dialect } = input;
|
|
2280
2487
|
if (!ast.groupBy || ast.groupBy.fields.length === 0) {
|
|
@@ -2321,18 +2528,29 @@ function buildStandardHaving(input) {
|
|
|
2321
2528
|
return drizzleOrm.sql`HAVING ${condition}`;
|
|
2322
2529
|
}
|
|
2323
2530
|
function buildStandardEmbeddingsCte(input) {
|
|
2324
|
-
const { ctx, graphId, vectorPredicate } = input;
|
|
2531
|
+
const { ctx, graphId, nodeKinds, vectorPredicate } = input;
|
|
2325
2532
|
const { dialect } = ctx;
|
|
2326
2533
|
const { field: field2, metric, minScore, queryEmbedding } = vectorPredicate;
|
|
2327
|
-
const
|
|
2534
|
+
const embeddingsTableName = ctx.schema.tables.embeddings;
|
|
2535
|
+
if (nodeKinds.length === 0) {
|
|
2536
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2537
|
+
"Vector predicate must resolve to at least one node kind"
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
const fieldPath = resolveEmbeddingFieldPath(field2);
|
|
2328
2541
|
const distanceExpr = dialect.vectorDistance(
|
|
2329
|
-
|
|
2542
|
+
qualifyColumn(embeddingsTableName, "embedding"),
|
|
2330
2543
|
queryEmbedding,
|
|
2331
2544
|
metric
|
|
2332
2545
|
);
|
|
2546
|
+
const scopedNodes = buildScopedNodeIdsSubquery(field2.alias);
|
|
2333
2547
|
const conditions = [
|
|
2334
|
-
drizzleOrm.sql
|
|
2335
|
-
|
|
2548
|
+
drizzleOrm.sql`${qualifyColumn(embeddingsTableName, "graph_id")} = ${graphId}`,
|
|
2549
|
+
compileKindFilter(
|
|
2550
|
+
qualifyColumn(embeddingsTableName, "node_kind"),
|
|
2551
|
+
nodeKinds
|
|
2552
|
+
),
|
|
2553
|
+
drizzleOrm.sql`${qualifyColumn(embeddingsTableName, "field_path")} = ${fieldPath}`
|
|
2336
2554
|
];
|
|
2337
2555
|
if (minScore !== void 0) {
|
|
2338
2556
|
conditions.push(
|
|
@@ -2341,14 +2559,29 @@ function buildStandardEmbeddingsCte(input) {
|
|
|
2341
2559
|
}
|
|
2342
2560
|
const scoreExpr = compileVectorScoreExpression(distanceExpr, metric);
|
|
2343
2561
|
return drizzleOrm.sql`
|
|
2344
|
-
|
|
2562
|
+
${drizzleOrm.sql.raw(EMBEDDINGS_CTE_ALIAS)} AS (
|
|
2345
2563
|
SELECT
|
|
2346
2564
|
node_id,
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2565
|
+
node_kind,
|
|
2566
|
+
distance,
|
|
2567
|
+
score,
|
|
2568
|
+
ROW_NUMBER() OVER (ORDER BY distance ASC) AS ord
|
|
2569
|
+
FROM (
|
|
2570
|
+
SELECT
|
|
2571
|
+
${qualifyColumn(embeddingsTableName, "node_id")} AS node_id,
|
|
2572
|
+
${qualifyColumn(embeddingsTableName, "node_kind")} AS node_kind,
|
|
2573
|
+
${distanceExpr} AS distance,
|
|
2574
|
+
${scoreExpr} AS score
|
|
2575
|
+
FROM ${ctx.schema.embeddingsTable}
|
|
2576
|
+
INNER JOIN ${scopedNodes}
|
|
2577
|
+
ON ${drizzleOrm.sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_id`)} =
|
|
2578
|
+
${qualifyColumn(embeddingsTableName, "node_id")}
|
|
2579
|
+
AND ${drizzleOrm.sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_kind`)} =
|
|
2580
|
+
${qualifyColumn(embeddingsTableName, "node_kind")}
|
|
2581
|
+
WHERE ${drizzleOrm.sql.join(conditions, drizzleOrm.sql` AND `)}
|
|
2582
|
+
ORDER BY distance ASC
|
|
2583
|
+
LIMIT ${vectorPredicate.limit}
|
|
2584
|
+
) AS vec_inner
|
|
2352
2585
|
)
|
|
2353
2586
|
`;
|
|
2354
2587
|
}
|
|
@@ -2378,37 +2611,130 @@ function compileVectorMinScoreCondition(distanceExpr, metric, minScore) {
|
|
|
2378
2611
|
}
|
|
2379
2612
|
}
|
|
2380
2613
|
}
|
|
2381
|
-
function
|
|
2382
|
-
const {
|
|
2383
|
-
const
|
|
2384
|
-
const
|
|
2385
|
-
if (
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2614
|
+
function buildStandardFulltextCte(input) {
|
|
2615
|
+
const { ctx, fulltextPredicate, graphId, nodeKinds } = input;
|
|
2616
|
+
const { dialect, schema } = ctx;
|
|
2617
|
+
const { query, mode, language, limit, minScore } = fulltextPredicate;
|
|
2618
|
+
if (nodeKinds.length === 0) {
|
|
2619
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2620
|
+
"Fulltext predicate must resolve to at least one node kind"
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2623
|
+
const tableName = schema.tables.fulltext;
|
|
2624
|
+
const scopedNodes = buildScopedNodeIdsSubquery(fulltextPredicate.field.alias);
|
|
2625
|
+
const fulltextStrategy = dialect.fulltext;
|
|
2626
|
+
if (fulltextStrategy === void 0) {
|
|
2627
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2628
|
+
`Fulltext match predicates are not supported for dialect "${dialect.name}"`
|
|
2629
|
+
);
|
|
2630
|
+
}
|
|
2631
|
+
const matchCondition = fulltextStrategy.matchCondition(
|
|
2632
|
+
tableName,
|
|
2633
|
+
query,
|
|
2634
|
+
mode,
|
|
2635
|
+
language
|
|
2636
|
+
);
|
|
2637
|
+
const rankExpression = fulltextStrategy.rankExpression(
|
|
2638
|
+
tableName,
|
|
2639
|
+
query,
|
|
2640
|
+
mode,
|
|
2641
|
+
language
|
|
2642
|
+
);
|
|
2643
|
+
const conditions = [
|
|
2644
|
+
drizzleOrm.sql`${qualifyColumn(tableName, "graph_id")} = ${graphId}`,
|
|
2645
|
+
compileKindFilter(qualifyColumn(tableName, "node_kind"), nodeKinds),
|
|
2646
|
+
matchCondition
|
|
2647
|
+
];
|
|
2648
|
+
if (minScore !== void 0) {
|
|
2649
|
+
conditions.push(drizzleOrm.sql`${rankExpression} >= ${minScore}`);
|
|
2650
|
+
}
|
|
2651
|
+
return drizzleOrm.sql`
|
|
2652
|
+
${drizzleOrm.sql.raw(FULLTEXT_CTE_ALIAS)} AS (
|
|
2653
|
+
SELECT
|
|
2654
|
+
node_id,
|
|
2655
|
+
node_kind,
|
|
2656
|
+
rank,
|
|
2657
|
+
ROW_NUMBER() OVER (ORDER BY rank DESC, node_id ASC) AS ord
|
|
2658
|
+
FROM (
|
|
2659
|
+
SELECT
|
|
2660
|
+
${qualifyColumn(tableName, "node_id")} AS node_id,
|
|
2661
|
+
${qualifyColumn(tableName, "node_kind")} AS node_kind,
|
|
2662
|
+
${rankExpression} AS rank
|
|
2663
|
+
FROM ${schema.fulltextTable}
|
|
2664
|
+
INNER JOIN ${scopedNodes}
|
|
2665
|
+
ON ${drizzleOrm.sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_id`)} =
|
|
2666
|
+
${qualifyColumn(tableName, "node_id")}
|
|
2667
|
+
AND ${drizzleOrm.sql.raw(`${SCOPED_RELEVANCE_NODES_ALIAS}.node_kind`)} =
|
|
2668
|
+
${qualifyColumn(tableName, "node_kind")}
|
|
2669
|
+
WHERE ${drizzleOrm.sql.join(conditions, drizzleOrm.sql` AND `)}
|
|
2670
|
+
ORDER BY rank DESC, ${qualifyColumn(tableName, "node_id")} ASC
|
|
2671
|
+
LIMIT ${limit}
|
|
2672
|
+
) AS fts_inner
|
|
2673
|
+
)
|
|
2674
|
+
`;
|
|
2675
|
+
}
|
|
2676
|
+
function buildStandardHybridCandidateCte() {
|
|
2677
|
+
return drizzleOrm.sql`
|
|
2678
|
+
${drizzleOrm.sql.raw(HYBRID_CANDIDATES_CTE_ALIAS)} AS (
|
|
2679
|
+
SELECT node_id, node_kind FROM ${drizzleOrm.sql.raw(EMBEDDINGS_CTE_ALIAS)}
|
|
2680
|
+
UNION
|
|
2681
|
+
SELECT node_id, node_kind FROM ${drizzleOrm.sql.raw(FULLTEXT_CTE_ALIAS)}
|
|
2682
|
+
)
|
|
2683
|
+
`;
|
|
2684
|
+
}
|
|
2685
|
+
function compileUserOrderBy(ast, dialect) {
|
|
2686
|
+
if (!ast.orderBy || ast.orderBy.length === 0) return [];
|
|
2687
|
+
const aliasToCte = buildAliasToCteMap(ast);
|
|
2688
|
+
const fragments = [];
|
|
2689
|
+
for (const orderSpec of ast.orderBy) {
|
|
2690
|
+
const valueType = orderSpec.field.valueType;
|
|
2691
|
+
if (valueType === "array" || valueType === "object") {
|
|
2692
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2693
|
+
"Ordering by JSON arrays or objects is not supported"
|
|
2407
2694
|
);
|
|
2408
2695
|
}
|
|
2696
|
+
const cteAlias = aliasToCte.get(orderSpec.field.alias) ?? `${ALIAS_CTE_PREFIX}${orderSpec.field.alias}`;
|
|
2697
|
+
const field2 = compileFieldValue(
|
|
2698
|
+
orderSpec.field,
|
|
2699
|
+
dialect,
|
|
2700
|
+
valueType,
|
|
2701
|
+
cteAlias
|
|
2702
|
+
);
|
|
2703
|
+
const direction = drizzleOrm.sql.raw(orderSpec.direction.toUpperCase());
|
|
2704
|
+
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
2705
|
+
const nullsDirection = drizzleOrm.sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
2706
|
+
fragments.push(
|
|
2707
|
+
drizzleOrm.sql`(${field2} IS NULL) ${nullsDirection}`,
|
|
2708
|
+
drizzleOrm.sql`${field2} ${direction}`
|
|
2709
|
+
);
|
|
2409
2710
|
}
|
|
2410
|
-
|
|
2411
|
-
|
|
2711
|
+
return fragments;
|
|
2712
|
+
}
|
|
2713
|
+
function buildStandardFulltextOrderBy(input) {
|
|
2714
|
+
const { ast, dialect } = input;
|
|
2715
|
+
const rankOrder = drizzleOrm.sql.raw(`${FULLTEXT_CTE_ALIAS}.rank DESC`);
|
|
2716
|
+
const userOrders = compileUserOrderBy(ast, dialect);
|
|
2717
|
+
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join([rankOrder, ...userOrders], drizzleOrm.sql`, `)}`;
|
|
2718
|
+
}
|
|
2719
|
+
function buildStandardHybridRrfOrderBy(input) {
|
|
2720
|
+
const { ast, dialect, fusion } = input;
|
|
2721
|
+
const k = fusion?.k ?? DEFAULT_RRF_K;
|
|
2722
|
+
const vectorWeight = fusion?.weights?.vector ?? DEFAULT_RRF_WEIGHT;
|
|
2723
|
+
const fulltextWeight = fusion?.weights?.fulltext ?? DEFAULT_RRF_WEIGHT;
|
|
2724
|
+
const rrfOrder = drizzleOrm.sql.raw(
|
|
2725
|
+
`(COALESCE(${vectorWeight} / (${k} + ${EMBEDDINGS_CTE_ALIAS}.ord), 0) + COALESCE(${fulltextWeight} / (${k} + ${FULLTEXT_CTE_ALIAS}.ord), 0)) DESC`
|
|
2726
|
+
);
|
|
2727
|
+
const idTiebreak = drizzleOrm.sql.raw(
|
|
2728
|
+
`COALESCE(${FULLTEXT_CTE_ALIAS}.node_id, ${EMBEDDINGS_CTE_ALIAS}.node_id) ASC`
|
|
2729
|
+
);
|
|
2730
|
+
const userOrders = compileUserOrderBy(ast, dialect);
|
|
2731
|
+
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join([rrfOrder, ...userOrders, idTiebreak], drizzleOrm.sql`, `)}`;
|
|
2732
|
+
}
|
|
2733
|
+
function buildStandardVectorOrderBy(input) {
|
|
2734
|
+
const { ast, dialect } = input;
|
|
2735
|
+
const distanceOrder = drizzleOrm.sql.raw(`${EMBEDDINGS_CTE_ALIAS}.distance ASC`);
|
|
2736
|
+
const userOrders = compileUserOrderBy(ast, dialect);
|
|
2737
|
+
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join([distanceOrder, ...userOrders], drizzleOrm.sql`, `)}`;
|
|
2412
2738
|
}
|
|
2413
2739
|
function buildLimitOffsetClause(input) {
|
|
2414
2740
|
const { limit, offset } = input;
|
|
@@ -2422,6 +2748,74 @@ function buildLimitOffsetClause(input) {
|
|
|
2422
2748
|
return parts.length > 0 ? drizzleOrm.sql.join(parts, drizzleOrm.sql` `) : void 0;
|
|
2423
2749
|
}
|
|
2424
2750
|
|
|
2751
|
+
// src/query/compiler/passes/fulltext.ts
|
|
2752
|
+
function runFulltextPredicatePass(ast, dialect) {
|
|
2753
|
+
const fulltextPredicates = extractFulltextMatchPredicates(ast.predicates);
|
|
2754
|
+
if (fulltextPredicates.length > 1) {
|
|
2755
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2756
|
+
"Multiple fulltext match predicates in a single query are not supported"
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
const fulltextPredicate = fulltextPredicates[0];
|
|
2760
|
+
if (fulltextPredicate === void 0) {
|
|
2761
|
+
return { fulltextPredicate: void 0 };
|
|
2762
|
+
}
|
|
2763
|
+
if (!dialect.capabilities.supportsFulltext) {
|
|
2764
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2765
|
+
`Fulltext match predicates are not supported for dialect "${dialect.name}"`
|
|
2766
|
+
);
|
|
2767
|
+
}
|
|
2768
|
+
const strategy = dialect.fulltext;
|
|
2769
|
+
if (strategy === void 0) {
|
|
2770
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2771
|
+
`Dialect "${dialect.name}" advertises fulltext support but has no strategy configured`
|
|
2772
|
+
);
|
|
2773
|
+
}
|
|
2774
|
+
if (!strategy.supportedModes.includes(fulltextPredicate.mode)) {
|
|
2775
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2776
|
+
`Fulltext query mode "${fulltextPredicate.mode}" is not supported by the "${strategy.name}" strategy. Supported modes: ${strategy.supportedModes.join(", ")}.`
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
if (!Number.isFinite(fulltextPredicate.limit) || fulltextPredicate.limit <= 0) {
|
|
2780
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2781
|
+
`Fulltext match limit must be a positive finite number, got ${String(fulltextPredicate.limit)}`
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2784
|
+
const { minScore } = fulltextPredicate;
|
|
2785
|
+
if (minScore !== void 0 && !Number.isFinite(minScore)) {
|
|
2786
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2787
|
+
`Fulltext minScore must be a finite number, got ${String(minScore)}`
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
return { fulltextPredicate };
|
|
2791
|
+
}
|
|
2792
|
+
function resolveFulltextAwareLimit(astLimit, fulltextPredicate) {
|
|
2793
|
+
if (fulltextPredicate === void 0) {
|
|
2794
|
+
return astLimit;
|
|
2795
|
+
}
|
|
2796
|
+
if (astLimit === void 0) {
|
|
2797
|
+
return fulltextPredicate.limit;
|
|
2798
|
+
}
|
|
2799
|
+
return Math.min(astLimit, fulltextPredicate.limit);
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
// src/query/compiler/passes/fusion.ts
|
|
2803
|
+
function runFusionConfigPass(ast, vectorPredicate, fulltextPredicate) {
|
|
2804
|
+
const fusion = ast.fusion;
|
|
2805
|
+
if (fusion === void 0) return { fusion: void 0 };
|
|
2806
|
+
if (vectorPredicate === void 0 || fulltextPredicate === void 0) {
|
|
2807
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2808
|
+
`.fuseWith() requires both a .similarTo() and a .$fulltext.matches() predicate in the same query. Remove .fuseWith(), or add the missing predicate.`
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
if (vectorPredicate.field.alias !== fulltextPredicate.field.alias) {
|
|
2812
|
+
throw new chunkO5PST6TB_cjs.UnsupportedPredicateError(
|
|
2813
|
+
`.fuseWith() requires .similarTo() and .$fulltext.matches() to target the same node alias. Got vector=${vectorPredicate.field.alias}, fulltext=${fulltextPredicate.field.alias}.`
|
|
2814
|
+
);
|
|
2815
|
+
}
|
|
2816
|
+
return { fusion };
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2425
2819
|
// src/query/compiler/passes/recursive.ts
|
|
2426
2820
|
function runRecursiveTraversalSelectionPass(ast) {
|
|
2427
2821
|
const variableLengthTraversal = ast.traversals.find(
|
|
@@ -2691,6 +3085,14 @@ function lowerStandardQueryToLogicalPlanNode(input) {
|
|
|
2691
3085
|
predicate: input.vectorPredicate
|
|
2692
3086
|
};
|
|
2693
3087
|
}
|
|
3088
|
+
if (input.fulltextPredicate !== void 0) {
|
|
3089
|
+
currentNode = {
|
|
3090
|
+
id: nextPlanNodeId(),
|
|
3091
|
+
input: currentNode,
|
|
3092
|
+
op: "fulltext_match",
|
|
3093
|
+
predicate: input.fulltextPredicate
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
2694
3096
|
return appendAggregateSortLimitAndProjectNodes(
|
|
2695
3097
|
currentNode,
|
|
2696
3098
|
ast,
|
|
@@ -2768,17 +3170,30 @@ function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlan
|
|
|
2768
3170
|
nextPlanNodeId
|
|
2769
3171
|
});
|
|
2770
3172
|
}
|
|
3173
|
+
const dialectAdapter = chunkFQCQM3KG_cjs.getDialect(dialect);
|
|
2771
3174
|
const vectorPredicate = runVectorPredicatePass(
|
|
2772
3175
|
query,
|
|
2773
|
-
|
|
3176
|
+
dialectAdapter
|
|
2774
3177
|
).vectorPredicate;
|
|
2775
|
-
const
|
|
3178
|
+
const fulltextPredicate = runFulltextPredicatePass(
|
|
3179
|
+
query,
|
|
3180
|
+
dialectAdapter
|
|
3181
|
+
).fulltextPredicate;
|
|
3182
|
+
const limitAfterVector = resolveVectorAwareLimit(
|
|
3183
|
+
query.limit,
|
|
3184
|
+
vectorPredicate
|
|
3185
|
+
);
|
|
3186
|
+
const effectiveLimit = resolveFulltextAwareLimit(
|
|
3187
|
+
limitAfterVector,
|
|
3188
|
+
fulltextPredicate
|
|
3189
|
+
);
|
|
2776
3190
|
const loweringInput = {
|
|
2777
3191
|
ast: query,
|
|
2778
3192
|
graphId,
|
|
2779
3193
|
nextPlanNodeId,
|
|
2780
3194
|
...effectiveLimit === void 0 ? {} : { effectiveLimit },
|
|
2781
|
-
...vectorPredicate === void 0 ? {} : { vectorPredicate }
|
|
3195
|
+
...vectorPredicate === void 0 ? {} : { vectorPredicate },
|
|
3196
|
+
...fulltextPredicate === void 0 ? {} : { fulltextPredicate }
|
|
2782
3197
|
};
|
|
2783
3198
|
return lowerStandardQueryToLogicalPlanNode(loweringInput);
|
|
2784
3199
|
}
|
|
@@ -3285,10 +3700,10 @@ function compileRecursiveProjection(ast, traversal, dialect) {
|
|
|
3285
3700
|
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_deleted_at`
|
|
3286
3701
|
];
|
|
3287
3702
|
if (vl.depthAlias !== void 0) {
|
|
3288
|
-
fields.push(drizzleOrm.sql`depth AS ${
|
|
3703
|
+
fields.push(drizzleOrm.sql`depth AS ${quoteIdentifier2(vl.depthAlias)}`);
|
|
3289
3704
|
}
|
|
3290
3705
|
if (vl.pathAlias !== void 0) {
|
|
3291
|
-
fields.push(drizzleOrm.sql`path AS ${
|
|
3706
|
+
fields.push(drizzleOrm.sql`path AS ${quoteIdentifier2(vl.pathAlias)}`);
|
|
3292
3707
|
}
|
|
3293
3708
|
return drizzleOrm.sql.join(fields, drizzleOrm.sql`, `);
|
|
3294
3709
|
}
|
|
@@ -3302,23 +3717,23 @@ function compileRecursiveSelectiveProjection(fields, ast, traversal, dialect) {
|
|
|
3302
3717
|
}
|
|
3303
3718
|
if (field2.isSystemField) {
|
|
3304
3719
|
const dbColumn = mapSelectiveSystemFieldToColumn(field2.field);
|
|
3305
|
-
return drizzleOrm.sql`${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${
|
|
3720
|
+
return drizzleOrm.sql`${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${quoteIdentifier2(field2.outputName)}`;
|
|
3306
3721
|
}
|
|
3307
3722
|
const column = drizzleOrm.sql.raw(`${field2.alias}_props`);
|
|
3308
3723
|
const extracted = compileTypedJsonExtract({
|
|
3309
3724
|
column,
|
|
3310
3725
|
dialect,
|
|
3311
|
-
pointer:
|
|
3726
|
+
pointer: chunkUVZHTBZ5_cjs.jsonPointer([field2.field]),
|
|
3312
3727
|
valueType: field2.valueType
|
|
3313
3728
|
});
|
|
3314
|
-
return drizzleOrm.sql`${extracted} AS ${
|
|
3729
|
+
return drizzleOrm.sql`${extracted} AS ${quoteIdentifier2(field2.outputName)}`;
|
|
3315
3730
|
});
|
|
3316
3731
|
const vl = traversal.variableLength;
|
|
3317
3732
|
if (vl.depthAlias !== void 0) {
|
|
3318
|
-
columns.push(drizzleOrm.sql`depth AS ${
|
|
3733
|
+
columns.push(drizzleOrm.sql`depth AS ${quoteIdentifier2(vl.depthAlias)}`);
|
|
3319
3734
|
}
|
|
3320
3735
|
if (vl.pathAlias !== void 0) {
|
|
3321
|
-
columns.push(drizzleOrm.sql`path AS ${
|
|
3736
|
+
columns.push(drizzleOrm.sql`path AS ${quoteIdentifier2(vl.pathAlias)}`);
|
|
3322
3737
|
}
|
|
3323
3738
|
return drizzleOrm.sql.join(columns, drizzleOrm.sql`, `);
|
|
3324
3739
|
}
|
|
@@ -3335,63 +3750,26 @@ function compileRecursiveOrderBy(ast, dialect) {
|
|
|
3335
3750
|
);
|
|
3336
3751
|
}
|
|
3337
3752
|
const field2 = compileFieldValue(orderSpec.field, dialect, valueType);
|
|
3338
|
-
const direction = drizzleOrm.sql.raw(orderSpec.direction.toUpperCase());
|
|
3339
|
-
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
3340
|
-
const nullsDirection = drizzleOrm.sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
3341
|
-
parts.push(
|
|
3342
|
-
drizzleOrm.sql`(${field2} IS NULL) ${nullsDirection}`,
|
|
3343
|
-
drizzleOrm.sql`${field2} ${direction}`
|
|
3344
|
-
);
|
|
3345
|
-
}
|
|
3346
|
-
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join(parts, drizzleOrm.sql`, `)}`;
|
|
3347
|
-
}
|
|
3348
|
-
function compileLimitOffset(ast) {
|
|
3349
|
-
const parts = [];
|
|
3350
|
-
if (ast.limit !== void 0) {
|
|
3351
|
-
parts.push(drizzleOrm.sql`LIMIT ${ast.limit}`);
|
|
3352
|
-
}
|
|
3353
|
-
if (ast.offset !== void 0) {
|
|
3354
|
-
parts.push(drizzleOrm.sql`OFFSET ${ast.offset}`);
|
|
3355
|
-
}
|
|
3356
|
-
return parts.length > 0 ? drizzleOrm.sql.join(parts, drizzleOrm.sql` `) : void 0;
|
|
3357
|
-
}
|
|
3358
|
-
var DEFAULT_TABLE_NAMES = {
|
|
3359
|
-
nodes: "typegraph_nodes",
|
|
3360
|
-
edges: "typegraph_edges",
|
|
3361
|
-
embeddings: "typegraph_node_embeddings"
|
|
3362
|
-
};
|
|
3363
|
-
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
3364
|
-
function validateTableName(name, label) {
|
|
3365
|
-
if (!name || name.length === 0) {
|
|
3366
|
-
throw new chunkO5PST6TB_cjs.ConfigurationError(`${label} table name cannot be empty`);
|
|
3367
|
-
}
|
|
3368
|
-
if (name.length > chunkMME3H4ZF_cjs.MAX_PG_IDENTIFIER_LENGTH) {
|
|
3369
|
-
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
3370
|
-
`${label} table name exceeds maximum length of ${chunkMME3H4ZF_cjs.MAX_PG_IDENTIFIER_LENGTH} characters`
|
|
3371
|
-
);
|
|
3372
|
-
}
|
|
3373
|
-
if (!VALID_IDENTIFIER_PATTERN.test(name)) {
|
|
3374
|
-
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
3375
|
-
`${label} table name "${name}" is not a valid SQL identifier. Table names must start with a letter or underscore and contain only letters, digits, underscores, or dollar signs.`
|
|
3753
|
+
const direction = drizzleOrm.sql.raw(orderSpec.direction.toUpperCase());
|
|
3754
|
+
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
3755
|
+
const nullsDirection = drizzleOrm.sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
3756
|
+
parts.push(
|
|
3757
|
+
drizzleOrm.sql`(${field2} IS NULL) ${nullsDirection}`,
|
|
3758
|
+
drizzleOrm.sql`${field2} ${direction}`
|
|
3376
3759
|
);
|
|
3377
3760
|
}
|
|
3761
|
+
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join(parts, drizzleOrm.sql`, `)}`;
|
|
3378
3762
|
}
|
|
3379
|
-
function
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
return
|
|
3388
|
-
tables,
|
|
3389
|
-
nodesTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.nodes)),
|
|
3390
|
-
edgesTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.edges)),
|
|
3391
|
-
embeddingsTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.embeddings))
|
|
3392
|
-
};
|
|
3763
|
+
function compileLimitOffset(ast) {
|
|
3764
|
+
const parts = [];
|
|
3765
|
+
if (ast.limit !== void 0) {
|
|
3766
|
+
parts.push(drizzleOrm.sql`LIMIT ${ast.limit}`);
|
|
3767
|
+
}
|
|
3768
|
+
if (ast.offset !== void 0) {
|
|
3769
|
+
parts.push(drizzleOrm.sql`OFFSET ${ast.offset}`);
|
|
3770
|
+
}
|
|
3771
|
+
return parts.length > 0 ? drizzleOrm.sql.join(parts, drizzleOrm.sql` `) : void 0;
|
|
3393
3772
|
}
|
|
3394
|
-
var DEFAULT_SQL_SCHEMA = createSqlSchema();
|
|
3395
3773
|
|
|
3396
3774
|
// src/query/execution/value-decoder.ts
|
|
3397
3775
|
function nullToUndefined(value) {
|
|
@@ -3622,9 +4000,9 @@ function truncateToBytes(value, maxBytes) {
|
|
|
3622
4000
|
}
|
|
3623
4001
|
function projectionAlias(entityPrefix, kind, field2) {
|
|
3624
4002
|
const prefix = entityPrefix === "node" ? "sg_n" : "sg_e";
|
|
3625
|
-
const hash =
|
|
4003
|
+
const hash = chunkFQCQM3KG_cjs.fnv1aBase36(`${kind}\0${field2}`);
|
|
3626
4004
|
const fixedBytes = prefix.length + 1 + 1 + hash.length;
|
|
3627
|
-
const maxKindBytes =
|
|
4005
|
+
const maxKindBytes = chunkFQCQM3KG_cjs.MAX_PG_IDENTIFIER_LENGTH - fixedBytes;
|
|
3628
4006
|
const truncatedKind = truncateToBytes(kind, maxKindBytes);
|
|
3629
4007
|
return `${prefix}_${truncatedKind}_${hash}`;
|
|
3630
4008
|
}
|
|
@@ -3696,12 +4074,7 @@ async function executeSubgraph(params) {
|
|
|
3696
4074
|
for (const row of edgeRows) {
|
|
3697
4075
|
const edge = mapSubgraphEdgeRow(row, edgeProjectionPlan);
|
|
3698
4076
|
insertAdjacencyEntry(adjacency, edge.fromId, edge.kind, edge);
|
|
3699
|
-
insertAdjacencyEntry(
|
|
3700
|
-
reverseAdjacency,
|
|
3701
|
-
edge.toId,
|
|
3702
|
-
edge.kind,
|
|
3703
|
-
edge
|
|
3704
|
-
);
|
|
4077
|
+
insertAdjacencyEntry(reverseAdjacency, edge.toId, edge.kind, edge);
|
|
3705
4078
|
}
|
|
3706
4079
|
const root = nodesMap.get(ctx.rootId);
|
|
3707
4080
|
return {
|
|
@@ -3727,7 +4100,7 @@ function getSubgraphSchemaIntrospector(graph) {
|
|
|
3727
4100
|
{ schema: definition.type.schema }
|
|
3728
4101
|
])
|
|
3729
4102
|
);
|
|
3730
|
-
const introspector =
|
|
4103
|
+
const introspector = chunkUVZHTBZ5_cjs.createSchemaIntrospector(nodeKinds, edgeKinds);
|
|
3731
4104
|
introspectorCache.set(graph, introspector);
|
|
3732
4105
|
return introspector;
|
|
3733
4106
|
}
|
|
@@ -3871,11 +4244,11 @@ function buildProjectedPropertyColumns(alias, plan, dialect) {
|
|
|
3871
4244
|
const extracted = compileTypedJsonExtract({
|
|
3872
4245
|
column: drizzleOrm.sql.raw(`${alias}.props`),
|
|
3873
4246
|
dialect,
|
|
3874
|
-
pointer:
|
|
4247
|
+
pointer: chunkUVZHTBZ5_cjs.jsonPointer([fieldPlan.field]),
|
|
3875
4248
|
valueType: fieldPlan.typeInfo?.valueType
|
|
3876
4249
|
});
|
|
3877
4250
|
columns.push(
|
|
3878
|
-
drizzleOrm.sql`CASE WHEN ${drizzleOrm.sql.raw(alias)}.kind = ${kind} THEN ${extracted} ELSE NULL END AS ${
|
|
4251
|
+
drizzleOrm.sql`CASE WHEN ${drizzleOrm.sql.raw(alias)}.kind = ${kind} THEN ${extracted} ELSE NULL END AS ${quoteIdentifier2(fieldPlan.outputName)}`
|
|
3879
4252
|
);
|
|
3880
4253
|
}
|
|
3881
4254
|
}
|
|
@@ -3942,16 +4315,6 @@ function mapSubgraphEdgeRow(row, projectionPlan) {
|
|
|
3942
4315
|
applyProjectedFields(projectedEdge, row, kindPlan);
|
|
3943
4316
|
return projectedEdge;
|
|
3944
4317
|
}
|
|
3945
|
-
|
|
3946
|
-
// src/query/ast.ts
|
|
3947
|
-
function mergeEdgeKinds(traversal) {
|
|
3948
|
-
const inverse = traversal.inverseEdgeKinds;
|
|
3949
|
-
if (inverse === void 0 || inverse.length === 0) return traversal.edgeKinds;
|
|
3950
|
-
return [
|
|
3951
|
-
...traversal.edgeKinds,
|
|
3952
|
-
...inverse.filter((kind) => !traversal.edgeKinds.includes(kind))
|
|
3953
|
-
];
|
|
3954
|
-
}
|
|
3955
4318
|
var OPERATOR_MAP = {
|
|
3956
4319
|
union: "UNION",
|
|
3957
4320
|
unionAll: "UNION ALL",
|
|
@@ -4108,6 +4471,9 @@ function validateSqliteSetOpLeaf(ast) {
|
|
|
4108
4471
|
if (hasVectorSimilarityPredicates(ast)) {
|
|
4109
4472
|
unsupported.push("vector similarity predicates");
|
|
4110
4473
|
}
|
|
4474
|
+
if (hasFulltextMatchPredicates(ast)) {
|
|
4475
|
+
unsupported.push("fulltext match predicates");
|
|
4476
|
+
}
|
|
4111
4477
|
if (ast.groupBy !== void 0) {
|
|
4112
4478
|
unsupported.push("GROUP BY");
|
|
4113
4479
|
}
|
|
@@ -4157,7 +4523,42 @@ function hasVectorSimilarityInExpression(expr) {
|
|
|
4157
4523
|
case "between":
|
|
4158
4524
|
case "array_op":
|
|
4159
4525
|
case "object_op":
|
|
4160
|
-
case "aggregate_comparison":
|
|
4526
|
+
case "aggregate_comparison":
|
|
4527
|
+
case "fulltext_match": {
|
|
4528
|
+
return false;
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
return false;
|
|
4533
|
+
}
|
|
4534
|
+
function hasFulltextMatchPredicates(ast) {
|
|
4535
|
+
return ast.predicates.some(
|
|
4536
|
+
(predicate2) => hasFulltextMatchInExpression(predicate2.expression)
|
|
4537
|
+
);
|
|
4538
|
+
}
|
|
4539
|
+
function hasFulltextMatchInExpression(expr) {
|
|
4540
|
+
if ("__type" in expr) {
|
|
4541
|
+
switch (expr.__type) {
|
|
4542
|
+
case "and":
|
|
4543
|
+
case "or": {
|
|
4544
|
+
return expr.predicates.some((p) => hasFulltextMatchInExpression(p));
|
|
4545
|
+
}
|
|
4546
|
+
case "not": {
|
|
4547
|
+
return hasFulltextMatchInExpression(expr.predicate);
|
|
4548
|
+
}
|
|
4549
|
+
case "fulltext_match": {
|
|
4550
|
+
return true;
|
|
4551
|
+
}
|
|
4552
|
+
case "exists":
|
|
4553
|
+
case "in_subquery":
|
|
4554
|
+
case "comparison":
|
|
4555
|
+
case "string_op":
|
|
4556
|
+
case "null_check":
|
|
4557
|
+
case "between":
|
|
4558
|
+
case "array_op":
|
|
4559
|
+
case "object_op":
|
|
4560
|
+
case "aggregate_comparison":
|
|
4561
|
+
case "vector_similarity": {
|
|
4161
4562
|
return false;
|
|
4162
4563
|
}
|
|
4163
4564
|
}
|
|
@@ -4193,7 +4594,8 @@ function hasSubqueryInExpression(expr) {
|
|
|
4193
4594
|
case "array_op":
|
|
4194
4595
|
case "object_op":
|
|
4195
4596
|
case "aggregate_comparison":
|
|
4196
|
-
case "vector_similarity":
|
|
4597
|
+
case "vector_similarity":
|
|
4598
|
+
case "fulltext_match": {
|
|
4197
4599
|
return false;
|
|
4198
4600
|
}
|
|
4199
4601
|
}
|
|
@@ -4359,7 +4761,7 @@ function getLeftmostProjection(op) {
|
|
|
4359
4761
|
function normalizeFieldRefKey(field2) {
|
|
4360
4762
|
let pointer = field2.jsonPointer;
|
|
4361
4763
|
if (pointer === void 0 && field2.path.length > 1 && field2.path[0] === "props") {
|
|
4362
|
-
pointer =
|
|
4764
|
+
pointer = chunkUVZHTBZ5_cjs.jsonPointer(field2.path.slice(1));
|
|
4363
4765
|
}
|
|
4364
4766
|
const basePath = field2.path.length > 0 && field2.path[0] === "props" ? "props" : field2.path.join(".");
|
|
4365
4767
|
return `${field2.alias}:${basePath}:${pointer ?? ""}`;
|
|
@@ -4471,6 +4873,10 @@ function markPredicateFieldsAsRequired(requiredColumnsByAlias, expression) {
|
|
|
4471
4873
|
markFieldRefAsRequired(requiredColumnsByAlias, expression.field);
|
|
4472
4874
|
return;
|
|
4473
4875
|
}
|
|
4876
|
+
case "fulltext_match": {
|
|
4877
|
+
markFieldRefAsRequired(requiredColumnsByAlias, expression.field);
|
|
4878
|
+
return;
|
|
4879
|
+
}
|
|
4474
4880
|
case "exists": {
|
|
4475
4881
|
return;
|
|
4476
4882
|
}
|
|
@@ -4535,7 +4941,8 @@ function hasIdEqualityPredicate(expression, alias) {
|
|
|
4535
4941
|
case "aggregate_comparison":
|
|
4536
4942
|
case "exists":
|
|
4537
4943
|
case "in_subquery":
|
|
4538
|
-
case "vector_similarity":
|
|
4944
|
+
case "vector_similarity":
|
|
4945
|
+
case "fulltext_match": {
|
|
4539
4946
|
return false;
|
|
4540
4947
|
}
|
|
4541
4948
|
}
|
|
@@ -4576,10 +4983,13 @@ function resolveTraversalCteLimit(ast, predicateIndex) {
|
|
|
4576
4983
|
);
|
|
4577
4984
|
return Math.max(ast.limit, pushdownLimit);
|
|
4578
4985
|
}
|
|
4579
|
-
function canCollapseSelectiveTraversalRowset(ast, vectorPredicate) {
|
|
4986
|
+
function canCollapseSelectiveTraversalRowset(ast, vectorPredicate, fulltextPredicate) {
|
|
4580
4987
|
if (vectorPredicate !== void 0) {
|
|
4581
4988
|
return false;
|
|
4582
4989
|
}
|
|
4990
|
+
if (fulltextPredicate !== void 0) {
|
|
4991
|
+
return false;
|
|
4992
|
+
}
|
|
4583
4993
|
if (ast.traversals.length === 0) {
|
|
4584
4994
|
return false;
|
|
4585
4995
|
}
|
|
@@ -4619,6 +5029,8 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
|
|
|
4619
5029
|
collapsedTraversalCteAlias: void 0,
|
|
4620
5030
|
ctx,
|
|
4621
5031
|
effectiveLimit: void 0,
|
|
5032
|
+
fulltextPredicate: void 0,
|
|
5033
|
+
fusion: void 0,
|
|
4622
5034
|
logicalPlan: void 0,
|
|
4623
5035
|
predicateIndex: buildPredicateIndex(ast),
|
|
4624
5036
|
requiredColumnsByAlias: void 0,
|
|
@@ -4640,6 +5052,39 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
|
|
|
4640
5052
|
}
|
|
4641
5053
|
});
|
|
4642
5054
|
state = vectorPass.state;
|
|
5055
|
+
const fulltextPass = runCompilerPass(state, {
|
|
5056
|
+
name: "fulltext_predicate",
|
|
5057
|
+
execute(currentState) {
|
|
5058
|
+
return runFulltextPredicatePass(
|
|
5059
|
+
currentState.ast,
|
|
5060
|
+
currentState.ctx.dialect
|
|
5061
|
+
).fulltextPredicate;
|
|
5062
|
+
},
|
|
5063
|
+
update(currentState, fulltextPredicate) {
|
|
5064
|
+
return {
|
|
5065
|
+
...currentState,
|
|
5066
|
+
fulltextPredicate
|
|
5067
|
+
};
|
|
5068
|
+
}
|
|
5069
|
+
});
|
|
5070
|
+
state = fulltextPass.state;
|
|
5071
|
+
const fusionPass = runCompilerPass(state, {
|
|
5072
|
+
name: "fusion_config",
|
|
5073
|
+
execute(currentState) {
|
|
5074
|
+
return runFusionConfigPass(
|
|
5075
|
+
currentState.ast,
|
|
5076
|
+
currentState.vectorPredicate,
|
|
5077
|
+
currentState.fulltextPredicate
|
|
5078
|
+
).fusion;
|
|
5079
|
+
},
|
|
5080
|
+
update(currentState, fusion) {
|
|
5081
|
+
return {
|
|
5082
|
+
...currentState,
|
|
5083
|
+
fusion
|
|
5084
|
+
};
|
|
5085
|
+
}
|
|
5086
|
+
});
|
|
5087
|
+
state = fusionPass.state;
|
|
4643
5088
|
const temporalPass = runCompilerPass(state, {
|
|
4644
5089
|
name: "temporal_filters",
|
|
4645
5090
|
execute(currentState) {
|
|
@@ -4674,7 +5119,8 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
|
|
|
4674
5119
|
execute(currentState) {
|
|
4675
5120
|
const shouldCollapseSelectiveTraversalRowset = canCollapseSelectiveTraversalRowset(
|
|
4676
5121
|
currentState.ast,
|
|
4677
|
-
currentState.vectorPredicate
|
|
5122
|
+
currentState.vectorPredicate,
|
|
5123
|
+
currentState.fulltextPredicate
|
|
4678
5124
|
);
|
|
4679
5125
|
const lastTraversal = currentState.ast.traversals.at(-1);
|
|
4680
5126
|
const collapsedTraversalCteAlias = shouldCollapseSelectiveTraversalRowset && lastTraversal !== void 0 ? `cte_${lastTraversal.nodeAlias}` : void 0;
|
|
@@ -4710,9 +5156,9 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
|
|
|
4710
5156
|
state = traversalLimitPass.state;
|
|
4711
5157
|
state = {
|
|
4712
5158
|
...state,
|
|
4713
|
-
effectiveLimit:
|
|
4714
|
-
state.ast.limit,
|
|
4715
|
-
state.
|
|
5159
|
+
effectiveLimit: resolveFulltextAwareLimit(
|
|
5160
|
+
resolveVectorAwareLimit(state.ast.limit, state.vectorPredicate),
|
|
5161
|
+
state.fulltextPredicate
|
|
4716
5162
|
)
|
|
4717
5163
|
};
|
|
4718
5164
|
const logicalPlanPass = runCompilerPass(state, {
|
|
@@ -4729,7 +5175,8 @@ function runStandardQueryPassPipeline(ast, graphId, ctx) {
|
|
|
4729
5175
|
collapsedTraversalCteAlias: currentState.collapsedTraversalCteAlias
|
|
4730
5176
|
},
|
|
4731
5177
|
...currentState.effectiveLimit === void 0 ? {} : { effectiveLimit: currentState.effectiveLimit },
|
|
4732
|
-
...currentState.vectorPredicate === void 0 ? {} : { vectorPredicate: currentState.vectorPredicate }
|
|
5178
|
+
...currentState.vectorPredicate === void 0 ? {} : { vectorPredicate: currentState.vectorPredicate },
|
|
5179
|
+
...currentState.fulltextPredicate === void 0 ? {} : { fulltextPredicate: currentState.fulltextPredicate }
|
|
4733
5180
|
});
|
|
4734
5181
|
},
|
|
4735
5182
|
update(currentState, logicalPlan) {
|
|
@@ -4748,11 +5195,11 @@ function compileQuery(ast, graphId, options = "sqlite") {
|
|
|
4748
5195
|
const options_ = typeof options === "string" ? { dialect: options } : options;
|
|
4749
5196
|
const dialect = options_.dialect ?? "sqlite";
|
|
4750
5197
|
const schema = options_.schema ?? DEFAULT_SQL_SCHEMA;
|
|
4751
|
-
const adapter =
|
|
5198
|
+
const adapter = resolveDialectAdapter(dialect, options_.fulltextStrategy);
|
|
4752
5199
|
const ctx = {
|
|
4753
5200
|
dialect: adapter,
|
|
4754
5201
|
schema,
|
|
4755
|
-
compileQuery: (subAst, subGraphId) => compileQuery(subAst, subGraphId,
|
|
5202
|
+
compileQuery: (subAst, subGraphId) => compileQuery(subAst, subGraphId, propagateOptions(options_))
|
|
4756
5203
|
};
|
|
4757
5204
|
if (hasVariableLengthTraversal(ast)) {
|
|
4758
5205
|
const lowered = tryLowerSingleHopRecursiveTraversal(ast);
|
|
@@ -4788,15 +5235,29 @@ function compileSetOperation2(op, graphId, options = "sqlite") {
|
|
|
4788
5235
|
const options_ = typeof options === "string" ? { dialect: options } : options;
|
|
4789
5236
|
const dialect = options_.dialect ?? "sqlite";
|
|
4790
5237
|
const schema = options_.schema ?? DEFAULT_SQL_SCHEMA;
|
|
4791
|
-
const adapter =
|
|
5238
|
+
const adapter = resolveDialectAdapter(dialect, options_.fulltextStrategy);
|
|
4792
5239
|
return compileSetOperation(
|
|
4793
5240
|
op,
|
|
4794
5241
|
graphId,
|
|
4795
5242
|
adapter,
|
|
4796
5243
|
schema,
|
|
4797
|
-
(ast, gid) => compileQuery(ast, gid,
|
|
5244
|
+
(ast, gid) => compileQuery(ast, gid, propagateOptions(options_))
|
|
4798
5245
|
);
|
|
4799
5246
|
}
|
|
5247
|
+
function resolveDialectAdapter(dialect, fulltextStrategy) {
|
|
5248
|
+
const baseAdapter = chunkFQCQM3KG_cjs.getDialect(dialect);
|
|
5249
|
+
if (fulltextStrategy === void 0 || fulltextStrategy === baseAdapter.fulltext) {
|
|
5250
|
+
return baseAdapter;
|
|
5251
|
+
}
|
|
5252
|
+
return { ...baseAdapter, fulltext: fulltextStrategy };
|
|
5253
|
+
}
|
|
5254
|
+
function propagateOptions(options_) {
|
|
5255
|
+
return {
|
|
5256
|
+
dialect: options_.dialect ?? "sqlite",
|
|
5257
|
+
...options_.schema === void 0 ? {} : { schema: options_.schema },
|
|
5258
|
+
...options_.fulltextStrategy === void 0 ? {} : { fulltextStrategy: options_.fulltextStrategy }
|
|
5259
|
+
};
|
|
5260
|
+
}
|
|
4800
5261
|
function resolveCountAggregateFastPath(ast) {
|
|
4801
5262
|
if (ast.traversals.length !== 1) {
|
|
4802
5263
|
return void 0;
|
|
@@ -4945,12 +5406,12 @@ function compileCountAggregateFastPath(ast, graphId, ctx, logicalPlan, requiredC
|
|
|
4945
5406
|
source.valueType,
|
|
4946
5407
|
`cte_${source.alias}`
|
|
4947
5408
|
);
|
|
4948
|
-
return drizzleOrm.sql`${value} AS ${
|
|
5409
|
+
return drizzleOrm.sql`${value} AS ${quoteIdentifier2(projectedField.outputName)}`;
|
|
4949
5410
|
}
|
|
4950
5411
|
const projectedCountColumn = source.function === "countDistinct" ? countDistinctColumn : countColumn;
|
|
4951
5412
|
const countValue = drizzleOrm.sql`${drizzleOrm.sql.raw(countCteAlias)}.${drizzleOrm.sql.raw(projectedCountColumn)}`;
|
|
4952
5413
|
const aggregateValue = traversal.optional ? drizzleOrm.sql`COALESCE(${countValue}, 0)` : countValue;
|
|
4953
|
-
return drizzleOrm.sql`${aggregateValue} AS ${
|
|
5414
|
+
return drizzleOrm.sql`${aggregateValue} AS ${quoteIdentifier2(projectedField.outputName)}`;
|
|
4954
5415
|
}),
|
|
4955
5416
|
drizzleOrm.sql`, `
|
|
4956
5417
|
);
|
|
@@ -4983,11 +5444,37 @@ function compileStandardQuery(ast, graphId, ctx) {
|
|
|
4983
5444
|
const handler = STANDARD_QUERY_STRATEGY_HANDLERS[strategy];
|
|
4984
5445
|
return handler(ast, graphId, ctx);
|
|
4985
5446
|
}
|
|
5447
|
+
function selectStandardOrderBy(input) {
|
|
5448
|
+
const {
|
|
5449
|
+
ast,
|
|
5450
|
+
collapsedTraversalCteAlias,
|
|
5451
|
+
dialect,
|
|
5452
|
+
fulltextPredicate,
|
|
5453
|
+
fusion,
|
|
5454
|
+
vectorPredicate
|
|
5455
|
+
} = input;
|
|
5456
|
+
if (vectorPredicate && fulltextPredicate) {
|
|
5457
|
+
return buildStandardHybridRrfOrderBy({ ast, dialect, fusion });
|
|
5458
|
+
}
|
|
5459
|
+
if (vectorPredicate) {
|
|
5460
|
+
return buildStandardVectorOrderBy({ ast, dialect });
|
|
5461
|
+
}
|
|
5462
|
+
if (fulltextPredicate) {
|
|
5463
|
+
return buildStandardFulltextOrderBy({ ast, dialect });
|
|
5464
|
+
}
|
|
5465
|
+
return buildStandardOrderBy({
|
|
5466
|
+
ast,
|
|
5467
|
+
...collapsedTraversalCteAlias === void 0 ? {} : { collapsedTraversalCteAlias },
|
|
5468
|
+
dialect
|
|
5469
|
+
});
|
|
5470
|
+
}
|
|
4986
5471
|
function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
4987
5472
|
const { dialect } = ctx;
|
|
4988
5473
|
const {
|
|
4989
5474
|
collapsedTraversalCteAlias,
|
|
4990
5475
|
effectiveLimit,
|
|
5476
|
+
fulltextPredicate,
|
|
5477
|
+
fusion,
|
|
4991
5478
|
logicalPlan,
|
|
4992
5479
|
predicateIndex,
|
|
4993
5480
|
requiredColumnsByAlias,
|
|
@@ -5008,7 +5495,7 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
5008
5495
|
{ phase: "standard-pass-pipeline" }
|
|
5009
5496
|
);
|
|
5010
5497
|
}
|
|
5011
|
-
if (!vectorPredicate) {
|
|
5498
|
+
if (!vectorPredicate && !fulltextPredicate) {
|
|
5012
5499
|
const fastPathSql = compileCountAggregateFastPath(
|
|
5013
5500
|
ast,
|
|
5014
5501
|
graphId,
|
|
@@ -5054,7 +5541,29 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
5054
5541
|
);
|
|
5055
5542
|
}
|
|
5056
5543
|
if (vectorPredicate) {
|
|
5057
|
-
|
|
5544
|
+
const nodeKinds = getNodeKindsForAlias(ast, vectorPredicate.field.alias);
|
|
5545
|
+
ctes.push(
|
|
5546
|
+
buildStandardEmbeddingsCte({
|
|
5547
|
+
ctx,
|
|
5548
|
+
graphId,
|
|
5549
|
+
nodeKinds,
|
|
5550
|
+
vectorPredicate
|
|
5551
|
+
})
|
|
5552
|
+
);
|
|
5553
|
+
}
|
|
5554
|
+
if (fulltextPredicate) {
|
|
5555
|
+
const nodeKinds = getNodeKindsForAlias(ast, fulltextPredicate.field.alias);
|
|
5556
|
+
ctes.push(
|
|
5557
|
+
buildStandardFulltextCte({
|
|
5558
|
+
ctx,
|
|
5559
|
+
fulltextPredicate,
|
|
5560
|
+
graphId,
|
|
5561
|
+
nodeKinds
|
|
5562
|
+
})
|
|
5563
|
+
);
|
|
5564
|
+
}
|
|
5565
|
+
if (getHybridTargetAlias(vectorPredicate, fulltextPredicate) !== void 0) {
|
|
5566
|
+
ctes.push(buildStandardHybridCandidateCte());
|
|
5058
5567
|
}
|
|
5059
5568
|
const projection = buildStandardProjection({
|
|
5060
5569
|
ast,
|
|
@@ -5064,14 +5573,18 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
5064
5573
|
const fromClause = buildStandardFromClause({
|
|
5065
5574
|
ast,
|
|
5066
5575
|
...collapsedTraversalCteAlias === void 0 ? {} : { collapsedTraversalCteAlias },
|
|
5067
|
-
...vectorPredicate === void 0 ? {} : { vectorPredicate }
|
|
5576
|
+
...vectorPredicate === void 0 ? {} : { vectorPredicate },
|
|
5577
|
+
...fulltextPredicate === void 0 ? {} : { fulltextPredicate }
|
|
5068
5578
|
});
|
|
5069
5579
|
const groupBy = buildStandardGroupBy({ ast, dialect });
|
|
5070
5580
|
const having2 = buildStandardHaving({ ast, ctx });
|
|
5071
|
-
const orderBy =
|
|
5581
|
+
const orderBy = selectStandardOrderBy({
|
|
5072
5582
|
ast,
|
|
5073
|
-
|
|
5074
|
-
dialect
|
|
5583
|
+
collapsedTraversalCteAlias,
|
|
5584
|
+
dialect,
|
|
5585
|
+
fulltextPredicate,
|
|
5586
|
+
fusion,
|
|
5587
|
+
vectorPredicate
|
|
5075
5588
|
});
|
|
5076
5589
|
const limitOffset = buildLimitOffsetClause({
|
|
5077
5590
|
limit: effectiveLimit,
|
|
@@ -5193,7 +5706,7 @@ function extractCursorValue(row, spec) {
|
|
|
5193
5706
|
current = record[segment];
|
|
5194
5707
|
}
|
|
5195
5708
|
if (jsonPointer2) {
|
|
5196
|
-
const segments =
|
|
5709
|
+
const segments = chunkUVZHTBZ5_cjs.parseJsonPointer(jsonPointer2);
|
|
5197
5710
|
for (const segment of segments) {
|
|
5198
5711
|
if (current === null || current === void 0) return void 0;
|
|
5199
5712
|
if (typeof current !== "object") return void 0;
|
|
@@ -5263,14 +5776,14 @@ function generateId() {
|
|
|
5263
5776
|
|
|
5264
5777
|
// src/utils/path.ts
|
|
5265
5778
|
function parseSqlitePath(path) {
|
|
5266
|
-
const emptyPath = `${
|
|
5779
|
+
const emptyPath = `${chunkFQCQM3KG_cjs.SQLITE_PATH_DELIMITER}${chunkFQCQM3KG_cjs.SQLITE_PATH_DELIMITER}`;
|
|
5267
5780
|
if (!path || path === emptyPath) return [];
|
|
5268
5781
|
const trimmed = path.slice(1, -1);
|
|
5269
5782
|
if (trimmed === "") return [];
|
|
5270
|
-
return trimmed.split(
|
|
5783
|
+
return trimmed.split(chunkFQCQM3KG_cjs.SQLITE_PATH_DELIMITER);
|
|
5271
5784
|
}
|
|
5272
5785
|
function isSqlitePath(value) {
|
|
5273
|
-
return typeof value === "string" && value.startsWith(
|
|
5786
|
+
return typeof value === "string" && value.startsWith(chunkFQCQM3KG_cjs.SQLITE_PATH_DELIMITER) && value.endsWith(chunkFQCQM3KG_cjs.SQLITE_PATH_DELIMITER);
|
|
5274
5787
|
}
|
|
5275
5788
|
function normalizePath(value) {
|
|
5276
5789
|
if (Array.isArray(value)) {
|
|
@@ -5285,12 +5798,12 @@ function normalizePath(value) {
|
|
|
5285
5798
|
return [];
|
|
5286
5799
|
}
|
|
5287
5800
|
function isPostgresTextArray(value) {
|
|
5288
|
-
return typeof value === "string" && value.startsWith(
|
|
5801
|
+
return typeof value === "string" && value.startsWith(chunkFQCQM3KG_cjs.PG_ARRAY_START) && value.endsWith(chunkFQCQM3KG_cjs.PG_ARRAY_END);
|
|
5289
5802
|
}
|
|
5290
5803
|
function parsePostgresTextArray(value) {
|
|
5291
5804
|
const inner = value.slice(1, -1);
|
|
5292
5805
|
if (inner === "") return [];
|
|
5293
|
-
return inner.split(
|
|
5806
|
+
return inner.split(chunkFQCQM3KG_cjs.PG_PATH_ELEMENT_SEPARATOR);
|
|
5294
5807
|
}
|
|
5295
5808
|
|
|
5296
5809
|
// src/query/execution/result-mapper.ts
|
|
@@ -5492,11 +6005,7 @@ function buildComparisonPredicate(field2, op, value) {
|
|
|
5492
6005
|
};
|
|
5493
6006
|
}
|
|
5494
6007
|
function buildCursorFromContext(context, orderBy, direction) {
|
|
5495
|
-
return buildCursorFromRow(
|
|
5496
|
-
context,
|
|
5497
|
-
orderBy,
|
|
5498
|
-
direction
|
|
5499
|
-
);
|
|
6008
|
+
return buildCursorFromRow(context, orderBy, direction);
|
|
5500
6009
|
}
|
|
5501
6010
|
function buildPaginatedResult(data, orderedRows, orderBy, limit, hasMore, isBackward, cursor, buildContext) {
|
|
5502
6011
|
let nextCursor;
|
|
@@ -5531,7 +6040,7 @@ async function* createStreamIterable(batchSize, paginate) {
|
|
|
5531
6040
|
}
|
|
5532
6041
|
}
|
|
5533
6042
|
function getStreamBatchSize(options) {
|
|
5534
|
-
return options?.batchSize ??
|
|
6043
|
+
return options?.batchSize ?? chunkFQCQM3KG_cjs.DEFAULT_STREAM_BATCH_SIZE;
|
|
5535
6044
|
}
|
|
5536
6045
|
|
|
5537
6046
|
// src/query/execution/field-tracker.ts
|
|
@@ -5613,7 +6122,7 @@ function createNodeTrackingProxy(alias, kindNames, tracker, options) {
|
|
|
5613
6122
|
return getPlaceholderForSystemField(property, options.mode);
|
|
5614
6123
|
}
|
|
5615
6124
|
if (property === "meta") {
|
|
5616
|
-
for (const key of
|
|
6125
|
+
for (const key of chunkFQCQM3KG_cjs.NODE_META_KEYS) {
|
|
5617
6126
|
tracker.record(alias, `meta.${key}`, true);
|
|
5618
6127
|
}
|
|
5619
6128
|
return buildNodeMetaPlaceholder(options.mode);
|
|
@@ -5646,7 +6155,7 @@ function createEdgeTrackingProxy(alias, edgeKindNames, tracker, options) {
|
|
|
5646
6155
|
return getPlaceholderForSystemField(property, options.mode);
|
|
5647
6156
|
}
|
|
5648
6157
|
if (property === "meta") {
|
|
5649
|
-
for (const key of
|
|
6158
|
+
for (const key of chunkFQCQM3KG_cjs.EDGE_META_KEYS) {
|
|
5650
6159
|
tracker.record(alias, `meta.${key}`, true);
|
|
5651
6160
|
}
|
|
5652
6161
|
return buildEdgeMetaPlaceholder(options.mode);
|
|
@@ -6089,59 +6598,41 @@ function validateSqlIdentifier(alias) {
|
|
|
6089
6598
|
);
|
|
6090
6599
|
}
|
|
6091
6600
|
}
|
|
6092
|
-
function
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
{
|
|
6098
|
-
path,
|
|
6099
|
-
message: "Vector similarity predicates are only supported at top-level or inside AND groups."
|
|
6100
|
-
}
|
|
6101
|
-
]
|
|
6102
|
-
},
|
|
6103
|
-
{
|
|
6104
|
-
suggestion: "Rewrite the predicate to keep vector similarity at top-level or combine with additional filters using AND."
|
|
6105
|
-
}
|
|
6106
|
-
);
|
|
6107
|
-
}
|
|
6108
|
-
function validateVectorPredicateExpression(expression, inDisallowedBranch, path) {
|
|
6601
|
+
function validateStructuralPredicatePlacement(expression, matchType, buildError, inDisallowedBranch, path) {
|
|
6602
|
+
if (expression.__type === matchType) {
|
|
6603
|
+
if (inDisallowedBranch) buildError(path);
|
|
6604
|
+
return;
|
|
6605
|
+
}
|
|
6109
6606
|
switch (expression.__type) {
|
|
6110
|
-
case "vector_similarity": {
|
|
6111
|
-
if (inDisallowedBranch) {
|
|
6112
|
-
throwInvalidVectorPredicatePlacement(path);
|
|
6113
|
-
}
|
|
6114
|
-
return;
|
|
6115
|
-
}
|
|
6116
6607
|
case "and": {
|
|
6117
|
-
for (const [
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
predicate2,
|
|
6608
|
+
for (const [index, child] of expression.predicates.entries()) {
|
|
6609
|
+
validateStructuralPredicatePlacement(
|
|
6610
|
+
child,
|
|
6611
|
+
matchType,
|
|
6612
|
+
buildError,
|
|
6123
6613
|
inDisallowedBranch,
|
|
6124
|
-
`${path}.predicates[${
|
|
6614
|
+
`${path}.predicates[${index}]`
|
|
6125
6615
|
);
|
|
6126
6616
|
}
|
|
6127
6617
|
return;
|
|
6128
6618
|
}
|
|
6129
6619
|
case "or": {
|
|
6130
|
-
for (const [
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
predicate2,
|
|
6620
|
+
for (const [index, child] of expression.predicates.entries()) {
|
|
6621
|
+
validateStructuralPredicatePlacement(
|
|
6622
|
+
child,
|
|
6623
|
+
matchType,
|
|
6624
|
+
buildError,
|
|
6136
6625
|
true,
|
|
6137
|
-
`${path}.predicates[${
|
|
6626
|
+
`${path}.predicates[${index}]`
|
|
6138
6627
|
);
|
|
6139
6628
|
}
|
|
6140
6629
|
return;
|
|
6141
6630
|
}
|
|
6142
6631
|
case "not": {
|
|
6143
|
-
|
|
6632
|
+
validateStructuralPredicatePlacement(
|
|
6144
6633
|
expression.predicate,
|
|
6634
|
+
matchType,
|
|
6635
|
+
buildError,
|
|
6145
6636
|
true,
|
|
6146
6637
|
`${path}.predicate`
|
|
6147
6638
|
);
|
|
@@ -6155,24 +6646,108 @@ function validateVectorPredicateExpression(expression, inDisallowedBranch, path)
|
|
|
6155
6646
|
case "object_op":
|
|
6156
6647
|
case "aggregate_comparison":
|
|
6157
6648
|
case "exists":
|
|
6158
|
-
case "in_subquery":
|
|
6649
|
+
case "in_subquery":
|
|
6650
|
+
case "vector_similarity":
|
|
6651
|
+
case "fulltext_match": {
|
|
6159
6652
|
return;
|
|
6160
6653
|
}
|
|
6161
6654
|
}
|
|
6162
6655
|
}
|
|
6656
|
+
function throwInvalidVectorPredicatePlacement(path) {
|
|
6657
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
6658
|
+
"Vector similarity predicates cannot be nested under OR or NOT. Use top-level AND combinations instead.",
|
|
6659
|
+
{
|
|
6660
|
+
issues: [
|
|
6661
|
+
{
|
|
6662
|
+
path,
|
|
6663
|
+
message: "Vector similarity predicates are only supported at top-level or inside AND groups."
|
|
6664
|
+
}
|
|
6665
|
+
]
|
|
6666
|
+
},
|
|
6667
|
+
{
|
|
6668
|
+
suggestion: "Rewrite the predicate to keep vector similarity at top-level or combine with additional filters using AND."
|
|
6669
|
+
}
|
|
6670
|
+
);
|
|
6671
|
+
}
|
|
6672
|
+
function throwInvalidFulltextPredicatePlacement(path) {
|
|
6673
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
6674
|
+
"Fulltext match predicates (.matches()) cannot be nested under OR or NOT. Use top-level AND combinations instead.",
|
|
6675
|
+
{
|
|
6676
|
+
issues: [
|
|
6677
|
+
{
|
|
6678
|
+
path,
|
|
6679
|
+
message: "Fulltext match predicates are only supported at top-level or inside AND groups."
|
|
6680
|
+
}
|
|
6681
|
+
]
|
|
6682
|
+
},
|
|
6683
|
+
{
|
|
6684
|
+
suggestion: "Restructure your query so the fulltext match appears at the top level of a whereNode() or inside an .and() combination."
|
|
6685
|
+
}
|
|
6686
|
+
);
|
|
6687
|
+
}
|
|
6163
6688
|
function validateVectorPredicatePlacement(predicates) {
|
|
6164
|
-
for (const [
|
|
6165
|
-
|
|
6689
|
+
for (const [index, predicate2] of predicates.entries()) {
|
|
6690
|
+
validateStructuralPredicatePlacement(
|
|
6691
|
+
predicate2.expression,
|
|
6692
|
+
"vector_similarity",
|
|
6693
|
+
throwInvalidVectorPredicatePlacement,
|
|
6694
|
+
false,
|
|
6695
|
+
`predicates[${index}].expression`
|
|
6696
|
+
);
|
|
6697
|
+
}
|
|
6698
|
+
}
|
|
6699
|
+
function validateFulltextPredicatePlacement(predicates) {
|
|
6700
|
+
for (const [index, predicate2] of predicates.entries()) {
|
|
6701
|
+
validateStructuralPredicatePlacement(
|
|
6166
6702
|
predicate2.expression,
|
|
6703
|
+
"fulltext_match",
|
|
6704
|
+
throwInvalidFulltextPredicatePlacement,
|
|
6167
6705
|
false,
|
|
6168
|
-
`predicates[${
|
|
6706
|
+
`predicates[${index}].expression`
|
|
6169
6707
|
);
|
|
6170
6708
|
}
|
|
6171
6709
|
}
|
|
6710
|
+
function validateHybridFusionOptions(options) {
|
|
6711
|
+
const method = options.method;
|
|
6712
|
+
if (method !== void 0 && method !== "rrf") {
|
|
6713
|
+
throw new chunkO5PST6TB_cjs.ValidationError(`Unsupported fusion method: ${method}`, {
|
|
6714
|
+
issues: [{ path: "fusion.method", message: `Only "rrf" is supported.` }]
|
|
6715
|
+
});
|
|
6716
|
+
}
|
|
6717
|
+
const { k } = options;
|
|
6718
|
+
if (k !== void 0 && (!Number.isFinite(k) || k <= 0)) {
|
|
6719
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
6720
|
+
`Fusion k must be a positive finite number, got: ${String(k)}`,
|
|
6721
|
+
{
|
|
6722
|
+
issues: [{ path: "fusion.k", message: "Must be a positive number." }]
|
|
6723
|
+
}
|
|
6724
|
+
);
|
|
6725
|
+
}
|
|
6726
|
+
const weights = options.weights;
|
|
6727
|
+
if (weights !== void 0) {
|
|
6728
|
+
for (const key of ["vector", "fulltext"]) {
|
|
6729
|
+
const weight = weights[key];
|
|
6730
|
+
if (weight !== void 0 && (!Number.isFinite(weight) || weight < 0)) {
|
|
6731
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
6732
|
+
`Fusion weight for "${key}" must be a non-negative finite number, got: ${String(weight)}`,
|
|
6733
|
+
{
|
|
6734
|
+
issues: [
|
|
6735
|
+
{
|
|
6736
|
+
path: `fusion.weights.${key}`,
|
|
6737
|
+
message: "Must be a non-negative number."
|
|
6738
|
+
}
|
|
6739
|
+
]
|
|
6740
|
+
}
|
|
6741
|
+
);
|
|
6742
|
+
}
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6172
6746
|
|
|
6173
6747
|
// src/query/builder/ast-builder.ts
|
|
6174
6748
|
function buildQueryAst(config, state) {
|
|
6175
6749
|
validateVectorPredicatePlacement(state.predicates);
|
|
6750
|
+
validateFulltextPredicatePlacement(state.predicates);
|
|
6176
6751
|
const temporalMode = {
|
|
6177
6752
|
mode: state.temporalMode
|
|
6178
6753
|
};
|
|
@@ -6196,7 +6771,18 @@ function buildQueryAst(config, state) {
|
|
|
6196
6771
|
...state.limit !== void 0 && { limit: state.limit },
|
|
6197
6772
|
...state.offset !== void 0 && { offset: state.offset },
|
|
6198
6773
|
...state.groupBy !== void 0 && { groupBy: state.groupBy },
|
|
6199
|
-
...state.having !== void 0 && { having: state.having }
|
|
6774
|
+
...state.having !== void 0 && { having: state.having },
|
|
6775
|
+
...state.fusion !== void 0 && { fusion: state.fusion }
|
|
6776
|
+
};
|
|
6777
|
+
}
|
|
6778
|
+
|
|
6779
|
+
// src/query/builder/compile-options.ts
|
|
6780
|
+
function buildCompileOptions(config) {
|
|
6781
|
+
const fulltextStrategy = config.backend?.fulltextStrategy;
|
|
6782
|
+
return {
|
|
6783
|
+
dialect: config.dialect ?? "sqlite",
|
|
6784
|
+
schema: config.schema,
|
|
6785
|
+
...fulltextStrategy === void 0 ? {} : { fulltextStrategy }
|
|
6200
6786
|
};
|
|
6201
6787
|
}
|
|
6202
6788
|
function toLiteral(value) {
|
|
@@ -6298,7 +6884,8 @@ function substitutePredicateExpression(expr, bindings) {
|
|
|
6298
6884
|
case "array_op":
|
|
6299
6885
|
case "object_op":
|
|
6300
6886
|
case "aggregate_comparison":
|
|
6301
|
-
case "vector_similarity":
|
|
6887
|
+
case "vector_similarity":
|
|
6888
|
+
case "fulltext_match": {
|
|
6302
6889
|
return expr;
|
|
6303
6890
|
}
|
|
6304
6891
|
case "exists": {
|
|
@@ -6337,7 +6924,7 @@ function substituteParameters(ast, bindings) {
|
|
|
6337
6924
|
};
|
|
6338
6925
|
}
|
|
6339
6926
|
function fillPlaceholders(params, bindings, dialect) {
|
|
6340
|
-
const adapter =
|
|
6927
|
+
const adapter = chunkFQCQM3KG_cjs.getDialect(dialect);
|
|
6341
6928
|
return params.map((parameter) => {
|
|
6342
6929
|
if (parameter instanceof drizzleOrm.Placeholder) {
|
|
6343
6930
|
const name = parameter.name;
|
|
@@ -6550,7 +7137,8 @@ function collectParameterMetadataFromExpression(expression, names, stringOpParam
|
|
|
6550
7137
|
case "array_op":
|
|
6551
7138
|
case "object_op":
|
|
6552
7139
|
case "aggregate_comparison":
|
|
6553
|
-
case "vector_similarity":
|
|
7140
|
+
case "vector_similarity":
|
|
7141
|
+
case "fulltext_match": {
|
|
6554
7142
|
return;
|
|
6555
7143
|
}
|
|
6556
7144
|
case "exists": {
|
|
@@ -6681,7 +7269,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6681
7269
|
direction
|
|
6682
7270
|
} : {
|
|
6683
7271
|
field: fieldRef(alias, ["props"], {
|
|
6684
|
-
jsonPointer:
|
|
7272
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
6685
7273
|
valueType: typeInfo?.valueType,
|
|
6686
7274
|
elementType: typeInfo?.elementType
|
|
6687
7275
|
}),
|
|
@@ -6905,10 +7493,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6905
7493
|
* Builds compile options from the config.
|
|
6906
7494
|
*/
|
|
6907
7495
|
#compileOptions() {
|
|
6908
|
-
return
|
|
6909
|
-
dialect: this.#config.dialect ?? "sqlite",
|
|
6910
|
-
schema: this.#config.schema
|
|
6911
|
-
};
|
|
7496
|
+
return buildCompileOptions(this.#config);
|
|
6912
7497
|
}
|
|
6913
7498
|
#requireBackend() {
|
|
6914
7499
|
const { backend } = this.#config;
|
|
@@ -7290,7 +7875,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7290
7875
|
if (field2.jsonPointer === void 0) {
|
|
7291
7876
|
return false;
|
|
7292
7877
|
}
|
|
7293
|
-
const segments =
|
|
7878
|
+
const segments = chunkUVZHTBZ5_cjs.parseJsonPointer(field2.jsonPointer);
|
|
7294
7879
|
if (segments.length !== 1) {
|
|
7295
7880
|
return false;
|
|
7296
7881
|
}
|
|
@@ -7338,7 +7923,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7338
7923
|
aliasObject2[fieldName] = nullToUndefined(row[outputName2]);
|
|
7339
7924
|
continue;
|
|
7340
7925
|
}
|
|
7341
|
-
const segments =
|
|
7926
|
+
const segments = chunkUVZHTBZ5_cjs.parseJsonPointer(jsonPointer2);
|
|
7342
7927
|
if (segments.length === 0) {
|
|
7343
7928
|
throw new MissingSelectiveFieldError(alias, "orderBy");
|
|
7344
7929
|
}
|
|
@@ -7434,7 +8019,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7434
8019
|
);
|
|
7435
8020
|
}
|
|
7436
8021
|
const isBackward = options.last !== void 0 || options.before !== void 0;
|
|
7437
|
-
const limit = options.first ?? options.last ??
|
|
8022
|
+
const limit = options.first ?? options.last ?? chunkFQCQM3KG_cjs.DEFAULT_PAGINATION_LIMIT;
|
|
7438
8023
|
const cursor = options.after ?? options.before;
|
|
7439
8024
|
let cursorData;
|
|
7440
8025
|
if (cursor) {
|
|
@@ -7623,14 +8208,8 @@ var ExecutableAggregateQuery = class _ExecutableAggregateQuery {
|
|
|
7623
8208
|
this.#cachedCompiled = compiled;
|
|
7624
8209
|
return compiled;
|
|
7625
8210
|
}
|
|
7626
|
-
/**
|
|
7627
|
-
* Builds compile options from the config.
|
|
7628
|
-
*/
|
|
7629
8211
|
#compileOptions() {
|
|
7630
|
-
return
|
|
7631
|
-
dialect: this.#config.dialect ?? "sqlite",
|
|
7632
|
-
schema: this.#config.schema
|
|
7633
|
-
};
|
|
8212
|
+
return buildCompileOptions(this.#config);
|
|
7634
8213
|
}
|
|
7635
8214
|
/**
|
|
7636
8215
|
* Executes the query and returns typed results.
|
|
@@ -7861,7 +8440,7 @@ var TraversalBuilder = class _TraversalBuilder {
|
|
|
7861
8440
|
const valueType = typeInfo?.valueType;
|
|
7862
8441
|
const elementType = typeInfo?.elementType;
|
|
7863
8442
|
const ref = fieldRef(alias, ["props"], {
|
|
7864
|
-
jsonPointer:
|
|
8443
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([propertyName]),
|
|
7865
8444
|
valueType,
|
|
7866
8445
|
elementType
|
|
7867
8446
|
});
|
|
@@ -8181,7 +8760,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8181
8760
|
if (source.valueType !== void 0 || source.path.length !== 1 || source.path[0] !== "props" || source.jsonPointer === void 0) {
|
|
8182
8761
|
return [outputName, source];
|
|
8183
8762
|
}
|
|
8184
|
-
const segments =
|
|
8763
|
+
const segments = chunkUVZHTBZ5_cjs.parseJsonPointer(source.jsonPointer);
|
|
8185
8764
|
if (segments.length !== 1) {
|
|
8186
8765
|
return [outputName, source];
|
|
8187
8766
|
}
|
|
@@ -8235,7 +8814,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8235
8814
|
direction
|
|
8236
8815
|
} : {
|
|
8237
8816
|
field: fieldRef(alias, ["props"], {
|
|
8238
|
-
jsonPointer:
|
|
8817
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8239
8818
|
valueType: typeInfo?.valueType,
|
|
8240
8819
|
elementType: typeInfo?.elementType
|
|
8241
8820
|
}),
|
|
@@ -8310,7 +8889,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8310
8889
|
__type: "field_ref",
|
|
8311
8890
|
alias,
|
|
8312
8891
|
path: ["props"],
|
|
8313
|
-
jsonPointer:
|
|
8892
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8314
8893
|
valueType: typeInfo?.valueType,
|
|
8315
8894
|
elementType: typeInfo?.elementType
|
|
8316
8895
|
};
|
|
@@ -8357,6 +8936,36 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8357
8936
|
having: predicate2
|
|
8358
8937
|
});
|
|
8359
8938
|
}
|
|
8939
|
+
/**
|
|
8940
|
+
* Sets fusion parameters for hybrid (vector + fulltext) queries.
|
|
8941
|
+
*
|
|
8942
|
+
* Applies only when the query contains both a `.similarTo()` and a
|
|
8943
|
+
* `.$fulltext.matches()` predicate. Without this call, the default is
|
|
8944
|
+
* RRF with k=60 and equal weights. A mismatch between `.fuseWith()`
|
|
8945
|
+
* configuration and the predicates on the query is caught during
|
|
8946
|
+
* compilation, not here.
|
|
8947
|
+
*
|
|
8948
|
+
* @example
|
|
8949
|
+
* ```typescript
|
|
8950
|
+
* store.query()
|
|
8951
|
+
* .from("Document", "d")
|
|
8952
|
+
* .whereNode("d", d =>
|
|
8953
|
+
* d.$fulltext.matches("renewable energy", 50)
|
|
8954
|
+
* .and(d.embedding.similarTo(vec, 50))
|
|
8955
|
+
* .and(d.tenantId.eq(tenant))
|
|
8956
|
+
* )
|
|
8957
|
+
* .fuseWith({ k: 60, weights: { fulltext: 1.5 } })
|
|
8958
|
+
* .limit(10)
|
|
8959
|
+
* .execute();
|
|
8960
|
+
* ```
|
|
8961
|
+
*/
|
|
8962
|
+
fuseWith(options) {
|
|
8963
|
+
validateHybridFusionOptions(options);
|
|
8964
|
+
return new _QueryBuilder(this.#config, {
|
|
8965
|
+
...this.#state,
|
|
8966
|
+
fusion: options
|
|
8967
|
+
});
|
|
8968
|
+
}
|
|
8360
8969
|
/**
|
|
8361
8970
|
* Applies a query fragment to transform this builder.
|
|
8362
8971
|
*
|
|
@@ -8408,42 +9017,14 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8408
9017
|
property
|
|
8409
9018
|
) : void 0;
|
|
8410
9019
|
const ref = fieldRef(alias, ["props"], {
|
|
8411
|
-
jsonPointer:
|
|
9020
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([property]),
|
|
8412
9021
|
valueType: typeInfo?.valueType,
|
|
8413
9022
|
elementType: typeInfo?.elementType
|
|
8414
9023
|
});
|
|
8415
9024
|
return this.#buildFieldBuilderForTypeInfo(ref, typeInfo);
|
|
8416
9025
|
}
|
|
8417
9026
|
#buildFieldBuilderForTypeInfo(ref, typeInfo) {
|
|
8418
|
-
|
|
8419
|
-
return baseField(ref);
|
|
8420
|
-
}
|
|
8421
|
-
switch (typeInfo.valueType) {
|
|
8422
|
-
case "string": {
|
|
8423
|
-
return stringField(ref);
|
|
8424
|
-
}
|
|
8425
|
-
case "number": {
|
|
8426
|
-
return numberField(ref);
|
|
8427
|
-
}
|
|
8428
|
-
case "boolean": {
|
|
8429
|
-
return baseField(ref);
|
|
8430
|
-
}
|
|
8431
|
-
case "date": {
|
|
8432
|
-
return dateField(ref);
|
|
8433
|
-
}
|
|
8434
|
-
case "array": {
|
|
8435
|
-
return arrayField(ref);
|
|
8436
|
-
}
|
|
8437
|
-
case "object": {
|
|
8438
|
-
return objectField(ref, { typeInfo });
|
|
8439
|
-
}
|
|
8440
|
-
case "embedding": {
|
|
8441
|
-
return embeddingField(ref);
|
|
8442
|
-
}
|
|
8443
|
-
case "unknown": {
|
|
8444
|
-
return baseField(ref);
|
|
8445
|
-
}
|
|
8446
|
-
}
|
|
9027
|
+
return buildFieldBuilderForTypeInfo(ref, typeInfo);
|
|
8447
9028
|
}
|
|
8448
9029
|
#createNodeAccessor(alias) {
|
|
8449
9030
|
const kindNames = this.#getKindNamesForAlias(alias);
|
|
@@ -8453,6 +9034,10 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8453
9034
|
const kindAccessor = stringField(
|
|
8454
9035
|
fieldRef(alias, ["kind"], { valueType: "string" })
|
|
8455
9036
|
);
|
|
9037
|
+
const fulltextAccessor = createFulltextAccessor(
|
|
9038
|
+
alias,
|
|
9039
|
+
() => this.#hasSearchableField(kindNames)
|
|
9040
|
+
);
|
|
8456
9041
|
return new Proxy({}, {
|
|
8457
9042
|
get: (_, property) => {
|
|
8458
9043
|
if (typeof property === "symbol") return;
|
|
@@ -8460,10 +9045,15 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8460
9045
|
if (property === "toJSON") return;
|
|
8461
9046
|
if (property === "id") return idAccessor;
|
|
8462
9047
|
if (property === "kind") return kindAccessor;
|
|
9048
|
+
if (property === "$fulltext") return fulltextAccessor;
|
|
8463
9049
|
return this.#getFieldBuilderForProperty(kindNames, property, alias);
|
|
8464
9050
|
}
|
|
8465
9051
|
});
|
|
8466
9052
|
}
|
|
9053
|
+
#hasSearchableField(kindNames) {
|
|
9054
|
+
if (!kindNames) return false;
|
|
9055
|
+
return this.#config.schemaIntrospector.hasSearchableField(kindNames);
|
|
9056
|
+
}
|
|
8467
9057
|
#expandTraversalEdgeKinds(edgeKind, includeImplyingEdges) {
|
|
8468
9058
|
return includeImplyingEdges ? this.#config.registry.expandImplyingEdges(edgeKind) : [edgeKind];
|
|
8469
9059
|
}
|
|
@@ -8506,7 +9096,7 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
8506
9096
|
property
|
|
8507
9097
|
) : void 0;
|
|
8508
9098
|
const ref = fieldRef(alias, ["props"], {
|
|
8509
|
-
jsonPointer:
|
|
9099
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([property]),
|
|
8510
9100
|
valueType: typeInfo?.valueType,
|
|
8511
9101
|
elementType: typeInfo?.elementType
|
|
8512
9102
|
});
|
|
@@ -8689,14 +9279,8 @@ var UnionableQuery = class _UnionableQuery {
|
|
|
8689
9279
|
this.#cachedCompiled = compiled;
|
|
8690
9280
|
return compiled;
|
|
8691
9281
|
}
|
|
8692
|
-
/**
|
|
8693
|
-
* Builds compile options from the config.
|
|
8694
|
-
*/
|
|
8695
9282
|
#compileOptions() {
|
|
8696
|
-
return
|
|
8697
|
-
dialect: this.#config.dialect ?? "sqlite",
|
|
8698
|
-
schema: this.#config.schema
|
|
8699
|
-
};
|
|
9283
|
+
return buildCompileOptions(this.#config);
|
|
8700
9284
|
}
|
|
8701
9285
|
/**
|
|
8702
9286
|
* Executes the combined query.
|
|
@@ -8758,7 +9342,7 @@ function count(alias, field2) {
|
|
|
8758
9342
|
__type: "field_ref",
|
|
8759
9343
|
alias,
|
|
8760
9344
|
path: field2 ? ["props"] : ["id"],
|
|
8761
|
-
jsonPointer: field2 ?
|
|
9345
|
+
jsonPointer: field2 ? chunkUVZHTBZ5_cjs.jsonPointer([field2]) : void 0,
|
|
8762
9346
|
valueType: field2 ? void 0 : "string"
|
|
8763
9347
|
}
|
|
8764
9348
|
};
|
|
@@ -8771,7 +9355,7 @@ function countDistinct(alias, field2) {
|
|
|
8771
9355
|
__type: "field_ref",
|
|
8772
9356
|
alias,
|
|
8773
9357
|
path: field2 ? ["props"] : ["id"],
|
|
8774
|
-
jsonPointer: field2 ?
|
|
9358
|
+
jsonPointer: field2 ? chunkUVZHTBZ5_cjs.jsonPointer([field2]) : void 0,
|
|
8775
9359
|
valueType: field2 ? void 0 : "string"
|
|
8776
9360
|
}
|
|
8777
9361
|
};
|
|
@@ -8784,7 +9368,7 @@ function sum(alias, field2) {
|
|
|
8784
9368
|
__type: "field_ref",
|
|
8785
9369
|
alias,
|
|
8786
9370
|
path: ["props"],
|
|
8787
|
-
jsonPointer:
|
|
9371
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8788
9372
|
valueType: "number"
|
|
8789
9373
|
}
|
|
8790
9374
|
};
|
|
@@ -8797,7 +9381,7 @@ function avg(alias, field2) {
|
|
|
8797
9381
|
__type: "field_ref",
|
|
8798
9382
|
alias,
|
|
8799
9383
|
path: ["props"],
|
|
8800
|
-
jsonPointer:
|
|
9384
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8801
9385
|
valueType: "number"
|
|
8802
9386
|
}
|
|
8803
9387
|
};
|
|
@@ -8810,7 +9394,7 @@ function min(alias, field2) {
|
|
|
8810
9394
|
__type: "field_ref",
|
|
8811
9395
|
alias,
|
|
8812
9396
|
path: ["props"],
|
|
8813
|
-
jsonPointer:
|
|
9397
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8814
9398
|
valueType: "number"
|
|
8815
9399
|
}
|
|
8816
9400
|
};
|
|
@@ -8823,7 +9407,7 @@ function max(alias, field2) {
|
|
|
8823
9407
|
__type: "field_ref",
|
|
8824
9408
|
alias,
|
|
8825
9409
|
path: ["props"],
|
|
8826
|
-
jsonPointer:
|
|
9410
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer([field2]),
|
|
8827
9411
|
valueType: "number"
|
|
8828
9412
|
}
|
|
8829
9413
|
};
|
|
@@ -8854,7 +9438,7 @@ function field(alias, ...path) {
|
|
|
8854
9438
|
__type: "field_ref",
|
|
8855
9439
|
alias,
|
|
8856
9440
|
path: ["props"],
|
|
8857
|
-
jsonPointer:
|
|
9441
|
+
jsonPointer: chunkUVZHTBZ5_cjs.jsonPointer(path)
|
|
8858
9442
|
};
|
|
8859
9443
|
}
|
|
8860
9444
|
function having(aggregate, op, value) {
|
|
@@ -8912,16 +9496,12 @@ function offsetFragment(n) {
|
|
|
8912
9496
|
}
|
|
8913
9497
|
|
|
8914
9498
|
// src/query/builder/index.ts
|
|
8915
|
-
setQueryBuilderClass(
|
|
8916
|
-
|
|
8917
|
-
);
|
|
8918
|
-
setUnionableQueryClass(
|
|
8919
|
-
UnionableQuery
|
|
8920
|
-
);
|
|
9499
|
+
setQueryBuilderClass(QueryBuilder);
|
|
9500
|
+
setUnionableQueryClass(UnionableQuery);
|
|
8921
9501
|
|
|
8922
9502
|
// src/query/builder.ts
|
|
8923
9503
|
function createQueryBuilder(graphId, registry, options) {
|
|
8924
|
-
const schemaIntrospector =
|
|
9504
|
+
const schemaIntrospector = chunkUVZHTBZ5_cjs.createSchemaIntrospector(
|
|
8925
9505
|
registry.nodeKinds,
|
|
8926
9506
|
registry.edgeKinds
|
|
8927
9507
|
);
|
|
@@ -8948,7 +9528,8 @@ function createQueryBuilder(graphId, registry, options) {
|
|
|
8948
9528
|
temporalMode: "current",
|
|
8949
9529
|
asOf: void 0,
|
|
8950
9530
|
groupBy: void 0,
|
|
8951
|
-
having: void 0
|
|
9531
|
+
having: void 0,
|
|
9532
|
+
fusion: void 0
|
|
8952
9533
|
};
|
|
8953
9534
|
return new QueryBuilder(config, initialState);
|
|
8954
9535
|
}
|
|
@@ -8957,12 +9538,12 @@ function createQueryBuilder(graphId, registry, options) {
|
|
|
8957
9538
|
function buildKindRegistry(graph) {
|
|
8958
9539
|
const nodeTypes = extractNodeTypes(graph);
|
|
8959
9540
|
const edgeTypes = extractEdgeTypes(graph);
|
|
8960
|
-
const closures = graph.ontology.length > 0 ?
|
|
8961
|
-
return new
|
|
9541
|
+
const closures = graph.ontology.length > 0 ? chunkHRNQ3DVJ_cjs.computeClosuresFromOntology(graph.ontology) : chunkHRNQ3DVJ_cjs.createEmptyClosures();
|
|
9542
|
+
return new chunkHRNQ3DVJ_cjs.KindRegistry(nodeTypes, edgeTypes, closures);
|
|
8962
9543
|
}
|
|
8963
9544
|
function extractNodeTypes(graph) {
|
|
8964
9545
|
const result = /* @__PURE__ */ new Map();
|
|
8965
|
-
for (const typeName of
|
|
9546
|
+
for (const typeName of chunkWRWVWKQL_cjs.getNodeKinds(graph)) {
|
|
8966
9547
|
const registration = graph.nodes[typeName];
|
|
8967
9548
|
result.set(typeName, registration.type);
|
|
8968
9549
|
}
|
|
@@ -8970,7 +9551,7 @@ function extractNodeTypes(graph) {
|
|
|
8970
9551
|
}
|
|
8971
9552
|
function extractEdgeTypes(graph) {
|
|
8972
9553
|
const result = /* @__PURE__ */ new Map();
|
|
8973
|
-
for (const typeName of
|
|
9554
|
+
for (const typeName of chunkWRWVWKQL_cjs.getEdgeKinds(graph)) {
|
|
8974
9555
|
const registration = graph.edges[typeName];
|
|
8975
9556
|
result.set(typeName, registration.type);
|
|
8976
9557
|
}
|
|
@@ -9184,7 +9765,7 @@ function createGraphAlgorithms(params) {
|
|
|
9184
9765
|
const ctx = {
|
|
9185
9766
|
graphId: params.graphId,
|
|
9186
9767
|
backend: params.backend,
|
|
9187
|
-
dialect:
|
|
9768
|
+
dialect: chunkFQCQM3KG_cjs.getDialect(params.backend.dialect),
|
|
9188
9769
|
schema: params.schema ?? (params.backend.tableNames ? createSqlSchema(params.backend.tableNames) : createSqlSchema()),
|
|
9189
9770
|
defaultTemporalMode: params.defaultTemporalMode
|
|
9190
9771
|
};
|
|
@@ -9289,20 +9870,13 @@ function createEdgeCollection(config) {
|
|
|
9289
9870
|
const result = {};
|
|
9290
9871
|
if (options?.matchOn !== void 0)
|
|
9291
9872
|
result.matchOn = options.matchOn;
|
|
9292
|
-
if (options?.props !== void 0)
|
|
9293
|
-
result.props = options.props;
|
|
9873
|
+
if (options?.props !== void 0) result.props = options.props;
|
|
9294
9874
|
return result;
|
|
9295
9875
|
}
|
|
9296
9876
|
return {
|
|
9297
9877
|
async create(from, to, props, options) {
|
|
9298
9878
|
const result = await executeEdgeCreate2(
|
|
9299
|
-
buildCreateEdgeInput(
|
|
9300
|
-
kind,
|
|
9301
|
-
from,
|
|
9302
|
-
to,
|
|
9303
|
-
props ?? {},
|
|
9304
|
-
options
|
|
9305
|
-
),
|
|
9879
|
+
buildCreateEdgeInput(kind, from, to, props ?? {}, options),
|
|
9306
9880
|
backend
|
|
9307
9881
|
);
|
|
9308
9882
|
return narrowEdge(result);
|
|
@@ -9397,7 +9971,7 @@ function createEdgeCollection(config) {
|
|
|
9397
9971
|
temporalMode: mode
|
|
9398
9972
|
};
|
|
9399
9973
|
if (mode === "current" || mode === "asOf") {
|
|
9400
|
-
params.asOf = options?.asOf ??
|
|
9974
|
+
params.asOf = options?.asOf ?? chunkWRWVWKQL_cjs.nowIso();
|
|
9401
9975
|
}
|
|
9402
9976
|
if (options?.from?.kind !== void 0)
|
|
9403
9977
|
params.fromKind = options.from.kind;
|
|
@@ -9418,7 +9992,7 @@ function createEdgeCollection(config) {
|
|
|
9418
9992
|
temporalMode: mode
|
|
9419
9993
|
};
|
|
9420
9994
|
if (mode === "current" || mode === "asOf") {
|
|
9421
|
-
params.asOf = options?.asOf ??
|
|
9995
|
+
params.asOf = options?.asOf ?? chunkWRWVWKQL_cjs.nowIso();
|
|
9422
9996
|
}
|
|
9423
9997
|
if (options?.from?.kind !== void 0)
|
|
9424
9998
|
params.fromKind = options.from.kind;
|
|
@@ -9428,10 +10002,7 @@ function createEdgeCollection(config) {
|
|
|
9428
10002
|
return backend.countEdgesByKind(params);
|
|
9429
10003
|
},
|
|
9430
10004
|
async bulkCreate(items) {
|
|
9431
|
-
const batchInputs = mapBulkEdgeInputs(
|
|
9432
|
-
kind,
|
|
9433
|
-
items
|
|
9434
|
-
);
|
|
10005
|
+
const batchInputs = mapBulkEdgeInputs(kind, items);
|
|
9435
10006
|
if (backend.capabilities.transactions && "transaction" in backend) {
|
|
9436
10007
|
const results2 = await backend.transaction(
|
|
9437
10008
|
async (txBackend) => executeEdgeCreateBatch2(batchInputs, txBackend)
|
|
@@ -9467,11 +10038,7 @@ function createEdgeCollection(config) {
|
|
|
9467
10038
|
if (existing) {
|
|
9468
10039
|
toUpdate.push({
|
|
9469
10040
|
index: itemIndex,
|
|
9470
|
-
input: buildUpdateEdgeInput(
|
|
9471
|
-
item.id,
|
|
9472
|
-
item.props ?? {},
|
|
9473
|
-
item
|
|
9474
|
-
),
|
|
10041
|
+
input: buildUpdateEdgeInput(item.id, item.props ?? {}, item),
|
|
9475
10042
|
clearDeleted: existing.deleted_at !== void 0
|
|
9476
10043
|
});
|
|
9477
10044
|
} else {
|
|
@@ -9510,10 +10077,7 @@ function createEdgeCollection(config) {
|
|
|
9510
10077
|
return upsertAll(backend);
|
|
9511
10078
|
},
|
|
9512
10079
|
async bulkInsert(items) {
|
|
9513
|
-
const batchInputs = mapBulkEdgeInputs(
|
|
9514
|
-
kind,
|
|
9515
|
-
items
|
|
9516
|
-
);
|
|
10080
|
+
const batchInputs = mapBulkEdgeInputs(kind, items);
|
|
9517
10081
|
if (backend.capabilities.transactions && "transaction" in backend) {
|
|
9518
10082
|
await backend.transaction(async (txBackend) => {
|
|
9519
10083
|
await executeEdgeCreateNoReturnBatch2(batchInputs, txBackend);
|
|
@@ -9664,11 +10228,7 @@ function createNodeCollection(config) {
|
|
|
9664
10228
|
async getByIds(ids, options) {
|
|
9665
10229
|
if (ids.length === 0) return [];
|
|
9666
10230
|
if (backend.getNodes !== void 0) {
|
|
9667
|
-
const rows = await backend.getNodes(
|
|
9668
|
-
graphId,
|
|
9669
|
-
kind,
|
|
9670
|
-
ids
|
|
9671
|
-
);
|
|
10231
|
+
const rows = await backend.getNodes(graphId, kind, ids);
|
|
9672
10232
|
const rowMap = /* @__PURE__ */ new Map();
|
|
9673
10233
|
for (const row of rows) {
|
|
9674
10234
|
rowMap.set(row.id, row);
|
|
@@ -9713,7 +10273,7 @@ function createNodeCollection(config) {
|
|
|
9713
10273
|
const mode2 = options.temporalMode ?? defaultTemporalMode;
|
|
9714
10274
|
let query = createQuery().from(kind, "_n").temporal(
|
|
9715
10275
|
mode2,
|
|
9716
|
-
mode2 === "asOf" ? options.asOf ??
|
|
10276
|
+
mode2 === "asOf" ? options.asOf ?? chunkWRWVWKQL_cjs.nowIso() : void 0
|
|
9717
10277
|
).whereNode("_n", options.where).select((ctx) => ctx._n);
|
|
9718
10278
|
if (options.limit !== void 0) query = query.limit(options.limit);
|
|
9719
10279
|
if (options.offset !== void 0) query = query.offset(options.offset);
|
|
@@ -9728,7 +10288,7 @@ function createNodeCollection(config) {
|
|
|
9728
10288
|
temporalMode: mode
|
|
9729
10289
|
};
|
|
9730
10290
|
if (mode === "current" || mode === "asOf") {
|
|
9731
|
-
params.asOf = options?.asOf ??
|
|
10291
|
+
params.asOf = options?.asOf ?? chunkWRWVWKQL_cjs.nowIso();
|
|
9732
10292
|
}
|
|
9733
10293
|
if (options?.limit !== void 0) params.limit = options.limit;
|
|
9734
10294
|
if (options?.offset !== void 0) params.offset = options.offset;
|
|
@@ -9744,16 +10304,12 @@ function createNodeCollection(config) {
|
|
|
9744
10304
|
temporalMode: mode
|
|
9745
10305
|
};
|
|
9746
10306
|
if (mode === "current" || mode === "asOf") {
|
|
9747
|
-
params.asOf = options?.asOf ??
|
|
10307
|
+
params.asOf = options?.asOf ?? chunkWRWVWKQL_cjs.nowIso();
|
|
9748
10308
|
}
|
|
9749
10309
|
return backend.countNodesByKind(params);
|
|
9750
10310
|
},
|
|
9751
10311
|
async upsertById(id, props, options) {
|
|
9752
|
-
return this.upsertByIdFromRecord(
|
|
9753
|
-
id,
|
|
9754
|
-
props,
|
|
9755
|
-
options
|
|
9756
|
-
);
|
|
10312
|
+
return this.upsertByIdFromRecord(id, props, options);
|
|
9757
10313
|
},
|
|
9758
10314
|
async upsertByIdFromRecord(id, data, options) {
|
|
9759
10315
|
const existing = await backend.getNode(graphId, kind, id);
|
|
@@ -9773,10 +10329,7 @@ function createNodeCollection(config) {
|
|
|
9773
10329
|
return narrowNode(result);
|
|
9774
10330
|
},
|
|
9775
10331
|
async bulkCreate(items) {
|
|
9776
|
-
const batchInputs = mapBulkNodeInputs(
|
|
9777
|
-
kind,
|
|
9778
|
-
items
|
|
9779
|
-
);
|
|
10332
|
+
const batchInputs = mapBulkNodeInputs(kind, items);
|
|
9780
10333
|
if (backend.capabilities.transactions && "transaction" in backend) {
|
|
9781
10334
|
const results2 = await backend.transaction(
|
|
9782
10335
|
async (txBackend) => executeNodeCreateBatch2(batchInputs, txBackend)
|
|
@@ -9799,11 +10352,7 @@ function createNodeCollection(config) {
|
|
|
9799
10352
|
if (row !== void 0) existingMap.set(row.id, row);
|
|
9800
10353
|
}
|
|
9801
10354
|
} else {
|
|
9802
|
-
const rows = await target.getNodes(
|
|
9803
|
-
graphId,
|
|
9804
|
-
kind,
|
|
9805
|
-
ids
|
|
9806
|
-
);
|
|
10355
|
+
const rows = await target.getNodes(graphId, kind, ids);
|
|
9807
10356
|
for (const row of rows) {
|
|
9808
10357
|
existingMap.set(row.id, row);
|
|
9809
10358
|
}
|
|
@@ -9816,22 +10365,13 @@ function createNodeCollection(config) {
|
|
|
9816
10365
|
if (existing) {
|
|
9817
10366
|
toUpdate.push({
|
|
9818
10367
|
index: itemIndex,
|
|
9819
|
-
input: buildUpdateInput(
|
|
9820
|
-
kind,
|
|
9821
|
-
item.id,
|
|
9822
|
-
item.props,
|
|
9823
|
-
item
|
|
9824
|
-
),
|
|
10368
|
+
input: buildUpdateInput(kind, item.id, item.props, item),
|
|
9825
10369
|
clearDeleted: existing.deleted_at !== void 0
|
|
9826
10370
|
});
|
|
9827
10371
|
} else {
|
|
9828
10372
|
toCreate.push({
|
|
9829
10373
|
index: itemIndex,
|
|
9830
|
-
input: buildCreateInput(
|
|
9831
|
-
kind,
|
|
9832
|
-
item.props,
|
|
9833
|
-
item
|
|
9834
|
-
)
|
|
10374
|
+
input: buildCreateInput(kind, item.props, item)
|
|
9835
10375
|
});
|
|
9836
10376
|
}
|
|
9837
10377
|
itemIndex++;
|
|
@@ -9858,10 +10398,7 @@ function createNodeCollection(config) {
|
|
|
9858
10398
|
return upsertAll(backend);
|
|
9859
10399
|
},
|
|
9860
10400
|
async bulkInsert(items) {
|
|
9861
|
-
const batchInputs = mapBulkNodeInputs(
|
|
9862
|
-
kind,
|
|
9863
|
-
items
|
|
9864
|
-
);
|
|
10401
|
+
const batchInputs = mapBulkNodeInputs(kind, items);
|
|
9865
10402
|
if (backend.capabilities.transactions && "transaction" in backend) {
|
|
9866
10403
|
await backend.transaction(async (txBackend) => {
|
|
9867
10404
|
await executeNodeCreateNoReturnBatch2(batchInputs, txBackend);
|
|
@@ -10394,12 +10931,12 @@ async function validateAndPrepareEdgeCreate(ctx, input, id, backend) {
|
|
|
10394
10931
|
nodeId: input.toId
|
|
10395
10932
|
});
|
|
10396
10933
|
}
|
|
10397
|
-
const validatedProps =
|
|
10934
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateEdgeProps(edgeKind.schema, input.props, {
|
|
10398
10935
|
kind,
|
|
10399
10936
|
operation: "create"
|
|
10400
10937
|
});
|
|
10401
|
-
const validFrom =
|
|
10402
|
-
const validTo =
|
|
10938
|
+
const validFrom = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validFrom, "validFrom");
|
|
10939
|
+
const validTo = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validTo, "validTo");
|
|
10403
10940
|
const cardinality = registration.cardinality ?? "many";
|
|
10404
10941
|
const constraintContext = {
|
|
10405
10942
|
graphId: ctx.graphId,
|
|
@@ -10544,12 +11081,12 @@ async function executeEdgeUpdate(ctx, input, backend) {
|
|
|
10544
11081
|
const edgeKind = registration.type;
|
|
10545
11082
|
const existingProps = JSON.parse(existing.props);
|
|
10546
11083
|
const mergedProps = { ...existingProps, ...input.props };
|
|
10547
|
-
const validatedProps =
|
|
11084
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateEdgeProps(edgeKind.schema, mergedProps, {
|
|
10548
11085
|
kind: existing.kind,
|
|
10549
11086
|
operation: "update",
|
|
10550
11087
|
id
|
|
10551
11088
|
});
|
|
10552
|
-
const validTo =
|
|
11089
|
+
const validTo = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validTo, "validTo");
|
|
10553
11090
|
const updateParams = {
|
|
10554
11091
|
graphId: ctx.graphId,
|
|
10555
11092
|
id,
|
|
@@ -10570,12 +11107,12 @@ async function executeEdgeUpsertUpdate(ctx, input, backend, options) {
|
|
|
10570
11107
|
const edgeKind = registration.type;
|
|
10571
11108
|
const existingProps = JSON.parse(existing.props);
|
|
10572
11109
|
const mergedProps = { ...existingProps, ...input.props };
|
|
10573
|
-
const validatedProps =
|
|
11110
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateEdgeProps(edgeKind.schema, mergedProps, {
|
|
10574
11111
|
kind: existing.kind,
|
|
10575
11112
|
operation: "update",
|
|
10576
11113
|
id
|
|
10577
11114
|
});
|
|
10578
|
-
const validTo =
|
|
11115
|
+
const validTo = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validTo, "validTo");
|
|
10579
11116
|
const updateParams = {
|
|
10580
11117
|
graphId: ctx.graphId,
|
|
10581
11118
|
id,
|
|
@@ -10727,7 +11264,7 @@ async function executeEdgeGetOrCreateByEndpoints(ctx, kind, fromKind, fromId, to
|
|
|
10727
11264
|
const matchOn = options?.matchOn ?? [];
|
|
10728
11265
|
const registration = getEdgeRegistration(ctx.graph, kind);
|
|
10729
11266
|
const edgeKind = registration.type;
|
|
10730
|
-
const validatedProps =
|
|
11267
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateEdgeProps(edgeKind.schema, props, {
|
|
10731
11268
|
kind,
|
|
10732
11269
|
operation: "create"
|
|
10733
11270
|
});
|
|
@@ -10809,7 +11346,7 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
|
|
|
10809
11346
|
validateMatchOnFields(edgeKind.schema, matchOn, kind);
|
|
10810
11347
|
const validated = [];
|
|
10811
11348
|
for (const item of items) {
|
|
10812
|
-
const validatedProps =
|
|
11349
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateEdgeProps(edgeKind.schema, item.props, {
|
|
10813
11350
|
kind,
|
|
10814
11351
|
operation: "create"
|
|
10815
11352
|
});
|
|
@@ -10967,15 +11504,19 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
|
|
|
10967
11504
|
}
|
|
10968
11505
|
|
|
10969
11506
|
// src/store/embedding-sync.ts
|
|
11507
|
+
var embeddingFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
10970
11508
|
function getEmbeddingFields(schema) {
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
11509
|
+
const cached = embeddingFieldsCache.get(schema);
|
|
11510
|
+
if (cached) return cached;
|
|
11511
|
+
const fields = computeEmbeddingFields(schema);
|
|
11512
|
+
embeddingFieldsCache.set(schema, fields);
|
|
11513
|
+
return fields;
|
|
11514
|
+
}
|
|
11515
|
+
function computeEmbeddingFields(schema) {
|
|
11516
|
+
if (schema.type !== "object") return [];
|
|
10974
11517
|
const def = schema.def;
|
|
10975
11518
|
const shape = def.shape;
|
|
10976
|
-
if (!shape)
|
|
10977
|
-
return [];
|
|
10978
|
-
}
|
|
11519
|
+
if (!shape) return [];
|
|
10979
11520
|
const fields = [];
|
|
10980
11521
|
for (const [fieldPath, fieldSchema] of Object.entries(shape)) {
|
|
10981
11522
|
const dimensions = getEmbeddingDimensionsFromField(fieldSchema);
|
|
@@ -10986,13 +11527,13 @@ function getEmbeddingFields(schema) {
|
|
|
10986
11527
|
return fields;
|
|
10987
11528
|
}
|
|
10988
11529
|
function getEmbeddingDimensionsFromField(schema) {
|
|
10989
|
-
const directDimensions =
|
|
11530
|
+
const directDimensions = chunkUVZHTBZ5_cjs.getEmbeddingDimensions(schema);
|
|
10990
11531
|
if (directDimensions !== void 0) {
|
|
10991
11532
|
return directDimensions;
|
|
10992
11533
|
}
|
|
10993
11534
|
const unwrapped = unwrapToEmbedding(schema);
|
|
10994
11535
|
if (unwrapped) {
|
|
10995
|
-
return
|
|
11536
|
+
return chunkUVZHTBZ5_cjs.getEmbeddingDimensions(unwrapped);
|
|
10996
11537
|
}
|
|
10997
11538
|
return void 0;
|
|
10998
11539
|
}
|
|
@@ -11000,7 +11541,7 @@ function unwrapToEmbedding(schema) {
|
|
|
11000
11541
|
const type = schema.type;
|
|
11001
11542
|
const def = schema.def;
|
|
11002
11543
|
if ((type === "optional" || type === "nullable" || type === "default" || type === "readonly") && def.innerType) {
|
|
11003
|
-
if (
|
|
11544
|
+
if (chunkUVZHTBZ5_cjs.isEmbeddingSchema(def.innerType)) {
|
|
11004
11545
|
return def.innerType;
|
|
11005
11546
|
}
|
|
11006
11547
|
return unwrapToEmbedding(def.innerType);
|
|
@@ -11062,6 +11603,101 @@ function isValidEmbeddingValue(value) {
|
|
|
11062
11603
|
return value.every((n) => typeof n === "number" && Number.isFinite(n));
|
|
11063
11604
|
}
|
|
11064
11605
|
|
|
11606
|
+
// src/store/fulltext-sync.ts
|
|
11607
|
+
var searchableFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
11608
|
+
function getSearchableFields(schema) {
|
|
11609
|
+
const cached = searchableFieldsCache.get(schema);
|
|
11610
|
+
if (cached) return cached;
|
|
11611
|
+
const fields = computeSearchableFields(schema);
|
|
11612
|
+
searchableFieldsCache.set(schema, fields);
|
|
11613
|
+
return fields;
|
|
11614
|
+
}
|
|
11615
|
+
function computeSearchableFields(schema) {
|
|
11616
|
+
if (schema.type !== "object") return [];
|
|
11617
|
+
const def = schema.def;
|
|
11618
|
+
const shape = def.shape;
|
|
11619
|
+
if (!shape) return [];
|
|
11620
|
+
const fields = [];
|
|
11621
|
+
for (const [fieldPath, fieldSchema] of Object.entries(shape)) {
|
|
11622
|
+
const metadata = chunkUVZHTBZ5_cjs.getSearchableMetadata(fieldSchema);
|
|
11623
|
+
if (metadata !== void 0) {
|
|
11624
|
+
fields.push({ fieldPath, metadata });
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
warnIfConflictingLanguages(fields);
|
|
11628
|
+
return fields;
|
|
11629
|
+
}
|
|
11630
|
+
function warnIfConflictingLanguages(fields) {
|
|
11631
|
+
if (fields.length < 2) return;
|
|
11632
|
+
const languages = new Set(fields.map((field2) => field2.metadata.language));
|
|
11633
|
+
if (languages.size < 2) return;
|
|
11634
|
+
if (typeof console === "undefined" || typeof console.warn !== "function") {
|
|
11635
|
+
return;
|
|
11636
|
+
}
|
|
11637
|
+
const fieldSummary = fields.map((field2) => `${field2.fieldPath}=${field2.metadata.language}`).join(", ");
|
|
11638
|
+
const winning = fields[0]?.metadata.language ?? chunkUVZHTBZ5_cjs.DEFAULT_SEARCHABLE_LANGUAGE;
|
|
11639
|
+
console.warn(
|
|
11640
|
+
`[typegraph] searchable() fields declare conflicting languages (${fieldSummary}). The first field's language ("${winning}") is recorded on the fulltext row; true multilingual indexing requires a dedicated node kind per language.`
|
|
11641
|
+
);
|
|
11642
|
+
}
|
|
11643
|
+
var FIELD_SEPARATOR = "\n";
|
|
11644
|
+
function resolveCombinedLanguage(fields) {
|
|
11645
|
+
return fields[0]?.metadata.language ?? chunkUVZHTBZ5_cjs.DEFAULT_SEARCHABLE_LANGUAGE;
|
|
11646
|
+
}
|
|
11647
|
+
function computeFulltextContent(schema, props) {
|
|
11648
|
+
const searchableFields = getSearchableFields(schema);
|
|
11649
|
+
if (searchableFields.length === 0) return void 0;
|
|
11650
|
+
const parts = [];
|
|
11651
|
+
for (const field2 of searchableFields) {
|
|
11652
|
+
const value = props[field2.fieldPath];
|
|
11653
|
+
if (typeof value === "string" && value.length > 0) {
|
|
11654
|
+
parts.push(value);
|
|
11655
|
+
}
|
|
11656
|
+
}
|
|
11657
|
+
if (parts.length === 0) return void 0;
|
|
11658
|
+
return {
|
|
11659
|
+
content: parts.join(FIELD_SEPARATOR),
|
|
11660
|
+
language: resolveCombinedLanguage(searchableFields)
|
|
11661
|
+
};
|
|
11662
|
+
}
|
|
11663
|
+
async function syncFulltext(ctx, schema, props) {
|
|
11664
|
+
const { backend } = ctx;
|
|
11665
|
+
if (!backend.upsertFulltext || !backend.deleteFulltext) {
|
|
11666
|
+
return;
|
|
11667
|
+
}
|
|
11668
|
+
const computed = computeFulltextContent(schema, props);
|
|
11669
|
+
if (computed !== void 0) {
|
|
11670
|
+
await backend.upsertFulltext({
|
|
11671
|
+
graphId: ctx.graphId,
|
|
11672
|
+
nodeKind: ctx.nodeKind,
|
|
11673
|
+
nodeId: ctx.nodeId,
|
|
11674
|
+
content: computed.content,
|
|
11675
|
+
language: computed.language
|
|
11676
|
+
});
|
|
11677
|
+
return;
|
|
11678
|
+
}
|
|
11679
|
+
if (getSearchableFields(schema).length === 0) return;
|
|
11680
|
+
await backend.deleteFulltext({
|
|
11681
|
+
graphId: ctx.graphId,
|
|
11682
|
+
nodeKind: ctx.nodeKind,
|
|
11683
|
+
nodeId: ctx.nodeId
|
|
11684
|
+
});
|
|
11685
|
+
}
|
|
11686
|
+
async function deleteNodeFulltext(ctx, schema) {
|
|
11687
|
+
const { backend } = ctx;
|
|
11688
|
+
if (!backend.deleteFulltext) {
|
|
11689
|
+
return;
|
|
11690
|
+
}
|
|
11691
|
+
if (getSearchableFields(schema).length === 0) {
|
|
11692
|
+
return;
|
|
11693
|
+
}
|
|
11694
|
+
await backend.deleteFulltext({
|
|
11695
|
+
graphId: ctx.graphId,
|
|
11696
|
+
nodeKind: ctx.nodeKind,
|
|
11697
|
+
nodeId: ctx.nodeId
|
|
11698
|
+
});
|
|
11699
|
+
}
|
|
11700
|
+
|
|
11065
11701
|
// src/store/uniqueness.ts
|
|
11066
11702
|
async function checkUniquenessConstraints(ctx, kind, id, props, constraints) {
|
|
11067
11703
|
for (const constraint of constraints) {
|
|
@@ -11255,6 +11891,9 @@ function createUniquenessContext(graphId, registry, backend) {
|
|
|
11255
11891
|
function createEmbeddingSyncContext(graphId, nodeKind, nodeId, backend) {
|
|
11256
11892
|
return { graphId, nodeKind, nodeId, backend };
|
|
11257
11893
|
}
|
|
11894
|
+
function createFulltextSyncContext(graphId, nodeKind, nodeId, backend) {
|
|
11895
|
+
return { graphId, nodeKind, nodeId, backend };
|
|
11896
|
+
}
|
|
11258
11897
|
function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
11259
11898
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
11260
11899
|
const pendingNodes = /* @__PURE__ */ new Map();
|
|
@@ -11354,12 +11993,12 @@ async function validateAndPrepareNodeCreate(ctx, input, id, backend) {
|
|
|
11354
11993
|
const kind = input.kind;
|
|
11355
11994
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11356
11995
|
const nodeKind = registration.type;
|
|
11357
|
-
const validatedProps =
|
|
11996
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateNodeProps(nodeKind.schema, input.props, {
|
|
11358
11997
|
kind,
|
|
11359
11998
|
operation: "create"
|
|
11360
11999
|
});
|
|
11361
|
-
const validFrom =
|
|
11362
|
-
const validTo =
|
|
12000
|
+
const validFrom = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validFrom, "validFrom");
|
|
12001
|
+
const validTo = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validTo, "validTo");
|
|
11363
12002
|
const existingNode = await backend.getNode(ctx.graphId, kind, id);
|
|
11364
12003
|
if (existingNode && !existingNode.deleted_at) {
|
|
11365
12004
|
throw createNodeAlreadyExistsError(kind, id);
|
|
@@ -11412,6 +12051,11 @@ async function finalizeNodeCreate(ctx, prepared, backend) {
|
|
|
11412
12051
|
prepared.nodeKind.schema,
|
|
11413
12052
|
prepared.validatedProps
|
|
11414
12053
|
);
|
|
12054
|
+
await syncFulltext(
|
|
12055
|
+
createFulltextSyncContext(ctx.graphId, prepared.kind, prepared.id, backend),
|
|
12056
|
+
prepared.nodeKind.schema,
|
|
12057
|
+
prepared.validatedProps
|
|
12058
|
+
);
|
|
11415
12059
|
}
|
|
11416
12060
|
async function performNodeUpdate(ctx, input, backend, options) {
|
|
11417
12061
|
const { kind, id } = input;
|
|
@@ -11423,12 +12067,12 @@ async function performNodeUpdate(ctx, input, backend, options) {
|
|
|
11423
12067
|
const existingProps = JSON.parse(existing.props);
|
|
11424
12068
|
const mergedProps = { ...existingProps, ...input.props };
|
|
11425
12069
|
const nodeKind = registration.type;
|
|
11426
|
-
const validatedProps =
|
|
12070
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateNodeProps(nodeKind.schema, mergedProps, {
|
|
11427
12071
|
kind,
|
|
11428
12072
|
operation: "update",
|
|
11429
12073
|
id
|
|
11430
12074
|
});
|
|
11431
|
-
const validTo =
|
|
12075
|
+
const validTo = chunkWRWVWKQL_cjs.validateOptionalIsoDate(input.validTo, "validTo");
|
|
11432
12076
|
await updateUniquenessEntries(
|
|
11433
12077
|
createUniquenessContext(ctx.graphId, ctx.registry, backend),
|
|
11434
12078
|
kind,
|
|
@@ -11452,6 +12096,11 @@ async function performNodeUpdate(ctx, input, backend, options) {
|
|
|
11452
12096
|
nodeKind.schema,
|
|
11453
12097
|
validatedProps
|
|
11454
12098
|
);
|
|
12099
|
+
await syncFulltext(
|
|
12100
|
+
createFulltextSyncContext(ctx.graphId, kind, id, backend),
|
|
12101
|
+
nodeKind.schema,
|
|
12102
|
+
validatedProps
|
|
12103
|
+
);
|
|
11455
12104
|
return rowToNode(row);
|
|
11456
12105
|
}
|
|
11457
12106
|
async function enforceDeleteBehavior(ctx, kind, id, mode, backend, registration) {
|
|
@@ -11668,6 +12317,10 @@ async function executeNodeDelete(ctx, kind, id, backend) {
|
|
|
11668
12317
|
createEmbeddingSyncContext(ctx.graphId, kind, id, backend),
|
|
11669
12318
|
nodeKind.schema
|
|
11670
12319
|
);
|
|
12320
|
+
await deleteNodeFulltext(
|
|
12321
|
+
createFulltextSyncContext(ctx.graphId, kind, id, backend),
|
|
12322
|
+
nodeKind.schema
|
|
12323
|
+
);
|
|
11671
12324
|
});
|
|
11672
12325
|
}
|
|
11673
12326
|
async function executeNodeHardDelete(ctx, kind, id, backend) {
|
|
@@ -11687,7 +12340,7 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
11687
12340
|
const ifExists = options?.ifExists ?? "return";
|
|
11688
12341
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11689
12342
|
const nodeKind = registration.type;
|
|
11690
|
-
const validatedProps =
|
|
12343
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateNodeProps(nodeKind.schema, props, {
|
|
11691
12344
|
kind,
|
|
11692
12345
|
operation: "create"
|
|
11693
12346
|
});
|
|
@@ -11759,7 +12412,7 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
11759
12412
|
async function executeNodeFindByConstraint(ctx, kind, constraintName, props, backend) {
|
|
11760
12413
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
11761
12414
|
const nodeKind = registration.type;
|
|
11762
|
-
const validatedProps =
|
|
12415
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateNodeProps(nodeKind.schema, props, {
|
|
11763
12416
|
kind,
|
|
11764
12417
|
operation: "create"
|
|
11765
12418
|
});
|
|
@@ -11796,7 +12449,7 @@ async function executeNodeFindByConstraint(ctx, kind, constraintName, props, bac
|
|
|
11796
12449
|
function validateAndComputeKeys(nodeKind, kind, constraint, items) {
|
|
11797
12450
|
const validated = [];
|
|
11798
12451
|
for (const item of items) {
|
|
11799
|
-
const validatedProps =
|
|
12452
|
+
const validatedProps = chunkHRNQ3DVJ_cjs.validateNodeProps(nodeKind.schema, item.props, {
|
|
11800
12453
|
kind,
|
|
11801
12454
|
operation: "create"
|
|
11802
12455
|
});
|
|
@@ -11974,6 +12627,503 @@ async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName,
|
|
|
11974
12627
|
return results;
|
|
11975
12628
|
}
|
|
11976
12629
|
|
|
12630
|
+
// src/store/fulltext-rebuild.ts
|
|
12631
|
+
var DEFAULT_PAGE_SIZE = 500;
|
|
12632
|
+
var DEFAULT_MAX_SKIPPED_IDS = 1e4;
|
|
12633
|
+
function validatePageSize(value) {
|
|
12634
|
+
if (value === void 0) return DEFAULT_PAGE_SIZE;
|
|
12635
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
12636
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
12637
|
+
`pageSize must be a positive integer, got: ${String(value)}`,
|
|
12638
|
+
{
|
|
12639
|
+
issues: [{ path: "pageSize", message: "Must be a positive integer." }]
|
|
12640
|
+
}
|
|
12641
|
+
);
|
|
12642
|
+
}
|
|
12643
|
+
return value;
|
|
12644
|
+
}
|
|
12645
|
+
function validateMaxSkippedIds(value) {
|
|
12646
|
+
if (value === void 0) return DEFAULT_MAX_SKIPPED_IDS;
|
|
12647
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
12648
|
+
throw new chunkO5PST6TB_cjs.ValidationError(
|
|
12649
|
+
`maxSkippedIds must be a non-negative integer, got: ${String(value)}`,
|
|
12650
|
+
{
|
|
12651
|
+
issues: [
|
|
12652
|
+
{
|
|
12653
|
+
path: "maxSkippedIds",
|
|
12654
|
+
message: "Must be a non-negative integer."
|
|
12655
|
+
}
|
|
12656
|
+
]
|
|
12657
|
+
}
|
|
12658
|
+
);
|
|
12659
|
+
}
|
|
12660
|
+
return value;
|
|
12661
|
+
}
|
|
12662
|
+
function isPropsObject(value) {
|
|
12663
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12664
|
+
}
|
|
12665
|
+
async function rebuildFulltextIndex(ctx, nodeKind, options) {
|
|
12666
|
+
const { backend, registry } = ctx;
|
|
12667
|
+
if (!backend.upsertFulltext || !backend.deleteFulltext) {
|
|
12668
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
12669
|
+
"Backend does not support fulltext; cannot rebuild index",
|
|
12670
|
+
{ backend: backend.dialect, capability: "fulltext" }
|
|
12671
|
+
);
|
|
12672
|
+
}
|
|
12673
|
+
const pageSize = validatePageSize(options.pageSize);
|
|
12674
|
+
const maxSkippedIds = validateMaxSkippedIds(options.maxSkippedIds);
|
|
12675
|
+
const targetKinds = nodeKind === void 0 ? [...registry.nodeKinds.keys()] : [nodeKind];
|
|
12676
|
+
const rebuiltKinds = [];
|
|
12677
|
+
let processed = 0;
|
|
12678
|
+
let upserted = 0;
|
|
12679
|
+
let cleared = 0;
|
|
12680
|
+
let skipped = 0;
|
|
12681
|
+
const skippedIds = [];
|
|
12682
|
+
for (const kind of targetKinds) {
|
|
12683
|
+
const nodeType = registry.getNodeType(kind);
|
|
12684
|
+
if (!nodeType) {
|
|
12685
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(`Unknown node kind: ${kind}`, { kind });
|
|
12686
|
+
}
|
|
12687
|
+
if (getSearchableFields(nodeType.schema).length === 0) {
|
|
12688
|
+
continue;
|
|
12689
|
+
}
|
|
12690
|
+
rebuiltKinds.push(kind);
|
|
12691
|
+
let cursor;
|
|
12692
|
+
for (; ; ) {
|
|
12693
|
+
const rows = await backend.findNodesByKind({
|
|
12694
|
+
graphId: ctx.graphId,
|
|
12695
|
+
kind,
|
|
12696
|
+
limit: pageSize,
|
|
12697
|
+
excludeDeleted: false,
|
|
12698
|
+
orderBy: "id",
|
|
12699
|
+
...cursor === void 0 ? {} : { after: cursor }
|
|
12700
|
+
});
|
|
12701
|
+
if (rows.length === 0) break;
|
|
12702
|
+
const pageResult = processPage(nodeType.schema, rows);
|
|
12703
|
+
skipped += pageResult.skipped;
|
|
12704
|
+
const remaining = maxSkippedIds - skippedIds.length;
|
|
12705
|
+
if (remaining > 0 && pageResult.skippedIds.length > 0) {
|
|
12706
|
+
skippedIds.push(...pageResult.skippedIds.slice(0, remaining));
|
|
12707
|
+
}
|
|
12708
|
+
await backend.transaction(async (tx) => {
|
|
12709
|
+
if (pageResult.toUpsert.length > 0) {
|
|
12710
|
+
if (tx.upsertFulltextBatch) {
|
|
12711
|
+
await tx.upsertFulltextBatch({
|
|
12712
|
+
graphId: ctx.graphId,
|
|
12713
|
+
nodeKind: kind,
|
|
12714
|
+
rows: pageResult.toUpsert
|
|
12715
|
+
});
|
|
12716
|
+
} else if (tx.upsertFulltext) {
|
|
12717
|
+
for (const item of pageResult.toUpsert) {
|
|
12718
|
+
await tx.upsertFulltext({
|
|
12719
|
+
graphId: ctx.graphId,
|
|
12720
|
+
nodeKind: kind,
|
|
12721
|
+
nodeId: item.nodeId,
|
|
12722
|
+
content: item.content,
|
|
12723
|
+
language: item.language
|
|
12724
|
+
});
|
|
12725
|
+
}
|
|
12726
|
+
}
|
|
12727
|
+
}
|
|
12728
|
+
if (pageResult.toDelete.length > 0) {
|
|
12729
|
+
if (tx.deleteFulltextBatch) {
|
|
12730
|
+
await tx.deleteFulltextBatch({
|
|
12731
|
+
graphId: ctx.graphId,
|
|
12732
|
+
nodeKind: kind,
|
|
12733
|
+
nodeIds: pageResult.toDelete
|
|
12734
|
+
});
|
|
12735
|
+
} else if (tx.deleteFulltext) {
|
|
12736
|
+
for (const nodeId of pageResult.toDelete) {
|
|
12737
|
+
await tx.deleteFulltext({
|
|
12738
|
+
graphId: ctx.graphId,
|
|
12739
|
+
nodeKind: kind,
|
|
12740
|
+
nodeId
|
|
12741
|
+
});
|
|
12742
|
+
}
|
|
12743
|
+
}
|
|
12744
|
+
}
|
|
12745
|
+
});
|
|
12746
|
+
processed += rows.length;
|
|
12747
|
+
upserted += pageResult.toUpsert.length;
|
|
12748
|
+
cleared += pageResult.toDelete.length;
|
|
12749
|
+
const lastRow = rows.at(-1);
|
|
12750
|
+
if (!lastRow) break;
|
|
12751
|
+
cursor = lastRow.id;
|
|
12752
|
+
if (rows.length < pageSize) break;
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
return {
|
|
12756
|
+
kinds: rebuiltKinds,
|
|
12757
|
+
processed,
|
|
12758
|
+
upserted,
|
|
12759
|
+
cleared,
|
|
12760
|
+
skipped,
|
|
12761
|
+
skippedIds,
|
|
12762
|
+
skippedTruncated: skipped > skippedIds.length
|
|
12763
|
+
};
|
|
12764
|
+
}
|
|
12765
|
+
function processPage(schema, rows) {
|
|
12766
|
+
const toUpsert = [];
|
|
12767
|
+
const toDelete = [];
|
|
12768
|
+
const skippedIds = [];
|
|
12769
|
+
let skipped = 0;
|
|
12770
|
+
for (const row of rows) {
|
|
12771
|
+
if (row.deleted_at !== void 0) {
|
|
12772
|
+
toDelete.push(row.id);
|
|
12773
|
+
continue;
|
|
12774
|
+
}
|
|
12775
|
+
let parsed;
|
|
12776
|
+
try {
|
|
12777
|
+
parsed = JSON.parse(row.props);
|
|
12778
|
+
} catch {
|
|
12779
|
+
skipped += 1;
|
|
12780
|
+
skippedIds.push(row.id);
|
|
12781
|
+
continue;
|
|
12782
|
+
}
|
|
12783
|
+
if (!isPropsObject(parsed)) {
|
|
12784
|
+
skipped += 1;
|
|
12785
|
+
skippedIds.push(row.id);
|
|
12786
|
+
continue;
|
|
12787
|
+
}
|
|
12788
|
+
const computed = computeFulltextContent(schema, parsed);
|
|
12789
|
+
if (computed === void 0) {
|
|
12790
|
+
toDelete.push(row.id);
|
|
12791
|
+
} else {
|
|
12792
|
+
toUpsert.push({
|
|
12793
|
+
nodeId: row.id,
|
|
12794
|
+
content: computed.content,
|
|
12795
|
+
language: computed.language
|
|
12796
|
+
});
|
|
12797
|
+
}
|
|
12798
|
+
}
|
|
12799
|
+
return { toUpsert, toDelete, skipped, skippedIds };
|
|
12800
|
+
}
|
|
12801
|
+
|
|
12802
|
+
// src/store/search.ts
|
|
12803
|
+
async function executeFulltextSearch(ctx, nodeKind, options) {
|
|
12804
|
+
const { backend, graphId } = ctx;
|
|
12805
|
+
if (!backend.fulltextSearch) {
|
|
12806
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError("Backend does not support fulltext search", {
|
|
12807
|
+
backend: backend.dialect,
|
|
12808
|
+
capability: "fulltext"
|
|
12809
|
+
});
|
|
12810
|
+
}
|
|
12811
|
+
if (!Number.isInteger(options.limit) || options.limit <= 0) {
|
|
12812
|
+
throw new RangeError(
|
|
12813
|
+
`fulltextSearch.limit must be a positive integer, got: ${options.limit}`
|
|
12814
|
+
);
|
|
12815
|
+
}
|
|
12816
|
+
validateFulltextCallOptions(backend, {
|
|
12817
|
+
mode: options.mode,
|
|
12818
|
+
includeSnippets: options.includeSnippets,
|
|
12819
|
+
language: options.language
|
|
12820
|
+
});
|
|
12821
|
+
const params = {
|
|
12822
|
+
graphId,
|
|
12823
|
+
nodeKind,
|
|
12824
|
+
query: options.query,
|
|
12825
|
+
limit: options.limit,
|
|
12826
|
+
...options.mode ? { mode: options.mode } : {},
|
|
12827
|
+
...options.language ? { language: options.language } : {},
|
|
12828
|
+
...options.minScore === void 0 ? {} : { minScore: options.minScore },
|
|
12829
|
+
...options.includeSnippets === void 0 ? {} : { includeSnippets: options.includeSnippets }
|
|
12830
|
+
};
|
|
12831
|
+
const rows = await backend.fulltextSearch(params);
|
|
12832
|
+
if (rows.length === 0) return [];
|
|
12833
|
+
const ids = rows.map((r) => r.nodeId);
|
|
12834
|
+
const nodeMap = await fetchNodesByIds(backend, graphId, nodeKind, ids);
|
|
12835
|
+
const hits = [];
|
|
12836
|
+
let rank = 1;
|
|
12837
|
+
for (const row of rows) {
|
|
12838
|
+
const node = nodeMap.get(row.nodeId);
|
|
12839
|
+
if (!node) continue;
|
|
12840
|
+
hits.push({
|
|
12841
|
+
node,
|
|
12842
|
+
score: row.score,
|
|
12843
|
+
rank,
|
|
12844
|
+
...row.snippet === void 0 ? {} : { snippet: row.snippet }
|
|
12845
|
+
});
|
|
12846
|
+
rank += 1;
|
|
12847
|
+
}
|
|
12848
|
+
return hits;
|
|
12849
|
+
}
|
|
12850
|
+
async function executeHybridSearch(ctx, nodeKind, options) {
|
|
12851
|
+
const { backend, graphId } = ctx;
|
|
12852
|
+
if (!backend.vectorSearch) {
|
|
12853
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError("Backend does not support vector search", {
|
|
12854
|
+
backend: backend.dialect,
|
|
12855
|
+
capability: "vector"
|
|
12856
|
+
});
|
|
12857
|
+
}
|
|
12858
|
+
if (!backend.fulltextSearch) {
|
|
12859
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError("Backend does not support fulltext search", {
|
|
12860
|
+
backend: backend.dialect,
|
|
12861
|
+
capability: "fulltext"
|
|
12862
|
+
});
|
|
12863
|
+
}
|
|
12864
|
+
if (!Number.isInteger(options.limit) || options.limit <= 0) {
|
|
12865
|
+
throw new RangeError(
|
|
12866
|
+
`hybridSearch.limit must be a positive integer, got: ${options.limit}`
|
|
12867
|
+
);
|
|
12868
|
+
}
|
|
12869
|
+
if (options.fusion !== void 0) {
|
|
12870
|
+
validateHybridFusionOptions(options.fusion);
|
|
12871
|
+
}
|
|
12872
|
+
validateFulltextCallOptions(backend, {
|
|
12873
|
+
mode: options.fulltext.mode,
|
|
12874
|
+
includeSnippets: options.fulltext.includeSnippets,
|
|
12875
|
+
language: options.fulltext.language
|
|
12876
|
+
});
|
|
12877
|
+
const fusionK = options.fusion?.k ?? DEFAULT_RRF_K;
|
|
12878
|
+
const vectorWeight = options.fusion?.weights?.vector ?? DEFAULT_RRF_WEIGHT;
|
|
12879
|
+
const fulltextWeight = options.fusion?.weights?.fulltext ?? DEFAULT_RRF_WEIGHT;
|
|
12880
|
+
const overFetchMultiplier = 4;
|
|
12881
|
+
const vectorK = options.vector.k ?? options.limit * overFetchMultiplier;
|
|
12882
|
+
const fulltextK = options.fulltext.k ?? options.limit * overFetchMultiplier;
|
|
12883
|
+
const vectorPromise = backend.vectorSearch({
|
|
12884
|
+
graphId,
|
|
12885
|
+
nodeKind,
|
|
12886
|
+
fieldPath: options.vector.fieldPath,
|
|
12887
|
+
queryEmbedding: options.vector.queryEmbedding,
|
|
12888
|
+
metric: options.vector.metric ?? "cosine",
|
|
12889
|
+
limit: vectorK,
|
|
12890
|
+
...options.vector.minScore === void 0 ? {} : { minScore: options.vector.minScore }
|
|
12891
|
+
});
|
|
12892
|
+
const fulltextPromise = backend.fulltextSearch({
|
|
12893
|
+
graphId,
|
|
12894
|
+
nodeKind,
|
|
12895
|
+
query: options.fulltext.query,
|
|
12896
|
+
limit: fulltextK,
|
|
12897
|
+
...options.fulltext.mode ? { mode: options.fulltext.mode } : {},
|
|
12898
|
+
...options.fulltext.language ? { language: options.fulltext.language } : {},
|
|
12899
|
+
...options.fulltext.minScore === void 0 ? {} : { minScore: options.fulltext.minScore },
|
|
12900
|
+
...options.fulltext.includeSnippets === void 0 ? {} : { includeSnippets: options.fulltext.includeSnippets }
|
|
12901
|
+
});
|
|
12902
|
+
const [vectorRows, fulltextRows] = await Promise.all([
|
|
12903
|
+
vectorPromise,
|
|
12904
|
+
fulltextPromise
|
|
12905
|
+
]);
|
|
12906
|
+
const fused = /* @__PURE__ */ new Map();
|
|
12907
|
+
for (const [index, row] of vectorRows.entries()) {
|
|
12908
|
+
const rank2 = index + 1;
|
|
12909
|
+
const contribution = vectorWeight / (fusionK + rank2);
|
|
12910
|
+
const entry = fused.get(row.nodeId) ?? {
|
|
12911
|
+
nodeId: row.nodeId,
|
|
12912
|
+
fusedScore: 0
|
|
12913
|
+
};
|
|
12914
|
+
entry.fusedScore += contribution;
|
|
12915
|
+
entry.vectorRank = rank2;
|
|
12916
|
+
entry.vectorScore = row.score;
|
|
12917
|
+
fused.set(row.nodeId, entry);
|
|
12918
|
+
}
|
|
12919
|
+
for (const [index, row] of fulltextRows.entries()) {
|
|
12920
|
+
const rank2 = index + 1;
|
|
12921
|
+
const contribution = fulltextWeight / (fusionK + rank2);
|
|
12922
|
+
const entry = fused.get(row.nodeId) ?? {
|
|
12923
|
+
nodeId: row.nodeId,
|
|
12924
|
+
fusedScore: 0
|
|
12925
|
+
};
|
|
12926
|
+
entry.fusedScore += contribution;
|
|
12927
|
+
entry.fulltextRank = rank2;
|
|
12928
|
+
entry.fulltextScore = row.score;
|
|
12929
|
+
if (row.snippet !== void 0) {
|
|
12930
|
+
entry.fulltextSnippet = row.snippet;
|
|
12931
|
+
}
|
|
12932
|
+
fused.set(row.nodeId, entry);
|
|
12933
|
+
}
|
|
12934
|
+
const ranked = [...fused.values()].toSorted(
|
|
12935
|
+
(a, b) => b.fusedScore - a.fusedScore || a.nodeId.localeCompare(b.nodeId)
|
|
12936
|
+
).slice(0, options.limit);
|
|
12937
|
+
const ids = ranked.map((entry) => entry.nodeId);
|
|
12938
|
+
const nodeMap = await fetchNodesByIds(backend, graphId, nodeKind, ids);
|
|
12939
|
+
const hits = [];
|
|
12940
|
+
let rank = 1;
|
|
12941
|
+
for (const entry of ranked) {
|
|
12942
|
+
const node = nodeMap.get(entry.nodeId);
|
|
12943
|
+
if (!node) continue;
|
|
12944
|
+
const typedNode = node;
|
|
12945
|
+
const hit = {
|
|
12946
|
+
node: typedNode,
|
|
12947
|
+
score: entry.fusedScore,
|
|
12948
|
+
rank,
|
|
12949
|
+
...entry.vectorRank !== void 0 && entry.vectorScore !== void 0 ? {
|
|
12950
|
+
vector: {
|
|
12951
|
+
node: typedNode,
|
|
12952
|
+
score: entry.vectorScore,
|
|
12953
|
+
rank: entry.vectorRank
|
|
12954
|
+
}
|
|
12955
|
+
} : {},
|
|
12956
|
+
...entry.fulltextRank !== void 0 && entry.fulltextScore !== void 0 ? {
|
|
12957
|
+
fulltext: {
|
|
12958
|
+
node: typedNode,
|
|
12959
|
+
score: entry.fulltextScore,
|
|
12960
|
+
rank: entry.fulltextRank,
|
|
12961
|
+
...entry.fulltextSnippet === void 0 ? {} : { snippet: entry.fulltextSnippet }
|
|
12962
|
+
}
|
|
12963
|
+
} : {}
|
|
12964
|
+
};
|
|
12965
|
+
hits.push(hit);
|
|
12966
|
+
rank += 1;
|
|
12967
|
+
}
|
|
12968
|
+
return hits;
|
|
12969
|
+
}
|
|
12970
|
+
function validateFulltextCallOptions(backend, options) {
|
|
12971
|
+
const strategy = backend.fulltextStrategy;
|
|
12972
|
+
const capabilities = backend.capabilities.fulltext;
|
|
12973
|
+
if (options.mode !== void 0) {
|
|
12974
|
+
validateFulltextMode(backend, strategy, capabilities, options.mode);
|
|
12975
|
+
}
|
|
12976
|
+
if (options.includeSnippets === true) {
|
|
12977
|
+
validateFulltextSnippets(backend, strategy, capabilities);
|
|
12978
|
+
}
|
|
12979
|
+
if (options.language !== void 0) {
|
|
12980
|
+
validateFulltextLanguageOption(
|
|
12981
|
+
backend,
|
|
12982
|
+
strategy,
|
|
12983
|
+
capabilities,
|
|
12984
|
+
options.language
|
|
12985
|
+
);
|
|
12986
|
+
}
|
|
12987
|
+
}
|
|
12988
|
+
function validateFulltextMode(backend, strategy, capabilities, mode) {
|
|
12989
|
+
if (strategy !== void 0) {
|
|
12990
|
+
if (strategy.supportedModes.includes(mode)) return;
|
|
12991
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
12992
|
+
`Backend "${backend.dialect}" fulltext strategy "${strategy.name}" does not support mode "${mode}". Supported modes: ${strategy.supportedModes.join(", ")}`,
|
|
12993
|
+
{
|
|
12994
|
+
backend: backend.dialect,
|
|
12995
|
+
strategy: strategy.name,
|
|
12996
|
+
capability: `fulltext.modes.${mode}`
|
|
12997
|
+
}
|
|
12998
|
+
);
|
|
12999
|
+
}
|
|
13000
|
+
if (mode === "phrase" && capabilities && !capabilities.phraseQueries) {
|
|
13001
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
13002
|
+
`Backend "${backend.dialect}" does not support phrase queries`,
|
|
13003
|
+
{ backend: backend.dialect, capability: "fulltext.phraseQueries" }
|
|
13004
|
+
);
|
|
13005
|
+
}
|
|
13006
|
+
}
|
|
13007
|
+
function validateFulltextSnippets(backend, strategy, capabilities) {
|
|
13008
|
+
const supportsSnippets = strategy === void 0 ? capabilities?.highlighting !== false : strategy.supportsSnippets;
|
|
13009
|
+
if (supportsSnippets) return;
|
|
13010
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
13011
|
+
`Backend "${backend.dialect}" does not support snippet highlighting; drop includeSnippets or switch to a backend where highlighting is supported`,
|
|
13012
|
+
{ backend: backend.dialect, capability: "fulltext.highlighting" }
|
|
13013
|
+
);
|
|
13014
|
+
}
|
|
13015
|
+
function validateFulltextLanguageOption(backend, strategy, capabilities, language) {
|
|
13016
|
+
if (strategy !== void 0 && !strategy.supportsLanguageOverride) {
|
|
13017
|
+
throw new chunkO5PST6TB_cjs.ConfigurationError(
|
|
13018
|
+
`Backend "${backend.dialect}" fulltext strategy "${strategy.name}" does not honor a per-query \`language\` override (its tokenizer is fixed at table-create time). Drop the option, or pick a strategy that advertises \`supportsLanguageOverride: true\`.`,
|
|
13019
|
+
{
|
|
13020
|
+
backend: backend.dialect,
|
|
13021
|
+
strategy: strategy.name,
|
|
13022
|
+
capability: "fulltext.languageOverride"
|
|
13023
|
+
}
|
|
13024
|
+
);
|
|
13025
|
+
}
|
|
13026
|
+
if (capabilities !== void 0) {
|
|
13027
|
+
warnIfLanguageNotAdvertised(backend.dialect, capabilities, language);
|
|
13028
|
+
}
|
|
13029
|
+
}
|
|
13030
|
+
function warnIfLanguageNotAdvertised(dialect, capabilities, language) {
|
|
13031
|
+
if (capabilities.languages.length === 0) return;
|
|
13032
|
+
if (capabilities.languages.includes(language)) return;
|
|
13033
|
+
if (typeof console === "undefined" || typeof console.warn !== "function") {
|
|
13034
|
+
return;
|
|
13035
|
+
}
|
|
13036
|
+
console.warn(
|
|
13037
|
+
`[typegraph] fulltext language "${language}" is not in the advertised list for dialect "${dialect}" (${capabilities.languages.join(", ")}). If your backend has this language installed this warning is safe to ignore.`
|
|
13038
|
+
);
|
|
13039
|
+
}
|
|
13040
|
+
async function fetchNodesByIds(backend, graphId, nodeKind, ids) {
|
|
13041
|
+
if (ids.length === 0) return /* @__PURE__ */ new Map();
|
|
13042
|
+
const map = /* @__PURE__ */ new Map();
|
|
13043
|
+
if (backend.getNodes) {
|
|
13044
|
+
const rows = await backend.getNodes(graphId, nodeKind, ids);
|
|
13045
|
+
for (const row of rows) {
|
|
13046
|
+
if (row.deleted_at !== void 0) continue;
|
|
13047
|
+
map.set(row.id, rowToNode(row));
|
|
13048
|
+
}
|
|
13049
|
+
return map;
|
|
13050
|
+
}
|
|
13051
|
+
for (const id of ids) {
|
|
13052
|
+
const row = await backend.getNode(graphId, nodeKind, id);
|
|
13053
|
+
if (row && row.deleted_at === void 0) map.set(row.id, rowToNode(row));
|
|
13054
|
+
}
|
|
13055
|
+
return map;
|
|
13056
|
+
}
|
|
13057
|
+
|
|
13058
|
+
// src/store/search-facade.ts
|
|
13059
|
+
var StoreSearch = class {
|
|
13060
|
+
#context;
|
|
13061
|
+
constructor(context) {
|
|
13062
|
+
this.#context = context;
|
|
13063
|
+
}
|
|
13064
|
+
/**
|
|
13065
|
+
* Runs a fulltext search against nodes of the given kind.
|
|
13066
|
+
*
|
|
13067
|
+
* Requires fields on the node schema declared with `searchable()`.
|
|
13068
|
+
* The search hits the backend's fulltext index (tsvector + GIN on
|
|
13069
|
+
* Postgres, FTS5 on SQLite — or whatever strategy the backend is
|
|
13070
|
+
* configured with) and resolves the matching node IDs back to typed
|
|
13071
|
+
* `Node` objects.
|
|
13072
|
+
*/
|
|
13073
|
+
async fulltext(nodeKind, options) {
|
|
13074
|
+
return executeFulltextSearch(
|
|
13075
|
+
{ graphId: this.#context.graphId, backend: this.#context.backend },
|
|
13076
|
+
nodeKind,
|
|
13077
|
+
options
|
|
13078
|
+
);
|
|
13079
|
+
}
|
|
13080
|
+
/**
|
|
13081
|
+
* Runs a vector + fulltext hybrid search and fuses the results with
|
|
13082
|
+
* Reciprocal Rank Fusion.
|
|
13083
|
+
*
|
|
13084
|
+
* RRF is rank-based, so it composes well across heterogeneous score
|
|
13085
|
+
* scales (cosine similarity vs ts_rank_cd vs FTS5 BM25). Default
|
|
13086
|
+
* over-fetch is 4× `limit` from each source — tune via `vector.k` /
|
|
13087
|
+
* `fulltext.k` for higher-recall corpora.
|
|
13088
|
+
*/
|
|
13089
|
+
async hybrid(nodeKind, options) {
|
|
13090
|
+
return executeHybridSearch(
|
|
13091
|
+
{ graphId: this.#context.graphId, backend: this.#context.backend },
|
|
13092
|
+
nodeKind,
|
|
13093
|
+
options
|
|
13094
|
+
);
|
|
13095
|
+
}
|
|
13096
|
+
/**
|
|
13097
|
+
* Rebuilds the fulltext index from existing node data.
|
|
13098
|
+
*
|
|
13099
|
+
* Use when:
|
|
13100
|
+
* - A node kind gained a `searchable()` field after data was already
|
|
13101
|
+
* written and existing rows were never indexed.
|
|
13102
|
+
* - The fulltext table was dropped / truncated.
|
|
13103
|
+
* - `language` was changed on a `searchable()` field.
|
|
13104
|
+
*
|
|
13105
|
+
* Iterates nodes with keyset pagination (stable under shared
|
|
13106
|
+
* timestamps and light concurrent writes), transacts per page, skips
|
|
13107
|
+
* kinds with no searchable fields, and cleans up stale rows for
|
|
13108
|
+
* soft-deleted nodes. Corrupt or non-object `props` are counted in
|
|
13109
|
+
* `skipped` with their node IDs surfaced via `skippedIds` so operators
|
|
13110
|
+
* can investigate. Concurrent hard-deletes between page fetches can
|
|
13111
|
+
* be missed by a single pass — run during a maintenance window for
|
|
13112
|
+
* full consistency.
|
|
13113
|
+
*/
|
|
13114
|
+
async rebuildFulltext(nodeKind, options = {}) {
|
|
13115
|
+
return rebuildFulltextIndex(
|
|
13116
|
+
{
|
|
13117
|
+
graphId: this.#context.graphId,
|
|
13118
|
+
backend: this.#context.backend,
|
|
13119
|
+
registry: this.#context.registry
|
|
13120
|
+
},
|
|
13121
|
+
nodeKind,
|
|
13122
|
+
options
|
|
13123
|
+
);
|
|
13124
|
+
}
|
|
13125
|
+
};
|
|
13126
|
+
|
|
11977
13127
|
// src/store/store.ts
|
|
11978
13128
|
var Store = class {
|
|
11979
13129
|
#graph;
|
|
@@ -11985,6 +13135,7 @@ var Store = class {
|
|
|
11985
13135
|
#nodeCollections;
|
|
11986
13136
|
#edgeCollections;
|
|
11987
13137
|
#algorithms;
|
|
13138
|
+
#search;
|
|
11988
13139
|
constructor(graph, backend, options) {
|
|
11989
13140
|
this.#graph = graph;
|
|
11990
13141
|
this.#backend = backend;
|
|
@@ -12233,6 +13384,44 @@ var Store = class {
|
|
|
12233
13384
|
query() {
|
|
12234
13385
|
return this.#createQueryForBackend(this.#backend);
|
|
12235
13386
|
}
|
|
13387
|
+
// === Search ===
|
|
13388
|
+
/**
|
|
13389
|
+
* Search-related operations (fulltext, hybrid, and rebuild).
|
|
13390
|
+
*
|
|
13391
|
+
* All search methods live under this facade to keep the top-level
|
|
13392
|
+
* Store API focused on CRUD + graph traversal. The facade is
|
|
13393
|
+
* lazy-initialized and cached for the lifetime of the store.
|
|
13394
|
+
*
|
|
13395
|
+
* @example
|
|
13396
|
+
* ```typescript
|
|
13397
|
+
* // Fulltext
|
|
13398
|
+
* const hits = await store.search.fulltext("Document", {
|
|
13399
|
+
* query: "climate warming",
|
|
13400
|
+
* limit: 10,
|
|
13401
|
+
* includeSnippets: true,
|
|
13402
|
+
* });
|
|
13403
|
+
*
|
|
13404
|
+
* // Hybrid (vector + fulltext fused with RRF)
|
|
13405
|
+
* const ranked = await store.search.hybrid("Document", {
|
|
13406
|
+
* limit: 10,
|
|
13407
|
+
* vector: { fieldPath: "embedding", queryEmbedding: vec },
|
|
13408
|
+
* fulltext: { query: "climate warming" },
|
|
13409
|
+
* });
|
|
13410
|
+
*
|
|
13411
|
+
* // Rebuild index after schema change
|
|
13412
|
+
* const stats = await store.search.rebuildFulltext();
|
|
13413
|
+
* ```
|
|
13414
|
+
*/
|
|
13415
|
+
get search() {
|
|
13416
|
+
if (this.#search === void 0) {
|
|
13417
|
+
this.#search = new StoreSearch({
|
|
13418
|
+
graphId: this.graphId,
|
|
13419
|
+
backend: this.#backend,
|
|
13420
|
+
registry: this.#registry
|
|
13421
|
+
});
|
|
13422
|
+
}
|
|
13423
|
+
return this.#search;
|
|
13424
|
+
}
|
|
12236
13425
|
// === Batch Query Execution ===
|
|
12237
13426
|
/**
|
|
12238
13427
|
* Executes multiple queries over a single connection with snapshot consistency.
|
|
@@ -12306,7 +13495,7 @@ var Store = class {
|
|
|
12306
13495
|
graphId: this.graphId,
|
|
12307
13496
|
rootId,
|
|
12308
13497
|
backend: this.#backend,
|
|
12309
|
-
dialect:
|
|
13498
|
+
dialect: chunkFQCQM3KG_cjs.getDialect(this.#backend.dialect),
|
|
12310
13499
|
schema: this.#schema,
|
|
12311
13500
|
options
|
|
12312
13501
|
});
|
|
@@ -12377,6 +13566,7 @@ var Store = class {
|
|
|
12377
13566
|
this.#nodeCollections = void 0;
|
|
12378
13567
|
this.#edgeCollections = void 0;
|
|
12379
13568
|
this.#algorithms = void 0;
|
|
13569
|
+
this.#search = void 0;
|
|
12380
13570
|
}
|
|
12381
13571
|
// === Lifecycle ===
|
|
12382
13572
|
/**
|
|
@@ -12446,7 +13636,7 @@ var Store = class {
|
|
|
12446
13636
|
// === Internal: Temporal Filtering ===
|
|
12447
13637
|
#matchesTemporalMode(row, options) {
|
|
12448
13638
|
const mode = options?.temporalMode ?? this.#graph.defaults.temporalMode;
|
|
12449
|
-
const asOf = options?.asOf ??
|
|
13639
|
+
const asOf = options?.asOf ?? chunkWRWVWKQL_cjs.nowIso();
|
|
12450
13640
|
switch (mode) {
|
|
12451
13641
|
case "current":
|
|
12452
13642
|
case "asOf": {
|
|
@@ -12479,41 +13669,41 @@ function createStore(graph, backend, options) {
|
|
|
12479
13669
|
}
|
|
12480
13670
|
async function createStoreWithSchema(graph, backend, options) {
|
|
12481
13671
|
const store = createStore(graph, backend, options);
|
|
12482
|
-
const result = await
|
|
13672
|
+
const result = await chunkHRNQ3DVJ_cjs.ensureSchema(backend, graph, options);
|
|
12483
13673
|
return [store, result];
|
|
12484
13674
|
}
|
|
12485
13675
|
|
|
12486
13676
|
Object.defineProperty(exports, "isMetaEdge", {
|
|
12487
13677
|
enumerable: true,
|
|
12488
|
-
get: function () { return
|
|
13678
|
+
get: function () { return chunkHRNQ3DVJ_cjs.isMetaEdge; }
|
|
12489
13679
|
});
|
|
12490
13680
|
Object.defineProperty(exports, "defineGraph", {
|
|
12491
13681
|
enumerable: true,
|
|
12492
|
-
get: function () { return
|
|
13682
|
+
get: function () { return chunkWRWVWKQL_cjs.defineGraph; }
|
|
12493
13683
|
});
|
|
12494
13684
|
Object.defineProperty(exports, "getEdgeKinds", {
|
|
12495
13685
|
enumerable: true,
|
|
12496
|
-
get: function () { return
|
|
13686
|
+
get: function () { return chunkWRWVWKQL_cjs.getEdgeKinds; }
|
|
12497
13687
|
});
|
|
12498
13688
|
Object.defineProperty(exports, "getNodeKinds", {
|
|
12499
13689
|
enumerable: true,
|
|
12500
|
-
get: function () { return
|
|
13690
|
+
get: function () { return chunkWRWVWKQL_cjs.getNodeKinds; }
|
|
12501
13691
|
});
|
|
12502
13692
|
Object.defineProperty(exports, "isEdgeType", {
|
|
12503
13693
|
enumerable: true,
|
|
12504
|
-
get: function () { return
|
|
13694
|
+
get: function () { return chunkWRWVWKQL_cjs.isEdgeType; }
|
|
12505
13695
|
});
|
|
12506
13696
|
Object.defineProperty(exports, "isEdgeTypeWithEndpoints", {
|
|
12507
13697
|
enumerable: true,
|
|
12508
|
-
get: function () { return
|
|
13698
|
+
get: function () { return chunkWRWVWKQL_cjs.isEdgeTypeWithEndpoints; }
|
|
12509
13699
|
});
|
|
12510
13700
|
Object.defineProperty(exports, "isGraphDef", {
|
|
12511
13701
|
enumerable: true,
|
|
12512
|
-
get: function () { return
|
|
13702
|
+
get: function () { return chunkWRWVWKQL_cjs.isGraphDef; }
|
|
12513
13703
|
});
|
|
12514
13704
|
Object.defineProperty(exports, "isNodeType", {
|
|
12515
13705
|
enumerable: true,
|
|
12516
|
-
get: function () { return
|
|
13706
|
+
get: function () { return chunkWRWVWKQL_cjs.isNodeType; }
|
|
12517
13707
|
});
|
|
12518
13708
|
Object.defineProperty(exports, "BackendDisposedError", {
|
|
12519
13709
|
enumerable: true,
|
|
@@ -12615,37 +13805,61 @@ Object.defineProperty(exports, "isUserRecoverable", {
|
|
|
12615
13805
|
enumerable: true,
|
|
12616
13806
|
get: function () { return chunkO5PST6TB_cjs.isUserRecoverable; }
|
|
12617
13807
|
});
|
|
13808
|
+
Object.defineProperty(exports, "fts5Strategy", {
|
|
13809
|
+
enumerable: true,
|
|
13810
|
+
get: function () { return chunkFQCQM3KG_cjs.fts5Strategy; }
|
|
13811
|
+
});
|
|
13812
|
+
Object.defineProperty(exports, "tsvectorStrategy", {
|
|
13813
|
+
enumerable: true,
|
|
13814
|
+
get: function () { return chunkFQCQM3KG_cjs.tsvectorStrategy; }
|
|
13815
|
+
});
|
|
13816
|
+
Object.defineProperty(exports, "DEFAULT_SEARCHABLE_LANGUAGE", {
|
|
13817
|
+
enumerable: true,
|
|
13818
|
+
get: function () { return chunkUVZHTBZ5_cjs.DEFAULT_SEARCHABLE_LANGUAGE; }
|
|
13819
|
+
});
|
|
12618
13820
|
Object.defineProperty(exports, "MAX_JSON_POINTER_DEPTH", {
|
|
12619
13821
|
enumerable: true,
|
|
12620
|
-
get: function () { return
|
|
13822
|
+
get: function () { return chunkUVZHTBZ5_cjs.MAX_JSON_POINTER_DEPTH; }
|
|
12621
13823
|
});
|
|
12622
13824
|
Object.defineProperty(exports, "embedding", {
|
|
12623
13825
|
enumerable: true,
|
|
12624
|
-
get: function () { return
|
|
13826
|
+
get: function () { return chunkUVZHTBZ5_cjs.embedding; }
|
|
12625
13827
|
});
|
|
12626
13828
|
Object.defineProperty(exports, "getEmbeddingDimensions", {
|
|
12627
13829
|
enumerable: true,
|
|
12628
|
-
get: function () { return
|
|
13830
|
+
get: function () { return chunkUVZHTBZ5_cjs.getEmbeddingDimensions; }
|
|
13831
|
+
});
|
|
13832
|
+
Object.defineProperty(exports, "getSearchableMetadata", {
|
|
13833
|
+
enumerable: true,
|
|
13834
|
+
get: function () { return chunkUVZHTBZ5_cjs.getSearchableMetadata; }
|
|
12629
13835
|
});
|
|
12630
13836
|
Object.defineProperty(exports, "isEmbeddingSchema", {
|
|
12631
13837
|
enumerable: true,
|
|
12632
|
-
get: function () { return
|
|
13838
|
+
get: function () { return chunkUVZHTBZ5_cjs.isEmbeddingSchema; }
|
|
13839
|
+
});
|
|
13840
|
+
Object.defineProperty(exports, "isSearchableSchema", {
|
|
13841
|
+
enumerable: true,
|
|
13842
|
+
get: function () { return chunkUVZHTBZ5_cjs.isSearchableSchema; }
|
|
12633
13843
|
});
|
|
12634
13844
|
Object.defineProperty(exports, "joinJsonPointers", {
|
|
12635
13845
|
enumerable: true,
|
|
12636
|
-
get: function () { return
|
|
13846
|
+
get: function () { return chunkUVZHTBZ5_cjs.joinJsonPointers; }
|
|
12637
13847
|
});
|
|
12638
13848
|
Object.defineProperty(exports, "jsonPointer", {
|
|
12639
13849
|
enumerable: true,
|
|
12640
|
-
get: function () { return
|
|
13850
|
+
get: function () { return chunkUVZHTBZ5_cjs.jsonPointer; }
|
|
12641
13851
|
});
|
|
12642
13852
|
Object.defineProperty(exports, "normalizeJsonPointer", {
|
|
12643
13853
|
enumerable: true,
|
|
12644
|
-
get: function () { return
|
|
13854
|
+
get: function () { return chunkUVZHTBZ5_cjs.normalizeJsonPointer; }
|
|
12645
13855
|
});
|
|
12646
13856
|
Object.defineProperty(exports, "parseJsonPointer", {
|
|
12647
13857
|
enumerable: true,
|
|
12648
|
-
get: function () { return
|
|
13858
|
+
get: function () { return chunkUVZHTBZ5_cjs.parseJsonPointer; }
|
|
13859
|
+
});
|
|
13860
|
+
Object.defineProperty(exports, "searchable", {
|
|
13861
|
+
enumerable: true,
|
|
13862
|
+
get: function () { return chunkUVZHTBZ5_cjs.searchable; }
|
|
12649
13863
|
});
|
|
12650
13864
|
exports.DEFAULT_SQL_SCHEMA = DEFAULT_SQL_SCHEMA;
|
|
12651
13865
|
exports.ExecutableAggregateQuery = ExecutableAggregateQuery;
|
|
@@ -12654,6 +13868,7 @@ exports.MAX_EXPLICIT_RECURSIVE_DEPTH = MAX_EXPLICIT_RECURSIVE_DEPTH;
|
|
|
12654
13868
|
exports.MAX_RECURSIVE_DEPTH = MAX_RECURSIVE_DEPTH;
|
|
12655
13869
|
exports.PreparedQuery = PreparedQuery;
|
|
12656
13870
|
exports.QueryBuilder = QueryBuilder;
|
|
13871
|
+
exports.StoreSearch = StoreSearch;
|
|
12657
13872
|
exports.UnionableQuery = UnionableQuery;
|
|
12658
13873
|
exports.avg = avg;
|
|
12659
13874
|
exports.broader = broader;
|