@wiscale/velesdb-sdk 1.12.0 → 1.13.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/README.md +71 -17
- package/dist/index.d.mts +1148 -534
- package/dist/index.d.ts +1148 -534
- package/dist/index.js +2395 -1263
- package/dist/index.mjs +2350 -1263
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/types.ts
|
|
1
|
+
// src/types/errors.ts
|
|
2
2
|
var VelesDBError = class extends Error {
|
|
3
3
|
constructor(message, code, cause) {
|
|
4
4
|
super(message);
|
|
@@ -32,6 +32,610 @@ var BackpressureError = class extends VelesDBError {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
// src/capabilities.ts
|
|
36
|
+
var REST_CAPABILITIES = Object.freeze({
|
|
37
|
+
vectorSearch: true,
|
|
38
|
+
textSearch: true,
|
|
39
|
+
hybridSearch: true,
|
|
40
|
+
multiQuerySearch: true,
|
|
41
|
+
sparseSearch: true,
|
|
42
|
+
scroll: true,
|
|
43
|
+
graphTraversal: true,
|
|
44
|
+
secondaryIndexes: true,
|
|
45
|
+
agentMemory: true,
|
|
46
|
+
streamInsert: true,
|
|
47
|
+
pqTraining: true,
|
|
48
|
+
velesqlQuery: true,
|
|
49
|
+
collectionIntrospection: true
|
|
50
|
+
});
|
|
51
|
+
var WASM_CAPABILITIES = Object.freeze({
|
|
52
|
+
vectorSearch: true,
|
|
53
|
+
textSearch: true,
|
|
54
|
+
hybridSearch: true,
|
|
55
|
+
multiQuerySearch: true,
|
|
56
|
+
sparseSearch: false,
|
|
57
|
+
scroll: false,
|
|
58
|
+
graphTraversal: false,
|
|
59
|
+
secondaryIndexes: false,
|
|
60
|
+
agentMemory: false,
|
|
61
|
+
streamInsert: false,
|
|
62
|
+
pqTraining: false,
|
|
63
|
+
velesqlQuery: true,
|
|
64
|
+
collectionIntrospection: false
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// src/backends/wasm-helpers.ts
|
|
68
|
+
function normalizeIdString(id) {
|
|
69
|
+
const trimmed = id.trim();
|
|
70
|
+
return /^\d+$/.test(trimmed) ? trimmed : null;
|
|
71
|
+
}
|
|
72
|
+
function canonicalPayloadKeyFromResultId(id) {
|
|
73
|
+
if (typeof id === "bigint") {
|
|
74
|
+
return id.toString();
|
|
75
|
+
}
|
|
76
|
+
if (typeof id === "number") {
|
|
77
|
+
return String(Math.trunc(id));
|
|
78
|
+
}
|
|
79
|
+
const normalized = normalizeIdString(id);
|
|
80
|
+
if (normalized !== null) {
|
|
81
|
+
return normalized.replace(/^0+(?=\d)/, "");
|
|
82
|
+
}
|
|
83
|
+
return String(toNumericId(id));
|
|
84
|
+
}
|
|
85
|
+
function canonicalPayloadKey(id) {
|
|
86
|
+
if (typeof id === "number") {
|
|
87
|
+
return String(Math.trunc(id));
|
|
88
|
+
}
|
|
89
|
+
const normalized = normalizeIdString(id);
|
|
90
|
+
if (normalized !== null) {
|
|
91
|
+
return normalized.replace(/^0+(?=\d)/, "");
|
|
92
|
+
}
|
|
93
|
+
return String(toNumericId(id));
|
|
94
|
+
}
|
|
95
|
+
function sparseVectorToArrays(sv) {
|
|
96
|
+
const indices = [];
|
|
97
|
+
const values = [];
|
|
98
|
+
for (const [k, v] of Object.entries(sv)) {
|
|
99
|
+
indices.push(Number(k));
|
|
100
|
+
values.push(v);
|
|
101
|
+
}
|
|
102
|
+
return { indices, values };
|
|
103
|
+
}
|
|
104
|
+
function toNumericId(id) {
|
|
105
|
+
if (typeof id === "number") {
|
|
106
|
+
return id;
|
|
107
|
+
}
|
|
108
|
+
const normalized = normalizeIdString(id);
|
|
109
|
+
if (normalized !== null) {
|
|
110
|
+
const parsed = Number(normalized);
|
|
111
|
+
if (Number.isSafeInteger(parsed)) {
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
let hash = 0;
|
|
116
|
+
for (let i = 0; i < id.length; i++) {
|
|
117
|
+
const char = id.charCodeAt(i);
|
|
118
|
+
hash = (hash << 5) - hash + char;
|
|
119
|
+
hash = hash & hash;
|
|
120
|
+
}
|
|
121
|
+
return Math.abs(hash);
|
|
122
|
+
}
|
|
123
|
+
function buildWasmContext(wasmModule, collections) {
|
|
124
|
+
return {
|
|
125
|
+
wasmModule,
|
|
126
|
+
getCollection: (name) => collections.get(name),
|
|
127
|
+
canonicalPayloadKeyFromResultId: (id) => canonicalPayloadKeyFromResultId(id),
|
|
128
|
+
canonicalPayloadKey: (id) => canonicalPayloadKey(id),
|
|
129
|
+
sparseVectorToArrays: (sv) => sparseVectorToArrays(sv),
|
|
130
|
+
toNumericId: (id) => toNumericId(id)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function buildCollectionInfo(name, data) {
|
|
134
|
+
return {
|
|
135
|
+
name,
|
|
136
|
+
dimension: data.config.dimension ?? 0,
|
|
137
|
+
metric: data.config.metric ?? "cosine",
|
|
138
|
+
count: data.store.len,
|
|
139
|
+
createdAt: data.createdAt
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/backends/wasm-search.ts
|
|
144
|
+
function searchSparseOnly(ctx, collection, indices, values, k) {
|
|
145
|
+
const sparseResults = collection.store.sparse_search(
|
|
146
|
+
new Uint32Array(indices),
|
|
147
|
+
new Float32Array(values),
|
|
148
|
+
k
|
|
149
|
+
);
|
|
150
|
+
return sparseResults.map((r) => ({
|
|
151
|
+
id: String(r.doc_id),
|
|
152
|
+
score: r.score,
|
|
153
|
+
payload: collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
function searchHybridFusion(ctx, collection, queryVector, indices, values, k) {
|
|
157
|
+
const denseResults = collection.store.search(queryVector, k);
|
|
158
|
+
const sparseResults = collection.store.sparse_search(
|
|
159
|
+
new Uint32Array(indices),
|
|
160
|
+
new Float32Array(values),
|
|
161
|
+
k
|
|
162
|
+
);
|
|
163
|
+
const denseForFuse = denseResults.map(
|
|
164
|
+
([id, score]) => [Number(id), score]
|
|
165
|
+
);
|
|
166
|
+
const sparseForFuse = sparseResults.map(
|
|
167
|
+
(r) => [Number(r.doc_id), r.score]
|
|
168
|
+
);
|
|
169
|
+
const fused = ctx.wasmModule.hybrid_search_fuse(
|
|
170
|
+
denseForFuse,
|
|
171
|
+
sparseForFuse,
|
|
172
|
+
60,
|
|
173
|
+
k
|
|
174
|
+
);
|
|
175
|
+
return fused.slice(0, k).map((r) => ({
|
|
176
|
+
id: String(r.doc_id),
|
|
177
|
+
score: r.score,
|
|
178
|
+
payload: collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
function searchWithFilter(ctx, collection, queryVector, k, filter) {
|
|
182
|
+
const results = collection.store.search_with_filter(
|
|
183
|
+
queryVector,
|
|
184
|
+
k,
|
|
185
|
+
filter
|
|
186
|
+
);
|
|
187
|
+
return results.map((r) => ({
|
|
188
|
+
id: String(r.id),
|
|
189
|
+
score: r.score,
|
|
190
|
+
payload: r.payload || collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.id))
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
function searchDenseOnly(ctx, collection, queryVector, k) {
|
|
194
|
+
const rawResults = collection.store.search(queryVector, k);
|
|
195
|
+
return rawResults.map(([id, score]) => {
|
|
196
|
+
const result = { id: String(id), score };
|
|
197
|
+
const payload = collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(id));
|
|
198
|
+
if (payload) {
|
|
199
|
+
result.payload = payload;
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
async function wasmSearch(ctx, collectionName, query3, options) {
|
|
205
|
+
const collection = ctx.getCollection(collectionName);
|
|
206
|
+
if (!collection) {
|
|
207
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
208
|
+
}
|
|
209
|
+
const queryVector = query3 instanceof Float32Array ? query3 : new Float32Array(query3);
|
|
210
|
+
if (queryVector.length !== collection.config.dimension) {
|
|
211
|
+
throw new VelesDBError(
|
|
212
|
+
`Query dimension mismatch: expected ${collection.config.dimension}, got ${queryVector.length}`,
|
|
213
|
+
"DIMENSION_MISMATCH"
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const k = options?.k ?? 10;
|
|
217
|
+
if (options?.sparseVector) {
|
|
218
|
+
const { indices, values } = ctx.sparseVectorToArrays(options.sparseVector);
|
|
219
|
+
const hasDense = queryVector.length > 0 && collection.config.dimension !== void 0 && collection.config.dimension > 0;
|
|
220
|
+
return hasDense ? searchHybridFusion(ctx, collection, queryVector, indices, values, k) : searchSparseOnly(ctx, collection, indices, values, k);
|
|
221
|
+
}
|
|
222
|
+
if (options?.filter) {
|
|
223
|
+
return searchWithFilter(ctx, collection, queryVector, k, options.filter);
|
|
224
|
+
}
|
|
225
|
+
return searchDenseOnly(ctx, collection, queryVector, k);
|
|
226
|
+
}
|
|
227
|
+
async function wasmSearchBatch(ctx, collectionName, searches) {
|
|
228
|
+
const results = [];
|
|
229
|
+
for (const s of searches) {
|
|
230
|
+
results.push(
|
|
231
|
+
await wasmSearch(ctx, collectionName, s.vector, {
|
|
232
|
+
k: s.k,
|
|
233
|
+
filter: s.filter,
|
|
234
|
+
quality: s.quality
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
}
|
|
240
|
+
function mapWasmResult(ctx, collection, r) {
|
|
241
|
+
if (Array.isArray(r)) {
|
|
242
|
+
const key2 = ctx.canonicalPayloadKeyFromResultId(r[0]);
|
|
243
|
+
return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
|
|
244
|
+
}
|
|
245
|
+
const key = ctx.canonicalPayloadKeyFromResultId(r.id);
|
|
246
|
+
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
247
|
+
}
|
|
248
|
+
async function wasmTextSearch(ctx, collectionName, query3, options) {
|
|
249
|
+
const collection = ctx.getCollection(collectionName);
|
|
250
|
+
if (!collection) {
|
|
251
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
252
|
+
}
|
|
253
|
+
const k = options?.k ?? 10;
|
|
254
|
+
const raw = collection.store.text_search(query3, k, void 0);
|
|
255
|
+
return raw.map((r) => mapWasmResult(ctx, collection, r));
|
|
256
|
+
}
|
|
257
|
+
async function wasmHybridSearch(ctx, collectionName, vector, textQuery, options) {
|
|
258
|
+
const collection = ctx.getCollection(collectionName);
|
|
259
|
+
if (!collection) {
|
|
260
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
261
|
+
}
|
|
262
|
+
const queryVector = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
263
|
+
const k = options?.k ?? 10;
|
|
264
|
+
const vectorWeight = options?.vectorWeight ?? 0.5;
|
|
265
|
+
const raw = collection.store.hybrid_search(
|
|
266
|
+
queryVector,
|
|
267
|
+
textQuery,
|
|
268
|
+
k,
|
|
269
|
+
vectorWeight
|
|
270
|
+
);
|
|
271
|
+
return raw.map((r) => {
|
|
272
|
+
const key = ctx.canonicalPayloadKeyFromResultId(r.id);
|
|
273
|
+
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
async function wasmMultiQuerySearch(ctx, collectionName, vectors, options) {
|
|
277
|
+
const collection = ctx.getCollection(collectionName);
|
|
278
|
+
if (!collection) {
|
|
279
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
280
|
+
}
|
|
281
|
+
if (vectors.length === 0) {
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
const numVectors = vectors.length;
|
|
285
|
+
const dimension = collection.config.dimension ?? 0;
|
|
286
|
+
const flat = new Float32Array(numVectors * dimension);
|
|
287
|
+
vectors.forEach((vector, idx) => {
|
|
288
|
+
const src = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
289
|
+
flat.set(src, idx * dimension);
|
|
290
|
+
});
|
|
291
|
+
const strategy = options?.fusion ?? "rrf";
|
|
292
|
+
const raw = collection.store.multi_query_search(
|
|
293
|
+
flat,
|
|
294
|
+
numVectors,
|
|
295
|
+
options?.k ?? 10,
|
|
296
|
+
strategy,
|
|
297
|
+
options?.fusionParams?.k ?? 60
|
|
298
|
+
);
|
|
299
|
+
return raw.map((r) => mapWasmResult(ctx, collection, r));
|
|
300
|
+
}
|
|
301
|
+
async function wasmQuery(ctx, collectionName, _queryString, params, _options) {
|
|
302
|
+
const collection = ctx.getCollection(collectionName);
|
|
303
|
+
if (!collection) {
|
|
304
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
305
|
+
}
|
|
306
|
+
const paramsVector = params?.q;
|
|
307
|
+
if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
|
|
308
|
+
throw new VelesDBError(
|
|
309
|
+
"WASM query() expects params.q to contain the query embedding vector.",
|
|
310
|
+
"BAD_REQUEST"
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const requestedK = params?.k;
|
|
314
|
+
const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
|
|
315
|
+
const raw = collection.store.query(
|
|
316
|
+
paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
|
|
317
|
+
k
|
|
318
|
+
);
|
|
319
|
+
return {
|
|
320
|
+
results: raw,
|
|
321
|
+
stats: {
|
|
322
|
+
executionTimeMs: 0,
|
|
323
|
+
strategy: "wasm-query",
|
|
324
|
+
scannedNodes: raw.length
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/errors.ts
|
|
330
|
+
var VelesError = class extends VelesDBError {
|
|
331
|
+
constructor(message, code, cause) {
|
|
332
|
+
super(message, code, cause);
|
|
333
|
+
this.name = "VelesError";
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
var CollectionExistsError = class extends VelesError {
|
|
337
|
+
constructor(message) {
|
|
338
|
+
super(message, "VELES-001");
|
|
339
|
+
this.name = "CollectionExistsError";
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
var CollectionNotFoundError = class extends VelesError {
|
|
343
|
+
constructor(message) {
|
|
344
|
+
super(message, "VELES-002");
|
|
345
|
+
this.name = "CollectionNotFoundError";
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var PointNotFoundError = class extends VelesError {
|
|
349
|
+
constructor(message) {
|
|
350
|
+
super(message, "VELES-003");
|
|
351
|
+
this.name = "PointNotFoundError";
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
var DimensionMismatchError = class extends VelesError {
|
|
355
|
+
constructor(message) {
|
|
356
|
+
super(message, "VELES-004");
|
|
357
|
+
this.name = "DimensionMismatchError";
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
var InvalidVectorError = class extends VelesError {
|
|
361
|
+
constructor(message) {
|
|
362
|
+
super(message, "VELES-005");
|
|
363
|
+
this.name = "InvalidVectorError";
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
var StorageError = class extends VelesError {
|
|
367
|
+
constructor(message) {
|
|
368
|
+
super(message, "VELES-006");
|
|
369
|
+
this.name = "StorageError";
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
var IndexError = class extends VelesError {
|
|
373
|
+
constructor(message) {
|
|
374
|
+
super(message, "VELES-007");
|
|
375
|
+
this.name = "IndexError";
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
var IndexCorruptedError = class extends VelesError {
|
|
379
|
+
constructor(message) {
|
|
380
|
+
super(message, "VELES-008");
|
|
381
|
+
this.name = "IndexCorruptedError";
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
var ConfigError = class extends VelesError {
|
|
385
|
+
constructor(message) {
|
|
386
|
+
super(message, "VELES-009");
|
|
387
|
+
this.name = "ConfigError";
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var QueryError = class extends VelesError {
|
|
391
|
+
constructor(message) {
|
|
392
|
+
super(message, "VELES-010");
|
|
393
|
+
this.name = "QueryError";
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
var IoError = class extends VelesError {
|
|
397
|
+
constructor(message) {
|
|
398
|
+
super(message, "VELES-011");
|
|
399
|
+
this.name = "IoError";
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
var SerializationError = class extends VelesError {
|
|
403
|
+
constructor(message) {
|
|
404
|
+
super(message, "VELES-012");
|
|
405
|
+
this.name = "SerializationError";
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
var InternalError = class extends VelesError {
|
|
409
|
+
constructor(message) {
|
|
410
|
+
super(message, "VELES-013");
|
|
411
|
+
this.name = "InternalError";
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var VectorNotAllowedError = class extends VelesError {
|
|
415
|
+
constructor(message) {
|
|
416
|
+
super(message, "VELES-014");
|
|
417
|
+
this.name = "VectorNotAllowedError";
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
var SearchNotSupportedError = class extends VelesError {
|
|
421
|
+
constructor(message) {
|
|
422
|
+
super(message, "VELES-015");
|
|
423
|
+
this.name = "SearchNotSupportedError";
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
var VectorRequiredError = class extends VelesError {
|
|
427
|
+
constructor(message) {
|
|
428
|
+
super(message, "VELES-016");
|
|
429
|
+
this.name = "VectorRequiredError";
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
var SchemaValidationError = class extends VelesError {
|
|
433
|
+
constructor(message) {
|
|
434
|
+
super(message, "VELES-017");
|
|
435
|
+
this.name = "SchemaValidationError";
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
var GraphNotSupportedError = class extends VelesError {
|
|
439
|
+
constructor(message) {
|
|
440
|
+
super(message, "VELES-018");
|
|
441
|
+
this.name = "GraphNotSupportedError";
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
var EdgeExistsError = class extends VelesError {
|
|
445
|
+
constructor(message) {
|
|
446
|
+
super(message, "VELES-019");
|
|
447
|
+
this.name = "EdgeExistsError";
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
var EdgeNotFoundError = class extends VelesError {
|
|
451
|
+
constructor(message) {
|
|
452
|
+
super(message, "VELES-020");
|
|
453
|
+
this.name = "EdgeNotFoundError";
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
var InvalidEdgeLabelError = class extends VelesError {
|
|
457
|
+
constructor(message) {
|
|
458
|
+
super(message, "VELES-021");
|
|
459
|
+
this.name = "InvalidEdgeLabelError";
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
var NodeNotFoundError = class extends VelesError {
|
|
463
|
+
constructor(message) {
|
|
464
|
+
super(message, "VELES-022");
|
|
465
|
+
this.name = "NodeNotFoundError";
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
var OverflowError = class extends VelesError {
|
|
469
|
+
constructor(message) {
|
|
470
|
+
super(message, "VELES-023");
|
|
471
|
+
this.name = "OverflowError";
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
var ColumnStoreError = class extends VelesError {
|
|
475
|
+
constructor(message) {
|
|
476
|
+
super(message, "VELES-024");
|
|
477
|
+
this.name = "ColumnStoreError";
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var GpuError = class extends VelesError {
|
|
481
|
+
constructor(message) {
|
|
482
|
+
super(message, "VELES-025");
|
|
483
|
+
this.name = "GpuError";
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
var EpochMismatchError = class extends VelesError {
|
|
487
|
+
constructor(message) {
|
|
488
|
+
super(message, "VELES-026");
|
|
489
|
+
this.name = "EpochMismatchError";
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
var GuardRailError = class extends VelesError {
|
|
493
|
+
constructor(message) {
|
|
494
|
+
super(message, "VELES-027");
|
|
495
|
+
this.name = "GuardRailError";
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
var InvalidQuantizerConfigError = class extends VelesError {
|
|
499
|
+
constructor(message) {
|
|
500
|
+
super(message, "VELES-028");
|
|
501
|
+
this.name = "InvalidQuantizerConfigError";
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
var TrainingFailedError = class extends VelesError {
|
|
505
|
+
constructor(message) {
|
|
506
|
+
super(message, "VELES-029");
|
|
507
|
+
this.name = "TrainingFailedError";
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
var SparseIndexError = class extends VelesError {
|
|
511
|
+
constructor(message) {
|
|
512
|
+
super(message, "VELES-030");
|
|
513
|
+
this.name = "SparseIndexError";
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
var DatabaseLockedError = class extends VelesError {
|
|
517
|
+
constructor(message) {
|
|
518
|
+
super(message, "VELES-031");
|
|
519
|
+
this.name = "DatabaseLockedError";
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
var InvalidDimensionError = class extends VelesError {
|
|
523
|
+
constructor(message) {
|
|
524
|
+
super(message, "VELES-032");
|
|
525
|
+
this.name = "InvalidDimensionError";
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
var AllocationFailedError = class extends VelesError {
|
|
529
|
+
constructor(message) {
|
|
530
|
+
super(message, "VELES-033");
|
|
531
|
+
this.name = "AllocationFailedError";
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
var InvalidCollectionNameError = class extends VelesError {
|
|
535
|
+
constructor(message) {
|
|
536
|
+
super(message, "VELES-034");
|
|
537
|
+
this.name = "InvalidCollectionNameError";
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
var SnapshotBuildFailedError = class extends VelesError {
|
|
541
|
+
constructor(message) {
|
|
542
|
+
super(message, "VELES-035");
|
|
543
|
+
this.name = "SnapshotBuildFailedError";
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
var IncompatibleSchemaVersionError = class extends VelesError {
|
|
547
|
+
constructor(message) {
|
|
548
|
+
super(message, "VELES-036");
|
|
549
|
+
this.name = "IncompatibleSchemaVersionError";
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
var VELES_ERROR_CODES = [
|
|
553
|
+
"VELES-001",
|
|
554
|
+
"VELES-002",
|
|
555
|
+
"VELES-003",
|
|
556
|
+
"VELES-004",
|
|
557
|
+
"VELES-005",
|
|
558
|
+
"VELES-006",
|
|
559
|
+
"VELES-007",
|
|
560
|
+
"VELES-008",
|
|
561
|
+
"VELES-009",
|
|
562
|
+
"VELES-010",
|
|
563
|
+
"VELES-011",
|
|
564
|
+
"VELES-012",
|
|
565
|
+
"VELES-013",
|
|
566
|
+
"VELES-014",
|
|
567
|
+
"VELES-015",
|
|
568
|
+
"VELES-016",
|
|
569
|
+
"VELES-017",
|
|
570
|
+
"VELES-018",
|
|
571
|
+
"VELES-019",
|
|
572
|
+
"VELES-020",
|
|
573
|
+
"VELES-021",
|
|
574
|
+
"VELES-022",
|
|
575
|
+
"VELES-023",
|
|
576
|
+
"VELES-024",
|
|
577
|
+
"VELES-025",
|
|
578
|
+
"VELES-026",
|
|
579
|
+
"VELES-027",
|
|
580
|
+
"VELES-028",
|
|
581
|
+
"VELES-029",
|
|
582
|
+
"VELES-030",
|
|
583
|
+
"VELES-031",
|
|
584
|
+
"VELES-032",
|
|
585
|
+
"VELES-033",
|
|
586
|
+
"VELES-034",
|
|
587
|
+
"VELES-035",
|
|
588
|
+
"VELES-036"
|
|
589
|
+
];
|
|
590
|
+
var CODE_TO_CLASS = {
|
|
591
|
+
"VELES-001": CollectionExistsError,
|
|
592
|
+
"VELES-002": CollectionNotFoundError,
|
|
593
|
+
"VELES-003": PointNotFoundError,
|
|
594
|
+
"VELES-004": DimensionMismatchError,
|
|
595
|
+
"VELES-005": InvalidVectorError,
|
|
596
|
+
"VELES-006": StorageError,
|
|
597
|
+
"VELES-007": IndexError,
|
|
598
|
+
"VELES-008": IndexCorruptedError,
|
|
599
|
+
"VELES-009": ConfigError,
|
|
600
|
+
"VELES-010": QueryError,
|
|
601
|
+
"VELES-011": IoError,
|
|
602
|
+
"VELES-012": SerializationError,
|
|
603
|
+
"VELES-013": InternalError,
|
|
604
|
+
"VELES-014": VectorNotAllowedError,
|
|
605
|
+
"VELES-015": SearchNotSupportedError,
|
|
606
|
+
"VELES-016": VectorRequiredError,
|
|
607
|
+
"VELES-017": SchemaValidationError,
|
|
608
|
+
"VELES-018": GraphNotSupportedError,
|
|
609
|
+
"VELES-019": EdgeExistsError,
|
|
610
|
+
"VELES-020": EdgeNotFoundError,
|
|
611
|
+
"VELES-021": InvalidEdgeLabelError,
|
|
612
|
+
"VELES-022": NodeNotFoundError,
|
|
613
|
+
"VELES-023": OverflowError,
|
|
614
|
+
"VELES-024": ColumnStoreError,
|
|
615
|
+
"VELES-025": GpuError,
|
|
616
|
+
"VELES-026": EpochMismatchError,
|
|
617
|
+
"VELES-027": GuardRailError,
|
|
618
|
+
"VELES-028": InvalidQuantizerConfigError,
|
|
619
|
+
"VELES-029": TrainingFailedError,
|
|
620
|
+
"VELES-030": SparseIndexError,
|
|
621
|
+
"VELES-031": DatabaseLockedError,
|
|
622
|
+
"VELES-032": InvalidDimensionError,
|
|
623
|
+
"VELES-033": AllocationFailedError,
|
|
624
|
+
"VELES-034": InvalidCollectionNameError,
|
|
625
|
+
"VELES-035": SnapshotBuildFailedError,
|
|
626
|
+
"VELES-036": IncompatibleSchemaVersionError
|
|
627
|
+
};
|
|
628
|
+
function parseVelesError(code, message) {
|
|
629
|
+
if (code === null || code === void 0) {
|
|
630
|
+
return new VelesError(message, "VELES-UNKNOWN");
|
|
631
|
+
}
|
|
632
|
+
const Cls = CODE_TO_CLASS[code];
|
|
633
|
+
if (Cls !== void 0) {
|
|
634
|
+
return new Cls(message);
|
|
635
|
+
}
|
|
636
|
+
return new VelesError(message, code);
|
|
637
|
+
}
|
|
638
|
+
|
|
35
639
|
// src/backends/shared.ts
|
|
36
640
|
function throwOnError(response, resourceLabel) {
|
|
37
641
|
if (!response.error) {
|
|
@@ -40,20 +644,87 @@ function throwOnError(response, resourceLabel) {
|
|
|
40
644
|
if (response.error.code === "NOT_FOUND" && resourceLabel !== void 0) {
|
|
41
645
|
throw new NotFoundError(resourceLabel);
|
|
42
646
|
}
|
|
43
|
-
throw
|
|
647
|
+
throw parseVelesError(response.error.code, response.error.message);
|
|
44
648
|
}
|
|
45
649
|
function returnNullOnNotFound(response) {
|
|
46
650
|
if (!response.error) {
|
|
47
651
|
return void 0;
|
|
48
652
|
}
|
|
49
|
-
if (response.error.code
|
|
653
|
+
if (isNotFoundError(response.error.code)) {
|
|
50
654
|
return true;
|
|
51
655
|
}
|
|
52
|
-
throw
|
|
656
|
+
throw parseVelesError(response.error.code, response.error.message);
|
|
657
|
+
}
|
|
658
|
+
function isNotFoundError(code) {
|
|
659
|
+
if (code === void 0) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
if (code === "NOT_FOUND") {
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
const err = parseVelesError(code, "");
|
|
666
|
+
return err instanceof CollectionNotFoundError || err instanceof PointNotFoundError || err instanceof EdgeNotFoundError || err instanceof NodeNotFoundError;
|
|
53
667
|
}
|
|
54
668
|
function collectionPath(collection) {
|
|
55
669
|
return `/collections/${encodeURIComponent(collection)}`;
|
|
56
670
|
}
|
|
671
|
+
var MAX_COLLECTION_NAME_LENGTH = 128;
|
|
672
|
+
var WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
673
|
+
"CON",
|
|
674
|
+
"PRN",
|
|
675
|
+
"AUX",
|
|
676
|
+
"NUL",
|
|
677
|
+
"COM1",
|
|
678
|
+
"COM2",
|
|
679
|
+
"COM3",
|
|
680
|
+
"COM4",
|
|
681
|
+
"COM5",
|
|
682
|
+
"COM6",
|
|
683
|
+
"COM7",
|
|
684
|
+
"COM8",
|
|
685
|
+
"COM9",
|
|
686
|
+
"LPT1",
|
|
687
|
+
"LPT2",
|
|
688
|
+
"LPT3",
|
|
689
|
+
"LPT4",
|
|
690
|
+
"LPT5",
|
|
691
|
+
"LPT6",
|
|
692
|
+
"LPT7",
|
|
693
|
+
"LPT8",
|
|
694
|
+
"LPT9"
|
|
695
|
+
]);
|
|
696
|
+
function validateCollectionName(name) {
|
|
697
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
698
|
+
throw new InvalidCollectionNameError(
|
|
699
|
+
"Collection name must be a non-empty string"
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
if (name.length > MAX_COLLECTION_NAME_LENGTH) {
|
|
703
|
+
throw new InvalidCollectionNameError(
|
|
704
|
+
`Collection name '${name}' exceeds maximum length of ${MAX_COLLECTION_NAME_LENGTH} characters`
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
if (name === "." || name === "..") {
|
|
708
|
+
throw new InvalidCollectionNameError(
|
|
709
|
+
`Collection name '${name}' is not allowed (path traversal)`
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
if (name.startsWith("-")) {
|
|
713
|
+
throw new InvalidCollectionNameError(
|
|
714
|
+
`Collection name '${name}' must not start with a hyphen`
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
if (!/^[A-Za-z0-9_-]+$/.test(name)) {
|
|
718
|
+
throw new InvalidCollectionNameError(
|
|
719
|
+
`Collection name '${name}' contains forbidden characters; only ASCII letters, digits, underscores, and hyphens are allowed`
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
if (WINDOWS_RESERVED_NAMES.has(name.toUpperCase())) {
|
|
723
|
+
throw new InvalidCollectionNameError(
|
|
724
|
+
`Collection name '${name}' is a Windows reserved device name`
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
57
728
|
function toNumberArray(v) {
|
|
58
729
|
return v instanceof Float32Array ? Array.from(v) : v;
|
|
59
730
|
}
|
|
@@ -64,6 +735,127 @@ function wasmNotSupported(feature) {
|
|
|
64
735
|
);
|
|
65
736
|
}
|
|
66
737
|
|
|
738
|
+
// src/backends/wasm-stubs.ts
|
|
739
|
+
async function wasmCreateIndex(_collection, _options) {
|
|
740
|
+
wasmNotSupported("Index management (createIndex)");
|
|
741
|
+
}
|
|
742
|
+
async function wasmListIndexes(_collection) {
|
|
743
|
+
wasmNotSupported("Index management (listIndexes)");
|
|
744
|
+
}
|
|
745
|
+
async function wasmHasIndex(_collection, _label, _property) {
|
|
746
|
+
wasmNotSupported("Index management (hasIndex)");
|
|
747
|
+
}
|
|
748
|
+
async function wasmDropIndex(_collection, _label, _property) {
|
|
749
|
+
wasmNotSupported("Index management (dropIndex)");
|
|
750
|
+
}
|
|
751
|
+
async function wasmAddEdge(_collection, _edge) {
|
|
752
|
+
wasmNotSupported("Knowledge Graph operations");
|
|
753
|
+
}
|
|
754
|
+
async function wasmGetEdges(_collection, _options) {
|
|
755
|
+
wasmNotSupported("Knowledge Graph operations");
|
|
756
|
+
}
|
|
757
|
+
async function wasmTraverseGraph(_collection, _request) {
|
|
758
|
+
wasmNotSupported("Graph traversal");
|
|
759
|
+
}
|
|
760
|
+
async function wasmTraverseParallel(_collection, _request) {
|
|
761
|
+
wasmNotSupported("Graph parallel traversal");
|
|
762
|
+
}
|
|
763
|
+
async function wasmGetNodeDegree(_collection, _nodeId) {
|
|
764
|
+
wasmNotSupported("Graph degree query");
|
|
765
|
+
}
|
|
766
|
+
async function wasmQueryExplain(_queryString, _params, _options) {
|
|
767
|
+
if (_options?.analyze) {
|
|
768
|
+
wasmNotSupported("EXPLAIN ANALYZE");
|
|
769
|
+
}
|
|
770
|
+
wasmNotSupported("Query explain");
|
|
771
|
+
}
|
|
772
|
+
async function wasmCollectionSanity(_collection) {
|
|
773
|
+
wasmNotSupported("Collection sanity endpoint");
|
|
774
|
+
}
|
|
775
|
+
async function wasmScroll(_collection, _request) {
|
|
776
|
+
wasmNotSupported("scroll");
|
|
777
|
+
}
|
|
778
|
+
async function wasmTrainPq(_collection, _options) {
|
|
779
|
+
wasmNotSupported("PQ training");
|
|
780
|
+
}
|
|
781
|
+
async function wasmStreamInsert(_collection, _docs) {
|
|
782
|
+
wasmNotSupported("Streaming insert");
|
|
783
|
+
}
|
|
784
|
+
async function wasmStreamUpsertPoints(_collection, _docs) {
|
|
785
|
+
wasmNotSupported("Streaming batch upsert");
|
|
786
|
+
}
|
|
787
|
+
async function wasmCreateGraphCollection(_name, _config) {
|
|
788
|
+
wasmNotSupported("Graph collections");
|
|
789
|
+
}
|
|
790
|
+
async function wasmGetCollectionStats(_collection) {
|
|
791
|
+
wasmNotSupported("Collection stats");
|
|
792
|
+
}
|
|
793
|
+
async function wasmAnalyzeCollection(_collection) {
|
|
794
|
+
wasmNotSupported("Collection analyze");
|
|
795
|
+
}
|
|
796
|
+
async function wasmGetCollectionConfig(_collection) {
|
|
797
|
+
wasmNotSupported("Collection config");
|
|
798
|
+
}
|
|
799
|
+
async function wasmSearchIds(_collection, _query, _options) {
|
|
800
|
+
wasmNotSupported("searchIds");
|
|
801
|
+
}
|
|
802
|
+
async function wasmStoreSemanticFact(_collection, _entry) {
|
|
803
|
+
wasmNotSupported("Agent memory");
|
|
804
|
+
}
|
|
805
|
+
async function wasmSearchSemanticMemory(_collection, _embedding, _k) {
|
|
806
|
+
wasmNotSupported("Agent memory");
|
|
807
|
+
}
|
|
808
|
+
async function wasmRecordEpisodicEvent(_collection, _event) {
|
|
809
|
+
wasmNotSupported("Agent memory");
|
|
810
|
+
}
|
|
811
|
+
async function wasmRecallEpisodicEvents(_collection, _embedding, _k) {
|
|
812
|
+
wasmNotSupported("Agent memory");
|
|
813
|
+
}
|
|
814
|
+
async function wasmStoreProceduralPattern(_collection, _pattern) {
|
|
815
|
+
wasmNotSupported("Agent memory");
|
|
816
|
+
}
|
|
817
|
+
async function wasmMatchProceduralPatterns(_collection, _embedding, _k) {
|
|
818
|
+
wasmNotSupported("Agent memory");
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/backends/wasm-wave4-stubs.ts
|
|
822
|
+
function wasmRebuildIndex(_c) {
|
|
823
|
+
return Promise.resolve(wasmNotSupported("Index rebuild"));
|
|
824
|
+
}
|
|
825
|
+
function wasmGetGuardrails() {
|
|
826
|
+
return Promise.resolve(wasmNotSupported("Guardrails"));
|
|
827
|
+
}
|
|
828
|
+
function wasmUpdateGuardrails(_r) {
|
|
829
|
+
return Promise.resolve(wasmNotSupported("Guardrails"));
|
|
830
|
+
}
|
|
831
|
+
function wasmAggregate(_q, _p, _o) {
|
|
832
|
+
return Promise.resolve(wasmNotSupported("Aggregate queries"));
|
|
833
|
+
}
|
|
834
|
+
function wasmMatchQuery(_c, _q, _p, _o) {
|
|
835
|
+
return Promise.resolve(wasmNotSupported("MATCH queries"));
|
|
836
|
+
}
|
|
837
|
+
function wasmRemoveEdge(_c, _id) {
|
|
838
|
+
return Promise.resolve(wasmNotSupported("Graph edge removal"));
|
|
839
|
+
}
|
|
840
|
+
function wasmGetEdgeCount(_c) {
|
|
841
|
+
return Promise.resolve(wasmNotSupported("Graph edge count"));
|
|
842
|
+
}
|
|
843
|
+
function wasmListNodes(_c) {
|
|
844
|
+
return Promise.resolve(wasmNotSupported("Graph list nodes"));
|
|
845
|
+
}
|
|
846
|
+
function wasmGetNodeEdges(_c, _id, _o) {
|
|
847
|
+
return Promise.resolve(wasmNotSupported("Graph node edges"));
|
|
848
|
+
}
|
|
849
|
+
function wasmGetNodePayload(_c, _id) {
|
|
850
|
+
return Promise.resolve(wasmNotSupported("Graph node payload (read)"));
|
|
851
|
+
}
|
|
852
|
+
function wasmUpsertNodePayload(_c, _id, _p) {
|
|
853
|
+
return Promise.resolve(wasmNotSupported("Graph node payload (upsert)"));
|
|
854
|
+
}
|
|
855
|
+
function wasmGraphSearch(_c, _r) {
|
|
856
|
+
return Promise.resolve(wasmNotSupported("Graph search"));
|
|
857
|
+
}
|
|
858
|
+
|
|
67
859
|
// src/backends/wasm.ts
|
|
68
860
|
var WasmBackend = class {
|
|
69
861
|
constructor() {
|
|
@@ -71,6 +863,9 @@ var WasmBackend = class {
|
|
|
71
863
|
this.collections = /* @__PURE__ */ new Map();
|
|
72
864
|
this._initialized = false;
|
|
73
865
|
}
|
|
866
|
+
// ========================================================================
|
|
867
|
+
// Lifecycle
|
|
868
|
+
// ========================================================================
|
|
74
869
|
async init() {
|
|
75
870
|
if (this._initialized) {
|
|
76
871
|
return;
|
|
@@ -89,45 +884,32 @@ var WasmBackend = class {
|
|
|
89
884
|
isInitialized() {
|
|
90
885
|
return this._initialized;
|
|
91
886
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
887
|
+
async close() {
|
|
888
|
+
for (const [, data] of this.collections) {
|
|
889
|
+
data.store.free();
|
|
95
890
|
}
|
|
891
|
+
this.collections.clear();
|
|
892
|
+
this._initialized = false;
|
|
96
893
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return /^\d+$/.test(trimmed) ? trimmed : null;
|
|
894
|
+
capabilities() {
|
|
895
|
+
return WASM_CAPABILITIES;
|
|
100
896
|
}
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
if (typeof id === "number") {
|
|
106
|
-
return String(Math.trunc(id));
|
|
107
|
-
}
|
|
108
|
-
const normalized = this.normalizeIdString(id);
|
|
109
|
-
if (normalized !== null) {
|
|
110
|
-
return normalized.replace(/^0+(?=\d)/, "");
|
|
111
|
-
}
|
|
112
|
-
return String(this.toNumericId(id));
|
|
113
|
-
}
|
|
114
|
-
canonicalPayloadKey(id) {
|
|
115
|
-
if (typeof id === "number") {
|
|
116
|
-
return String(Math.trunc(id));
|
|
117
|
-
}
|
|
118
|
-
const normalized = this.normalizeIdString(id);
|
|
119
|
-
if (normalized !== null) {
|
|
120
|
-
return normalized.replace(/^0+(?=\d)/, "");
|
|
897
|
+
ensureInitialized() {
|
|
898
|
+
if (!this._initialized || !this.wasmModule) {
|
|
899
|
+
throw new ConnectionError("WASM backend not initialized");
|
|
121
900
|
}
|
|
122
|
-
return String(this.toNumericId(id));
|
|
123
901
|
}
|
|
902
|
+
// ========================================================================
|
|
903
|
+
// Collection management
|
|
904
|
+
// ========================================================================
|
|
124
905
|
async createCollection(name, config) {
|
|
125
906
|
this.ensureInitialized();
|
|
126
907
|
if (this.collections.has(name)) {
|
|
127
908
|
throw new VelesDBError(`Collection '${name}' already exists`, "COLLECTION_EXISTS");
|
|
128
909
|
}
|
|
910
|
+
const dimension = config.dimension ?? 0;
|
|
129
911
|
const metric = config.metric ?? "cosine";
|
|
130
|
-
const store = new this.wasmModule.VectorStore(
|
|
912
|
+
const store = new this.wasmModule.VectorStore(dimension, metric);
|
|
131
913
|
this.collections.set(name, {
|
|
132
914
|
config: { ...config, metric },
|
|
133
915
|
store,
|
|
@@ -146,39 +928,27 @@ var WasmBackend = class {
|
|
|
146
928
|
}
|
|
147
929
|
async getCollection(name) {
|
|
148
930
|
this.ensureInitialized();
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
return {
|
|
154
|
-
name,
|
|
155
|
-
dimension: collection.config.dimension ?? 0,
|
|
156
|
-
metric: collection.config.metric ?? "cosine",
|
|
157
|
-
count: collection.store.len,
|
|
158
|
-
createdAt: collection.createdAt
|
|
159
|
-
};
|
|
931
|
+
const data = this.collections.get(name);
|
|
932
|
+
return data ? buildCollectionInfo(name, data) : null;
|
|
160
933
|
}
|
|
161
934
|
async listCollections() {
|
|
162
935
|
this.ensureInitialized();
|
|
163
936
|
const result = [];
|
|
164
937
|
for (const [name, data] of this.collections) {
|
|
165
|
-
result.push(
|
|
166
|
-
name,
|
|
167
|
-
dimension: data.config.dimension ?? 0,
|
|
168
|
-
metric: data.config.metric ?? "cosine",
|
|
169
|
-
count: data.store.len,
|
|
170
|
-
createdAt: data.createdAt
|
|
171
|
-
});
|
|
938
|
+
result.push(buildCollectionInfo(name, data));
|
|
172
939
|
}
|
|
173
940
|
return result;
|
|
174
941
|
}
|
|
175
|
-
|
|
942
|
+
// ========================================================================
|
|
943
|
+
// Point CRUD
|
|
944
|
+
// ========================================================================
|
|
945
|
+
async upsert(collectionName, doc) {
|
|
176
946
|
this.ensureInitialized();
|
|
177
947
|
const collection = this.collections.get(collectionName);
|
|
178
948
|
if (!collection) {
|
|
179
949
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
180
950
|
}
|
|
181
|
-
const id =
|
|
951
|
+
const id = toNumericId(doc.id);
|
|
182
952
|
const vector = doc.vector instanceof Float32Array ? doc.vector : new Float32Array(doc.vector);
|
|
183
953
|
if (vector.length !== collection.config.dimension) {
|
|
184
954
|
throw new VelesDBError(
|
|
@@ -192,20 +962,19 @@ var WasmBackend = class {
|
|
|
192
962
|
collection.store.insert(BigInt(id), vector);
|
|
193
963
|
}
|
|
194
964
|
if (doc.payload) {
|
|
195
|
-
collection.payloads.set(
|
|
965
|
+
collection.payloads.set(canonicalPayloadKey(doc.id), doc.payload);
|
|
196
966
|
}
|
|
197
967
|
}
|
|
198
|
-
async
|
|
968
|
+
async upsertBatch(collectionName, docs) {
|
|
199
969
|
this.ensureInitialized();
|
|
200
970
|
const collection = this.collections.get(collectionName);
|
|
201
971
|
if (!collection) {
|
|
202
972
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
203
973
|
}
|
|
204
974
|
for (const doc of docs) {
|
|
205
|
-
|
|
206
|
-
if (vectorLen !== collection.config.dimension) {
|
|
975
|
+
if (doc.vector.length !== collection.config.dimension) {
|
|
207
976
|
throw new VelesDBError(
|
|
208
|
-
`Vector dimension mismatch for doc ${doc.id}: expected ${collection.config.dimension}, got ${
|
|
977
|
+
`Vector dimension mismatch for doc ${doc.id}: expected ${collection.config.dimension}, got ${doc.vector.length}`,
|
|
209
978
|
"DIMENSION_MISMATCH"
|
|
210
979
|
);
|
|
211
980
|
}
|
|
@@ -213,7 +982,7 @@ var WasmBackend = class {
|
|
|
213
982
|
collection.store.reserve(docs.length);
|
|
214
983
|
const batch = [];
|
|
215
984
|
for (const doc of docs) {
|
|
216
|
-
const id = BigInt(
|
|
985
|
+
const id = BigInt(toNumericId(doc.id));
|
|
217
986
|
const vector = doc.vector instanceof Float32Array ? doc.vector : new Float32Array(doc.vector);
|
|
218
987
|
if (doc.payload) {
|
|
219
988
|
collection.store.insert_with_payload(id, vector, doc.payload);
|
|
@@ -226,95 +995,20 @@ var WasmBackend = class {
|
|
|
226
995
|
}
|
|
227
996
|
for (const doc of docs) {
|
|
228
997
|
if (doc.payload) {
|
|
229
|
-
collection.payloads.set(
|
|
998
|
+
collection.payloads.set(canonicalPayloadKey(doc.id), doc.payload);
|
|
230
999
|
}
|
|
231
1000
|
}
|
|
232
1001
|
}
|
|
233
|
-
async search(collectionName, query2, options) {
|
|
234
|
-
this.ensureInitialized();
|
|
235
|
-
const collection = this.collections.get(collectionName);
|
|
236
|
-
if (!collection) {
|
|
237
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
238
|
-
}
|
|
239
|
-
const queryVector = query2 instanceof Float32Array ? query2 : new Float32Array(query2);
|
|
240
|
-
if (queryVector.length !== collection.config.dimension) {
|
|
241
|
-
throw new VelesDBError(
|
|
242
|
-
`Query dimension mismatch: expected ${collection.config.dimension}, got ${queryVector.length}`,
|
|
243
|
-
"DIMENSION_MISMATCH"
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
const k = options?.k ?? 10;
|
|
247
|
-
if (options?.sparseVector) {
|
|
248
|
-
const { indices, values } = this.sparseVectorToArrays(options.sparseVector);
|
|
249
|
-
if (queryVector.length > 0 && collection.config.dimension && collection.config.dimension > 0) {
|
|
250
|
-
const denseResults = collection.store.search(queryVector, k);
|
|
251
|
-
const sparseResults = collection.store.sparse_search(
|
|
252
|
-
new Uint32Array(indices),
|
|
253
|
-
new Float32Array(values),
|
|
254
|
-
k
|
|
255
|
-
);
|
|
256
|
-
const sparseArray = sparseResults;
|
|
257
|
-
const denseForFuse = denseResults.map(([id, score]) => [Number(id), score]);
|
|
258
|
-
const sparseForFuse = sparseArray.map((r) => [Number(r.doc_id), r.score]);
|
|
259
|
-
const fused = this.wasmModule.hybrid_search_fuse(denseForFuse, sparseForFuse, 60);
|
|
260
|
-
return fused.slice(0, k).map((r) => ({
|
|
261
|
-
id: String(r.doc_id),
|
|
262
|
-
score: r.score,
|
|
263
|
-
payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
264
|
-
}));
|
|
265
|
-
} else {
|
|
266
|
-
const sparseResults = collection.store.sparse_search(
|
|
267
|
-
new Uint32Array(indices),
|
|
268
|
-
new Float32Array(values),
|
|
269
|
-
k
|
|
270
|
-
);
|
|
271
|
-
return sparseResults.map((r) => ({
|
|
272
|
-
id: String(r.doc_id),
|
|
273
|
-
score: r.score,
|
|
274
|
-
payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
275
|
-
}));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (options?.filter) {
|
|
279
|
-
const results = collection.store.search_with_filter(queryVector, k, options.filter);
|
|
280
|
-
return results.map((r) => ({
|
|
281
|
-
id: String(r.id),
|
|
282
|
-
score: r.score,
|
|
283
|
-
payload: r.payload || collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.id))
|
|
284
|
-
}));
|
|
285
|
-
}
|
|
286
|
-
const rawResults = collection.store.search(queryVector, k);
|
|
287
|
-
return rawResults.map(([id, score]) => {
|
|
288
|
-
const stringId = String(id);
|
|
289
|
-
const result = {
|
|
290
|
-
id: stringId,
|
|
291
|
-
score
|
|
292
|
-
};
|
|
293
|
-
const payload = collection.payloads.get(this.canonicalPayloadKeyFromResultId(id));
|
|
294
|
-
if (payload) {
|
|
295
|
-
result.payload = payload;
|
|
296
|
-
}
|
|
297
|
-
return result;
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
async searchBatch(collectionName, searches) {
|
|
301
|
-
this.ensureInitialized();
|
|
302
|
-
const results = [];
|
|
303
|
-
for (const s of searches) {
|
|
304
|
-
results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
|
|
305
|
-
}
|
|
306
|
-
return results;
|
|
307
|
-
}
|
|
308
1002
|
async delete(collectionName, id) {
|
|
309
1003
|
this.ensureInitialized();
|
|
310
1004
|
const collection = this.collections.get(collectionName);
|
|
311
1005
|
if (!collection) {
|
|
312
1006
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
313
1007
|
}
|
|
314
|
-
const numericId =
|
|
1008
|
+
const numericId = toNumericId(id);
|
|
315
1009
|
const removed = collection.store.remove(BigInt(numericId));
|
|
316
1010
|
if (removed) {
|
|
317
|
-
collection.payloads.delete(
|
|
1011
|
+
collection.payloads.delete(canonicalPayloadKey(id));
|
|
318
1012
|
}
|
|
319
1013
|
return removed;
|
|
320
1014
|
}
|
|
@@ -324,291 +1018,691 @@ var WasmBackend = class {
|
|
|
324
1018
|
if (!collection) {
|
|
325
1019
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
326
1020
|
}
|
|
327
|
-
const numericId =
|
|
1021
|
+
const numericId = toNumericId(id);
|
|
328
1022
|
const point = collection.store.get(BigInt(numericId));
|
|
329
1023
|
if (!point) {
|
|
330
1024
|
return null;
|
|
331
1025
|
}
|
|
332
|
-
const payload = point.payload ?? collection.payloads.get(
|
|
1026
|
+
const payload = point.payload ?? collection.payloads.get(canonicalPayloadKey(numericId));
|
|
333
1027
|
return {
|
|
334
1028
|
id: String(point.id),
|
|
335
1029
|
vector: Array.isArray(point.vector) ? point.vector : Array.from(point.vector),
|
|
336
1030
|
payload
|
|
337
1031
|
};
|
|
338
1032
|
}
|
|
339
|
-
|
|
1033
|
+
// ========================================================================
|
|
1034
|
+
// Collection utilities
|
|
1035
|
+
// ========================================================================
|
|
1036
|
+
async isEmpty(collectionName) {
|
|
340
1037
|
this.ensureInitialized();
|
|
341
|
-
const collection = this.collections.get(
|
|
1038
|
+
const collection = this.collections.get(collectionName);
|
|
342
1039
|
if (!collection) {
|
|
343
|
-
throw new NotFoundError(`Collection '${
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
1040
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
1041
|
+
}
|
|
1042
|
+
return collection.store.is_empty;
|
|
1043
|
+
}
|
|
1044
|
+
async flush(collectionName) {
|
|
1045
|
+
this.ensureInitialized();
|
|
1046
|
+
const collection = this.collections.get(collectionName);
|
|
1047
|
+
if (!collection) {
|
|
1048
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// ========================================================================
|
|
1052
|
+
// Search & Query -- delegates to wasm-search.ts
|
|
1053
|
+
// ========================================================================
|
|
1054
|
+
async search(c, q, o) {
|
|
1055
|
+
this.ensureInitialized();
|
|
1056
|
+
return wasmSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
|
|
1057
|
+
}
|
|
1058
|
+
async searchBatch(c, s) {
|
|
1059
|
+
this.ensureInitialized();
|
|
1060
|
+
return wasmSearchBatch(buildWasmContext(this.wasmModule, this.collections), c, s);
|
|
1061
|
+
}
|
|
1062
|
+
async textSearch(c, q, o) {
|
|
1063
|
+
this.ensureInitialized();
|
|
1064
|
+
return wasmTextSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
|
|
1065
|
+
}
|
|
1066
|
+
async hybridSearch(c, v, t, o) {
|
|
1067
|
+
this.ensureInitialized();
|
|
1068
|
+
return wasmHybridSearch(buildWasmContext(this.wasmModule, this.collections), c, v, t, o);
|
|
1069
|
+
}
|
|
1070
|
+
async query(c, q, p, o) {
|
|
1071
|
+
this.ensureInitialized();
|
|
1072
|
+
return wasmQuery(buildWasmContext(this.wasmModule, this.collections), c, q, p, o);
|
|
1073
|
+
}
|
|
1074
|
+
async multiQuerySearch(c, v, o) {
|
|
1075
|
+
this.ensureInitialized();
|
|
1076
|
+
return wasmMultiQuerySearch(buildWasmContext(this.wasmModule, this.collections), c, v, o);
|
|
1077
|
+
}
|
|
1078
|
+
// ========================================================================
|
|
1079
|
+
// Stubs -- delegates to wasm-stubs.ts & wasm-wave4-stubs.ts
|
|
1080
|
+
// ========================================================================
|
|
1081
|
+
async queryExplain(q, p, o) {
|
|
1082
|
+
this.ensureInitialized();
|
|
1083
|
+
return wasmQueryExplain(q, p, o);
|
|
1084
|
+
}
|
|
1085
|
+
async collectionSanity(c) {
|
|
1086
|
+
this.ensureInitialized();
|
|
1087
|
+
return wasmCollectionSanity(c);
|
|
1088
|
+
}
|
|
1089
|
+
async scroll(c, r) {
|
|
1090
|
+
this.ensureInitialized();
|
|
1091
|
+
return wasmScroll(c, r);
|
|
1092
|
+
}
|
|
1093
|
+
async createIndex(c, o) {
|
|
1094
|
+
this.ensureInitialized();
|
|
1095
|
+
return wasmCreateIndex(c, o);
|
|
1096
|
+
}
|
|
1097
|
+
async listIndexes(c) {
|
|
1098
|
+
this.ensureInitialized();
|
|
1099
|
+
return wasmListIndexes(c);
|
|
1100
|
+
}
|
|
1101
|
+
async hasIndex(c, l, p) {
|
|
1102
|
+
this.ensureInitialized();
|
|
1103
|
+
return wasmHasIndex(c, l, p);
|
|
356
1104
|
}
|
|
357
|
-
async
|
|
1105
|
+
async dropIndex(c, l, p) {
|
|
358
1106
|
this.ensureInitialized();
|
|
359
|
-
|
|
360
|
-
if (!collection) {
|
|
361
|
-
throw new NotFoundError(`Collection '${_collection}'`);
|
|
362
|
-
}
|
|
363
|
-
const queryVector = _vector instanceof Float32Array ? _vector : new Float32Array(_vector);
|
|
364
|
-
const k = _options?.k ?? 10;
|
|
365
|
-
const vectorWeight = _options?.vectorWeight ?? 0.5;
|
|
366
|
-
const raw = collection.store.hybrid_search(queryVector, _textQuery, k, vectorWeight);
|
|
367
|
-
return raw.map((r) => {
|
|
368
|
-
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
369
|
-
return {
|
|
370
|
-
id: String(r.id),
|
|
371
|
-
score: r.score,
|
|
372
|
-
payload: r.payload ?? collection.payloads.get(key)
|
|
373
|
-
};
|
|
374
|
-
});
|
|
1107
|
+
return wasmDropIndex(c, l, p);
|
|
375
1108
|
}
|
|
376
|
-
async
|
|
1109
|
+
async addEdge(c, e) {
|
|
377
1110
|
this.ensureInitialized();
|
|
378
|
-
|
|
379
|
-
if (!collection) {
|
|
380
|
-
throw new NotFoundError(`Collection '${_collection}'`);
|
|
381
|
-
}
|
|
382
|
-
const paramsVector = _params?.q;
|
|
383
|
-
if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
|
|
384
|
-
throw new VelesDBError(
|
|
385
|
-
"WASM query() expects params.q to contain the query embedding vector.",
|
|
386
|
-
"BAD_REQUEST"
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
const requestedK = _params?.k;
|
|
390
|
-
const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
|
|
391
|
-
const raw = collection.store.query(
|
|
392
|
-
paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
|
|
393
|
-
k
|
|
394
|
-
);
|
|
395
|
-
return {
|
|
396
|
-
results: raw,
|
|
397
|
-
stats: {
|
|
398
|
-
executionTimeMs: 0,
|
|
399
|
-
strategy: "wasm-query",
|
|
400
|
-
scannedNodes: raw.length
|
|
401
|
-
}
|
|
402
|
-
};
|
|
1111
|
+
return wasmAddEdge(c, e);
|
|
403
1112
|
}
|
|
404
|
-
async
|
|
1113
|
+
async getEdges(c, o) {
|
|
405
1114
|
this.ensureInitialized();
|
|
406
|
-
|
|
407
|
-
if (!collection) {
|
|
408
|
-
throw new NotFoundError(`Collection '${_collection}'`);
|
|
409
|
-
}
|
|
410
|
-
if (_vectors.length === 0) {
|
|
411
|
-
return [];
|
|
412
|
-
}
|
|
413
|
-
const numVectors = _vectors.length;
|
|
414
|
-
const dimension = collection.config.dimension ?? 0;
|
|
415
|
-
const flat = new Float32Array(numVectors * dimension);
|
|
416
|
-
_vectors.forEach((vector, idx) => {
|
|
417
|
-
const src = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
418
|
-
flat.set(src, idx * dimension);
|
|
419
|
-
});
|
|
420
|
-
const strategy = _options?.fusion ?? "rrf";
|
|
421
|
-
if (strategy === "weighted") {
|
|
422
|
-
throw new VelesDBError(
|
|
423
|
-
"Fusion strategy 'weighted' is not supported in WASM backend.",
|
|
424
|
-
"NOT_SUPPORTED"
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
const raw = collection.store.multi_query_search(
|
|
428
|
-
flat,
|
|
429
|
-
numVectors,
|
|
430
|
-
_options?.k ?? 10,
|
|
431
|
-
strategy,
|
|
432
|
-
_options?.fusionParams?.k ?? 60
|
|
433
|
-
);
|
|
434
|
-
return raw.map((r) => {
|
|
435
|
-
if (Array.isArray(r)) {
|
|
436
|
-
const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
|
|
437
|
-
return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
|
|
438
|
-
}
|
|
439
|
-
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
440
|
-
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
441
|
-
});
|
|
1115
|
+
return wasmGetEdges(c, o);
|
|
442
1116
|
}
|
|
443
|
-
async
|
|
1117
|
+
async traverseGraph(c, r) {
|
|
444
1118
|
this.ensureInitialized();
|
|
445
|
-
|
|
1119
|
+
return wasmTraverseGraph(c, r);
|
|
446
1120
|
}
|
|
447
|
-
async
|
|
1121
|
+
async traverseParallel(c, r) {
|
|
448
1122
|
this.ensureInitialized();
|
|
449
|
-
|
|
1123
|
+
return wasmTraverseParallel(c, r);
|
|
450
1124
|
}
|
|
451
|
-
async
|
|
1125
|
+
async getNodeDegree(c, n) {
|
|
452
1126
|
this.ensureInitialized();
|
|
453
|
-
|
|
454
|
-
if (!collection) {
|
|
455
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
456
|
-
}
|
|
457
|
-
return collection.store.is_empty();
|
|
1127
|
+
return wasmGetNodeDegree(c, n);
|
|
458
1128
|
}
|
|
459
|
-
async
|
|
1129
|
+
async trainPq(c, o) {
|
|
460
1130
|
this.ensureInitialized();
|
|
461
|
-
|
|
462
|
-
if (!collection) {
|
|
463
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
464
|
-
}
|
|
1131
|
+
return wasmTrainPq(c, o);
|
|
465
1132
|
}
|
|
466
|
-
async
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
this.collections.clear();
|
|
471
|
-
this._initialized = false;
|
|
1133
|
+
async streamInsert(c, d) {
|
|
1134
|
+
this.ensureInitialized();
|
|
1135
|
+
return wasmStreamInsert(c, d);
|
|
472
1136
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
for (const [k, v] of Object.entries(sv)) {
|
|
477
|
-
indices.push(Number(k));
|
|
478
|
-
values.push(v);
|
|
479
|
-
}
|
|
480
|
-
return { indices, values };
|
|
1137
|
+
async streamUpsertPoints(c, d) {
|
|
1138
|
+
this.ensureInitialized();
|
|
1139
|
+
return wasmStreamUpsertPoints(c, d);
|
|
481
1140
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
const normalized = this.normalizeIdString(id);
|
|
487
|
-
if (normalized !== null) {
|
|
488
|
-
const parsed = Number(normalized);
|
|
489
|
-
if (Number.isSafeInteger(parsed)) {
|
|
490
|
-
return parsed;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
let hash = 0;
|
|
494
|
-
for (let i = 0; i < id.length; i++) {
|
|
495
|
-
const char = id.charCodeAt(i);
|
|
496
|
-
hash = (hash << 5) - hash + char;
|
|
497
|
-
hash = hash & hash;
|
|
498
|
-
}
|
|
499
|
-
return Math.abs(hash);
|
|
1141
|
+
async createGraphCollection(n, c) {
|
|
1142
|
+
this.ensureInitialized();
|
|
1143
|
+
return wasmCreateGraphCollection(n, c);
|
|
500
1144
|
}
|
|
501
|
-
|
|
502
|
-
// Index Management (EPIC-009) - Stubs for WASM backend
|
|
503
|
-
// Note: Full implementation requires velesdb-wasm support
|
|
504
|
-
// ========================================================================
|
|
505
|
-
async createIndex(_collection, _options) {
|
|
1145
|
+
async getCollectionStats(c) {
|
|
506
1146
|
this.ensureInitialized();
|
|
507
|
-
|
|
508
|
-
"WasmBackend: createIndex is not yet supported. Index operations require the REST backend with velesdb-server."
|
|
509
|
-
);
|
|
1147
|
+
return wasmGetCollectionStats(c);
|
|
510
1148
|
}
|
|
511
|
-
async
|
|
1149
|
+
async analyzeCollection(c) {
|
|
512
1150
|
this.ensureInitialized();
|
|
513
|
-
return
|
|
1151
|
+
return wasmAnalyzeCollection(c);
|
|
514
1152
|
}
|
|
515
|
-
async
|
|
1153
|
+
async getCollectionConfig(c) {
|
|
516
1154
|
this.ensureInitialized();
|
|
517
|
-
return
|
|
1155
|
+
return wasmGetCollectionConfig(c);
|
|
518
1156
|
}
|
|
519
|
-
async
|
|
1157
|
+
async searchIds(c, q, o) {
|
|
520
1158
|
this.ensureInitialized();
|
|
521
|
-
return
|
|
1159
|
+
return wasmSearchIds(c, q, o);
|
|
522
1160
|
}
|
|
523
|
-
|
|
524
|
-
// Knowledge Graph (EPIC-016 US-041) - Stubs for WASM backend
|
|
525
|
-
// Note: Graph operations require server-side EdgeStore
|
|
526
|
-
// ========================================================================
|
|
527
|
-
async addEdge(_collection, _edge) {
|
|
1161
|
+
async storeSemanticFact(c, e) {
|
|
528
1162
|
this.ensureInitialized();
|
|
529
|
-
|
|
1163
|
+
return wasmStoreSemanticFact(c, e);
|
|
530
1164
|
}
|
|
531
|
-
async
|
|
1165
|
+
async searchSemanticMemory(c, e, k) {
|
|
532
1166
|
this.ensureInitialized();
|
|
533
|
-
|
|
1167
|
+
return wasmSearchSemanticMemory(c, e, k);
|
|
534
1168
|
}
|
|
535
|
-
async
|
|
1169
|
+
async recordEpisodicEvent(c, e) {
|
|
536
1170
|
this.ensureInitialized();
|
|
537
|
-
|
|
1171
|
+
return wasmRecordEpisodicEvent(c, e);
|
|
538
1172
|
}
|
|
539
|
-
async
|
|
1173
|
+
async recallEpisodicEvents(c, e, k) {
|
|
540
1174
|
this.ensureInitialized();
|
|
541
|
-
|
|
1175
|
+
return wasmRecallEpisodicEvents(c, e, k);
|
|
542
1176
|
}
|
|
543
|
-
async
|
|
1177
|
+
async storeProceduralPattern(c, p) {
|
|
544
1178
|
this.ensureInitialized();
|
|
545
|
-
|
|
1179
|
+
return wasmStoreProceduralPattern(c, p);
|
|
546
1180
|
}
|
|
547
|
-
|
|
548
|
-
// Sparse / PQ / Streaming (v1.5)
|
|
549
|
-
// ========================================================================
|
|
550
|
-
async trainPq(_collection, _options) {
|
|
1181
|
+
async matchProceduralPatterns(c, e, k) {
|
|
551
1182
|
this.ensureInitialized();
|
|
552
|
-
|
|
1183
|
+
return wasmMatchProceduralPatterns(c, e, k);
|
|
553
1184
|
}
|
|
554
|
-
|
|
1185
|
+
// Wave 4 stubs
|
|
1186
|
+
async rebuildIndex(c) {
|
|
555
1187
|
this.ensureInitialized();
|
|
556
|
-
|
|
1188
|
+
return wasmRebuildIndex(c);
|
|
557
1189
|
}
|
|
558
|
-
|
|
559
|
-
// Graph Collection / Stats / Agent Memory (Phase 8) - WASM stubs
|
|
560
|
-
// ========================================================================
|
|
561
|
-
async createGraphCollection(_name, _config) {
|
|
1190
|
+
async getGuardrails() {
|
|
562
1191
|
this.ensureInitialized();
|
|
563
|
-
|
|
1192
|
+
return wasmGetGuardrails();
|
|
564
1193
|
}
|
|
565
|
-
async
|
|
1194
|
+
async updateGuardrails(r) {
|
|
566
1195
|
this.ensureInitialized();
|
|
567
|
-
|
|
1196
|
+
return wasmUpdateGuardrails(r);
|
|
568
1197
|
}
|
|
569
|
-
async
|
|
1198
|
+
async aggregate(_q, _p, _o) {
|
|
570
1199
|
this.ensureInitialized();
|
|
571
|
-
|
|
1200
|
+
return wasmAggregate(_q, _p, _o);
|
|
572
1201
|
}
|
|
573
|
-
async
|
|
1202
|
+
async matchQuery(c, q, p, o) {
|
|
574
1203
|
this.ensureInitialized();
|
|
575
|
-
|
|
1204
|
+
return wasmMatchQuery(c, q, p, o);
|
|
576
1205
|
}
|
|
577
|
-
async
|
|
1206
|
+
async removeEdge(c, id) {
|
|
578
1207
|
this.ensureInitialized();
|
|
579
|
-
|
|
1208
|
+
return wasmRemoveEdge(c, id);
|
|
580
1209
|
}
|
|
581
|
-
async
|
|
1210
|
+
async getEdgeCount(c) {
|
|
582
1211
|
this.ensureInitialized();
|
|
583
|
-
|
|
1212
|
+
return wasmGetEdgeCount(c);
|
|
584
1213
|
}
|
|
585
|
-
async
|
|
1214
|
+
async listNodes(c) {
|
|
586
1215
|
this.ensureInitialized();
|
|
587
|
-
|
|
1216
|
+
return wasmListNodes(c);
|
|
588
1217
|
}
|
|
589
|
-
async
|
|
1218
|
+
async getNodeEdges(c, id, o) {
|
|
590
1219
|
this.ensureInitialized();
|
|
591
|
-
|
|
1220
|
+
return wasmGetNodeEdges(c, id, o);
|
|
592
1221
|
}
|
|
593
|
-
async
|
|
1222
|
+
async getNodePayload(c, id) {
|
|
594
1223
|
this.ensureInitialized();
|
|
595
|
-
|
|
1224
|
+
return wasmGetNodePayload(c, id);
|
|
596
1225
|
}
|
|
597
|
-
async
|
|
1226
|
+
async upsertNodePayload(c, id, p) {
|
|
598
1227
|
this.ensureInitialized();
|
|
599
|
-
|
|
1228
|
+
return wasmUpsertNodePayload(c, id, p);
|
|
600
1229
|
}
|
|
601
|
-
async
|
|
1230
|
+
async graphSearch(c, r) {
|
|
602
1231
|
this.ensureInitialized();
|
|
603
|
-
|
|
1232
|
+
return wasmGraphSearch(c, r);
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
|
|
1236
|
+
// src/backends/crud-backend.ts
|
|
1237
|
+
function parseRestPointId(id) {
|
|
1238
|
+
if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
|
|
1239
|
+
throw new ValidationError(
|
|
1240
|
+
`REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
return id;
|
|
1244
|
+
}
|
|
1245
|
+
function sparseVectorToRestFormat(sv) {
|
|
1246
|
+
const result = {};
|
|
1247
|
+
for (const [k, v] of Object.entries(sv)) {
|
|
1248
|
+
result[String(k)] = v;
|
|
1249
|
+
}
|
|
1250
|
+
return result;
|
|
1251
|
+
}
|
|
1252
|
+
function toDeferredIndexingWire(opts) {
|
|
1253
|
+
if (!opts) return void 0;
|
|
1254
|
+
const wire = {};
|
|
1255
|
+
if (opts.enabled !== void 0) wire.enabled = opts.enabled;
|
|
1256
|
+
if (opts.mergeThreshold !== void 0) wire.merge_threshold = opts.mergeThreshold;
|
|
1257
|
+
if (opts.maxBufferAgeMs !== void 0) wire.max_buffer_age_ms = opts.maxBufferAgeMs;
|
|
1258
|
+
return wire;
|
|
1259
|
+
}
|
|
1260
|
+
function toAsyncIndexBuilderWire(opts) {
|
|
1261
|
+
if (!opts) return void 0;
|
|
1262
|
+
const wire = {};
|
|
1263
|
+
if (opts.mergeThreshold !== void 0) wire.merge_threshold = opts.mergeThreshold;
|
|
1264
|
+
if (opts.segmentCount !== void 0) wire.segment_count = opts.segmentCount;
|
|
1265
|
+
return wire;
|
|
1266
|
+
}
|
|
1267
|
+
async function createCollection(transport, name, config) {
|
|
1268
|
+
const body = {
|
|
1269
|
+
name,
|
|
1270
|
+
dimension: config.dimension,
|
|
1271
|
+
metric: config.metric ?? "cosine",
|
|
1272
|
+
storage_mode: config.storageMode ?? "full",
|
|
1273
|
+
collection_type: config.collectionType ?? "vector",
|
|
1274
|
+
description: config.description,
|
|
1275
|
+
hnsw_m: config.hnsw?.m,
|
|
1276
|
+
hnsw_ef_construction: config.hnsw?.efConstruction,
|
|
1277
|
+
hnsw_alpha: config.hnsw?.alpha,
|
|
1278
|
+
hnsw_max_elements: config.hnsw?.maxElements
|
|
1279
|
+
};
|
|
1280
|
+
if (config.pqRescoreOversampling !== void 0) {
|
|
1281
|
+
body.pq_rescore_oversampling = config.pqRescoreOversampling;
|
|
1282
|
+
}
|
|
1283
|
+
const deferredWire = toDeferredIndexingWire(config.deferredIndexing);
|
|
1284
|
+
if (deferredWire !== void 0) {
|
|
1285
|
+
body.deferred_indexing = deferredWire;
|
|
1286
|
+
}
|
|
1287
|
+
const asyncWire = toAsyncIndexBuilderWire(config.asyncIndexBuilder);
|
|
1288
|
+
if (asyncWire !== void 0) {
|
|
1289
|
+
body.async_index_builder = asyncWire;
|
|
1290
|
+
}
|
|
1291
|
+
const response = await transport.requestJson("POST", "/collections", body);
|
|
1292
|
+
throwOnError(response);
|
|
1293
|
+
}
|
|
1294
|
+
async function deleteCollection(transport, name) {
|
|
1295
|
+
const response = await transport.requestJson(
|
|
1296
|
+
"DELETE",
|
|
1297
|
+
collectionPath(name)
|
|
1298
|
+
);
|
|
1299
|
+
throwOnError(response, `Collection '${name}'`);
|
|
1300
|
+
}
|
|
1301
|
+
async function getCollection(transport, name) {
|
|
1302
|
+
const response = await transport.requestJson(
|
|
1303
|
+
"GET",
|
|
1304
|
+
collectionPath(name)
|
|
1305
|
+
);
|
|
1306
|
+
if (returnNullOnNotFound(response)) {
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
return response.data ?? null;
|
|
1310
|
+
}
|
|
1311
|
+
async function listCollections(transport) {
|
|
1312
|
+
const response = await transport.requestJson("GET", "/collections");
|
|
1313
|
+
throwOnError(response);
|
|
1314
|
+
return response.data ?? [];
|
|
1315
|
+
}
|
|
1316
|
+
async function upsert(transport, collection, doc) {
|
|
1317
|
+
const restId = parseRestPointId(doc.id);
|
|
1318
|
+
const vector = toNumberArray(doc.vector);
|
|
1319
|
+
const response = await transport.requestJson(
|
|
1320
|
+
"POST",
|
|
1321
|
+
`${collectionPath(collection)}/points`,
|
|
1322
|
+
{ points: [{ id: restId, vector, payload: doc.payload }] }
|
|
1323
|
+
);
|
|
1324
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1325
|
+
}
|
|
1326
|
+
async function upsertBatch(transport, collection, docs) {
|
|
1327
|
+
const vectors = docs.map((doc) => ({
|
|
1328
|
+
id: parseRestPointId(doc.id),
|
|
1329
|
+
vector: toNumberArray(doc.vector),
|
|
1330
|
+
payload: doc.payload
|
|
1331
|
+
}));
|
|
1332
|
+
const response = await transport.requestJson(
|
|
1333
|
+
"POST",
|
|
1334
|
+
`${collectionPath(collection)}/points`,
|
|
1335
|
+
{ points: vectors }
|
|
1336
|
+
);
|
|
1337
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1338
|
+
}
|
|
1339
|
+
async function deletePoint(transport, collection, id) {
|
|
1340
|
+
const restId = parseRestPointId(id);
|
|
1341
|
+
const response = await transport.requestJson(
|
|
1342
|
+
"DELETE",
|
|
1343
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1344
|
+
);
|
|
1345
|
+
if (returnNullOnNotFound(response)) {
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
return response.data?.deleted ?? false;
|
|
1349
|
+
}
|
|
1350
|
+
async function get(transport, collection, id) {
|
|
1351
|
+
const restId = parseRestPointId(id);
|
|
1352
|
+
const response = await transport.requestJson(
|
|
1353
|
+
"GET",
|
|
1354
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1355
|
+
);
|
|
1356
|
+
if (returnNullOnNotFound(response)) {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
return response.data ?? null;
|
|
1360
|
+
}
|
|
1361
|
+
async function isEmpty(transport, collection) {
|
|
1362
|
+
const response = await transport.requestJson(
|
|
1363
|
+
"GET",
|
|
1364
|
+
`${collectionPath(collection)}/empty`
|
|
1365
|
+
);
|
|
1366
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1367
|
+
return response.data?.is_empty ?? true;
|
|
1368
|
+
}
|
|
1369
|
+
async function flush(transport, collection) {
|
|
1370
|
+
const response = await transport.requestJson(
|
|
1371
|
+
"POST",
|
|
1372
|
+
`${collectionPath(collection)}/flush`
|
|
1373
|
+
);
|
|
1374
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/backends/rest-http.ts
|
|
1378
|
+
var STATUS_ERROR_CODES = {
|
|
1379
|
+
400: "BAD_REQUEST",
|
|
1380
|
+
401: "UNAUTHORIZED",
|
|
1381
|
+
403: "FORBIDDEN",
|
|
1382
|
+
404: "NOT_FOUND",
|
|
1383
|
+
409: "CONFLICT",
|
|
1384
|
+
429: "RATE_LIMITED",
|
|
1385
|
+
500: "INTERNAL_ERROR",
|
|
1386
|
+
503: "SERVICE_UNAVAILABLE"
|
|
1387
|
+
};
|
|
1388
|
+
function mapStatusToErrorCode(status) {
|
|
1389
|
+
return STATUS_ERROR_CODES[status] ?? "UNKNOWN_ERROR";
|
|
1390
|
+
}
|
|
1391
|
+
function stringField(obj, ...keys) {
|
|
1392
|
+
for (const key of keys) {
|
|
1393
|
+
if (typeof obj[key] === "string") return obj[key];
|
|
1394
|
+
}
|
|
1395
|
+
return void 0;
|
|
1396
|
+
}
|
|
1397
|
+
function extractErrorPayload(data) {
|
|
1398
|
+
if (!data || typeof data !== "object") return {};
|
|
1399
|
+
const payload = data;
|
|
1400
|
+
const nested = typeof payload.error === "object" && payload.error ? payload.error : payload;
|
|
1401
|
+
return {
|
|
1402
|
+
code: stringField(nested, "code") ?? stringField(payload, "code"),
|
|
1403
|
+
message: stringField(nested, "message") ?? stringField(payload, "message", "error")
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
function parseNodeId(value) {
|
|
1407
|
+
if (value === null || value === void 0) {
|
|
1408
|
+
return 0;
|
|
1409
|
+
}
|
|
1410
|
+
if (typeof value === "bigint") {
|
|
1411
|
+
return value;
|
|
1412
|
+
}
|
|
1413
|
+
if (typeof value === "string") {
|
|
1414
|
+
const num = Number(value);
|
|
1415
|
+
return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
|
|
1416
|
+
}
|
|
1417
|
+
if (typeof value === "number") {
|
|
1418
|
+
return value;
|
|
1419
|
+
}
|
|
1420
|
+
return 0;
|
|
1421
|
+
}
|
|
1422
|
+
function buildHeaders(config) {
|
|
1423
|
+
const headers = { "Content-Type": "application/json" };
|
|
1424
|
+
if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1425
|
+
return headers;
|
|
1426
|
+
}
|
|
1427
|
+
function wrapCatchError(error) {
|
|
1428
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1429
|
+
throw new ConnectionError("Request timeout");
|
|
1430
|
+
}
|
|
1431
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1432
|
+
const cause = error instanceof Error ? error : void 0;
|
|
1433
|
+
throw new ConnectionError(`Request failed: ${message}`, cause);
|
|
1434
|
+
}
|
|
1435
|
+
async function request(config, method, path, body) {
|
|
1436
|
+
const controller = new AbortController();
|
|
1437
|
+
const timeoutId = setTimeout(() => controller.abort(), config.timeout);
|
|
1438
|
+
try {
|
|
1439
|
+
const response = await fetch(`${config.baseUrl}${path}`, {
|
|
1440
|
+
method,
|
|
1441
|
+
headers: buildHeaders(config),
|
|
1442
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
1443
|
+
signal: controller.signal
|
|
1444
|
+
});
|
|
1445
|
+
clearTimeout(timeoutId);
|
|
1446
|
+
const data = await response.json().catch(() => ({}));
|
|
1447
|
+
if (!response.ok) {
|
|
1448
|
+
const ep = extractErrorPayload(data);
|
|
1449
|
+
return { error: {
|
|
1450
|
+
code: ep.code ?? mapStatusToErrorCode(response.status),
|
|
1451
|
+
message: ep.message ?? `HTTP ${response.status}`
|
|
1452
|
+
} };
|
|
1453
|
+
}
|
|
1454
|
+
return { data };
|
|
1455
|
+
} catch (error) {
|
|
1456
|
+
clearTimeout(timeoutId);
|
|
1457
|
+
wrapCatchError(error);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function buildBaseTransport(config) {
|
|
1461
|
+
return {
|
|
1462
|
+
requestJson: (m, p, b) => request(config, m, p, b)
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
function buildCrudTransport(config) {
|
|
1466
|
+
return {
|
|
1467
|
+
requestJson: (m, p, b) => request(config, m, p, b)
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
function buildSearchTransport(config) {
|
|
1471
|
+
return {
|
|
1472
|
+
requestJson: (m, p, b) => request(config, m, p, b),
|
|
1473
|
+
sparseToRest: (sv) => sparseVectorToRestFormat(sv)
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
function buildQueryTransport(config) {
|
|
1477
|
+
return {
|
|
1478
|
+
requestJson: (m, p, b) => request(config, m, p, b),
|
|
1479
|
+
parseNodeId: (v) => parseNodeId(v)
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
function buildStreamingTransport(config) {
|
|
1483
|
+
return {
|
|
1484
|
+
requestJson: (m, p, b) => request(config, m, p, b),
|
|
1485
|
+
baseUrl: config.baseUrl,
|
|
1486
|
+
apiKey: config.apiKey,
|
|
1487
|
+
timeout: config.timeout,
|
|
1488
|
+
parseRestPointId,
|
|
1489
|
+
sparseVectorToRestFormat,
|
|
1490
|
+
mapStatusToErrorCode: (s) => mapStatusToErrorCode(s),
|
|
1491
|
+
extractErrorPayload: (d) => extractErrorPayload(d)
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function buildAgentMemoryTransport(config, searchFn) {
|
|
1495
|
+
return {
|
|
1496
|
+
requestJson: (m, p, b) => request(config, m, p, b),
|
|
1497
|
+
searchVectors: (c, e, k, f2) => searchFn(c, e, { k, filter: f2 })
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// src/backends/missing-endpoints.ts
|
|
1502
|
+
async function rebuildIndex(transport, collection) {
|
|
1503
|
+
const response = await transport.requestJson(
|
|
1504
|
+
"POST",
|
|
1505
|
+
`${collectionPath(collection)}/index/rebuild`
|
|
1506
|
+
);
|
|
1507
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1508
|
+
const data = response.data;
|
|
1509
|
+
return {
|
|
1510
|
+
message: data.message,
|
|
1511
|
+
collection: data.collection,
|
|
1512
|
+
compactedEntries: data.compacted_entries
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
function mapGuardRailsWire(data) {
|
|
1516
|
+
return {
|
|
1517
|
+
maxDepth: data.max_depth,
|
|
1518
|
+
maxCardinality: data.max_cardinality,
|
|
1519
|
+
memoryLimitBytes: data.memory_limit_bytes,
|
|
1520
|
+
timeoutMs: data.timeout_ms,
|
|
1521
|
+
rateLimitQps: data.rate_limit_qps,
|
|
1522
|
+
circuitFailureThreshold: data.circuit_failure_threshold,
|
|
1523
|
+
circuitRecoverySeconds: data.circuit_recovery_seconds
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
function toGuardRailsWireUpdate(req) {
|
|
1527
|
+
const wire = {};
|
|
1528
|
+
if (req.maxDepth !== void 0) wire.max_depth = req.maxDepth;
|
|
1529
|
+
if (req.maxCardinality !== void 0) wire.max_cardinality = req.maxCardinality;
|
|
1530
|
+
if (req.memoryLimitBytes !== void 0) wire.memory_limit_bytes = req.memoryLimitBytes;
|
|
1531
|
+
if (req.timeoutMs !== void 0) wire.timeout_ms = req.timeoutMs;
|
|
1532
|
+
if (req.rateLimitQps !== void 0) wire.rate_limit_qps = req.rateLimitQps;
|
|
1533
|
+
if (req.circuitFailureThreshold !== void 0) {
|
|
1534
|
+
wire.circuit_failure_threshold = req.circuitFailureThreshold;
|
|
1535
|
+
}
|
|
1536
|
+
if (req.circuitRecoverySeconds !== void 0) {
|
|
1537
|
+
wire.circuit_recovery_seconds = req.circuitRecoverySeconds;
|
|
1538
|
+
}
|
|
1539
|
+
return wire;
|
|
1540
|
+
}
|
|
1541
|
+
async function getGuardrails(transport) {
|
|
1542
|
+
const response = await transport.requestJson("GET", "/guardrails");
|
|
1543
|
+
throwOnError(response);
|
|
1544
|
+
return mapGuardRailsWire(response.data);
|
|
1545
|
+
}
|
|
1546
|
+
async function updateGuardrails(transport, req) {
|
|
1547
|
+
const response = await transport.requestJson(
|
|
1548
|
+
"PUT",
|
|
1549
|
+
"/guardrails",
|
|
1550
|
+
toGuardRailsWireUpdate(req)
|
|
1551
|
+
);
|
|
1552
|
+
throwOnError(response);
|
|
1553
|
+
return mapGuardRailsWire(response.data);
|
|
1554
|
+
}
|
|
1555
|
+
async function aggregate(transport, queryString, params, options) {
|
|
1556
|
+
const body = {
|
|
1557
|
+
query: queryString,
|
|
1558
|
+
params: params ?? {}
|
|
1559
|
+
};
|
|
1560
|
+
if (options?.collection !== void 0) {
|
|
1561
|
+
body.collection = options.collection;
|
|
1562
|
+
}
|
|
1563
|
+
const response = await transport.requestJson(
|
|
1564
|
+
"POST",
|
|
1565
|
+
"/aggregate",
|
|
1566
|
+
body
|
|
1567
|
+
);
|
|
1568
|
+
throwOnError(response);
|
|
1569
|
+
const data = response.data;
|
|
1570
|
+
return {
|
|
1571
|
+
result: data.result,
|
|
1572
|
+
timingMs: data.timing_ms,
|
|
1573
|
+
meta: {
|
|
1574
|
+
velesqlContractVersion: data.meta.velesql_contract_version,
|
|
1575
|
+
count: data.meta.count
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
async function matchQuery(transport, collection, queryString, params, options) {
|
|
1580
|
+
const body = {
|
|
1581
|
+
query: queryString,
|
|
1582
|
+
params: params ?? {}
|
|
1583
|
+
};
|
|
1584
|
+
if (options?.vector !== void 0) {
|
|
1585
|
+
body.vector = toNumberArray(options.vector);
|
|
1586
|
+
}
|
|
1587
|
+
if (options?.threshold !== void 0) {
|
|
1588
|
+
body.threshold = options.threshold;
|
|
1589
|
+
}
|
|
1590
|
+
const response = await transport.requestJson(
|
|
1591
|
+
"POST",
|
|
1592
|
+
`${collectionPath(collection)}/match`,
|
|
1593
|
+
body
|
|
1594
|
+
);
|
|
1595
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1596
|
+
const data = response.data;
|
|
1597
|
+
const items = data.results.map((r) => ({
|
|
1598
|
+
bindings: r.bindings,
|
|
1599
|
+
score: r.score,
|
|
1600
|
+
depth: r.depth,
|
|
1601
|
+
projected: r.projected ?? {}
|
|
1602
|
+
}));
|
|
1603
|
+
return {
|
|
1604
|
+
results: items,
|
|
1605
|
+
tookMs: data.took_ms,
|
|
1606
|
+
count: data.count,
|
|
1607
|
+
meta: { velesqlContractVersion: data.meta.velesql_contract_version }
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
async function removeEdge(transport, collection, edgeId) {
|
|
1611
|
+
const response = await transport.requestJson(
|
|
1612
|
+
"DELETE",
|
|
1613
|
+
`${collectionPath(collection)}/graph/edges/${edgeId}`
|
|
1614
|
+
);
|
|
1615
|
+
if (response.error !== void 0) {
|
|
1616
|
+
const { code, message } = response.error;
|
|
1617
|
+
const err = parseVelesError(code, message);
|
|
1618
|
+
if (err instanceof EdgeNotFoundError) {
|
|
1619
|
+
return false;
|
|
1620
|
+
}
|
|
1621
|
+
if (code === "NOT_FOUND") {
|
|
1622
|
+
return false;
|
|
1623
|
+
}
|
|
1624
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
604
1625
|
}
|
|
605
|
-
|
|
1626
|
+
return true;
|
|
1627
|
+
}
|
|
1628
|
+
async function getEdgeCount(transport, collection) {
|
|
1629
|
+
const response = await transport.requestJson(
|
|
1630
|
+
"GET",
|
|
1631
|
+
`${collectionPath(collection)}/graph/edges/count`
|
|
1632
|
+
);
|
|
1633
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1634
|
+
return response.data?.count ?? 0;
|
|
1635
|
+
}
|
|
1636
|
+
async function listNodes(transport, collection) {
|
|
1637
|
+
const response = await transport.requestJson(
|
|
1638
|
+
"GET",
|
|
1639
|
+
`${collectionPath(collection)}/graph/nodes`
|
|
1640
|
+
);
|
|
1641
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1642
|
+
const data = response.data;
|
|
1643
|
+
return { nodeIds: data.node_ids, count: data.count };
|
|
1644
|
+
}
|
|
1645
|
+
function idToNumber(id) {
|
|
1646
|
+
return typeof id === "string" ? Number(id) : id;
|
|
1647
|
+
}
|
|
1648
|
+
async function getNodeEdges(transport, collection, nodeId, options) {
|
|
1649
|
+
const params = new URLSearchParams();
|
|
1650
|
+
if (options?.direction) params.set("direction", options.direction);
|
|
1651
|
+
if (options?.label) params.set("label", options.label);
|
|
1652
|
+
const qs = params.toString();
|
|
1653
|
+
const url = `${collectionPath(collection)}/graph/nodes/${nodeId}/edges` + (qs ? `?${qs}` : "");
|
|
1654
|
+
const response = await transport.requestJson("GET", url);
|
|
1655
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1656
|
+
return (response.data?.edges ?? []).map((e) => ({
|
|
1657
|
+
id: idToNumber(e.id),
|
|
1658
|
+
source: idToNumber(e.source),
|
|
1659
|
+
target: idToNumber(e.target),
|
|
1660
|
+
label: e.label,
|
|
1661
|
+
properties: e.properties
|
|
1662
|
+
}));
|
|
1663
|
+
}
|
|
1664
|
+
async function getNodePayload(transport, collection, nodeId) {
|
|
1665
|
+
const response = await transport.requestJson("GET", `${collectionPath(collection)}/graph/nodes/${nodeId}/payload`);
|
|
1666
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1667
|
+
const data = response.data;
|
|
1668
|
+
return {
|
|
1669
|
+
nodeId: idToNumber(data.node_id),
|
|
1670
|
+
payload: data.payload
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
async function upsertNodePayload(transport, collection, nodeId, payload) {
|
|
1674
|
+
const response = await transport.requestJson(
|
|
1675
|
+
"PUT",
|
|
1676
|
+
`${collectionPath(collection)}/graph/nodes/${nodeId}/payload`,
|
|
1677
|
+
{ payload }
|
|
1678
|
+
);
|
|
1679
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1680
|
+
}
|
|
1681
|
+
async function graphSearch(transport, collection, request2) {
|
|
1682
|
+
const response = await transport.requestJson(
|
|
1683
|
+
"POST",
|
|
1684
|
+
`${collectionPath(collection)}/graph/search`,
|
|
1685
|
+
{
|
|
1686
|
+
vector: toNumberArray(request2.vector),
|
|
1687
|
+
top_k: request2.k ?? 10
|
|
1688
|
+
}
|
|
1689
|
+
);
|
|
1690
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1691
|
+
const items = (response.data?.results ?? []).map(
|
|
1692
|
+
(r) => ({
|
|
1693
|
+
id: idToNumber(r.id),
|
|
1694
|
+
score: r.score,
|
|
1695
|
+
payload: r.payload
|
|
1696
|
+
})
|
|
1697
|
+
);
|
|
1698
|
+
return { results: items };
|
|
1699
|
+
}
|
|
606
1700
|
|
|
607
1701
|
// src/backends/agent-memory-backend.ts
|
|
608
1702
|
var _idCounter = 0;
|
|
609
1703
|
var _lastTimestamp = 0;
|
|
610
1704
|
function generateUniqueId() {
|
|
611
|
-
|
|
1705
|
+
const now = Date.now();
|
|
612
1706
|
if (now <= _lastTimestamp) {
|
|
613
1707
|
_idCounter++;
|
|
614
1708
|
if (_idCounter >= 1e3) {
|
|
@@ -689,14 +1783,23 @@ async function matchProceduralPatterns(transport, collection, embedding, k = 5)
|
|
|
689
1783
|
return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
|
|
690
1784
|
}
|
|
691
1785
|
|
|
1786
|
+
// src/search-quality.ts
|
|
1787
|
+
function searchQualityToMode(quality) {
|
|
1788
|
+
if (quality === void 0) {
|
|
1789
|
+
return {};
|
|
1790
|
+
}
|
|
1791
|
+
return { mode: quality };
|
|
1792
|
+
}
|
|
1793
|
+
|
|
692
1794
|
// src/backends/search-backend.ts
|
|
693
|
-
async function search(transport, collection,
|
|
694
|
-
const queryVector = toNumberArray(
|
|
1795
|
+
async function search(transport, collection, query3, options) {
|
|
1796
|
+
const queryVector = toNumberArray(query3);
|
|
695
1797
|
const body = {
|
|
696
1798
|
vector: queryVector,
|
|
697
1799
|
top_k: options?.k ?? 10,
|
|
698
1800
|
filter: options?.filter,
|
|
699
|
-
include_vectors: options?.includeVectors ?? false
|
|
1801
|
+
include_vectors: options?.includeVectors ?? false,
|
|
1802
|
+
...searchQualityToMode(options?.quality)
|
|
700
1803
|
};
|
|
701
1804
|
if (options?.sparseVector) {
|
|
702
1805
|
body.sparse_vector = transport.sparseToRest(options.sparseVector);
|
|
@@ -713,7 +1816,8 @@ async function searchBatch(transport, collection, searches) {
|
|
|
713
1816
|
const formattedSearches = searches.map((s) => ({
|
|
714
1817
|
vector: toNumberArray(s.vector),
|
|
715
1818
|
top_k: s.k ?? 10,
|
|
716
|
-
filter: s.filter
|
|
1819
|
+
filter: s.filter,
|
|
1820
|
+
...searchQualityToMode(s.quality)
|
|
717
1821
|
}));
|
|
718
1822
|
const response = await transport.requestJson(
|
|
719
1823
|
"POST",
|
|
@@ -723,12 +1827,12 @@ async function searchBatch(transport, collection, searches) {
|
|
|
723
1827
|
throwOnError(response, `Collection '${collection}'`);
|
|
724
1828
|
return response.data?.results.map((r) => r.results) ?? [];
|
|
725
1829
|
}
|
|
726
|
-
async function textSearch(transport, collection,
|
|
1830
|
+
async function textSearch(transport, collection, query3, options) {
|
|
727
1831
|
const response = await transport.requestJson(
|
|
728
1832
|
"POST",
|
|
729
1833
|
`${collectionPath(collection)}/search/text`,
|
|
730
1834
|
{
|
|
731
|
-
query:
|
|
1835
|
+
query: query3,
|
|
732
1836
|
top_k: options?.k ?? 10,
|
|
733
1837
|
filter: options?.filter
|
|
734
1838
|
}
|
|
@@ -771,15 +1875,16 @@ async function multiQuerySearch(transport, collection, vectors, options) {
|
|
|
771
1875
|
throwOnError(response, `Collection '${collection}'`);
|
|
772
1876
|
return response.data?.results ?? [];
|
|
773
1877
|
}
|
|
774
|
-
async function searchIds(transport, collection,
|
|
775
|
-
const queryVector = toNumberArray(
|
|
1878
|
+
async function searchIds(transport, collection, query3, options) {
|
|
1879
|
+
const queryVector = toNumberArray(query3);
|
|
776
1880
|
const response = await transport.requestJson(
|
|
777
1881
|
"POST",
|
|
778
1882
|
`${collectionPath(collection)}/search/ids`,
|
|
779
1883
|
{
|
|
780
1884
|
vector: queryVector,
|
|
781
1885
|
top_k: options?.k ?? 10,
|
|
782
|
-
filter: options?.filter
|
|
1886
|
+
filter: options?.filter,
|
|
1887
|
+
...searchQualityToMode(options?.quality)
|
|
783
1888
|
}
|
|
784
1889
|
);
|
|
785
1890
|
throwOnError(response, `Collection '${collection}'`);
|
|
@@ -801,6 +1906,16 @@ async function addEdge(transport, collection, edge) {
|
|
|
801
1906
|
);
|
|
802
1907
|
throwOnError(response, `Collection '${collection}'`);
|
|
803
1908
|
}
|
|
1909
|
+
function toGraphEdge(e) {
|
|
1910
|
+
const toNum = (v) => typeof v === "string" ? Number(v) : v;
|
|
1911
|
+
return {
|
|
1912
|
+
id: toNum(e.id),
|
|
1913
|
+
source: toNum(e.source),
|
|
1914
|
+
target: toNum(e.target),
|
|
1915
|
+
label: e.label,
|
|
1916
|
+
properties: e.properties
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
804
1919
|
async function getEdges(transport, collection, options) {
|
|
805
1920
|
const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
|
|
806
1921
|
const response = await transport.requestJson(
|
|
@@ -808,19 +1923,19 @@ async function getEdges(transport, collection, options) {
|
|
|
808
1923
|
`${collectionPath(collection)}/graph/edges${queryParams}`
|
|
809
1924
|
);
|
|
810
1925
|
throwOnError(response, `Collection '${collection}'`);
|
|
811
|
-
return response.data?.edges ?? [];
|
|
1926
|
+
return (response.data?.edges ?? []).map(toGraphEdge);
|
|
812
1927
|
}
|
|
813
|
-
async function traverseGraph(transport, collection,
|
|
1928
|
+
async function traverseGraph(transport, collection, request2) {
|
|
814
1929
|
const response = await transport.requestJson(
|
|
815
1930
|
"POST",
|
|
816
1931
|
`${collectionPath(collection)}/graph/traverse`,
|
|
817
1932
|
{
|
|
818
|
-
source:
|
|
819
|
-
strategy:
|
|
820
|
-
max_depth:
|
|
821
|
-
limit:
|
|
822
|
-
cursor:
|
|
823
|
-
rel_types:
|
|
1933
|
+
source: request2.source,
|
|
1934
|
+
strategy: request2.strategy ?? "bfs",
|
|
1935
|
+
max_depth: request2.maxDepth ?? 3,
|
|
1936
|
+
limit: request2.limit ?? 100,
|
|
1937
|
+
cursor: request2.cursor,
|
|
1938
|
+
rel_types: request2.relTypes ?? []
|
|
824
1939
|
}
|
|
825
1940
|
);
|
|
826
1941
|
throwOnError(response, `Collection '${collection}'`);
|
|
@@ -860,15 +1975,15 @@ async function createGraphCollection(transport, name, config) {
|
|
|
860
1975
|
});
|
|
861
1976
|
throwOnError(response);
|
|
862
1977
|
}
|
|
863
|
-
async function traverseParallel(transport, collection,
|
|
1978
|
+
async function traverseParallel(transport, collection, request2) {
|
|
864
1979
|
const response = await transport.requestJson(
|
|
865
1980
|
"POST",
|
|
866
1981
|
`${collectionPath(collection)}/graph/traverse/parallel`,
|
|
867
1982
|
{
|
|
868
|
-
sources:
|
|
869
|
-
max_depth:
|
|
870
|
-
limit:
|
|
871
|
-
rel_types:
|
|
1983
|
+
sources: request2.sources,
|
|
1984
|
+
max_depth: request2.maxDepth ?? 3,
|
|
1985
|
+
limit: request2.limit ?? 100,
|
|
1986
|
+
rel_types: request2.relTypes ?? []
|
|
872
1987
|
}
|
|
873
1988
|
);
|
|
874
1989
|
throwOnError(response, `Collection '${collection}'`);
|
|
@@ -931,14 +2046,18 @@ async function query(transport, collection, queryString, params, options) {
|
|
|
931
2046
|
}
|
|
932
2047
|
};
|
|
933
2048
|
}
|
|
934
|
-
async function queryExplain(transport, queryString, params) {
|
|
2049
|
+
async function queryExplain(transport, queryString, params, options) {
|
|
2050
|
+
const body = {
|
|
2051
|
+
query: queryString,
|
|
2052
|
+
params: params ?? {}
|
|
2053
|
+
};
|
|
2054
|
+
if (options?.analyze) {
|
|
2055
|
+
body.analyze = true;
|
|
2056
|
+
}
|
|
935
2057
|
const response = await transport.requestJson(
|
|
936
2058
|
"POST",
|
|
937
2059
|
"/query/explain",
|
|
938
|
-
|
|
939
|
-
query: queryString,
|
|
940
|
-
params: params ?? {}
|
|
941
|
-
}
|
|
2060
|
+
body
|
|
942
2061
|
);
|
|
943
2062
|
throwOnError(response);
|
|
944
2063
|
const data = response.data;
|
|
@@ -950,7 +2069,8 @@ async function queryExplain(transport, queryString, params) {
|
|
|
950
2069
|
step: step.step,
|
|
951
2070
|
operation: step.operation,
|
|
952
2071
|
description: step.description,
|
|
953
|
-
estimatedRows: step.estimated_rows
|
|
2072
|
+
estimatedRows: step.estimated_rows,
|
|
2073
|
+
estimationMethod: step.estimation_method ?? null
|
|
954
2074
|
})),
|
|
955
2075
|
estimatedCost: {
|
|
956
2076
|
usesIndex: data.estimated_cost.uses_index,
|
|
@@ -968,7 +2088,22 @@ async function queryExplain(transport, queryString, params) {
|
|
|
968
2088
|
hasFusion: data.features.has_fusion,
|
|
969
2089
|
limit: data.features.limit,
|
|
970
2090
|
offset: data.features.offset
|
|
971
|
-
}
|
|
2091
|
+
},
|
|
2092
|
+
actualStats: data.actual_stats ? {
|
|
2093
|
+
actualRows: data.actual_stats.actual_rows,
|
|
2094
|
+
actualTimeMs: data.actual_stats.actual_time_ms,
|
|
2095
|
+
loops: data.actual_stats.loops,
|
|
2096
|
+
nodesVisited: data.actual_stats.nodes_visited,
|
|
2097
|
+
edgesTraversed: data.actual_stats.edges_traversed
|
|
2098
|
+
} : data.actual_stats === null ? null : void 0,
|
|
2099
|
+
nodeStats: data.node_stats ? data.node_stats.map((ns) => ({
|
|
2100
|
+
nodeLabel: ns.node_label,
|
|
2101
|
+
actualTimeMs: ns.actual_time_ms,
|
|
2102
|
+
actualRowsIn: ns.actual_rows_in,
|
|
2103
|
+
actualRowsOut: ns.actual_rows_out,
|
|
2104
|
+
loops: ns.loops,
|
|
2105
|
+
estimated: ns.estimated
|
|
2106
|
+
})) : data.node_stats === null ? null : void 0
|
|
972
2107
|
};
|
|
973
2108
|
}
|
|
974
2109
|
async function collectionSanity(transport, collection) {
|
|
@@ -999,8 +2134,49 @@ async function collectionSanity(transport, collection) {
|
|
|
999
2134
|
};
|
|
1000
2135
|
}
|
|
1001
2136
|
|
|
2137
|
+
// src/backends/scroll-backend.ts
|
|
2138
|
+
async function scroll(transport, collection, request2) {
|
|
2139
|
+
const body = {};
|
|
2140
|
+
if (request2?.cursor !== void 0) {
|
|
2141
|
+
body.cursor = request2.cursor;
|
|
2142
|
+
}
|
|
2143
|
+
if (request2?.batchSize !== void 0) {
|
|
2144
|
+
body.batch_size = request2.batchSize;
|
|
2145
|
+
}
|
|
2146
|
+
if (request2?.filter !== void 0) {
|
|
2147
|
+
body.filter = request2.filter;
|
|
2148
|
+
}
|
|
2149
|
+
const response = await transport.requestJson(
|
|
2150
|
+
"POST",
|
|
2151
|
+
`${collectionPath(collection)}/points/scroll`,
|
|
2152
|
+
body
|
|
2153
|
+
);
|
|
2154
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2155
|
+
const data = response.data;
|
|
2156
|
+
return {
|
|
2157
|
+
points: data.points,
|
|
2158
|
+
nextCursor: data.next_cursor
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
|
|
1002
2162
|
// src/backends/admin-backend.ts
|
|
1003
2163
|
function mapStatsResponse(data) {
|
|
2164
|
+
let columnStats;
|
|
2165
|
+
if (data.column_stats) {
|
|
2166
|
+
columnStats = {};
|
|
2167
|
+
for (const [key, col] of Object.entries(data.column_stats)) {
|
|
2168
|
+
columnStats[key] = {
|
|
2169
|
+
name: col.name,
|
|
2170
|
+
nullCount: col.null_count,
|
|
2171
|
+
distinctCount: col.distinct_count,
|
|
2172
|
+
minValue: col.min_value,
|
|
2173
|
+
maxValue: col.max_value,
|
|
2174
|
+
avgSizeBytes: col.avg_size_bytes,
|
|
2175
|
+
histogramBuckets: col.histogram_buckets,
|
|
2176
|
+
histogramStale: col.histogram_stale
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
1004
2180
|
return {
|
|
1005
2181
|
totalPoints: data.total_points,
|
|
1006
2182
|
totalSizeBytes: data.total_size_bytes,
|
|
@@ -1008,7 +2184,8 @@ function mapStatsResponse(data) {
|
|
|
1008
2184
|
deletedCount: data.deleted_count,
|
|
1009
2185
|
avgRowSizeBytes: data.avg_row_size_bytes,
|
|
1010
2186
|
payloadSizeBytes: data.payload_size_bytes,
|
|
1011
|
-
lastAnalyzedEpochMs: data.last_analyzed_epoch_ms
|
|
2187
|
+
lastAnalyzedEpochMs: data.last_analyzed_epoch_ms,
|
|
2188
|
+
columnStats
|
|
1012
2189
|
};
|
|
1013
2190
|
}
|
|
1014
2191
|
async function getCollectionStats(transport, collection) {
|
|
@@ -1029,10 +2206,7 @@ async function analyzeCollection(transport, collection) {
|
|
|
1029
2206
|
throwOnError(response, `Collection '${collection}'`);
|
|
1030
2207
|
return mapStatsResponse(response.data);
|
|
1031
2208
|
}
|
|
1032
|
-
|
|
1033
|
-
const response = await transport.requestJson("GET", `${collectionPath(collection)}/config`);
|
|
1034
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1035
|
-
const data = response.data;
|
|
2209
|
+
function mapConfigResponse(data) {
|
|
1036
2210
|
return {
|
|
1037
2211
|
name: data.name,
|
|
1038
2212
|
dimension: data.dimension,
|
|
@@ -1041,9 +2215,22 @@ async function getCollectionConfig(transport, collection) {
|
|
|
1041
2215
|
pointCount: data.point_count,
|
|
1042
2216
|
metadataOnly: data.metadata_only,
|
|
1043
2217
|
graphSchema: data.graph_schema,
|
|
1044
|
-
embeddingDimension: data.embedding_dimension
|
|
2218
|
+
embeddingDimension: data.embedding_dimension,
|
|
2219
|
+
schemaVersion: data.schema_version,
|
|
2220
|
+
pqRescoreOversampling: data.pq_rescore_oversampling,
|
|
2221
|
+
hnswParams: data.hnsw_params,
|
|
2222
|
+
deferredIndexing: data.deferred_indexing,
|
|
2223
|
+
asyncIndexBuilder: data.async_index_builder
|
|
1045
2224
|
};
|
|
1046
2225
|
}
|
|
2226
|
+
async function getCollectionConfig(transport, collection) {
|
|
2227
|
+
const response = await transport.requestJson(
|
|
2228
|
+
"GET",
|
|
2229
|
+
`${collectionPath(collection)}/config`
|
|
2230
|
+
);
|
|
2231
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2232
|
+
return mapConfigResponse(response.data);
|
|
2233
|
+
}
|
|
1047
2234
|
|
|
1048
2235
|
// src/backends/index-backend.ts
|
|
1049
2236
|
async function createIndex(transport, collection, options) {
|
|
@@ -1088,208 +2275,160 @@ async function dropIndex(transport, collection, label, property) {
|
|
|
1088
2275
|
}
|
|
1089
2276
|
|
|
1090
2277
|
// src/backends/streaming-backend.ts
|
|
1091
|
-
async function trainPq(transport, collection, options) {
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
const
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1097
|
-
"POST",
|
|
1098
|
-
"/query",
|
|
1099
|
-
{ query: queryString }
|
|
1100
|
-
);
|
|
1101
|
-
throwOnError(response);
|
|
1102
|
-
return response.data?.message ?? "PQ training initiated";
|
|
1103
|
-
}
|
|
1104
|
-
async function streamInsert(transport, collection, docs) {
|
|
1105
|
-
for (const doc of docs) {
|
|
1106
|
-
const restId = transport.parseRestPointId(doc.id);
|
|
1107
|
-
const vector = toNumberArray(doc.vector);
|
|
1108
|
-
const body = {
|
|
1109
|
-
id: restId,
|
|
1110
|
-
vector,
|
|
1111
|
-
payload: doc.payload
|
|
1112
|
-
};
|
|
1113
|
-
if (doc.sparseVector) {
|
|
1114
|
-
body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
|
|
1115
|
-
}
|
|
1116
|
-
const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
|
|
1117
|
-
const headers = {
|
|
1118
|
-
"Content-Type": "application/json"
|
|
1119
|
-
};
|
|
1120
|
-
if (transport.apiKey) {
|
|
1121
|
-
headers["Authorization"] = `Bearer ${transport.apiKey}`;
|
|
1122
|
-
}
|
|
1123
|
-
const controller = new AbortController();
|
|
1124
|
-
const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
|
|
1125
|
-
try {
|
|
1126
|
-
const response = await fetch(url, {
|
|
1127
|
-
method: "POST",
|
|
1128
|
-
headers,
|
|
1129
|
-
body: JSON.stringify(body),
|
|
1130
|
-
signal: controller.signal
|
|
1131
|
-
});
|
|
1132
|
-
clearTimeout(timeoutId);
|
|
1133
|
-
if (response.status === 429) {
|
|
1134
|
-
throw new BackpressureError();
|
|
1135
|
-
}
|
|
1136
|
-
if (!response.ok && response.status !== 202) {
|
|
1137
|
-
const data = await response.json().catch(() => ({}));
|
|
1138
|
-
const errorPayload = transport.extractErrorPayload(data);
|
|
1139
|
-
throw new VelesDBError(
|
|
1140
|
-
errorPayload.message ?? `HTTP ${response.status}`,
|
|
1141
|
-
errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
|
|
1142
|
-
);
|
|
1143
|
-
}
|
|
1144
|
-
} catch (error) {
|
|
1145
|
-
clearTimeout(timeoutId);
|
|
1146
|
-
if (error instanceof BackpressureError || error instanceof VelesDBError) {
|
|
1147
|
-
throw error;
|
|
1148
|
-
}
|
|
1149
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1150
|
-
throw new ConnectionError("Request timeout");
|
|
1151
|
-
}
|
|
1152
|
-
throw new ConnectionError(
|
|
1153
|
-
`Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1154
|
-
error instanceof Error ? error : void 0
|
|
1155
|
-
);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
// src/backends/crud-backend.ts
|
|
1161
|
-
function parseRestPointId(id) {
|
|
1162
|
-
if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
|
|
1163
|
-
throw new ValidationError(
|
|
1164
|
-
`REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
return id;
|
|
1168
|
-
}
|
|
1169
|
-
function sparseVectorToRestFormat(sv) {
|
|
1170
|
-
const result = {};
|
|
1171
|
-
for (const [k, v] of Object.entries(sv)) {
|
|
1172
|
-
result[String(k)] = v;
|
|
1173
|
-
}
|
|
1174
|
-
return result;
|
|
1175
|
-
}
|
|
1176
|
-
async function createCollection(transport, name, config) {
|
|
1177
|
-
const response = await transport.requestJson("POST", "/collections", {
|
|
1178
|
-
name,
|
|
1179
|
-
dimension: config.dimension,
|
|
1180
|
-
metric: config.metric ?? "cosine",
|
|
1181
|
-
storage_mode: config.storageMode ?? "full",
|
|
1182
|
-
collection_type: config.collectionType ?? "vector",
|
|
1183
|
-
description: config.description,
|
|
1184
|
-
hnsw_m: config.hnsw?.m,
|
|
1185
|
-
hnsw_ef_construction: config.hnsw?.efConstruction
|
|
1186
|
-
});
|
|
1187
|
-
throwOnError(response);
|
|
1188
|
-
}
|
|
1189
|
-
async function deleteCollection(transport, name) {
|
|
1190
|
-
const response = await transport.requestJson(
|
|
1191
|
-
"DELETE",
|
|
1192
|
-
collectionPath(name)
|
|
1193
|
-
);
|
|
1194
|
-
throwOnError(response, `Collection '${name}'`);
|
|
1195
|
-
}
|
|
1196
|
-
async function getCollection(transport, name) {
|
|
1197
|
-
const response = await transport.requestJson(
|
|
1198
|
-
"GET",
|
|
1199
|
-
collectionPath(name)
|
|
1200
|
-
);
|
|
1201
|
-
if (returnNullOnNotFound(response)) {
|
|
1202
|
-
return null;
|
|
1203
|
-
}
|
|
1204
|
-
return response.data ?? null;
|
|
1205
|
-
}
|
|
1206
|
-
async function listCollections(transport) {
|
|
1207
|
-
const response = await transport.requestJson("GET", "/collections");
|
|
1208
|
-
throwOnError(response);
|
|
1209
|
-
return response.data ?? [];
|
|
1210
|
-
}
|
|
1211
|
-
async function insert(transport, collection, doc) {
|
|
1212
|
-
const restId = parseRestPointId(doc.id);
|
|
1213
|
-
const vector = toNumberArray(doc.vector);
|
|
1214
|
-
const response = await transport.requestJson(
|
|
1215
|
-
"POST",
|
|
1216
|
-
`${collectionPath(collection)}/points`,
|
|
1217
|
-
{ points: [{ id: restId, vector, payload: doc.payload }] }
|
|
1218
|
-
);
|
|
1219
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1220
|
-
}
|
|
1221
|
-
async function insertBatch(transport, collection, docs) {
|
|
1222
|
-
const vectors = docs.map((doc) => ({
|
|
1223
|
-
id: parseRestPointId(doc.id),
|
|
1224
|
-
vector: toNumberArray(doc.vector),
|
|
1225
|
-
payload: doc.payload
|
|
1226
|
-
}));
|
|
1227
|
-
const response = await transport.requestJson(
|
|
1228
|
-
"POST",
|
|
1229
|
-
`${collectionPath(collection)}/points`,
|
|
1230
|
-
{ points: vectors }
|
|
1231
|
-
);
|
|
1232
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1233
|
-
}
|
|
1234
|
-
async function deletePoint(transport, collection, id) {
|
|
1235
|
-
const restId = parseRestPointId(id);
|
|
1236
|
-
const response = await transport.requestJson(
|
|
1237
|
-
"DELETE",
|
|
1238
|
-
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1239
|
-
);
|
|
1240
|
-
if (returnNullOnNotFound(response)) {
|
|
1241
|
-
return false;
|
|
1242
|
-
}
|
|
1243
|
-
return response.data?.deleted ?? false;
|
|
1244
|
-
}
|
|
1245
|
-
async function get(transport, collection, id) {
|
|
1246
|
-
const restId = parseRestPointId(id);
|
|
1247
|
-
const response = await transport.requestJson(
|
|
1248
|
-
"GET",
|
|
1249
|
-
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1250
|
-
);
|
|
1251
|
-
if (returnNullOnNotFound(response)) {
|
|
1252
|
-
return null;
|
|
1253
|
-
}
|
|
1254
|
-
return response.data ?? null;
|
|
1255
|
-
}
|
|
1256
|
-
async function isEmpty(transport, collection) {
|
|
1257
|
-
const response = await transport.requestJson(
|
|
1258
|
-
"GET",
|
|
1259
|
-
`${collectionPath(collection)}/empty`
|
|
1260
|
-
);
|
|
1261
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1262
|
-
return response.data?.is_empty ?? true;
|
|
1263
|
-
}
|
|
1264
|
-
async function flush(transport, collection) {
|
|
2278
|
+
async function trainPq(transport, collection, options) {
|
|
2279
|
+
validateCollectionName(collection);
|
|
2280
|
+
const m = options?.m ?? 8;
|
|
2281
|
+
const k = options?.k ?? 256;
|
|
2282
|
+
const withClause = options?.opq ? `WITH (m=${m}, k=${k}, opq=true)` : `WITH (m=${m}, k=${k})`;
|
|
2283
|
+
const queryString = `TRAIN QUANTIZER ON ${collection} ${withClause}`;
|
|
1265
2284
|
const response = await transport.requestJson(
|
|
1266
2285
|
"POST",
|
|
1267
|
-
|
|
2286
|
+
"/query",
|
|
2287
|
+
{ query: queryString }
|
|
1268
2288
|
);
|
|
1269
|
-
throwOnError(response
|
|
2289
|
+
throwOnError(response);
|
|
2290
|
+
return response.data?.message ?? "PQ training initiated";
|
|
2291
|
+
}
|
|
2292
|
+
async function streamInsert(transport, collection, docs) {
|
|
2293
|
+
for (const doc of docs) {
|
|
2294
|
+
const restId = transport.parseRestPointId(doc.id);
|
|
2295
|
+
const vector = toNumberArray(doc.vector);
|
|
2296
|
+
const body = {
|
|
2297
|
+
id: restId,
|
|
2298
|
+
vector,
|
|
2299
|
+
payload: doc.payload ?? null
|
|
2300
|
+
};
|
|
2301
|
+
if (doc.sparseVector) {
|
|
2302
|
+
body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
|
|
2303
|
+
}
|
|
2304
|
+
const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
|
|
2305
|
+
const headers = {
|
|
2306
|
+
"Content-Type": "application/json"
|
|
2307
|
+
};
|
|
2308
|
+
if (transport.apiKey) {
|
|
2309
|
+
headers["Authorization"] = `Bearer ${transport.apiKey}`;
|
|
2310
|
+
}
|
|
2311
|
+
const controller = new AbortController();
|
|
2312
|
+
const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
|
|
2313
|
+
try {
|
|
2314
|
+
const response = await fetch(url, {
|
|
2315
|
+
method: "POST",
|
|
2316
|
+
headers,
|
|
2317
|
+
body: JSON.stringify(body),
|
|
2318
|
+
signal: controller.signal
|
|
2319
|
+
});
|
|
2320
|
+
clearTimeout(timeoutId);
|
|
2321
|
+
if (response.status === 429) {
|
|
2322
|
+
throw new BackpressureError();
|
|
2323
|
+
}
|
|
2324
|
+
if (!response.ok && response.status !== 202) {
|
|
2325
|
+
const data = await response.json().catch(() => ({}));
|
|
2326
|
+
const errorPayload = transport.extractErrorPayload(data);
|
|
2327
|
+
throw new VelesDBError(
|
|
2328
|
+
errorPayload.message ?? `HTTP ${response.status}`,
|
|
2329
|
+
errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
|
|
2330
|
+
);
|
|
2331
|
+
}
|
|
2332
|
+
} catch (error) {
|
|
2333
|
+
clearTimeout(timeoutId);
|
|
2334
|
+
if (error instanceof BackpressureError || error instanceof VelesDBError) {
|
|
2335
|
+
throw error;
|
|
2336
|
+
}
|
|
2337
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2338
|
+
throw new ConnectionError("Request timeout");
|
|
2339
|
+
}
|
|
2340
|
+
throw new ConnectionError(
|
|
2341
|
+
`Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
2342
|
+
error instanceof Error ? error : void 0
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
async function streamUpsertPoints(transport, collection, docs) {
|
|
2348
|
+
const ndjsonLines = docs.map((doc) => {
|
|
2349
|
+
const restId = transport.parseRestPointId(doc.id);
|
|
2350
|
+
const vector = toNumberArray(doc.vector);
|
|
2351
|
+
const point = {
|
|
2352
|
+
id: restId,
|
|
2353
|
+
vector,
|
|
2354
|
+
payload: doc.payload ?? null
|
|
2355
|
+
};
|
|
2356
|
+
if (doc.sparseVector) {
|
|
2357
|
+
point.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
|
|
2358
|
+
}
|
|
2359
|
+
return JSON.stringify(point);
|
|
2360
|
+
});
|
|
2361
|
+
const body = ndjsonLines.join("\n");
|
|
2362
|
+
const url = `${transport.baseUrl}${collectionPath(collection)}/points/stream`;
|
|
2363
|
+
const headers = {
|
|
2364
|
+
"Content-Type": "application/x-ndjson"
|
|
2365
|
+
};
|
|
2366
|
+
if (transport.apiKey) {
|
|
2367
|
+
headers["Authorization"] = `Bearer ${transport.apiKey}`;
|
|
2368
|
+
}
|
|
2369
|
+
const controller = new AbortController();
|
|
2370
|
+
const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
|
|
2371
|
+
try {
|
|
2372
|
+
const response = await fetch(url, {
|
|
2373
|
+
method: "POST",
|
|
2374
|
+
headers,
|
|
2375
|
+
body,
|
|
2376
|
+
signal: controller.signal
|
|
2377
|
+
});
|
|
2378
|
+
clearTimeout(timeoutId);
|
|
2379
|
+
if (response.status === 429) {
|
|
2380
|
+
throw new BackpressureError();
|
|
2381
|
+
}
|
|
2382
|
+
if (!response.ok) {
|
|
2383
|
+
const data2 = await response.json().catch(() => ({}));
|
|
2384
|
+
const errorPayload = transport.extractErrorPayload(data2);
|
|
2385
|
+
throw new VelesDBError(
|
|
2386
|
+
errorPayload.message ?? `HTTP ${response.status}`,
|
|
2387
|
+
errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
|
|
2388
|
+
);
|
|
2389
|
+
}
|
|
2390
|
+
const data = await response.json().catch(() => ({}));
|
|
2391
|
+
return {
|
|
2392
|
+
message: typeof data.message === "string" ? data.message : "Stream processed",
|
|
2393
|
+
inserted: typeof data.inserted === "number" ? data.inserted : 0,
|
|
2394
|
+
malformed: typeof data.malformed === "number" ? data.malformed : 0,
|
|
2395
|
+
failedUpserts: typeof data.failed_upserts === "number" ? data.failed_upserts : 0,
|
|
2396
|
+
networkErrors: typeof data.network_errors === "number" ? data.network_errors : 0
|
|
2397
|
+
};
|
|
2398
|
+
} catch (error) {
|
|
2399
|
+
clearTimeout(timeoutId);
|
|
2400
|
+
if (error instanceof BackpressureError || error instanceof VelesDBError) {
|
|
2401
|
+
throw error;
|
|
2402
|
+
}
|
|
2403
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2404
|
+
throw new ConnectionError("Request timeout");
|
|
2405
|
+
}
|
|
2406
|
+
throw new ConnectionError(
|
|
2407
|
+
`Stream upsert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
2408
|
+
error instanceof Error ? error : void 0
|
|
2409
|
+
);
|
|
2410
|
+
}
|
|
1270
2411
|
}
|
|
1271
2412
|
|
|
1272
2413
|
// src/backends/rest.ts
|
|
1273
2414
|
var RestBackend = class {
|
|
1274
2415
|
constructor(url, apiKey, timeout = 3e4) {
|
|
1275
2416
|
this._initialized = false;
|
|
1276
|
-
this.
|
|
1277
|
-
this.apiKey = apiKey;
|
|
1278
|
-
this.timeout = timeout;
|
|
2417
|
+
this.httpConfig = { baseUrl: url.replace(/\/$/, ""), apiKey, timeout };
|
|
1279
2418
|
}
|
|
1280
2419
|
async init() {
|
|
1281
2420
|
if (this._initialized) {
|
|
1282
2421
|
return;
|
|
1283
2422
|
}
|
|
1284
2423
|
try {
|
|
1285
|
-
const response = await this.
|
|
2424
|
+
const response = await request(this.httpConfig, "GET", "/health");
|
|
1286
2425
|
if (response.error) {
|
|
1287
2426
|
throw new Error(response.error.message);
|
|
1288
2427
|
}
|
|
1289
2428
|
this._initialized = true;
|
|
1290
2429
|
} catch (error) {
|
|
1291
2430
|
throw new ConnectionError(
|
|
1292
|
-
`Failed to connect to VelesDB server at ${this.baseUrl}`,
|
|
2431
|
+
`Failed to connect to VelesDB server at ${this.httpConfig.baseUrl}`,
|
|
1293
2432
|
error instanceof Error ? error : void 0
|
|
1294
2433
|
);
|
|
1295
2434
|
}
|
|
@@ -1297,320 +2436,242 @@ var RestBackend = class {
|
|
|
1297
2436
|
isInitialized() {
|
|
1298
2437
|
return this._initialized;
|
|
1299
2438
|
}
|
|
2439
|
+
capabilities() {
|
|
2440
|
+
return REST_CAPABILITIES;
|
|
2441
|
+
}
|
|
2442
|
+
async close() {
|
|
2443
|
+
this._initialized = false;
|
|
2444
|
+
}
|
|
1300
2445
|
ensureInitialized() {
|
|
1301
2446
|
if (!this._initialized) {
|
|
1302
2447
|
throw new ConnectionError("REST backend not initialized");
|
|
1303
2448
|
}
|
|
1304
2449
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
case 401:
|
|
1310
|
-
return "UNAUTHORIZED";
|
|
1311
|
-
case 403:
|
|
1312
|
-
return "FORBIDDEN";
|
|
1313
|
-
case 404:
|
|
1314
|
-
return "NOT_FOUND";
|
|
1315
|
-
case 409:
|
|
1316
|
-
return "CONFLICT";
|
|
1317
|
-
case 429:
|
|
1318
|
-
return "RATE_LIMITED";
|
|
1319
|
-
case 500:
|
|
1320
|
-
return "INTERNAL_ERROR";
|
|
1321
|
-
case 503:
|
|
1322
|
-
return "SERVICE_UNAVAILABLE";
|
|
1323
|
-
default:
|
|
1324
|
-
return "UNKNOWN_ERROR";
|
|
1325
|
-
}
|
|
2450
|
+
// Collection CRUD
|
|
2451
|
+
async createCollection(n, c) {
|
|
2452
|
+
this.ensureInitialized();
|
|
2453
|
+
return createCollection(buildCrudTransport(this.httpConfig), n, c);
|
|
1326
2454
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
}
|
|
1331
|
-
const payload = data;
|
|
1332
|
-
const nestedError = payload.error && typeof payload.error === "object" ? payload.error : void 0;
|
|
1333
|
-
const codeField = nestedError?.code ?? payload.code;
|
|
1334
|
-
const code = typeof codeField === "string" ? codeField : void 0;
|
|
1335
|
-
const messageField = nestedError?.message ?? payload.message ?? payload.error;
|
|
1336
|
-
const message = typeof messageField === "string" ? messageField : void 0;
|
|
1337
|
-
return { code, message };
|
|
2455
|
+
async deleteCollection(n) {
|
|
2456
|
+
this.ensureInitialized();
|
|
2457
|
+
return deleteCollection(buildCrudTransport(this.httpConfig), n);
|
|
1338
2458
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
}
|
|
1343
|
-
if (typeof value === "bigint") {
|
|
1344
|
-
return value;
|
|
1345
|
-
}
|
|
1346
|
-
if (typeof value === "string") {
|
|
1347
|
-
const num = Number(value);
|
|
1348
|
-
return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
|
|
1349
|
-
}
|
|
1350
|
-
if (typeof value === "number") {
|
|
1351
|
-
return value;
|
|
1352
|
-
}
|
|
1353
|
-
return 0;
|
|
2459
|
+
async getCollection(n) {
|
|
2460
|
+
this.ensureInitialized();
|
|
2461
|
+
return getCollection(buildCrudTransport(this.httpConfig), n);
|
|
1354
2462
|
}
|
|
1355
|
-
async
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
if (this.apiKey) {
|
|
1359
|
-
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
1360
|
-
}
|
|
1361
|
-
const controller = new AbortController();
|
|
1362
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1363
|
-
try {
|
|
1364
|
-
const response = await fetch(url, {
|
|
1365
|
-
method,
|
|
1366
|
-
headers,
|
|
1367
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
1368
|
-
signal: controller.signal
|
|
1369
|
-
});
|
|
1370
|
-
clearTimeout(timeoutId);
|
|
1371
|
-
const data = await response.json().catch(() => ({}));
|
|
1372
|
-
if (!response.ok) {
|
|
1373
|
-
const errorPayload = this.extractErrorPayload(data);
|
|
1374
|
-
return {
|
|
1375
|
-
error: {
|
|
1376
|
-
code: errorPayload.code ?? this.mapStatusToErrorCode(response.status),
|
|
1377
|
-
message: errorPayload.message ?? `HTTP ${response.status}`
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
}
|
|
1381
|
-
return { data };
|
|
1382
|
-
} catch (error) {
|
|
1383
|
-
clearTimeout(timeoutId);
|
|
1384
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1385
|
-
throw new ConnectionError("Request timeout");
|
|
1386
|
-
}
|
|
1387
|
-
throw new ConnectionError(
|
|
1388
|
-
`Request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1389
|
-
error instanceof Error ? error : void 0
|
|
1390
|
-
);
|
|
1391
|
-
}
|
|
2463
|
+
async listCollections() {
|
|
2464
|
+
this.ensureInitialized();
|
|
2465
|
+
return listCollections(buildCrudTransport(this.httpConfig));
|
|
1392
2466
|
}
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
asCrudTransport() {
|
|
1397
|
-
return {
|
|
1398
|
-
requestJson: (m, p, b) => this.request(m, p, b)
|
|
1399
|
-
};
|
|
2467
|
+
async upsert(c, d) {
|
|
2468
|
+
this.ensureInitialized();
|
|
2469
|
+
return upsert(buildCrudTransport(this.httpConfig), c, d);
|
|
1400
2470
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
sparseToRest: (sv) => sparseVectorToRestFormat(sv)
|
|
1405
|
-
};
|
|
2471
|
+
async upsertBatch(c, d) {
|
|
2472
|
+
this.ensureInitialized();
|
|
2473
|
+
return upsertBatch(buildCrudTransport(this.httpConfig), c, d);
|
|
1406
2474
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
searchVectors: (c, e, k, f) => this.search(c, e, { k, filter: f })
|
|
1411
|
-
};
|
|
2475
|
+
async delete(c, id) {
|
|
2476
|
+
this.ensureInitialized();
|
|
2477
|
+
return deletePoint(buildCrudTransport(this.httpConfig), c, id);
|
|
1412
2478
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
parseNodeId: (v) => this.parseNodeId(v)
|
|
1417
|
-
};
|
|
2479
|
+
async get(c, id) {
|
|
2480
|
+
this.ensureInitialized();
|
|
2481
|
+
return get(buildCrudTransport(this.httpConfig), c, id);
|
|
1418
2482
|
}
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
baseUrl: this.baseUrl,
|
|
1423
|
-
apiKey: this.apiKey,
|
|
1424
|
-
timeout: this.timeout,
|
|
1425
|
-
parseRestPointId,
|
|
1426
|
-
sparseVectorToRestFormat,
|
|
1427
|
-
mapStatusToErrorCode: (s) => this.mapStatusToErrorCode(s),
|
|
1428
|
-
extractErrorPayload: (d) => this.extractErrorPayload(d)
|
|
1429
|
-
};
|
|
2483
|
+
async isEmpty(c) {
|
|
2484
|
+
this.ensureInitialized();
|
|
2485
|
+
return isEmpty(buildCrudTransport(this.httpConfig), c);
|
|
1430
2486
|
}
|
|
1431
|
-
|
|
1432
|
-
// Collection CRUD — delegates to crud-backend.ts
|
|
1433
|
-
// ==========================================================================
|
|
1434
|
-
async createCollection(name, config) {
|
|
2487
|
+
async flush(c) {
|
|
1435
2488
|
this.ensureInitialized();
|
|
1436
|
-
return
|
|
2489
|
+
return flush(buildCrudTransport(this.httpConfig), c);
|
|
1437
2490
|
}
|
|
1438
|
-
|
|
2491
|
+
// Additional REST endpoints (Sprint 2 Wave 4)
|
|
2492
|
+
async rebuildIndex(c) {
|
|
1439
2493
|
this.ensureInitialized();
|
|
1440
|
-
return
|
|
2494
|
+
return rebuildIndex(buildBaseTransport(this.httpConfig), c);
|
|
1441
2495
|
}
|
|
1442
|
-
async
|
|
2496
|
+
async getGuardrails() {
|
|
1443
2497
|
this.ensureInitialized();
|
|
1444
|
-
return
|
|
2498
|
+
return getGuardrails(buildBaseTransport(this.httpConfig));
|
|
1445
2499
|
}
|
|
1446
|
-
async
|
|
2500
|
+
async updateGuardrails(r) {
|
|
1447
2501
|
this.ensureInitialized();
|
|
1448
|
-
return
|
|
2502
|
+
return updateGuardrails(buildBaseTransport(this.httpConfig), r);
|
|
1449
2503
|
}
|
|
1450
|
-
async
|
|
2504
|
+
async aggregate(q, p, o) {
|
|
1451
2505
|
this.ensureInitialized();
|
|
1452
|
-
return
|
|
2506
|
+
return aggregate(buildBaseTransport(this.httpConfig), q, p, o);
|
|
1453
2507
|
}
|
|
1454
|
-
async
|
|
2508
|
+
async matchQuery(c, q, p, o) {
|
|
1455
2509
|
this.ensureInitialized();
|
|
1456
|
-
return
|
|
2510
|
+
return matchQuery(buildBaseTransport(this.httpConfig), c, q, p, o);
|
|
1457
2511
|
}
|
|
1458
|
-
async
|
|
2512
|
+
async removeEdge(c, id) {
|
|
1459
2513
|
this.ensureInitialized();
|
|
1460
|
-
return
|
|
2514
|
+
return removeEdge(buildBaseTransport(this.httpConfig), c, id);
|
|
1461
2515
|
}
|
|
1462
|
-
async
|
|
2516
|
+
async getEdgeCount(c) {
|
|
1463
2517
|
this.ensureInitialized();
|
|
1464
|
-
return
|
|
2518
|
+
return getEdgeCount(buildBaseTransport(this.httpConfig), c);
|
|
1465
2519
|
}
|
|
1466
|
-
async
|
|
2520
|
+
async listNodes(c) {
|
|
1467
2521
|
this.ensureInitialized();
|
|
1468
|
-
return
|
|
2522
|
+
return listNodes(buildBaseTransport(this.httpConfig), c);
|
|
1469
2523
|
}
|
|
1470
|
-
async
|
|
2524
|
+
async getNodeEdges(c, id, o) {
|
|
1471
2525
|
this.ensureInitialized();
|
|
1472
|
-
return
|
|
2526
|
+
return getNodeEdges(buildBaseTransport(this.httpConfig), c, id, o);
|
|
1473
2527
|
}
|
|
1474
|
-
async
|
|
1475
|
-
this.
|
|
2528
|
+
async getNodePayload(c, id) {
|
|
2529
|
+
this.ensureInitialized();
|
|
2530
|
+
return getNodePayload(buildBaseTransport(this.httpConfig), c, id);
|
|
2531
|
+
}
|
|
2532
|
+
async upsertNodePayload(c, id, p) {
|
|
2533
|
+
this.ensureInitialized();
|
|
2534
|
+
return upsertNodePayload(buildBaseTransport(this.httpConfig), c, id, p);
|
|
2535
|
+
}
|
|
2536
|
+
async graphSearch(c, r) {
|
|
2537
|
+
this.ensureInitialized();
|
|
2538
|
+
return graphSearch(buildBaseTransport(this.httpConfig), c, r);
|
|
1476
2539
|
}
|
|
1477
|
-
//
|
|
1478
|
-
// Search — delegates to search-backend.ts
|
|
1479
|
-
// ==========================================================================
|
|
2540
|
+
// Search
|
|
1480
2541
|
async search(c, q, o) {
|
|
1481
2542
|
this.ensureInitialized();
|
|
1482
|
-
return search(this.
|
|
2543
|
+
return search(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1483
2544
|
}
|
|
1484
|
-
async searchBatch(
|
|
2545
|
+
async searchBatch(c, s) {
|
|
1485
2546
|
this.ensureInitialized();
|
|
1486
|
-
return searchBatch(this.
|
|
2547
|
+
return searchBatch(buildSearchTransport(this.httpConfig), c, s);
|
|
1487
2548
|
}
|
|
1488
2549
|
async textSearch(c, q, o) {
|
|
1489
2550
|
this.ensureInitialized();
|
|
1490
|
-
return textSearch(this.
|
|
2551
|
+
return textSearch(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1491
2552
|
}
|
|
1492
2553
|
async hybridSearch(c, v, t, o) {
|
|
1493
2554
|
this.ensureInitialized();
|
|
1494
|
-
return hybridSearch(this.
|
|
2555
|
+
return hybridSearch(buildSearchTransport(this.httpConfig), c, v, t, o);
|
|
1495
2556
|
}
|
|
1496
2557
|
async multiQuerySearch(c, v, o) {
|
|
1497
2558
|
this.ensureInitialized();
|
|
1498
|
-
return multiQuerySearch(this.
|
|
2559
|
+
return multiQuerySearch(buildSearchTransport(this.httpConfig), c, v, o);
|
|
1499
2560
|
}
|
|
1500
2561
|
async searchIds(c, q, o) {
|
|
1501
2562
|
this.ensureInitialized();
|
|
1502
|
-
return searchIds(this.
|
|
2563
|
+
return searchIds(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1503
2564
|
}
|
|
1504
|
-
//
|
|
1505
|
-
// Query — delegates to query-backend.ts
|
|
1506
|
-
// ==========================================================================
|
|
2565
|
+
// Query
|
|
1507
2566
|
async query(c, q, p, o) {
|
|
1508
2567
|
this.ensureInitialized();
|
|
1509
|
-
return query(this.
|
|
2568
|
+
return query(buildQueryTransport(this.httpConfig), c, q, p, o);
|
|
1510
2569
|
}
|
|
1511
|
-
async queryExplain(q, p) {
|
|
2570
|
+
async queryExplain(q, p, o) {
|
|
1512
2571
|
this.ensureInitialized();
|
|
1513
|
-
return queryExplain(this.
|
|
2572
|
+
return queryExplain(buildQueryTransport(this.httpConfig), q, p, o);
|
|
1514
2573
|
}
|
|
1515
|
-
async collectionSanity(
|
|
2574
|
+
async collectionSanity(c) {
|
|
1516
2575
|
this.ensureInitialized();
|
|
1517
|
-
return collectionSanity(this.
|
|
2576
|
+
return collectionSanity(buildQueryTransport(this.httpConfig), c);
|
|
1518
2577
|
}
|
|
1519
|
-
//
|
|
1520
|
-
|
|
1521
|
-
// ==========================================================================
|
|
1522
|
-
async addEdge(collection, edge) {
|
|
2578
|
+
// Scroll
|
|
2579
|
+
async scroll(c, r) {
|
|
1523
2580
|
this.ensureInitialized();
|
|
1524
|
-
return
|
|
2581
|
+
return scroll(buildCrudTransport(this.httpConfig), c, r);
|
|
1525
2582
|
}
|
|
1526
|
-
|
|
2583
|
+
// Graph
|
|
2584
|
+
async addEdge(c, e) {
|
|
1527
2585
|
this.ensureInitialized();
|
|
1528
|
-
return
|
|
2586
|
+
return addEdge(buildCrudTransport(this.httpConfig), c, e);
|
|
1529
2587
|
}
|
|
1530
|
-
async
|
|
2588
|
+
async getEdges(c, o) {
|
|
1531
2589
|
this.ensureInitialized();
|
|
1532
|
-
return
|
|
2590
|
+
return getEdges(buildCrudTransport(this.httpConfig), c, o);
|
|
1533
2591
|
}
|
|
1534
|
-
async
|
|
2592
|
+
async traverseGraph(c, r) {
|
|
1535
2593
|
this.ensureInitialized();
|
|
1536
|
-
return
|
|
2594
|
+
return traverseGraph(buildCrudTransport(this.httpConfig), c, r);
|
|
1537
2595
|
}
|
|
1538
|
-
async
|
|
2596
|
+
async traverseParallel(c, r) {
|
|
1539
2597
|
this.ensureInitialized();
|
|
1540
|
-
return
|
|
2598
|
+
return traverseParallel(buildCrudTransport(this.httpConfig), c, r);
|
|
1541
2599
|
}
|
|
1542
|
-
async
|
|
2600
|
+
async getNodeDegree(c, id) {
|
|
1543
2601
|
this.ensureInitialized();
|
|
1544
|
-
return
|
|
2602
|
+
return getNodeDegree(buildCrudTransport(this.httpConfig), c, id);
|
|
1545
2603
|
}
|
|
1546
|
-
|
|
1547
|
-
// Index — delegates to index-backend.ts
|
|
1548
|
-
// ==========================================================================
|
|
1549
|
-
async createIndex(collection, options) {
|
|
2604
|
+
async createGraphCollection(n, c) {
|
|
1550
2605
|
this.ensureInitialized();
|
|
1551
|
-
return
|
|
2606
|
+
return createGraphCollection(buildCrudTransport(this.httpConfig), n, c);
|
|
1552
2607
|
}
|
|
1553
|
-
|
|
2608
|
+
// Index
|
|
2609
|
+
async createIndex(c, o) {
|
|
1554
2610
|
this.ensureInitialized();
|
|
1555
|
-
return
|
|
2611
|
+
return createIndex(buildCrudTransport(this.httpConfig), c, o);
|
|
1556
2612
|
}
|
|
1557
|
-
async
|
|
2613
|
+
async listIndexes(c) {
|
|
1558
2614
|
this.ensureInitialized();
|
|
1559
|
-
return
|
|
2615
|
+
return listIndexes(buildCrudTransport(this.httpConfig), c);
|
|
1560
2616
|
}
|
|
1561
|
-
async
|
|
2617
|
+
async hasIndex(c, l, p) {
|
|
1562
2618
|
this.ensureInitialized();
|
|
1563
|
-
return
|
|
2619
|
+
return hasIndex(buildCrudTransport(this.httpConfig), c, l, p);
|
|
1564
2620
|
}
|
|
1565
|
-
|
|
1566
|
-
// Admin — delegates to admin-backend.ts
|
|
1567
|
-
// ==========================================================================
|
|
1568
|
-
async getCollectionStats(collection) {
|
|
2621
|
+
async dropIndex(c, l, p) {
|
|
1569
2622
|
this.ensureInitialized();
|
|
1570
|
-
return
|
|
2623
|
+
return dropIndex(buildCrudTransport(this.httpConfig), c, l, p);
|
|
1571
2624
|
}
|
|
1572
|
-
|
|
2625
|
+
// Admin
|
|
2626
|
+
async getCollectionStats(c) {
|
|
1573
2627
|
this.ensureInitialized();
|
|
1574
|
-
return
|
|
2628
|
+
return getCollectionStats(buildCrudTransport(this.httpConfig), c);
|
|
1575
2629
|
}
|
|
1576
|
-
async
|
|
2630
|
+
async analyzeCollection(c) {
|
|
1577
2631
|
this.ensureInitialized();
|
|
1578
|
-
return
|
|
2632
|
+
return analyzeCollection(buildCrudTransport(this.httpConfig), c);
|
|
1579
2633
|
}
|
|
1580
|
-
|
|
1581
|
-
// Streaming / PQ — delegates to streaming-backend.ts
|
|
1582
|
-
// ==========================================================================
|
|
1583
|
-
async trainPq(collection, options) {
|
|
2634
|
+
async getCollectionConfig(c) {
|
|
1584
2635
|
this.ensureInitialized();
|
|
1585
|
-
return
|
|
2636
|
+
return getCollectionConfig(buildCrudTransport(this.httpConfig), c);
|
|
1586
2637
|
}
|
|
1587
|
-
|
|
2638
|
+
// Streaming / PQ
|
|
2639
|
+
async trainPq(c, o) {
|
|
2640
|
+
this.ensureInitialized();
|
|
2641
|
+
return trainPq(buildStreamingTransport(this.httpConfig), c, o);
|
|
2642
|
+
}
|
|
2643
|
+
async streamInsert(c, d) {
|
|
1588
2644
|
this.ensureInitialized();
|
|
1589
|
-
return streamInsert(this.
|
|
2645
|
+
return streamInsert(buildStreamingTransport(this.httpConfig), c, d);
|
|
1590
2646
|
}
|
|
1591
|
-
|
|
1592
|
-
// Agent Memory — delegates to agent-memory-backend.ts
|
|
1593
|
-
// ==========================================================================
|
|
1594
|
-
async storeSemanticFact(collection, entry) {
|
|
2647
|
+
async streamUpsertPoints(c, d) {
|
|
1595
2648
|
this.ensureInitialized();
|
|
1596
|
-
return
|
|
2649
|
+
return streamUpsertPoints(buildStreamingTransport(this.httpConfig), c, d);
|
|
1597
2650
|
}
|
|
1598
|
-
|
|
1599
|
-
|
|
2651
|
+
// Agent Memory
|
|
2652
|
+
async storeSemanticFact(c, e) {
|
|
2653
|
+
this.ensureInitialized();
|
|
2654
|
+
return storeSemanticFact(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
|
|
2655
|
+
}
|
|
2656
|
+
async searchSemanticMemory(c, e, k = 5) {
|
|
2657
|
+
this.ensureInitialized();
|
|
2658
|
+
return searchSemanticMemory(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
|
|
1600
2659
|
}
|
|
1601
|
-
async recordEpisodicEvent(
|
|
2660
|
+
async recordEpisodicEvent(c, e) {
|
|
1602
2661
|
this.ensureInitialized();
|
|
1603
|
-
return recordEpisodicEvent(this.
|
|
2662
|
+
return recordEpisodicEvent(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
|
|
1604
2663
|
}
|
|
1605
|
-
async recallEpisodicEvents(
|
|
1606
|
-
|
|
2664
|
+
async recallEpisodicEvents(c, e, k = 5) {
|
|
2665
|
+
this.ensureInitialized();
|
|
2666
|
+
return recallEpisodicEvents(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
|
|
1607
2667
|
}
|
|
1608
|
-
async storeProceduralPattern(
|
|
2668
|
+
async storeProceduralPattern(c, p) {
|
|
1609
2669
|
this.ensureInitialized();
|
|
1610
|
-
return storeProceduralPattern(this.
|
|
2670
|
+
return storeProceduralPattern(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, p);
|
|
1611
2671
|
}
|
|
1612
|
-
async matchProceduralPatterns(
|
|
1613
|
-
|
|
2672
|
+
async matchProceduralPatterns(c, e, k = 5) {
|
|
2673
|
+
this.ensureInitialized();
|
|
2674
|
+
return matchProceduralPatterns(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
|
|
1614
2675
|
}
|
|
1615
2676
|
};
|
|
1616
2677
|
|
|
@@ -1650,7 +2711,7 @@ var AgentMemoryClient = class {
|
|
|
1650
2711
|
}
|
|
1651
2712
|
};
|
|
1652
2713
|
|
|
1653
|
-
// src/client.ts
|
|
2714
|
+
// src/client/validation.ts
|
|
1654
2715
|
function requireNonEmptyString(value, label) {
|
|
1655
2716
|
if (!value || typeof value !== "string") {
|
|
1656
2717
|
throw new ValidationError(`${label} must be a non-empty string`);
|
|
@@ -1669,13 +2730,187 @@ function validateDocsBatch(docs, validateDoc) {
|
|
|
1669
2730
|
validateDoc(doc);
|
|
1670
2731
|
}
|
|
1671
2732
|
}
|
|
2733
|
+
function validateDocument(doc, config) {
|
|
2734
|
+
if (doc.id === void 0 || doc.id === null) {
|
|
2735
|
+
throw new ValidationError("Document ID is required");
|
|
2736
|
+
}
|
|
2737
|
+
requireVector(doc.vector, "Vector");
|
|
2738
|
+
validateRestPointId(doc.id, config);
|
|
2739
|
+
}
|
|
2740
|
+
function validateRestPointId(id, config) {
|
|
2741
|
+
if (config.backend === "rest" && (typeof id !== "number" || !Number.isInteger(id) || id < 0 || id > Number.MAX_SAFE_INTEGER)) {
|
|
2742
|
+
throw new ValidationError(
|
|
2743
|
+
`REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
|
|
2744
|
+
);
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
// src/client/search-methods.ts
|
|
2749
|
+
function search2(backend, collection, query3, options) {
|
|
2750
|
+
requireVector(query3, "Query");
|
|
2751
|
+
return backend.search(collection, query3, options);
|
|
2752
|
+
}
|
|
2753
|
+
function searchBatch2(backend, collection, searches) {
|
|
2754
|
+
if (!Array.isArray(searches)) {
|
|
2755
|
+
throw new ValidationError("Searches must be an array");
|
|
2756
|
+
}
|
|
2757
|
+
for (const s of searches) {
|
|
2758
|
+
requireVector(s.vector, "Each search vector");
|
|
2759
|
+
}
|
|
2760
|
+
return backend.searchBatch(collection, searches);
|
|
2761
|
+
}
|
|
2762
|
+
function textSearch2(backend, collection, query3, options) {
|
|
2763
|
+
requireNonEmptyString(query3, "Query");
|
|
2764
|
+
return backend.textSearch(collection, query3, options);
|
|
2765
|
+
}
|
|
2766
|
+
function hybridSearch2(backend, collection, vector, textQuery, options) {
|
|
2767
|
+
requireVector(vector, "Vector");
|
|
2768
|
+
requireNonEmptyString(textQuery, "Text query");
|
|
2769
|
+
return backend.hybridSearch(collection, vector, textQuery, options);
|
|
2770
|
+
}
|
|
2771
|
+
function multiQuerySearch2(backend, collection, vectors, options) {
|
|
2772
|
+
if (!Array.isArray(vectors) || vectors.length === 0) {
|
|
2773
|
+
throw new ValidationError("Vectors must be a non-empty array");
|
|
2774
|
+
}
|
|
2775
|
+
for (const v of vectors) {
|
|
2776
|
+
requireVector(v, "Each vector");
|
|
2777
|
+
}
|
|
2778
|
+
return backend.multiQuerySearch(collection, vectors, options);
|
|
2779
|
+
}
|
|
2780
|
+
function trainPq2(backend, collection, options) {
|
|
2781
|
+
return backend.trainPq(collection, options);
|
|
2782
|
+
}
|
|
2783
|
+
function streamInsert2(backend, config, collection, docs) {
|
|
2784
|
+
validateDocsBatch(docs, (doc) => validateDocument(doc, config));
|
|
2785
|
+
return backend.streamInsert(collection, docs);
|
|
2786
|
+
}
|
|
2787
|
+
function streamUpsertPoints2(backend, config, collection, docs) {
|
|
2788
|
+
validateDocsBatch(docs, (doc) => validateDocument(doc, config));
|
|
2789
|
+
return backend.streamUpsertPoints(collection, docs);
|
|
2790
|
+
}
|
|
2791
|
+
function scroll2(backend, collection, request2) {
|
|
2792
|
+
requireNonEmptyString(collection, "Collection name");
|
|
2793
|
+
if (request2?.batchSize !== void 0) {
|
|
2794
|
+
if (request2.batchSize < 1 || request2.batchSize > 1e4) {
|
|
2795
|
+
throw new ValidationError("batchSize must be between 1 and 10000");
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
return backend.scroll(collection, request2);
|
|
2799
|
+
}
|
|
2800
|
+
function searchIds2(backend, collection, query3, options) {
|
|
2801
|
+
return backend.searchIds(collection, query3, options);
|
|
2802
|
+
}
|
|
2803
|
+
function query2(backend, collection, queryString, params, options) {
|
|
2804
|
+
requireNonEmptyString(collection, "Collection name");
|
|
2805
|
+
requireNonEmptyString(queryString, "Query string");
|
|
2806
|
+
return backend.query(collection, queryString, params, options);
|
|
2807
|
+
}
|
|
2808
|
+
function queryExplain2(backend, queryString, params, options) {
|
|
2809
|
+
requireNonEmptyString(queryString, "Query string");
|
|
2810
|
+
return backend.queryExplain(queryString, params, options);
|
|
2811
|
+
}
|
|
2812
|
+
function collectionSanity2(backend, collection) {
|
|
2813
|
+
requireNonEmptyString(collection, "Collection name");
|
|
2814
|
+
return backend.collectionSanity(collection);
|
|
2815
|
+
}
|
|
2816
|
+
function getCollectionStats2(backend, collection) {
|
|
2817
|
+
return backend.getCollectionStats(collection);
|
|
2818
|
+
}
|
|
2819
|
+
function analyzeCollection2(backend, collection) {
|
|
2820
|
+
return backend.analyzeCollection(collection);
|
|
2821
|
+
}
|
|
2822
|
+
function getCollectionConfig2(backend, collection) {
|
|
2823
|
+
return backend.getCollectionConfig(collection);
|
|
2824
|
+
}
|
|
2825
|
+
function rebuildIndex2(backend, collection) {
|
|
2826
|
+
requireNonEmptyString(collection, "Collection");
|
|
2827
|
+
return backend.rebuildIndex(collection);
|
|
2828
|
+
}
|
|
2829
|
+
function getGuardrails2(backend) {
|
|
2830
|
+
return backend.getGuardrails();
|
|
2831
|
+
}
|
|
2832
|
+
function updateGuardrails2(backend, req) {
|
|
2833
|
+
return backend.updateGuardrails(req);
|
|
2834
|
+
}
|
|
2835
|
+
function aggregate2(backend, queryString, params, options) {
|
|
2836
|
+
requireNonEmptyString(queryString, "Query string");
|
|
2837
|
+
return backend.aggregate(queryString, params, options);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
// src/client/graph-methods.ts
|
|
2841
|
+
function addEdge2(backend, collection, edge) {
|
|
2842
|
+
if (!edge.label || typeof edge.label !== "string") {
|
|
2843
|
+
throw new ValidationError("Edge label is required and must be a string");
|
|
2844
|
+
}
|
|
2845
|
+
if (typeof edge.source !== "number" || typeof edge.target !== "number") {
|
|
2846
|
+
throw new ValidationError("Edge source and target must be numbers");
|
|
2847
|
+
}
|
|
2848
|
+
return backend.addEdge(collection, edge);
|
|
2849
|
+
}
|
|
2850
|
+
function getEdges2(backend, collection, options) {
|
|
2851
|
+
return backend.getEdges(collection, options);
|
|
2852
|
+
}
|
|
2853
|
+
function traverseGraph2(backend, collection, request2) {
|
|
2854
|
+
if (typeof request2.source !== "number") {
|
|
2855
|
+
throw new ValidationError("Source node ID must be a number");
|
|
2856
|
+
}
|
|
2857
|
+
if (request2.strategy && !["bfs", "dfs"].includes(request2.strategy)) {
|
|
2858
|
+
throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
|
|
2859
|
+
}
|
|
2860
|
+
return backend.traverseGraph(collection, request2);
|
|
2861
|
+
}
|
|
2862
|
+
function traverseParallel2(backend, collection, request2) {
|
|
2863
|
+
if (!Array.isArray(request2.sources) || request2.sources.length === 0) {
|
|
2864
|
+
throw new ValidationError("At least one source node ID is required");
|
|
2865
|
+
}
|
|
2866
|
+
return backend.traverseParallel(collection, request2);
|
|
2867
|
+
}
|
|
2868
|
+
function getNodeDegree2(backend, collection, nodeId) {
|
|
2869
|
+
if (typeof nodeId !== "number") {
|
|
2870
|
+
throw new ValidationError("Node ID must be a number");
|
|
2871
|
+
}
|
|
2872
|
+
return backend.getNodeDegree(collection, nodeId);
|
|
2873
|
+
}
|
|
2874
|
+
function createGraphCollection2(backend, name, config) {
|
|
2875
|
+
requireNonEmptyString(name, "Collection name");
|
|
2876
|
+
return backend.createGraphCollection(name, config);
|
|
2877
|
+
}
|
|
2878
|
+
function matchQuery2(backend, collection, queryString, params, options) {
|
|
2879
|
+
requireNonEmptyString(collection, "Collection");
|
|
2880
|
+
requireNonEmptyString(queryString, "Query string");
|
|
2881
|
+
return backend.matchQuery(collection, queryString, params, options);
|
|
2882
|
+
}
|
|
2883
|
+
function removeEdge2(backend, collection, edgeId) {
|
|
2884
|
+
requireNonEmptyString(collection, "Collection");
|
|
2885
|
+
return backend.removeEdge(collection, edgeId);
|
|
2886
|
+
}
|
|
2887
|
+
function getEdgeCount2(backend, collection) {
|
|
2888
|
+
requireNonEmptyString(collection, "Collection");
|
|
2889
|
+
return backend.getEdgeCount(collection);
|
|
2890
|
+
}
|
|
2891
|
+
function listNodes2(backend, collection) {
|
|
2892
|
+
requireNonEmptyString(collection, "Collection");
|
|
2893
|
+
return backend.listNodes(collection);
|
|
2894
|
+
}
|
|
2895
|
+
function getNodeEdges2(backend, collection, nodeId, options) {
|
|
2896
|
+
requireNonEmptyString(collection, "Collection");
|
|
2897
|
+
return backend.getNodeEdges(collection, nodeId, options);
|
|
2898
|
+
}
|
|
2899
|
+
function getNodePayload2(backend, collection, nodeId) {
|
|
2900
|
+
requireNonEmptyString(collection, "Collection");
|
|
2901
|
+
return backend.getNodePayload(collection, nodeId);
|
|
2902
|
+
}
|
|
2903
|
+
function upsertNodePayload2(backend, collection, nodeId, payload) {
|
|
2904
|
+
requireNonEmptyString(collection, "Collection");
|
|
2905
|
+
return backend.upsertNodePayload(collection, nodeId, payload);
|
|
2906
|
+
}
|
|
2907
|
+
function graphSearch2(backend, collection, request2) {
|
|
2908
|
+
requireNonEmptyString(collection, "Collection");
|
|
2909
|
+
return backend.graphSearch(collection, request2);
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
// src/client.ts
|
|
1672
2913
|
var VelesDB = class {
|
|
1673
|
-
/**
|
|
1674
|
-
* Create a new VelesDB client
|
|
1675
|
-
*
|
|
1676
|
-
* @param config - Client configuration
|
|
1677
|
-
* @throws {ValidationError} If configuration is invalid
|
|
1678
|
-
*/
|
|
1679
2914
|
constructor(config) {
|
|
1680
2915
|
this.initialized = false;
|
|
1681
2916
|
this.validateConfig(config);
|
|
@@ -1703,10 +2938,7 @@ var VelesDB = class {
|
|
|
1703
2938
|
throw new ValidationError(`Unknown backend: ${config.backend}`);
|
|
1704
2939
|
}
|
|
1705
2940
|
}
|
|
1706
|
-
/**
|
|
1707
|
-
* Initialize the client
|
|
1708
|
-
* Must be called before any other operations
|
|
1709
|
-
*/
|
|
2941
|
+
/** Initialize the client. Must be called before any other operations. */
|
|
1710
2942
|
async init() {
|
|
1711
2943
|
if (this.initialized) {
|
|
1712
2944
|
return;
|
|
@@ -1714,9 +2946,7 @@ var VelesDB = class {
|
|
|
1714
2946
|
await this.backend.init();
|
|
1715
2947
|
this.initialized = true;
|
|
1716
2948
|
}
|
|
1717
|
-
/**
|
|
1718
|
-
* Check if client is initialized
|
|
1719
|
-
*/
|
|
2949
|
+
/** Check if client is initialized. */
|
|
1720
2950
|
isInitialized() {
|
|
1721
2951
|
return this.initialized;
|
|
1722
2952
|
}
|
|
@@ -1725,358 +2955,161 @@ var VelesDB = class {
|
|
|
1725
2955
|
throw new ValidationError("Client not initialized. Call init() first.");
|
|
1726
2956
|
}
|
|
1727
2957
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
* @param name - Collection name
|
|
1732
|
-
* @param config - Collection configuration
|
|
1733
|
-
*/
|
|
2958
|
+
// ========================================================================
|
|
2959
|
+
// Collection CRUD
|
|
2960
|
+
// ========================================================================
|
|
1734
2961
|
async createCollection(name, config) {
|
|
1735
2962
|
this.ensureInitialized();
|
|
1736
2963
|
requireNonEmptyString(name, "Collection name");
|
|
1737
|
-
const isMetadataOnly = config.collectionType === "metadata_only";
|
|
1738
|
-
if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
|
|
1739
|
-
throw new ValidationError("Dimension must be a positive integer for vector collections");
|
|
1740
|
-
}
|
|
1741
|
-
await this.backend.createCollection(name, config);
|
|
1742
|
-
}
|
|
1743
|
-
/**
|
|
1744
|
-
* Create a metadata-only collection (no vectors, just payload data)
|
|
1745
|
-
*
|
|
1746
|
-
* Useful for storing reference data that can be JOINed with vector collections.
|
|
1747
|
-
*
|
|
1748
|
-
* @param name - Collection name
|
|
1749
|
-
*
|
|
1750
|
-
* @example
|
|
1751
|
-
* ```typescript
|
|
1752
|
-
* await db.createMetadataCollection('products');
|
|
1753
|
-
* await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
|
|
1754
|
-
* ```
|
|
1755
|
-
*/
|
|
2964
|
+
const isMetadataOnly = config.collectionType === "metadata_only";
|
|
2965
|
+
if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
|
|
2966
|
+
throw new ValidationError("Dimension must be a positive integer for vector collections");
|
|
2967
|
+
}
|
|
2968
|
+
await this.backend.createCollection(name, config);
|
|
2969
|
+
}
|
|
1756
2970
|
async createMetadataCollection(name) {
|
|
1757
2971
|
this.ensureInitialized();
|
|
1758
2972
|
requireNonEmptyString(name, "Collection name");
|
|
1759
2973
|
await this.backend.createCollection(name, { collectionType: "metadata_only" });
|
|
1760
2974
|
}
|
|
1761
|
-
/**
|
|
1762
|
-
* Delete a collection
|
|
1763
|
-
*
|
|
1764
|
-
* @param name - Collection name
|
|
1765
|
-
*/
|
|
1766
2975
|
async deleteCollection(name) {
|
|
1767
2976
|
this.ensureInitialized();
|
|
1768
2977
|
await this.backend.deleteCollection(name);
|
|
1769
2978
|
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Get collection information
|
|
1772
|
-
*
|
|
1773
|
-
* @param name - Collection name
|
|
1774
|
-
* @returns Collection info or null if not found
|
|
1775
|
-
*/
|
|
1776
2979
|
async getCollection(name) {
|
|
1777
2980
|
this.ensureInitialized();
|
|
1778
2981
|
return this.backend.getCollection(name);
|
|
1779
2982
|
}
|
|
1780
|
-
/**
|
|
1781
|
-
* List all collections
|
|
1782
|
-
*
|
|
1783
|
-
* @returns Array of collections
|
|
1784
|
-
*/
|
|
1785
2983
|
async listCollections() {
|
|
1786
2984
|
this.ensureInitialized();
|
|
1787
2985
|
return this.backend.listCollections();
|
|
1788
2986
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
* @param doc - Document to insert
|
|
1794
|
-
*/
|
|
1795
|
-
async insert(collection, doc) {
|
|
2987
|
+
// ========================================================================
|
|
2988
|
+
// Point CRUD
|
|
2989
|
+
// ========================================================================
|
|
2990
|
+
async upsert(collection, doc) {
|
|
1796
2991
|
this.ensureInitialized();
|
|
1797
|
-
|
|
1798
|
-
await this.backend.
|
|
2992
|
+
validateDocument(doc, this.config);
|
|
2993
|
+
await this.backend.upsert(collection, doc);
|
|
1799
2994
|
}
|
|
1800
|
-
|
|
1801
|
-
* Insert multiple vector documents
|
|
1802
|
-
*
|
|
1803
|
-
* @param collection - Collection name
|
|
1804
|
-
* @param docs - Documents to insert
|
|
1805
|
-
*/
|
|
1806
|
-
async insertBatch(collection, docs) {
|
|
2995
|
+
async upsertBatch(collection, docs) {
|
|
1807
2996
|
this.ensureInitialized();
|
|
1808
|
-
validateDocsBatch(docs, (doc) =>
|
|
1809
|
-
await this.backend.
|
|
2997
|
+
validateDocsBatch(docs, (doc) => validateDocument(doc, this.config));
|
|
2998
|
+
await this.backend.upsertBatch(collection, docs);
|
|
1810
2999
|
}
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
requireVector(doc.vector, "Vector");
|
|
1816
|
-
this.validateRestPointId(doc.id);
|
|
3000
|
+
async delete(collection, id) {
|
|
3001
|
+
this.ensureInitialized();
|
|
3002
|
+
validateRestPointId(id, this.config);
|
|
3003
|
+
return this.backend.delete(collection, id);
|
|
1817
3004
|
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
);
|
|
1823
|
-
}
|
|
3005
|
+
async get(collection, id) {
|
|
3006
|
+
this.ensureInitialized();
|
|
3007
|
+
validateRestPointId(id, this.config);
|
|
3008
|
+
return this.backend.get(collection, id);
|
|
1824
3009
|
}
|
|
1825
|
-
|
|
1826
|
-
* Search for similar vectors
|
|
1827
|
-
*
|
|
1828
|
-
* @param collection - Collection name
|
|
1829
|
-
* @param query - Query vector
|
|
1830
|
-
* @param options - Search options
|
|
1831
|
-
* @returns Search results sorted by relevance
|
|
1832
|
-
*/
|
|
1833
|
-
async search(collection, query2, options) {
|
|
3010
|
+
async isEmpty(collection) {
|
|
1834
3011
|
this.ensureInitialized();
|
|
1835
|
-
|
|
1836
|
-
return this.backend.search(collection, query2, options);
|
|
3012
|
+
return this.backend.isEmpty(collection);
|
|
1837
3013
|
}
|
|
1838
|
-
|
|
1839
|
-
* Search for multiple vectors in parallel
|
|
1840
|
-
*
|
|
1841
|
-
* @param collection - Collection name
|
|
1842
|
-
* @param searches - List of search queries
|
|
1843
|
-
* @returns List of search results for each query
|
|
1844
|
-
*/
|
|
1845
|
-
async searchBatch(collection, searches) {
|
|
3014
|
+
async flush(collection) {
|
|
1846
3015
|
this.ensureInitialized();
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
3016
|
+
await this.backend.flush(collection);
|
|
3017
|
+
}
|
|
3018
|
+
async close() {
|
|
3019
|
+
if (this.initialized) {
|
|
3020
|
+
await this.backend.close();
|
|
3021
|
+
this.initialized = false;
|
|
1852
3022
|
}
|
|
1853
|
-
return this.backend.searchBatch(collection, searches);
|
|
1854
3023
|
}
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
* @param id - Document ID
|
|
1860
|
-
* @returns true if deleted, false if not found
|
|
1861
|
-
*/
|
|
1862
|
-
async delete(collection, id) {
|
|
3024
|
+
// ========================================================================
|
|
3025
|
+
// Search & Query -- delegates to client/search-methods.ts
|
|
3026
|
+
// ========================================================================
|
|
3027
|
+
async search(collection, query3, options) {
|
|
1863
3028
|
this.ensureInitialized();
|
|
1864
|
-
this.
|
|
1865
|
-
return this.backend.delete(collection, id);
|
|
3029
|
+
return search2(this.backend, collection, query3, options);
|
|
1866
3030
|
}
|
|
1867
|
-
|
|
1868
|
-
* Get a vector by ID
|
|
1869
|
-
*
|
|
1870
|
-
* @param collection - Collection name
|
|
1871
|
-
* @param id - Document ID
|
|
1872
|
-
* @returns Document or null if not found
|
|
1873
|
-
*/
|
|
1874
|
-
async get(collection, id) {
|
|
3031
|
+
async searchBatch(collection, searches) {
|
|
1875
3032
|
this.ensureInitialized();
|
|
1876
|
-
this.
|
|
1877
|
-
return this.backend.get(collection, id);
|
|
3033
|
+
return searchBatch2(this.backend, collection, searches);
|
|
1878
3034
|
}
|
|
1879
|
-
|
|
1880
|
-
* Perform full-text search using BM25
|
|
1881
|
-
*
|
|
1882
|
-
* @param collection - Collection name
|
|
1883
|
-
* @param query - Text query
|
|
1884
|
-
* @param options - Search options (k, filter)
|
|
1885
|
-
* @returns Search results sorted by BM25 score
|
|
1886
|
-
*/
|
|
1887
|
-
async textSearch(collection, query2, options) {
|
|
3035
|
+
async textSearch(collection, query3, options) {
|
|
1888
3036
|
this.ensureInitialized();
|
|
1889
|
-
|
|
1890
|
-
return this.backend.textSearch(collection, query2, options);
|
|
3037
|
+
return textSearch2(this.backend, collection, query3, options);
|
|
1891
3038
|
}
|
|
1892
|
-
/**
|
|
1893
|
-
* Perform hybrid search combining vector similarity and BM25 text search
|
|
1894
|
-
*
|
|
1895
|
-
* @param collection - Collection name
|
|
1896
|
-
* @param vector - Query vector
|
|
1897
|
-
* @param textQuery - Text query for BM25
|
|
1898
|
-
* @param options - Search options (k, vectorWeight, filter)
|
|
1899
|
-
* @returns Search results sorted by fused score
|
|
1900
|
-
*/
|
|
1901
3039
|
async hybridSearch(collection, vector, textQuery, options) {
|
|
1902
3040
|
this.ensureInitialized();
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
3041
|
+
return hybridSearch2(this.backend, collection, vector, textQuery, options);
|
|
3042
|
+
}
|
|
3043
|
+
async multiQuerySearch(collection, vectors, options) {
|
|
3044
|
+
this.ensureInitialized();
|
|
3045
|
+
return multiQuerySearch2(this.backend, collection, vectors, options);
|
|
1906
3046
|
}
|
|
1907
|
-
/**
|
|
1908
|
-
* Execute a VelesQL multi-model query (EPIC-031 US-011)
|
|
1909
|
-
*
|
|
1910
|
-
* Supports hybrid vector + graph queries with VelesQL syntax.
|
|
1911
|
-
*
|
|
1912
|
-
* @param collection - Collection name
|
|
1913
|
-
* @param queryString - VelesQL query string
|
|
1914
|
-
* @param params - Query parameters (vectors, scalars).
|
|
1915
|
-
* For cross-collection MATCH queries, pass `_collection` to specify the
|
|
1916
|
-
* primary collection (the one with graph edges). Nodes annotated with
|
|
1917
|
-
* `@collection` in the MATCH pattern will have their payloads enriched
|
|
1918
|
-
* from the named collection after traversal.
|
|
1919
|
-
* @param options - Query options (timeout, streaming)
|
|
1920
|
-
* @returns Query response with results and execution stats
|
|
1921
|
-
*
|
|
1922
|
-
* @example
|
|
1923
|
-
* ```typescript
|
|
1924
|
-
* const response = await db.query('docs', `
|
|
1925
|
-
* MATCH (d:Doc) WHERE vector NEAR $q LIMIT 20
|
|
1926
|
-
* `, { q: queryVector });
|
|
1927
|
-
*
|
|
1928
|
-
* for (const r of response.results) {
|
|
1929
|
-
* console.log(`ID ${r.id}, title: ${r.title}`);
|
|
1930
|
-
* }
|
|
1931
|
-
* ```
|
|
1932
|
-
*
|
|
1933
|
-
* @example Cross-collection MATCH
|
|
1934
|
-
* ```typescript
|
|
1935
|
-
* // Enrich Product nodes with Inventory data from the 'inventory' collection
|
|
1936
|
-
* const response = await db.query('catalog_graph', `
|
|
1937
|
-
* MATCH (p:Product)-[:STORED_IN]->(inv:Inventory@inventory)
|
|
1938
|
-
* RETURN p.name, inv.price, inv.stock
|
|
1939
|
-
* LIMIT 20
|
|
1940
|
-
* `);
|
|
1941
|
-
* ```
|
|
1942
|
-
*/
|
|
1943
3047
|
async query(collection, queryString, params, options) {
|
|
1944
3048
|
this.ensureInitialized();
|
|
1945
|
-
|
|
1946
|
-
requireNonEmptyString(queryString, "Query string");
|
|
1947
|
-
return this.backend.query(collection, queryString, params, options);
|
|
3049
|
+
return query2(this.backend, collection, queryString, params, options);
|
|
1948
3050
|
}
|
|
1949
|
-
|
|
1950
|
-
* Explain the execution plan for a VelesQL query without running it
|
|
1951
|
-
*
|
|
1952
|
-
* @param queryString - VelesQL query string to explain
|
|
1953
|
-
* @param params - Optional query parameters (vectors, scalars)
|
|
1954
|
-
* @returns Explain response with the query execution plan
|
|
1955
|
-
*/
|
|
1956
|
-
async queryExplain(queryString, params) {
|
|
3051
|
+
async queryExplain(queryString, params, options) {
|
|
1957
3052
|
this.ensureInitialized();
|
|
1958
|
-
|
|
1959
|
-
return this.backend.queryExplain(queryString, params);
|
|
3053
|
+
return queryExplain2(this.backend, queryString, params, options);
|
|
1960
3054
|
}
|
|
1961
3055
|
async collectionSanity(collection) {
|
|
1962
3056
|
this.ensureInitialized();
|
|
1963
|
-
|
|
1964
|
-
return this.backend.collectionSanity(collection);
|
|
3057
|
+
return collectionSanity2(this.backend, collection);
|
|
1965
3058
|
}
|
|
1966
|
-
|
|
1967
|
-
* Multi-query fusion search combining results from multiple query vectors
|
|
1968
|
-
*
|
|
1969
|
-
* Ideal for RAG pipelines using Multiple Query Generation (MQG).
|
|
1970
|
-
*
|
|
1971
|
-
* @param collection - Collection name
|
|
1972
|
-
* @param vectors - Array of query vectors
|
|
1973
|
-
* @param options - Search options (k, fusion strategy, fusionParams, filter)
|
|
1974
|
-
* @returns Fused search results
|
|
1975
|
-
*
|
|
1976
|
-
* @example
|
|
1977
|
-
* ```typescript
|
|
1978
|
-
* // RRF fusion (default)
|
|
1979
|
-
* const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
|
|
1980
|
-
* k: 10,
|
|
1981
|
-
* fusion: 'rrf',
|
|
1982
|
-
* fusionParams: { k: 60 }
|
|
1983
|
-
* });
|
|
1984
|
-
*
|
|
1985
|
-
* // Weighted fusion
|
|
1986
|
-
* const results = await db.multiQuerySearch('docs', [emb1, emb2], {
|
|
1987
|
-
* k: 10,
|
|
1988
|
-
* fusion: 'weighted',
|
|
1989
|
-
* fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
|
|
1990
|
-
* });
|
|
1991
|
-
* ```
|
|
1992
|
-
*/
|
|
1993
|
-
async multiQuerySearch(collection, vectors, options) {
|
|
3059
|
+
async scroll(collection, request2) {
|
|
1994
3060
|
this.ensureInitialized();
|
|
1995
|
-
|
|
1996
|
-
throw new ValidationError("Vectors must be a non-empty array");
|
|
1997
|
-
}
|
|
1998
|
-
for (const v of vectors) {
|
|
1999
|
-
requireVector(v, "Each vector");
|
|
2000
|
-
}
|
|
2001
|
-
return this.backend.multiQuerySearch(collection, vectors, options);
|
|
3061
|
+
return scroll2(this.backend, collection, request2);
|
|
2002
3062
|
}
|
|
2003
|
-
/**
|
|
2004
|
-
* Train Product Quantization on a collection
|
|
2005
|
-
*
|
|
2006
|
-
* @param collection - Collection name
|
|
2007
|
-
* @param options - PQ training options (m, k, opq)
|
|
2008
|
-
* @returns Server response message
|
|
2009
|
-
*/
|
|
2010
3063
|
async trainPq(collection, options) {
|
|
2011
3064
|
this.ensureInitialized();
|
|
2012
|
-
return this.backend
|
|
3065
|
+
return trainPq2(this.backend, collection, options);
|
|
2013
3066
|
}
|
|
2014
|
-
/**
|
|
2015
|
-
* Stream-insert documents with backpressure support
|
|
2016
|
-
*
|
|
2017
|
-
* Sends documents sequentially to respect server backpressure.
|
|
2018
|
-
* Throws BackpressureError on 429 responses.
|
|
2019
|
-
*
|
|
2020
|
-
* @param collection - Collection name
|
|
2021
|
-
* @param docs - Documents to insert
|
|
2022
|
-
*/
|
|
2023
3067
|
async streamInsert(collection, docs) {
|
|
2024
3068
|
this.ensureInitialized();
|
|
2025
|
-
|
|
2026
|
-
await this.backend.streamInsert(collection, docs);
|
|
3069
|
+
return streamInsert2(this.backend, this.config, collection, docs);
|
|
2027
3070
|
}
|
|
2028
|
-
|
|
2029
|
-
* Check if a collection is empty
|
|
2030
|
-
*
|
|
2031
|
-
* @param collection - Collection name
|
|
2032
|
-
* @returns true if empty, false otherwise
|
|
2033
|
-
*/
|
|
2034
|
-
async isEmpty(collection) {
|
|
3071
|
+
async streamUpsertPoints(collection, docs) {
|
|
2035
3072
|
this.ensureInitialized();
|
|
2036
|
-
return this.backend.
|
|
3073
|
+
return streamUpsertPoints2(this.backend, this.config, collection, docs);
|
|
2037
3074
|
}
|
|
2038
|
-
|
|
2039
|
-
* Flush pending changes to disk
|
|
2040
|
-
*
|
|
2041
|
-
* @param collection - Collection name
|
|
2042
|
-
*/
|
|
2043
|
-
async flush(collection) {
|
|
3075
|
+
async searchIds(collection, query3, options) {
|
|
2044
3076
|
this.ensureInitialized();
|
|
2045
|
-
|
|
3077
|
+
return searchIds2(this.backend, collection, query3, options);
|
|
2046
3078
|
}
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
async
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
this.initialized = false;
|
|
2054
|
-
}
|
|
3079
|
+
// ========================================================================
|
|
3080
|
+
// Admin / Stats -- delegates to client/search-methods.ts
|
|
3081
|
+
// ========================================================================
|
|
3082
|
+
async rebuildIndex(collection) {
|
|
3083
|
+
this.ensureInitialized();
|
|
3084
|
+
return rebuildIndex2(this.backend, collection);
|
|
2055
3085
|
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
3086
|
+
async getGuardrails() {
|
|
3087
|
+
this.ensureInitialized();
|
|
3088
|
+
return getGuardrails2(this.backend);
|
|
3089
|
+
}
|
|
3090
|
+
async updateGuardrails(req) {
|
|
3091
|
+
this.ensureInitialized();
|
|
3092
|
+
return updateGuardrails2(this.backend, req);
|
|
3093
|
+
}
|
|
3094
|
+
async aggregate(queryString, params, options) {
|
|
3095
|
+
this.ensureInitialized();
|
|
3096
|
+
return aggregate2(this.backend, queryString, params, options);
|
|
3097
|
+
}
|
|
3098
|
+
async getCollectionStats(collection) {
|
|
3099
|
+
this.ensureInitialized();
|
|
3100
|
+
return getCollectionStats2(this.backend, collection);
|
|
3101
|
+
}
|
|
3102
|
+
async analyzeCollection(collection) {
|
|
3103
|
+
this.ensureInitialized();
|
|
3104
|
+
return analyzeCollection2(this.backend, collection);
|
|
3105
|
+
}
|
|
3106
|
+
async getCollectionConfig(collection) {
|
|
3107
|
+
this.ensureInitialized();
|
|
3108
|
+
return getCollectionConfig2(this.backend, collection);
|
|
2061
3109
|
}
|
|
2062
3110
|
// ========================================================================
|
|
2063
3111
|
// Index Management (EPIC-009)
|
|
2064
3112
|
// ========================================================================
|
|
2065
|
-
/**
|
|
2066
|
-
* Create a property index for O(1) equality lookups or O(log n) range queries
|
|
2067
|
-
*
|
|
2068
|
-
* @param collection - Collection name
|
|
2069
|
-
* @param options - Index configuration (label, property, indexType)
|
|
2070
|
-
*
|
|
2071
|
-
* @example
|
|
2072
|
-
* ```typescript
|
|
2073
|
-
* // Create hash index for fast email lookups
|
|
2074
|
-
* await db.createIndex('users', { label: 'Person', property: 'email' });
|
|
2075
|
-
*
|
|
2076
|
-
* // Create range index for timestamp queries
|
|
2077
|
-
* await db.createIndex('events', { label: 'Event', property: 'timestamp', indexType: 'range' });
|
|
2078
|
-
* ```
|
|
2079
|
-
*/
|
|
2080
3113
|
async createIndex(collection, options) {
|
|
2081
3114
|
this.ensureInitialized();
|
|
2082
3115
|
if (!options.label || !options.property) {
|
|
@@ -2084,234 +3117,89 @@ var VelesDB = class {
|
|
|
2084
3117
|
}
|
|
2085
3118
|
await this.backend.createIndex(collection, options);
|
|
2086
3119
|
}
|
|
2087
|
-
/**
|
|
2088
|
-
* List all indexes on a collection
|
|
2089
|
-
*
|
|
2090
|
-
* @param collection - Collection name
|
|
2091
|
-
* @returns Array of index information
|
|
2092
|
-
*/
|
|
2093
3120
|
async listIndexes(collection) {
|
|
2094
3121
|
this.ensureInitialized();
|
|
2095
3122
|
return this.backend.listIndexes(collection);
|
|
2096
3123
|
}
|
|
2097
|
-
/**
|
|
2098
|
-
* Check if an index exists
|
|
2099
|
-
*
|
|
2100
|
-
* @param collection - Collection name
|
|
2101
|
-
* @param label - Node label
|
|
2102
|
-
* @param property - Property name
|
|
2103
|
-
* @returns true if index exists
|
|
2104
|
-
*/
|
|
2105
3124
|
async hasIndex(collection, label, property) {
|
|
2106
3125
|
this.ensureInitialized();
|
|
2107
3126
|
return this.backend.hasIndex(collection, label, property);
|
|
2108
3127
|
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Drop an index
|
|
2111
|
-
*
|
|
2112
|
-
* @param collection - Collection name
|
|
2113
|
-
* @param label - Node label
|
|
2114
|
-
* @param property - Property name
|
|
2115
|
-
* @returns true if index was dropped, false if it didn't exist
|
|
2116
|
-
*/
|
|
2117
3128
|
async dropIndex(collection, label, property) {
|
|
2118
3129
|
this.ensureInitialized();
|
|
2119
3130
|
return this.backend.dropIndex(collection, label, property);
|
|
2120
3131
|
}
|
|
2121
3132
|
// ========================================================================
|
|
2122
|
-
// Knowledge Graph
|
|
3133
|
+
// Knowledge Graph -- delegates to client/graph-methods.ts
|
|
2123
3134
|
// ========================================================================
|
|
2124
|
-
/**
|
|
2125
|
-
* Add an edge to the collection's knowledge graph
|
|
2126
|
-
*
|
|
2127
|
-
* @param collection - Collection name
|
|
2128
|
-
* @param edge - Edge to add (id, source, target, label, properties)
|
|
2129
|
-
*
|
|
2130
|
-
* @example
|
|
2131
|
-
* ```typescript
|
|
2132
|
-
* await db.addEdge('social', {
|
|
2133
|
-
* id: 1,
|
|
2134
|
-
* source: 100,
|
|
2135
|
-
* target: 200,
|
|
2136
|
-
* label: 'FOLLOWS',
|
|
2137
|
-
* properties: { since: '2024-01-01' }
|
|
2138
|
-
* });
|
|
2139
|
-
* ```
|
|
2140
|
-
*/
|
|
2141
3135
|
async addEdge(collection, edge) {
|
|
2142
3136
|
this.ensureInitialized();
|
|
2143
|
-
|
|
2144
|
-
throw new ValidationError("Edge label is required and must be a string");
|
|
2145
|
-
}
|
|
2146
|
-
if (typeof edge.source !== "number" || typeof edge.target !== "number") {
|
|
2147
|
-
throw new ValidationError("Edge source and target must be numbers");
|
|
2148
|
-
}
|
|
2149
|
-
await this.backend.addEdge(collection, edge);
|
|
3137
|
+
return addEdge2(this.backend, collection, edge);
|
|
2150
3138
|
}
|
|
2151
|
-
/**
|
|
2152
|
-
* Get edges from the collection's knowledge graph
|
|
2153
|
-
*
|
|
2154
|
-
* @param collection - Collection name
|
|
2155
|
-
* @param options - Query options (filter by label)
|
|
2156
|
-
* @returns Array of edges
|
|
2157
|
-
*
|
|
2158
|
-
* @example
|
|
2159
|
-
* ```typescript
|
|
2160
|
-
* // Get all edges with label "FOLLOWS"
|
|
2161
|
-
* const edges = await db.getEdges('social', { label: 'FOLLOWS' });
|
|
2162
|
-
* ```
|
|
2163
|
-
*/
|
|
2164
3139
|
async getEdges(collection, options) {
|
|
2165
3140
|
this.ensureInitialized();
|
|
2166
|
-
return this.backend
|
|
3141
|
+
return getEdges2(this.backend, collection, options);
|
|
2167
3142
|
}
|
|
2168
|
-
|
|
2169
|
-
// Graph Traversal (EPIC-016 US-050)
|
|
2170
|
-
// ========================================================================
|
|
2171
|
-
/**
|
|
2172
|
-
* Traverse the graph using BFS or DFS from a source node
|
|
2173
|
-
*
|
|
2174
|
-
* @param collection - Collection name
|
|
2175
|
-
* @param request - Traversal request options
|
|
2176
|
-
* @returns Traversal response with results and stats
|
|
2177
|
-
*
|
|
2178
|
-
* @example
|
|
2179
|
-
* ```typescript
|
|
2180
|
-
* // BFS traversal from node 100
|
|
2181
|
-
* const result = await db.traverseGraph('social', {
|
|
2182
|
-
* source: 100,
|
|
2183
|
-
* strategy: 'bfs',
|
|
2184
|
-
* maxDepth: 3,
|
|
2185
|
-
* limit: 100,
|
|
2186
|
-
* relTypes: ['FOLLOWS', 'KNOWS']
|
|
2187
|
-
* });
|
|
2188
|
-
*
|
|
2189
|
-
* for (const node of result.results) {
|
|
2190
|
-
* console.log(`Reached node ${node.targetId} at depth ${node.depth}`);
|
|
2191
|
-
* }
|
|
2192
|
-
* ```
|
|
2193
|
-
*/
|
|
2194
|
-
async traverseGraph(collection, request) {
|
|
3143
|
+
async traverseGraph(collection, request2) {
|
|
2195
3144
|
this.ensureInitialized();
|
|
2196
|
-
|
|
2197
|
-
throw new ValidationError("Source node ID must be a number");
|
|
2198
|
-
}
|
|
2199
|
-
if (request.strategy && !["bfs", "dfs"].includes(request.strategy)) {
|
|
2200
|
-
throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
|
|
2201
|
-
}
|
|
2202
|
-
return this.backend.traverseGraph(collection, request);
|
|
3145
|
+
return traverseGraph2(this.backend, collection, request2);
|
|
2203
3146
|
}
|
|
2204
|
-
|
|
2205
|
-
* Multi-source parallel BFS traversal with deduplication.
|
|
2206
|
-
*
|
|
2207
|
-
* Starts BFS from multiple source nodes simultaneously and deduplicates
|
|
2208
|
-
* results by path signature.
|
|
2209
|
-
*
|
|
2210
|
-
* @param collection - Collection name
|
|
2211
|
-
* @param request - Parallel traverse request with sources array
|
|
2212
|
-
* @returns Traverse response with results, stats, and pagination
|
|
2213
|
-
*
|
|
2214
|
-
* @example
|
|
2215
|
-
* ```typescript
|
|
2216
|
-
* const result = await db.traverseParallel('social', {
|
|
2217
|
-
* sources: [100, 200, 300],
|
|
2218
|
-
* maxDepth: 3,
|
|
2219
|
-
* limit: 50,
|
|
2220
|
-
* });
|
|
2221
|
-
* ```
|
|
2222
|
-
*/
|
|
2223
|
-
async traverseParallel(collection, request) {
|
|
3147
|
+
async traverseParallel(collection, request2) {
|
|
2224
3148
|
this.ensureInitialized();
|
|
2225
|
-
|
|
2226
|
-
throw new ValidationError("At least one source node ID is required");
|
|
2227
|
-
}
|
|
2228
|
-
return this.backend.traverseParallel(collection, request);
|
|
3149
|
+
return traverseParallel2(this.backend, collection, request2);
|
|
2229
3150
|
}
|
|
2230
|
-
/**
|
|
2231
|
-
* Get the in-degree and out-degree of a node
|
|
2232
|
-
*
|
|
2233
|
-
* @param collection - Collection name
|
|
2234
|
-
* @param nodeId - Node ID
|
|
2235
|
-
* @returns Degree response with inDegree and outDegree
|
|
2236
|
-
*
|
|
2237
|
-
* @example
|
|
2238
|
-
* ```typescript
|
|
2239
|
-
* const degree = await db.getNodeDegree('social', 100);
|
|
2240
|
-
* console.log(`In: ${degree.inDegree}, Out: ${degree.outDegree}`);
|
|
2241
|
-
* ```
|
|
2242
|
-
*/
|
|
2243
3151
|
async getNodeDegree(collection, nodeId) {
|
|
2244
3152
|
this.ensureInitialized();
|
|
2245
|
-
|
|
2246
|
-
throw new ValidationError("Node ID must be a number");
|
|
2247
|
-
}
|
|
2248
|
-
return this.backend.getNodeDegree(collection, nodeId);
|
|
3153
|
+
return getNodeDegree2(this.backend, collection, nodeId);
|
|
2249
3154
|
}
|
|
2250
|
-
// ========================================================================
|
|
2251
|
-
// Graph Collection Management (Phase 8)
|
|
2252
|
-
// ========================================================================
|
|
2253
|
-
/**
|
|
2254
|
-
* Create a graph collection
|
|
2255
|
-
*
|
|
2256
|
-
* @param name - Collection name
|
|
2257
|
-
* @param config - Optional graph collection configuration
|
|
2258
|
-
*/
|
|
2259
3155
|
async createGraphCollection(name, config) {
|
|
2260
3156
|
this.ensureInitialized();
|
|
2261
|
-
|
|
2262
|
-
await this.backend.createGraphCollection(name, config);
|
|
3157
|
+
return createGraphCollection2(this.backend, name, config);
|
|
2263
3158
|
}
|
|
2264
|
-
|
|
2265
|
-
* Get collection statistics (requires prior analyze)
|
|
2266
|
-
*
|
|
2267
|
-
* @param collection - Collection name
|
|
2268
|
-
* @returns Statistics or null if not yet analyzed
|
|
2269
|
-
*/
|
|
2270
|
-
async getCollectionStats(collection) {
|
|
3159
|
+
async matchQuery(collection, queryString, params, options) {
|
|
2271
3160
|
this.ensureInitialized();
|
|
2272
|
-
return this.backend
|
|
3161
|
+
return matchQuery2(this.backend, collection, queryString, params, options);
|
|
2273
3162
|
}
|
|
2274
|
-
|
|
2275
|
-
* Analyze a collection to compute statistics
|
|
2276
|
-
*
|
|
2277
|
-
* @param collection - Collection name
|
|
2278
|
-
* @returns Computed statistics
|
|
2279
|
-
*/
|
|
2280
|
-
async analyzeCollection(collection) {
|
|
3163
|
+
async removeEdge(collection, edgeId) {
|
|
2281
3164
|
this.ensureInitialized();
|
|
2282
|
-
return this.backend
|
|
3165
|
+
return removeEdge2(this.backend, collection, edgeId);
|
|
2283
3166
|
}
|
|
2284
|
-
|
|
2285
|
-
* Get collection configuration
|
|
2286
|
-
*
|
|
2287
|
-
* @param collection - Collection name
|
|
2288
|
-
* @returns Collection configuration details
|
|
2289
|
-
*/
|
|
2290
|
-
async getCollectionConfig(collection) {
|
|
3167
|
+
async getEdgeCount(collection) {
|
|
2291
3168
|
this.ensureInitialized();
|
|
2292
|
-
return this.backend
|
|
3169
|
+
return getEdgeCount2(this.backend, collection);
|
|
2293
3170
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
async
|
|
3171
|
+
async listNodes(collection) {
|
|
3172
|
+
this.ensureInitialized();
|
|
3173
|
+
return listNodes2(this.backend, collection);
|
|
3174
|
+
}
|
|
3175
|
+
async getNodeEdges(collection, nodeId, options) {
|
|
3176
|
+
this.ensureInitialized();
|
|
3177
|
+
return getNodeEdges2(this.backend, collection, nodeId, options);
|
|
3178
|
+
}
|
|
3179
|
+
async getNodePayload(collection, nodeId) {
|
|
3180
|
+
this.ensureInitialized();
|
|
3181
|
+
return getNodePayload2(this.backend, collection, nodeId);
|
|
3182
|
+
}
|
|
3183
|
+
async upsertNodePayload(collection, nodeId, payload) {
|
|
3184
|
+
this.ensureInitialized();
|
|
3185
|
+
return upsertNodePayload2(this.backend, collection, nodeId, payload);
|
|
3186
|
+
}
|
|
3187
|
+
async graphSearch(collection, request2) {
|
|
2303
3188
|
this.ensureInitialized();
|
|
2304
|
-
return this.backend
|
|
3189
|
+
return graphSearch2(this.backend, collection, request2);
|
|
3190
|
+
}
|
|
3191
|
+
// ========================================================================
|
|
3192
|
+
// Capabilities & Backend Info
|
|
3193
|
+
// ========================================================================
|
|
3194
|
+
capabilities() {
|
|
3195
|
+
return this.backend.capabilities();
|
|
3196
|
+
}
|
|
3197
|
+
get backendType() {
|
|
3198
|
+
return this.config.backend;
|
|
2305
3199
|
}
|
|
2306
3200
|
// ========================================================================
|
|
2307
3201
|
// Agent Memory (Phase 8)
|
|
2308
3202
|
// ========================================================================
|
|
2309
|
-
/**
|
|
2310
|
-
* Create an agent memory interface
|
|
2311
|
-
*
|
|
2312
|
-
* @param config - Optional agent memory configuration
|
|
2313
|
-
* @returns AgentMemoryClient instance
|
|
2314
|
-
*/
|
|
2315
3203
|
agentMemory(config) {
|
|
2316
3204
|
this.ensureInitialized();
|
|
2317
3205
|
return new AgentMemoryClient(this.backend, config);
|
|
@@ -2411,6 +3299,16 @@ var VelesQLBuilder = class _VelesQLBuilder {
|
|
|
2411
3299
|
*
|
|
2412
3300
|
* @param condition - WHERE condition
|
|
2413
3301
|
* @param params - Optional parameters
|
|
3302
|
+
*
|
|
3303
|
+
* @example
|
|
3304
|
+
* ```typescript
|
|
3305
|
+
* // Substring matching with CONTAINS_TEXT
|
|
3306
|
+
* velesql()
|
|
3307
|
+
* .match('d', 'Document')
|
|
3308
|
+
* .where("content CONTAINS_TEXT 'keyword'")
|
|
3309
|
+
* .limit(10)
|
|
3310
|
+
* .toVelesQL();
|
|
3311
|
+
* ```
|
|
2414
3312
|
*/
|
|
2415
3313
|
where(condition, params) {
|
|
2416
3314
|
const newParams = params ? { ...this.state.params, ...params } : this.state.params;
|
|
@@ -2619,16 +3517,205 @@ var VelesQLBuilder = class _VelesQLBuilder {
|
|
|
2619
3517
|
function velesql() {
|
|
2620
3518
|
return new VelesQLBuilder();
|
|
2621
3519
|
}
|
|
3520
|
+
|
|
3521
|
+
// src/filter.ts
|
|
3522
|
+
function isTypedFilter(input) {
|
|
3523
|
+
if (typeof input !== "object" || input === null) {
|
|
3524
|
+
return false;
|
|
3525
|
+
}
|
|
3526
|
+
if (!("condition" in input)) {
|
|
3527
|
+
return false;
|
|
3528
|
+
}
|
|
3529
|
+
const cond = input.condition;
|
|
3530
|
+
return typeof cond === "object" && cond !== null;
|
|
3531
|
+
}
|
|
3532
|
+
function normalizeFilter(input) {
|
|
3533
|
+
if (input === void 0) {
|
|
3534
|
+
return void 0;
|
|
3535
|
+
}
|
|
3536
|
+
return input;
|
|
3537
|
+
}
|
|
3538
|
+
var f = {
|
|
3539
|
+
// --- Comparison -----------------------------------------------------------
|
|
3540
|
+
/** `field == value` */
|
|
3541
|
+
eq(field, value) {
|
|
3542
|
+
return { condition: { type: "eq", field, value } };
|
|
3543
|
+
},
|
|
3544
|
+
/** `field != value` */
|
|
3545
|
+
neq(field, value) {
|
|
3546
|
+
return { condition: { type: "neq", field, value } };
|
|
3547
|
+
},
|
|
3548
|
+
/** `field > value` */
|
|
3549
|
+
gt(field, value) {
|
|
3550
|
+
return { condition: { type: "gt", field, value } };
|
|
3551
|
+
},
|
|
3552
|
+
/** `field >= value` */
|
|
3553
|
+
gte(field, value) {
|
|
3554
|
+
return { condition: { type: "gte", field, value } };
|
|
3555
|
+
},
|
|
3556
|
+
/** `field < value` */
|
|
3557
|
+
lt(field, value) {
|
|
3558
|
+
return { condition: { type: "lt", field, value } };
|
|
3559
|
+
},
|
|
3560
|
+
/** `field <= value` */
|
|
3561
|
+
lte(field, value) {
|
|
3562
|
+
return { condition: { type: "lte", field, value } };
|
|
3563
|
+
},
|
|
3564
|
+
// --- Set / string / null --------------------------------------------------
|
|
3565
|
+
/** `field IN (values...)` — the values list is copied. */
|
|
3566
|
+
in(field, values) {
|
|
3567
|
+
return { condition: { type: "in", field, values: [...values] } };
|
|
3568
|
+
},
|
|
3569
|
+
/** Substring containment: `field LIKE '%value%'` (case-sensitive). */
|
|
3570
|
+
contains(field, value) {
|
|
3571
|
+
return { condition: { type: "contains", field, value } };
|
|
3572
|
+
},
|
|
3573
|
+
/** `field IS NULL` */
|
|
3574
|
+
isNull(field) {
|
|
3575
|
+
return { condition: { type: "is_null", field } };
|
|
3576
|
+
},
|
|
3577
|
+
/** `field IS NOT NULL` */
|
|
3578
|
+
isNotNull(field) {
|
|
3579
|
+
return { condition: { type: "is_not_null", field } };
|
|
3580
|
+
},
|
|
3581
|
+
// --- SQL patterns ---------------------------------------------------------
|
|
3582
|
+
/** SQL LIKE pattern matching (case-sensitive). Supports `%` and `_`. */
|
|
3583
|
+
like(field, pattern) {
|
|
3584
|
+
return { condition: { type: "like", field, pattern } };
|
|
3585
|
+
},
|
|
3586
|
+
/** SQL ILIKE pattern matching (case-insensitive). */
|
|
3587
|
+
ilike(field, pattern) {
|
|
3588
|
+
return { condition: { type: "ilike", field, pattern } };
|
|
3589
|
+
},
|
|
3590
|
+
// --- Array ----------------------------------------------------------------
|
|
3591
|
+
/** `value IN field` (field must be an array). */
|
|
3592
|
+
arrayContains(field, value) {
|
|
3593
|
+
return { condition: { type: "array_contains", field, value } };
|
|
3594
|
+
},
|
|
3595
|
+
/** At least one of `values` is present in the array field. */
|
|
3596
|
+
arrayContainsAny(field, values) {
|
|
3597
|
+
return { condition: { type: "array_contains_any", field, values: [...values] } };
|
|
3598
|
+
},
|
|
3599
|
+
/** Every value in `values` is present in the array field. */
|
|
3600
|
+
arrayContainsAll(field, values) {
|
|
3601
|
+
return { condition: { type: "array_contains_all", field, values: [...values] } };
|
|
3602
|
+
},
|
|
3603
|
+
// --- Geo ------------------------------------------------------------------
|
|
3604
|
+
/** Haversine distance comparison: `distance(field, (lat, lng)) <op> threshold`. */
|
|
3605
|
+
geoDistance(field, lat, lng, operator, threshold) {
|
|
3606
|
+
return {
|
|
3607
|
+
condition: { type: "geo_distance", field, lat, lng, operator, threshold }
|
|
3608
|
+
};
|
|
3609
|
+
},
|
|
3610
|
+
/** Bounding-box containment: point field falls inside `[lat_min, lat_max] x [lng_min, lng_max]`. */
|
|
3611
|
+
geoBbox(field, bounds) {
|
|
3612
|
+
return {
|
|
3613
|
+
condition: {
|
|
3614
|
+
type: "geo_bbox",
|
|
3615
|
+
field,
|
|
3616
|
+
lat_min: bounds.lat_min,
|
|
3617
|
+
lng_min: bounds.lng_min,
|
|
3618
|
+
lat_max: bounds.lat_max,
|
|
3619
|
+
lng_max: bounds.lng_max
|
|
3620
|
+
}
|
|
3621
|
+
};
|
|
3622
|
+
},
|
|
3623
|
+
// --- Convenience combinators ----------------------------------------------
|
|
3624
|
+
/** `field NOT IN (values...)` — shorthand for `not(in(field, values))`. */
|
|
3625
|
+
notIn(field, values) {
|
|
3626
|
+
return { condition: { type: "not", condition: { type: "in", field, values: [...values] } } };
|
|
3627
|
+
},
|
|
3628
|
+
/** `field BETWEEN low AND high` — shorthand for `and([gte(field, low), lte(field, high)])`. */
|
|
3629
|
+
between(field, low, high) {
|
|
3630
|
+
return {
|
|
3631
|
+
condition: {
|
|
3632
|
+
type: "and",
|
|
3633
|
+
conditions: [
|
|
3634
|
+
{ type: "gte", field, value: low },
|
|
3635
|
+
{ type: "lte", field, value: high }
|
|
3636
|
+
]
|
|
3637
|
+
}
|
|
3638
|
+
};
|
|
3639
|
+
},
|
|
3640
|
+
// --- Logical --------------------------------------------------------------
|
|
3641
|
+
/** Logical AND — the filters list is copied and flattened to root conditions. */
|
|
3642
|
+
and(filters) {
|
|
3643
|
+
return {
|
|
3644
|
+
condition: {
|
|
3645
|
+
type: "and",
|
|
3646
|
+
conditions: filters.map((item) => item.condition)
|
|
3647
|
+
}
|
|
3648
|
+
};
|
|
3649
|
+
},
|
|
3650
|
+
/** Logical OR — the filters list is copied and flattened to root conditions. */
|
|
3651
|
+
or(filters) {
|
|
3652
|
+
return {
|
|
3653
|
+
condition: {
|
|
3654
|
+
type: "or",
|
|
3655
|
+
conditions: filters.map((item) => item.condition)
|
|
3656
|
+
}
|
|
3657
|
+
};
|
|
3658
|
+
},
|
|
3659
|
+
/** Logical NOT — wraps a single filter. */
|
|
3660
|
+
not(filter) {
|
|
3661
|
+
return { condition: { type: "not", condition: filter.condition } };
|
|
3662
|
+
}
|
|
3663
|
+
};
|
|
2622
3664
|
export {
|
|
2623
3665
|
AgentMemoryClient,
|
|
3666
|
+
AllocationFailedError,
|
|
2624
3667
|
BackpressureError,
|
|
3668
|
+
CollectionExistsError,
|
|
3669
|
+
CollectionNotFoundError,
|
|
3670
|
+
ColumnStoreError,
|
|
3671
|
+
ConfigError,
|
|
2625
3672
|
ConnectionError,
|
|
3673
|
+
DatabaseLockedError,
|
|
3674
|
+
DimensionMismatchError,
|
|
3675
|
+
EdgeExistsError,
|
|
3676
|
+
EdgeNotFoundError,
|
|
3677
|
+
EpochMismatchError,
|
|
3678
|
+
GpuError,
|
|
3679
|
+
GraphNotSupportedError,
|
|
3680
|
+
GuardRailError,
|
|
3681
|
+
IncompatibleSchemaVersionError,
|
|
3682
|
+
IndexCorruptedError,
|
|
3683
|
+
IndexError,
|
|
3684
|
+
InternalError,
|
|
3685
|
+
InvalidCollectionNameError,
|
|
3686
|
+
InvalidDimensionError,
|
|
3687
|
+
InvalidEdgeLabelError,
|
|
3688
|
+
InvalidQuantizerConfigError,
|
|
3689
|
+
InvalidVectorError,
|
|
3690
|
+
IoError,
|
|
3691
|
+
NodeNotFoundError,
|
|
2626
3692
|
NotFoundError,
|
|
3693
|
+
OverflowError,
|
|
3694
|
+
PointNotFoundError,
|
|
3695
|
+
QueryError,
|
|
3696
|
+
REST_CAPABILITIES,
|
|
2627
3697
|
RestBackend,
|
|
3698
|
+
SchemaValidationError,
|
|
3699
|
+
SearchNotSupportedError,
|
|
3700
|
+
SerializationError,
|
|
3701
|
+
SnapshotBuildFailedError,
|
|
3702
|
+
SparseIndexError,
|
|
3703
|
+
StorageError,
|
|
3704
|
+
TrainingFailedError,
|
|
3705
|
+
VELES_ERROR_CODES,
|
|
2628
3706
|
ValidationError,
|
|
3707
|
+
VectorNotAllowedError,
|
|
3708
|
+
VectorRequiredError,
|
|
2629
3709
|
VelesDB,
|
|
2630
3710
|
VelesDBError,
|
|
3711
|
+
VelesError,
|
|
2631
3712
|
VelesQLBuilder,
|
|
3713
|
+
WASM_CAPABILITIES,
|
|
2632
3714
|
WasmBackend,
|
|
3715
|
+
f,
|
|
3716
|
+
isTypedFilter,
|
|
3717
|
+
normalizeFilter,
|
|
3718
|
+
parseVelesError,
|
|
3719
|
+
searchQualityToMode,
|
|
2633
3720
|
velesql
|
|
2634
3721
|
};
|