@wiscale/velesdb-sdk 1.11.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 +103 -17
- package/dist/index.d.mts +1162 -499
- package/dist/index.d.ts +1162 -499
- package/dist/index.js +2421 -1214
- package/dist/index.mjs +2376 -1214
- 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)) {
|
|
654
|
+
return true;
|
|
655
|
+
}
|
|
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") {
|
|
50
663
|
return true;
|
|
51
664
|
}
|
|
52
|
-
|
|
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
|
}
|
|
887
|
+
async close() {
|
|
888
|
+
for (const [, data] of this.collections) {
|
|
889
|
+
data.store.free();
|
|
890
|
+
}
|
|
891
|
+
this.collections.clear();
|
|
892
|
+
this._initialized = false;
|
|
893
|
+
}
|
|
894
|
+
capabilities() {
|
|
895
|
+
return WASM_CAPABILITIES;
|
|
896
|
+
}
|
|
92
897
|
ensureInitialized() {
|
|
93
898
|
if (!this._initialized || !this.wasmModule) {
|
|
94
899
|
throw new ConnectionError("WASM backend not initialized");
|
|
95
900
|
}
|
|
96
901
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
canonicalPayloadKeyFromResultId(id) {
|
|
102
|
-
if (typeof id === "bigint") {
|
|
103
|
-
return id.toString();
|
|
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)/, "");
|
|
121
|
-
}
|
|
122
|
-
return String(this.toNumericId(id));
|
|
123
|
-
}
|
|
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,287 +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
|
-
const field = void 0;
|
|
347
|
-
const raw = collection.store.text_search(_query, k, field);
|
|
348
|
-
return raw.map((r) => {
|
|
349
|
-
if (Array.isArray(r)) {
|
|
350
|
-
const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
|
|
351
|
-
return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
|
|
352
|
-
}
|
|
353
|
-
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
354
|
-
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
355
|
-
});
|
|
1040
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
1041
|
+
}
|
|
1042
|
+
return collection.store.is_empty;
|
|
356
1043
|
}
|
|
357
|
-
async
|
|
1044
|
+
async flush(collectionName) {
|
|
358
1045
|
this.ensureInitialized();
|
|
359
|
-
const collection = this.collections.get(
|
|
1046
|
+
const collection = this.collections.get(collectionName);
|
|
360
1047
|
if (!collection) {
|
|
361
|
-
throw new NotFoundError(`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
|
-
});
|
|
1048
|
+
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
1049
|
+
}
|
|
375
1050
|
}
|
|
376
|
-
|
|
1051
|
+
// ========================================================================
|
|
1052
|
+
// Search & Query -- delegates to wasm-search.ts
|
|
1053
|
+
// ========================================================================
|
|
1054
|
+
async search(c, q, o) {
|
|
377
1055
|
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
|
-
};
|
|
1056
|
+
return wasmSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
|
|
403
1057
|
}
|
|
404
|
-
async
|
|
1058
|
+
async searchBatch(c, s) {
|
|
405
1059
|
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
|
-
});
|
|
1060
|
+
return wasmSearchBatch(buildWasmContext(this.wasmModule, this.collections), c, s);
|
|
442
1061
|
}
|
|
443
|
-
async
|
|
1062
|
+
async textSearch(c, q, o) {
|
|
444
1063
|
this.ensureInitialized();
|
|
445
|
-
|
|
1064
|
+
return wasmTextSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
|
|
446
1065
|
}
|
|
447
|
-
async
|
|
1066
|
+
async hybridSearch(c, v, t, o) {
|
|
448
1067
|
this.ensureInitialized();
|
|
449
|
-
|
|
1068
|
+
return wasmHybridSearch(buildWasmContext(this.wasmModule, this.collections), c, v, t, o);
|
|
450
1069
|
}
|
|
451
|
-
async
|
|
1070
|
+
async query(c, q, p, o) {
|
|
452
1071
|
this.ensureInitialized();
|
|
453
|
-
|
|
454
|
-
if (!collection) {
|
|
455
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
456
|
-
}
|
|
457
|
-
return collection.store.is_empty();
|
|
1072
|
+
return wasmQuery(buildWasmContext(this.wasmModule, this.collections), c, q, p, o);
|
|
458
1073
|
}
|
|
459
|
-
async
|
|
1074
|
+
async multiQuerySearch(c, v, o) {
|
|
460
1075
|
this.ensureInitialized();
|
|
461
|
-
|
|
462
|
-
if (!collection) {
|
|
463
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
464
|
-
}
|
|
1076
|
+
return wasmMultiQuerySearch(buildWasmContext(this.wasmModule, this.collections), c, v, o);
|
|
465
1077
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
this.
|
|
471
|
-
|
|
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);
|
|
472
1084
|
}
|
|
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 };
|
|
1085
|
+
async collectionSanity(c) {
|
|
1086
|
+
this.ensureInitialized();
|
|
1087
|
+
return wasmCollectionSanity(c);
|
|
481
1088
|
}
|
|
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);
|
|
1089
|
+
async scroll(c, r) {
|
|
1090
|
+
this.ensureInitialized();
|
|
1091
|
+
return wasmScroll(c, r);
|
|
500
1092
|
}
|
|
501
|
-
|
|
502
|
-
// Index Management (EPIC-009) - Stubs for WASM backend
|
|
503
|
-
// Note: Full implementation requires velesdb-wasm support
|
|
504
|
-
// ========================================================================
|
|
505
|
-
async createIndex(_collection, _options) {
|
|
1093
|
+
async createIndex(c, o) {
|
|
506
1094
|
this.ensureInitialized();
|
|
507
|
-
|
|
508
|
-
"WasmBackend: createIndex is not yet supported. Index operations require the REST backend with velesdb-server."
|
|
509
|
-
);
|
|
1095
|
+
return wasmCreateIndex(c, o);
|
|
510
1096
|
}
|
|
511
|
-
async listIndexes(
|
|
1097
|
+
async listIndexes(c) {
|
|
512
1098
|
this.ensureInitialized();
|
|
513
|
-
return
|
|
1099
|
+
return wasmListIndexes(c);
|
|
514
1100
|
}
|
|
515
|
-
async hasIndex(
|
|
1101
|
+
async hasIndex(c, l, p) {
|
|
516
1102
|
this.ensureInitialized();
|
|
517
|
-
return
|
|
1103
|
+
return wasmHasIndex(c, l, p);
|
|
518
1104
|
}
|
|
519
|
-
async dropIndex(
|
|
1105
|
+
async dropIndex(c, l, p) {
|
|
520
1106
|
this.ensureInitialized();
|
|
521
|
-
return
|
|
1107
|
+
return wasmDropIndex(c, l, p);
|
|
522
1108
|
}
|
|
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) {
|
|
1109
|
+
async addEdge(c, e) {
|
|
528
1110
|
this.ensureInitialized();
|
|
529
|
-
|
|
1111
|
+
return wasmAddEdge(c, e);
|
|
530
1112
|
}
|
|
531
|
-
async getEdges(
|
|
1113
|
+
async getEdges(c, o) {
|
|
532
1114
|
this.ensureInitialized();
|
|
533
|
-
|
|
1115
|
+
return wasmGetEdges(c, o);
|
|
534
1116
|
}
|
|
535
|
-
async traverseGraph(
|
|
1117
|
+
async traverseGraph(c, r) {
|
|
536
1118
|
this.ensureInitialized();
|
|
537
|
-
|
|
1119
|
+
return wasmTraverseGraph(c, r);
|
|
538
1120
|
}
|
|
539
|
-
async
|
|
1121
|
+
async traverseParallel(c, r) {
|
|
540
1122
|
this.ensureInitialized();
|
|
541
|
-
|
|
1123
|
+
return wasmTraverseParallel(c, r);
|
|
542
1124
|
}
|
|
543
|
-
|
|
544
|
-
// Sparse / PQ / Streaming (v1.5)
|
|
545
|
-
// ========================================================================
|
|
546
|
-
async trainPq(_collection, _options) {
|
|
1125
|
+
async getNodeDegree(c, n) {
|
|
547
1126
|
this.ensureInitialized();
|
|
548
|
-
|
|
1127
|
+
return wasmGetNodeDegree(c, n);
|
|
549
1128
|
}
|
|
550
|
-
async
|
|
1129
|
+
async trainPq(c, o) {
|
|
551
1130
|
this.ensureInitialized();
|
|
552
|
-
|
|
1131
|
+
return wasmTrainPq(c, o);
|
|
553
1132
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
1133
|
+
async streamInsert(c, d) {
|
|
1134
|
+
this.ensureInitialized();
|
|
1135
|
+
return wasmStreamInsert(c, d);
|
|
1136
|
+
}
|
|
1137
|
+
async streamUpsertPoints(c, d) {
|
|
1138
|
+
this.ensureInitialized();
|
|
1139
|
+
return wasmStreamUpsertPoints(c, d);
|
|
1140
|
+
}
|
|
1141
|
+
async createGraphCollection(n, c) {
|
|
1142
|
+
this.ensureInitialized();
|
|
1143
|
+
return wasmCreateGraphCollection(n, c);
|
|
1144
|
+
}
|
|
1145
|
+
async getCollectionStats(c) {
|
|
1146
|
+
this.ensureInitialized();
|
|
1147
|
+
return wasmGetCollectionStats(c);
|
|
1148
|
+
}
|
|
1149
|
+
async analyzeCollection(c) {
|
|
1150
|
+
this.ensureInitialized();
|
|
1151
|
+
return wasmAnalyzeCollection(c);
|
|
1152
|
+
}
|
|
1153
|
+
async getCollectionConfig(c) {
|
|
1154
|
+
this.ensureInitialized();
|
|
1155
|
+
return wasmGetCollectionConfig(c);
|
|
1156
|
+
}
|
|
1157
|
+
async searchIds(c, q, o) {
|
|
1158
|
+
this.ensureInitialized();
|
|
1159
|
+
return wasmSearchIds(c, q, o);
|
|
1160
|
+
}
|
|
1161
|
+
async storeSemanticFact(c, e) {
|
|
558
1162
|
this.ensureInitialized();
|
|
559
|
-
|
|
1163
|
+
return wasmStoreSemanticFact(c, e);
|
|
560
1164
|
}
|
|
561
|
-
async
|
|
1165
|
+
async searchSemanticMemory(c, e, k) {
|
|
562
1166
|
this.ensureInitialized();
|
|
563
|
-
|
|
1167
|
+
return wasmSearchSemanticMemory(c, e, k);
|
|
564
1168
|
}
|
|
565
|
-
async
|
|
1169
|
+
async recordEpisodicEvent(c, e) {
|
|
566
1170
|
this.ensureInitialized();
|
|
567
|
-
|
|
1171
|
+
return wasmRecordEpisodicEvent(c, e);
|
|
568
1172
|
}
|
|
569
|
-
async
|
|
1173
|
+
async recallEpisodicEvents(c, e, k) {
|
|
570
1174
|
this.ensureInitialized();
|
|
571
|
-
|
|
1175
|
+
return wasmRecallEpisodicEvents(c, e, k);
|
|
572
1176
|
}
|
|
573
|
-
async
|
|
1177
|
+
async storeProceduralPattern(c, p) {
|
|
574
1178
|
this.ensureInitialized();
|
|
575
|
-
|
|
1179
|
+
return wasmStoreProceduralPattern(c, p);
|
|
576
1180
|
}
|
|
577
|
-
async
|
|
1181
|
+
async matchProceduralPatterns(c, e, k) {
|
|
578
1182
|
this.ensureInitialized();
|
|
579
|
-
|
|
1183
|
+
return wasmMatchProceduralPatterns(c, e, k);
|
|
580
1184
|
}
|
|
581
|
-
|
|
1185
|
+
// Wave 4 stubs
|
|
1186
|
+
async rebuildIndex(c) {
|
|
582
1187
|
this.ensureInitialized();
|
|
583
|
-
|
|
1188
|
+
return wasmRebuildIndex(c);
|
|
584
1189
|
}
|
|
585
|
-
async
|
|
1190
|
+
async getGuardrails() {
|
|
586
1191
|
this.ensureInitialized();
|
|
587
|
-
|
|
1192
|
+
return wasmGetGuardrails();
|
|
588
1193
|
}
|
|
589
|
-
async
|
|
1194
|
+
async updateGuardrails(r) {
|
|
590
1195
|
this.ensureInitialized();
|
|
591
|
-
|
|
1196
|
+
return wasmUpdateGuardrails(r);
|
|
592
1197
|
}
|
|
593
|
-
async
|
|
1198
|
+
async aggregate(_q, _p, _o) {
|
|
594
1199
|
this.ensureInitialized();
|
|
595
|
-
|
|
1200
|
+
return wasmAggregate(_q, _p, _o);
|
|
596
1201
|
}
|
|
597
|
-
async
|
|
1202
|
+
async matchQuery(c, q, p, o) {
|
|
598
1203
|
this.ensureInitialized();
|
|
599
|
-
|
|
1204
|
+
return wasmMatchQuery(c, q, p, o);
|
|
1205
|
+
}
|
|
1206
|
+
async removeEdge(c, id) {
|
|
1207
|
+
this.ensureInitialized();
|
|
1208
|
+
return wasmRemoveEdge(c, id);
|
|
1209
|
+
}
|
|
1210
|
+
async getEdgeCount(c) {
|
|
1211
|
+
this.ensureInitialized();
|
|
1212
|
+
return wasmGetEdgeCount(c);
|
|
1213
|
+
}
|
|
1214
|
+
async listNodes(c) {
|
|
1215
|
+
this.ensureInitialized();
|
|
1216
|
+
return wasmListNodes(c);
|
|
1217
|
+
}
|
|
1218
|
+
async getNodeEdges(c, id, o) {
|
|
1219
|
+
this.ensureInitialized();
|
|
1220
|
+
return wasmGetNodeEdges(c, id, o);
|
|
1221
|
+
}
|
|
1222
|
+
async getNodePayload(c, id) {
|
|
1223
|
+
this.ensureInitialized();
|
|
1224
|
+
return wasmGetNodePayload(c, id);
|
|
1225
|
+
}
|
|
1226
|
+
async upsertNodePayload(c, id, p) {
|
|
1227
|
+
this.ensureInitialized();
|
|
1228
|
+
return wasmUpsertNodePayload(c, id, p);
|
|
1229
|
+
}
|
|
1230
|
+
async graphSearch(c, r) {
|
|
1231
|
+
this.ensureInitialized();
|
|
1232
|
+
return wasmGraphSearch(c, r);
|
|
600
1233
|
}
|
|
601
1234
|
};
|
|
602
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}'`);
|
|
1625
|
+
}
|
|
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
|
+
}
|
|
1700
|
+
|
|
603
1701
|
// src/backends/agent-memory-backend.ts
|
|
604
1702
|
var _idCounter = 0;
|
|
605
1703
|
var _lastTimestamp = 0;
|
|
606
1704
|
function generateUniqueId() {
|
|
607
|
-
|
|
1705
|
+
const now = Date.now();
|
|
608
1706
|
if (now <= _lastTimestamp) {
|
|
609
1707
|
_idCounter++;
|
|
610
1708
|
if (_idCounter >= 1e3) {
|
|
@@ -685,14 +1783,23 @@ async function matchProceduralPatterns(transport, collection, embedding, k = 5)
|
|
|
685
1783
|
return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
|
|
686
1784
|
}
|
|
687
1785
|
|
|
1786
|
+
// src/search-quality.ts
|
|
1787
|
+
function searchQualityToMode(quality) {
|
|
1788
|
+
if (quality === void 0) {
|
|
1789
|
+
return {};
|
|
1790
|
+
}
|
|
1791
|
+
return { mode: quality };
|
|
1792
|
+
}
|
|
1793
|
+
|
|
688
1794
|
// src/backends/search-backend.ts
|
|
689
|
-
async function search(transport, collection,
|
|
690
|
-
const queryVector = toNumberArray(
|
|
1795
|
+
async function search(transport, collection, query3, options) {
|
|
1796
|
+
const queryVector = toNumberArray(query3);
|
|
691
1797
|
const body = {
|
|
692
1798
|
vector: queryVector,
|
|
693
1799
|
top_k: options?.k ?? 10,
|
|
694
1800
|
filter: options?.filter,
|
|
695
|
-
include_vectors: options?.includeVectors ?? false
|
|
1801
|
+
include_vectors: options?.includeVectors ?? false,
|
|
1802
|
+
...searchQualityToMode(options?.quality)
|
|
696
1803
|
};
|
|
697
1804
|
if (options?.sparseVector) {
|
|
698
1805
|
body.sparse_vector = transport.sparseToRest(options.sparseVector);
|
|
@@ -709,7 +1816,8 @@ async function searchBatch(transport, collection, searches) {
|
|
|
709
1816
|
const formattedSearches = searches.map((s) => ({
|
|
710
1817
|
vector: toNumberArray(s.vector),
|
|
711
1818
|
top_k: s.k ?? 10,
|
|
712
|
-
filter: s.filter
|
|
1819
|
+
filter: s.filter,
|
|
1820
|
+
...searchQualityToMode(s.quality)
|
|
713
1821
|
}));
|
|
714
1822
|
const response = await transport.requestJson(
|
|
715
1823
|
"POST",
|
|
@@ -719,12 +1827,12 @@ async function searchBatch(transport, collection, searches) {
|
|
|
719
1827
|
throwOnError(response, `Collection '${collection}'`);
|
|
720
1828
|
return response.data?.results.map((r) => r.results) ?? [];
|
|
721
1829
|
}
|
|
722
|
-
async function textSearch(transport, collection,
|
|
1830
|
+
async function textSearch(transport, collection, query3, options) {
|
|
723
1831
|
const response = await transport.requestJson(
|
|
724
1832
|
"POST",
|
|
725
1833
|
`${collectionPath(collection)}/search/text`,
|
|
726
1834
|
{
|
|
727
|
-
query:
|
|
1835
|
+
query: query3,
|
|
728
1836
|
top_k: options?.k ?? 10,
|
|
729
1837
|
filter: options?.filter
|
|
730
1838
|
}
|
|
@@ -767,15 +1875,16 @@ async function multiQuerySearch(transport, collection, vectors, options) {
|
|
|
767
1875
|
throwOnError(response, `Collection '${collection}'`);
|
|
768
1876
|
return response.data?.results ?? [];
|
|
769
1877
|
}
|
|
770
|
-
async function searchIds(transport, collection,
|
|
771
|
-
const queryVector = toNumberArray(
|
|
1878
|
+
async function searchIds(transport, collection, query3, options) {
|
|
1879
|
+
const queryVector = toNumberArray(query3);
|
|
772
1880
|
const response = await transport.requestJson(
|
|
773
1881
|
"POST",
|
|
774
1882
|
`${collectionPath(collection)}/search/ids`,
|
|
775
1883
|
{
|
|
776
1884
|
vector: queryVector,
|
|
777
1885
|
top_k: options?.k ?? 10,
|
|
778
|
-
filter: options?.filter
|
|
1886
|
+
filter: options?.filter,
|
|
1887
|
+
...searchQualityToMode(options?.quality)
|
|
779
1888
|
}
|
|
780
1889
|
);
|
|
781
1890
|
throwOnError(response, `Collection '${collection}'`);
|
|
@@ -797,6 +1906,16 @@ async function addEdge(transport, collection, edge) {
|
|
|
797
1906
|
);
|
|
798
1907
|
throwOnError(response, `Collection '${collection}'`);
|
|
799
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
|
+
}
|
|
800
1919
|
async function getEdges(transport, collection, options) {
|
|
801
1920
|
const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
|
|
802
1921
|
const response = await transport.requestJson(
|
|
@@ -804,19 +1923,19 @@ async function getEdges(transport, collection, options) {
|
|
|
804
1923
|
`${collectionPath(collection)}/graph/edges${queryParams}`
|
|
805
1924
|
);
|
|
806
1925
|
throwOnError(response, `Collection '${collection}'`);
|
|
807
|
-
return response.data?.edges ?? [];
|
|
1926
|
+
return (response.data?.edges ?? []).map(toGraphEdge);
|
|
808
1927
|
}
|
|
809
|
-
async function traverseGraph(transport, collection,
|
|
1928
|
+
async function traverseGraph(transport, collection, request2) {
|
|
810
1929
|
const response = await transport.requestJson(
|
|
811
1930
|
"POST",
|
|
812
1931
|
`${collectionPath(collection)}/graph/traverse`,
|
|
813
1932
|
{
|
|
814
|
-
source:
|
|
815
|
-
strategy:
|
|
816
|
-
max_depth:
|
|
817
|
-
limit:
|
|
818
|
-
cursor:
|
|
819
|
-
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 ?? []
|
|
820
1939
|
}
|
|
821
1940
|
);
|
|
822
1941
|
throwOnError(response, `Collection '${collection}'`);
|
|
@@ -856,6 +1975,33 @@ async function createGraphCollection(transport, name, config) {
|
|
|
856
1975
|
});
|
|
857
1976
|
throwOnError(response);
|
|
858
1977
|
}
|
|
1978
|
+
async function traverseParallel(transport, collection, request2) {
|
|
1979
|
+
const response = await transport.requestJson(
|
|
1980
|
+
"POST",
|
|
1981
|
+
`${collectionPath(collection)}/graph/traverse/parallel`,
|
|
1982
|
+
{
|
|
1983
|
+
sources: request2.sources,
|
|
1984
|
+
max_depth: request2.maxDepth ?? 3,
|
|
1985
|
+
limit: request2.limit ?? 100,
|
|
1986
|
+
rel_types: request2.relTypes ?? []
|
|
1987
|
+
}
|
|
1988
|
+
);
|
|
1989
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1990
|
+
const data = response.data;
|
|
1991
|
+
return {
|
|
1992
|
+
results: data.results.map((r) => ({
|
|
1993
|
+
targetId: r.target_id,
|
|
1994
|
+
depth: r.depth,
|
|
1995
|
+
path: r.path
|
|
1996
|
+
})),
|
|
1997
|
+
nextCursor: data.next_cursor ?? void 0,
|
|
1998
|
+
hasMore: data.has_more,
|
|
1999
|
+
stats: {
|
|
2000
|
+
visited: data.stats.visited,
|
|
2001
|
+
depthReached: data.stats.depth_reached
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
859
2005
|
|
|
860
2006
|
// src/backends/query-backend.ts
|
|
861
2007
|
function isLikelyAggregationQuery(queryString) {
|
|
@@ -900,14 +2046,18 @@ async function query(transport, collection, queryString, params, options) {
|
|
|
900
2046
|
}
|
|
901
2047
|
};
|
|
902
2048
|
}
|
|
903
|
-
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
|
+
}
|
|
904
2057
|
const response = await transport.requestJson(
|
|
905
2058
|
"POST",
|
|
906
2059
|
"/query/explain",
|
|
907
|
-
|
|
908
|
-
query: queryString,
|
|
909
|
-
params: params ?? {}
|
|
910
|
-
}
|
|
2060
|
+
body
|
|
911
2061
|
);
|
|
912
2062
|
throwOnError(response);
|
|
913
2063
|
const data = response.data;
|
|
@@ -919,7 +2069,8 @@ async function queryExplain(transport, queryString, params) {
|
|
|
919
2069
|
step: step.step,
|
|
920
2070
|
operation: step.operation,
|
|
921
2071
|
description: step.description,
|
|
922
|
-
estimatedRows: step.estimated_rows
|
|
2072
|
+
estimatedRows: step.estimated_rows,
|
|
2073
|
+
estimationMethod: step.estimation_method ?? null
|
|
923
2074
|
})),
|
|
924
2075
|
estimatedCost: {
|
|
925
2076
|
usesIndex: data.estimated_cost.uses_index,
|
|
@@ -937,7 +2088,22 @@ async function queryExplain(transport, queryString, params) {
|
|
|
937
2088
|
hasFusion: data.features.has_fusion,
|
|
938
2089
|
limit: data.features.limit,
|
|
939
2090
|
offset: data.features.offset
|
|
940
|
-
}
|
|
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
|
|
941
2107
|
};
|
|
942
2108
|
}
|
|
943
2109
|
async function collectionSanity(transport, collection) {
|
|
@@ -968,8 +2134,49 @@ async function collectionSanity(transport, collection) {
|
|
|
968
2134
|
};
|
|
969
2135
|
}
|
|
970
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
|
+
|
|
971
2162
|
// src/backends/admin-backend.ts
|
|
972
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
|
+
}
|
|
973
2180
|
return {
|
|
974
2181
|
totalPoints: data.total_points,
|
|
975
2182
|
totalSizeBytes: data.total_size_bytes,
|
|
@@ -977,7 +2184,8 @@ function mapStatsResponse(data) {
|
|
|
977
2184
|
deletedCount: data.deleted_count,
|
|
978
2185
|
avgRowSizeBytes: data.avg_row_size_bytes,
|
|
979
2186
|
payloadSizeBytes: data.payload_size_bytes,
|
|
980
|
-
lastAnalyzedEpochMs: data.last_analyzed_epoch_ms
|
|
2187
|
+
lastAnalyzedEpochMs: data.last_analyzed_epoch_ms,
|
|
2188
|
+
columnStats
|
|
981
2189
|
};
|
|
982
2190
|
}
|
|
983
2191
|
async function getCollectionStats(transport, collection) {
|
|
@@ -998,10 +2206,7 @@ async function analyzeCollection(transport, collection) {
|
|
|
998
2206
|
throwOnError(response, `Collection '${collection}'`);
|
|
999
2207
|
return mapStatsResponse(response.data);
|
|
1000
2208
|
}
|
|
1001
|
-
|
|
1002
|
-
const response = await transport.requestJson("GET", `${collectionPath(collection)}/config`);
|
|
1003
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1004
|
-
const data = response.data;
|
|
2209
|
+
function mapConfigResponse(data) {
|
|
1005
2210
|
return {
|
|
1006
2211
|
name: data.name,
|
|
1007
2212
|
dimension: data.dimension,
|
|
@@ -1010,9 +2215,22 @@ async function getCollectionConfig(transport, collection) {
|
|
|
1010
2215
|
pointCount: data.point_count,
|
|
1011
2216
|
metadataOnly: data.metadata_only,
|
|
1012
2217
|
graphSchema: data.graph_schema,
|
|
1013
|
-
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
|
|
1014
2224
|
};
|
|
1015
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
|
+
}
|
|
1016
2234
|
|
|
1017
2235
|
// src/backends/index-backend.ts
|
|
1018
2236
|
async function createIndex(transport, collection, options) {
|
|
@@ -1047,218 +2265,170 @@ async function hasIndex(transport, collection, label, property) {
|
|
|
1047
2265
|
}
|
|
1048
2266
|
async function dropIndex(transport, collection, label, property) {
|
|
1049
2267
|
const response = await transport.requestJson(
|
|
1050
|
-
"DELETE",
|
|
1051
|
-
`${collectionPath(collection)}/indexes/${encodeURIComponent(label)}/${encodeURIComponent(property)}`
|
|
1052
|
-
);
|
|
1053
|
-
if (returnNullOnNotFound(response)) {
|
|
1054
|
-
return false;
|
|
1055
|
-
}
|
|
1056
|
-
return response.data?.dropped ?? true;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// src/backends/streaming-backend.ts
|
|
1060
|
-
async function trainPq(transport, collection, options) {
|
|
1061
|
-
const m = options?.m ?? 8;
|
|
1062
|
-
const k = options?.k ?? 256;
|
|
1063
|
-
const withClause = options?.opq ? `WITH (m=${m}, k=${k}, opq=true)` : `WITH (m=${m}, k=${k})`;
|
|
1064
|
-
const queryString = `TRAIN QUANTIZER ON ${collection} ${withClause}`;
|
|
1065
|
-
const response = await transport.requestJson(
|
|
1066
|
-
"POST",
|
|
1067
|
-
"/query",
|
|
1068
|
-
{ query: queryString }
|
|
1069
|
-
);
|
|
1070
|
-
throwOnError(response);
|
|
1071
|
-
return response.data?.message ?? "PQ training initiated";
|
|
1072
|
-
}
|
|
1073
|
-
async function streamInsert(transport, collection, docs) {
|
|
1074
|
-
for (const doc of docs) {
|
|
1075
|
-
const restId = transport.parseRestPointId(doc.id);
|
|
1076
|
-
const vector = toNumberArray(doc.vector);
|
|
1077
|
-
const body = {
|
|
1078
|
-
id: restId,
|
|
1079
|
-
vector,
|
|
1080
|
-
payload: doc.payload
|
|
1081
|
-
};
|
|
1082
|
-
if (doc.sparseVector) {
|
|
1083
|
-
body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
|
|
1084
|
-
}
|
|
1085
|
-
const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
|
|
1086
|
-
const headers = {
|
|
1087
|
-
"Content-Type": "application/json"
|
|
1088
|
-
};
|
|
1089
|
-
if (transport.apiKey) {
|
|
1090
|
-
headers["Authorization"] = `Bearer ${transport.apiKey}`;
|
|
1091
|
-
}
|
|
1092
|
-
const controller = new AbortController();
|
|
1093
|
-
const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
|
|
1094
|
-
try {
|
|
1095
|
-
const response = await fetch(url, {
|
|
1096
|
-
method: "POST",
|
|
1097
|
-
headers,
|
|
1098
|
-
body: JSON.stringify(body),
|
|
1099
|
-
signal: controller.signal
|
|
1100
|
-
});
|
|
1101
|
-
clearTimeout(timeoutId);
|
|
1102
|
-
if (response.status === 429) {
|
|
1103
|
-
throw new BackpressureError();
|
|
1104
|
-
}
|
|
1105
|
-
if (!response.ok && response.status !== 202) {
|
|
1106
|
-
const data = await response.json().catch(() => ({}));
|
|
1107
|
-
const errorPayload = transport.extractErrorPayload(data);
|
|
1108
|
-
throw new VelesDBError(
|
|
1109
|
-
errorPayload.message ?? `HTTP ${response.status}`,
|
|
1110
|
-
errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
|
|
1111
|
-
);
|
|
1112
|
-
}
|
|
1113
|
-
} catch (error) {
|
|
1114
|
-
clearTimeout(timeoutId);
|
|
1115
|
-
if (error instanceof BackpressureError || error instanceof VelesDBError) {
|
|
1116
|
-
throw error;
|
|
1117
|
-
}
|
|
1118
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1119
|
-
throw new ConnectionError("Request timeout");
|
|
1120
|
-
}
|
|
1121
|
-
throw new ConnectionError(
|
|
1122
|
-
`Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1123
|
-
error instanceof Error ? error : void 0
|
|
1124
|
-
);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
// src/backends/crud-backend.ts
|
|
1130
|
-
function parseRestPointId(id) {
|
|
1131
|
-
if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
|
|
1132
|
-
throw new ValidationError(
|
|
1133
|
-
`REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
|
|
1134
|
-
);
|
|
1135
|
-
}
|
|
1136
|
-
return id;
|
|
1137
|
-
}
|
|
1138
|
-
function sparseVectorToRestFormat(sv) {
|
|
1139
|
-
const result = {};
|
|
1140
|
-
for (const [k, v] of Object.entries(sv)) {
|
|
1141
|
-
result[String(k)] = v;
|
|
1142
|
-
}
|
|
1143
|
-
return result;
|
|
1144
|
-
}
|
|
1145
|
-
async function createCollection(transport, name, config) {
|
|
1146
|
-
const response = await transport.requestJson("POST", "/collections", {
|
|
1147
|
-
name,
|
|
1148
|
-
dimension: config.dimension,
|
|
1149
|
-
metric: config.metric ?? "cosine",
|
|
1150
|
-
storage_mode: config.storageMode ?? "full",
|
|
1151
|
-
collection_type: config.collectionType ?? "vector",
|
|
1152
|
-
description: config.description,
|
|
1153
|
-
hnsw_m: config.hnsw?.m,
|
|
1154
|
-
hnsw_ef_construction: config.hnsw?.efConstruction
|
|
1155
|
-
});
|
|
1156
|
-
throwOnError(response);
|
|
1157
|
-
}
|
|
1158
|
-
async function deleteCollection(transport, name) {
|
|
1159
|
-
const response = await transport.requestJson(
|
|
1160
|
-
"DELETE",
|
|
1161
|
-
collectionPath(name)
|
|
1162
|
-
);
|
|
1163
|
-
throwOnError(response, `Collection '${name}'`);
|
|
1164
|
-
}
|
|
1165
|
-
async function getCollection(transport, name) {
|
|
1166
|
-
const response = await transport.requestJson(
|
|
1167
|
-
"GET",
|
|
1168
|
-
collectionPath(name)
|
|
1169
|
-
);
|
|
1170
|
-
if (returnNullOnNotFound(response)) {
|
|
1171
|
-
return null;
|
|
1172
|
-
}
|
|
1173
|
-
return response.data ?? null;
|
|
1174
|
-
}
|
|
1175
|
-
async function listCollections(transport) {
|
|
1176
|
-
const response = await transport.requestJson("GET", "/collections");
|
|
1177
|
-
throwOnError(response);
|
|
1178
|
-
return response.data ?? [];
|
|
1179
|
-
}
|
|
1180
|
-
async function insert(transport, collection, doc) {
|
|
1181
|
-
const restId = parseRestPointId(doc.id);
|
|
1182
|
-
const vector = toNumberArray(doc.vector);
|
|
1183
|
-
const response = await transport.requestJson(
|
|
1184
|
-
"POST",
|
|
1185
|
-
`${collectionPath(collection)}/points`,
|
|
1186
|
-
{ points: [{ id: restId, vector, payload: doc.payload }] }
|
|
1187
|
-
);
|
|
1188
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1189
|
-
}
|
|
1190
|
-
async function insertBatch(transport, collection, docs) {
|
|
1191
|
-
const vectors = docs.map((doc) => ({
|
|
1192
|
-
id: parseRestPointId(doc.id),
|
|
1193
|
-
vector: toNumberArray(doc.vector),
|
|
1194
|
-
payload: doc.payload
|
|
1195
|
-
}));
|
|
1196
|
-
const response = await transport.requestJson(
|
|
1197
|
-
"POST",
|
|
1198
|
-
`${collectionPath(collection)}/points`,
|
|
1199
|
-
{ points: vectors }
|
|
1200
|
-
);
|
|
1201
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1202
|
-
}
|
|
1203
|
-
async function deletePoint(transport, collection, id) {
|
|
1204
|
-
const restId = parseRestPointId(id);
|
|
1205
|
-
const response = await transport.requestJson(
|
|
1206
|
-
"DELETE",
|
|
1207
|
-
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1208
|
-
);
|
|
1209
|
-
if (returnNullOnNotFound(response)) {
|
|
1210
|
-
return false;
|
|
1211
|
-
}
|
|
1212
|
-
return response.data?.deleted ?? false;
|
|
1213
|
-
}
|
|
1214
|
-
async function get(transport, collection, id) {
|
|
1215
|
-
const restId = parseRestPointId(id);
|
|
1216
|
-
const response = await transport.requestJson(
|
|
1217
|
-
"GET",
|
|
1218
|
-
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
2268
|
+
"DELETE",
|
|
2269
|
+
`${collectionPath(collection)}/indexes/${encodeURIComponent(label)}/${encodeURIComponent(property)}`
|
|
1219
2270
|
);
|
|
1220
2271
|
if (returnNullOnNotFound(response)) {
|
|
1221
|
-
return
|
|
2272
|
+
return false;
|
|
1222
2273
|
}
|
|
1223
|
-
return response.data ??
|
|
1224
|
-
}
|
|
1225
|
-
async function isEmpty(transport, collection) {
|
|
1226
|
-
const response = await transport.requestJson(
|
|
1227
|
-
"GET",
|
|
1228
|
-
`${collectionPath(collection)}/empty`
|
|
1229
|
-
);
|
|
1230
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
1231
|
-
return response.data?.is_empty ?? true;
|
|
2274
|
+
return response.data?.dropped ?? true;
|
|
1232
2275
|
}
|
|
1233
|
-
|
|
2276
|
+
|
|
2277
|
+
// src/backends/streaming-backend.ts
|
|
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}`;
|
|
1234
2284
|
const response = await transport.requestJson(
|
|
1235
2285
|
"POST",
|
|
1236
|
-
|
|
2286
|
+
"/query",
|
|
2287
|
+
{ query: queryString }
|
|
1237
2288
|
);
|
|
1238
|
-
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
|
+
}
|
|
1239
2411
|
}
|
|
1240
2412
|
|
|
1241
2413
|
// src/backends/rest.ts
|
|
1242
2414
|
var RestBackend = class {
|
|
1243
2415
|
constructor(url, apiKey, timeout = 3e4) {
|
|
1244
2416
|
this._initialized = false;
|
|
1245
|
-
this.
|
|
1246
|
-
this.apiKey = apiKey;
|
|
1247
|
-
this.timeout = timeout;
|
|
2417
|
+
this.httpConfig = { baseUrl: url.replace(/\/$/, ""), apiKey, timeout };
|
|
1248
2418
|
}
|
|
1249
2419
|
async init() {
|
|
1250
2420
|
if (this._initialized) {
|
|
1251
2421
|
return;
|
|
1252
2422
|
}
|
|
1253
2423
|
try {
|
|
1254
|
-
const response = await this.
|
|
2424
|
+
const response = await request(this.httpConfig, "GET", "/health");
|
|
1255
2425
|
if (response.error) {
|
|
1256
2426
|
throw new Error(response.error.message);
|
|
1257
2427
|
}
|
|
1258
2428
|
this._initialized = true;
|
|
1259
2429
|
} catch (error) {
|
|
1260
2430
|
throw new ConnectionError(
|
|
1261
|
-
`Failed to connect to VelesDB server at ${this.baseUrl}`,
|
|
2431
|
+
`Failed to connect to VelesDB server at ${this.httpConfig.baseUrl}`,
|
|
1262
2432
|
error instanceof Error ? error : void 0
|
|
1263
2433
|
);
|
|
1264
2434
|
}
|
|
@@ -1266,316 +2436,242 @@ var RestBackend = class {
|
|
|
1266
2436
|
isInitialized() {
|
|
1267
2437
|
return this._initialized;
|
|
1268
2438
|
}
|
|
2439
|
+
capabilities() {
|
|
2440
|
+
return REST_CAPABILITIES;
|
|
2441
|
+
}
|
|
2442
|
+
async close() {
|
|
2443
|
+
this._initialized = false;
|
|
2444
|
+
}
|
|
1269
2445
|
ensureInitialized() {
|
|
1270
2446
|
if (!this._initialized) {
|
|
1271
2447
|
throw new ConnectionError("REST backend not initialized");
|
|
1272
2448
|
}
|
|
1273
2449
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
case 401:
|
|
1279
|
-
return "UNAUTHORIZED";
|
|
1280
|
-
case 403:
|
|
1281
|
-
return "FORBIDDEN";
|
|
1282
|
-
case 404:
|
|
1283
|
-
return "NOT_FOUND";
|
|
1284
|
-
case 409:
|
|
1285
|
-
return "CONFLICT";
|
|
1286
|
-
case 429:
|
|
1287
|
-
return "RATE_LIMITED";
|
|
1288
|
-
case 500:
|
|
1289
|
-
return "INTERNAL_ERROR";
|
|
1290
|
-
case 503:
|
|
1291
|
-
return "SERVICE_UNAVAILABLE";
|
|
1292
|
-
default:
|
|
1293
|
-
return "UNKNOWN_ERROR";
|
|
1294
|
-
}
|
|
2450
|
+
// Collection CRUD
|
|
2451
|
+
async createCollection(n, c) {
|
|
2452
|
+
this.ensureInitialized();
|
|
2453
|
+
return createCollection(buildCrudTransport(this.httpConfig), n, c);
|
|
1295
2454
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
}
|
|
1300
|
-
const payload = data;
|
|
1301
|
-
const nestedError = payload.error && typeof payload.error === "object" ? payload.error : void 0;
|
|
1302
|
-
const codeField = nestedError?.code ?? payload.code;
|
|
1303
|
-
const code = typeof codeField === "string" ? codeField : void 0;
|
|
1304
|
-
const messageField = nestedError?.message ?? payload.message ?? payload.error;
|
|
1305
|
-
const message = typeof messageField === "string" ? messageField : void 0;
|
|
1306
|
-
return { code, message };
|
|
2455
|
+
async deleteCollection(n) {
|
|
2456
|
+
this.ensureInitialized();
|
|
2457
|
+
return deleteCollection(buildCrudTransport(this.httpConfig), n);
|
|
1307
2458
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
}
|
|
1312
|
-
if (typeof value === "bigint") {
|
|
1313
|
-
return value;
|
|
1314
|
-
}
|
|
1315
|
-
if (typeof value === "string") {
|
|
1316
|
-
const num = Number(value);
|
|
1317
|
-
return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
|
|
1318
|
-
}
|
|
1319
|
-
if (typeof value === "number") {
|
|
1320
|
-
return value;
|
|
1321
|
-
}
|
|
1322
|
-
return 0;
|
|
2459
|
+
async getCollection(n) {
|
|
2460
|
+
this.ensureInitialized();
|
|
2461
|
+
return getCollection(buildCrudTransport(this.httpConfig), n);
|
|
1323
2462
|
}
|
|
1324
|
-
async
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
if (this.apiKey) {
|
|
1328
|
-
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
1329
|
-
}
|
|
1330
|
-
const controller = new AbortController();
|
|
1331
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1332
|
-
try {
|
|
1333
|
-
const response = await fetch(url, {
|
|
1334
|
-
method,
|
|
1335
|
-
headers,
|
|
1336
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
1337
|
-
signal: controller.signal
|
|
1338
|
-
});
|
|
1339
|
-
clearTimeout(timeoutId);
|
|
1340
|
-
const data = await response.json().catch(() => ({}));
|
|
1341
|
-
if (!response.ok) {
|
|
1342
|
-
const errorPayload = this.extractErrorPayload(data);
|
|
1343
|
-
return {
|
|
1344
|
-
error: {
|
|
1345
|
-
code: errorPayload.code ?? this.mapStatusToErrorCode(response.status),
|
|
1346
|
-
message: errorPayload.message ?? `HTTP ${response.status}`
|
|
1347
|
-
}
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
return { data };
|
|
1351
|
-
} catch (error) {
|
|
1352
|
-
clearTimeout(timeoutId);
|
|
1353
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1354
|
-
throw new ConnectionError("Request timeout");
|
|
1355
|
-
}
|
|
1356
|
-
throw new ConnectionError(
|
|
1357
|
-
`Request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1358
|
-
error instanceof Error ? error : void 0
|
|
1359
|
-
);
|
|
1360
|
-
}
|
|
2463
|
+
async listCollections() {
|
|
2464
|
+
this.ensureInitialized();
|
|
2465
|
+
return listCollections(buildCrudTransport(this.httpConfig));
|
|
1361
2466
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
asCrudTransport() {
|
|
1366
|
-
return {
|
|
1367
|
-
requestJson: (m, p, b) => this.request(m, p, b)
|
|
1368
|
-
};
|
|
2467
|
+
async upsert(c, d) {
|
|
2468
|
+
this.ensureInitialized();
|
|
2469
|
+
return upsert(buildCrudTransport(this.httpConfig), c, d);
|
|
1369
2470
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
sparseToRest: (sv) => sparseVectorToRestFormat(sv)
|
|
1374
|
-
};
|
|
2471
|
+
async upsertBatch(c, d) {
|
|
2472
|
+
this.ensureInitialized();
|
|
2473
|
+
return upsertBatch(buildCrudTransport(this.httpConfig), c, d);
|
|
1375
2474
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
searchVectors: (c, e, k, f) => this.search(c, e, { k, filter: f })
|
|
1380
|
-
};
|
|
2475
|
+
async delete(c, id) {
|
|
2476
|
+
this.ensureInitialized();
|
|
2477
|
+
return deletePoint(buildCrudTransport(this.httpConfig), c, id);
|
|
1381
2478
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
parseNodeId: (v) => this.parseNodeId(v)
|
|
1386
|
-
};
|
|
2479
|
+
async get(c, id) {
|
|
2480
|
+
this.ensureInitialized();
|
|
2481
|
+
return get(buildCrudTransport(this.httpConfig), c, id);
|
|
1387
2482
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
baseUrl: this.baseUrl,
|
|
1392
|
-
apiKey: this.apiKey,
|
|
1393
|
-
timeout: this.timeout,
|
|
1394
|
-
parseRestPointId,
|
|
1395
|
-
sparseVectorToRestFormat,
|
|
1396
|
-
mapStatusToErrorCode: (s) => this.mapStatusToErrorCode(s),
|
|
1397
|
-
extractErrorPayload: (d) => this.extractErrorPayload(d)
|
|
1398
|
-
};
|
|
2483
|
+
async isEmpty(c) {
|
|
2484
|
+
this.ensureInitialized();
|
|
2485
|
+
return isEmpty(buildCrudTransport(this.httpConfig), c);
|
|
1399
2486
|
}
|
|
1400
|
-
|
|
1401
|
-
// Collection CRUD — delegates to crud-backend.ts
|
|
1402
|
-
// ==========================================================================
|
|
1403
|
-
async createCollection(name, config) {
|
|
2487
|
+
async flush(c) {
|
|
1404
2488
|
this.ensureInitialized();
|
|
1405
|
-
return
|
|
2489
|
+
return flush(buildCrudTransport(this.httpConfig), c);
|
|
1406
2490
|
}
|
|
1407
|
-
|
|
2491
|
+
// Additional REST endpoints (Sprint 2 Wave 4)
|
|
2492
|
+
async rebuildIndex(c) {
|
|
1408
2493
|
this.ensureInitialized();
|
|
1409
|
-
return
|
|
2494
|
+
return rebuildIndex(buildBaseTransport(this.httpConfig), c);
|
|
1410
2495
|
}
|
|
1411
|
-
async
|
|
2496
|
+
async getGuardrails() {
|
|
1412
2497
|
this.ensureInitialized();
|
|
1413
|
-
return
|
|
2498
|
+
return getGuardrails(buildBaseTransport(this.httpConfig));
|
|
1414
2499
|
}
|
|
1415
|
-
async
|
|
2500
|
+
async updateGuardrails(r) {
|
|
1416
2501
|
this.ensureInitialized();
|
|
1417
|
-
return
|
|
2502
|
+
return updateGuardrails(buildBaseTransport(this.httpConfig), r);
|
|
1418
2503
|
}
|
|
1419
|
-
async
|
|
2504
|
+
async aggregate(q, p, o) {
|
|
1420
2505
|
this.ensureInitialized();
|
|
1421
|
-
return
|
|
2506
|
+
return aggregate(buildBaseTransport(this.httpConfig), q, p, o);
|
|
1422
2507
|
}
|
|
1423
|
-
async
|
|
2508
|
+
async matchQuery(c, q, p, o) {
|
|
1424
2509
|
this.ensureInitialized();
|
|
1425
|
-
return
|
|
2510
|
+
return matchQuery(buildBaseTransport(this.httpConfig), c, q, p, o);
|
|
1426
2511
|
}
|
|
1427
|
-
async
|
|
2512
|
+
async removeEdge(c, id) {
|
|
1428
2513
|
this.ensureInitialized();
|
|
1429
|
-
return
|
|
2514
|
+
return removeEdge(buildBaseTransport(this.httpConfig), c, id);
|
|
1430
2515
|
}
|
|
1431
|
-
async
|
|
2516
|
+
async getEdgeCount(c) {
|
|
1432
2517
|
this.ensureInitialized();
|
|
1433
|
-
return
|
|
2518
|
+
return getEdgeCount(buildBaseTransport(this.httpConfig), c);
|
|
1434
2519
|
}
|
|
1435
|
-
async
|
|
2520
|
+
async listNodes(c) {
|
|
1436
2521
|
this.ensureInitialized();
|
|
1437
|
-
return
|
|
2522
|
+
return listNodes(buildBaseTransport(this.httpConfig), c);
|
|
1438
2523
|
}
|
|
1439
|
-
async
|
|
2524
|
+
async getNodeEdges(c, id, o) {
|
|
1440
2525
|
this.ensureInitialized();
|
|
1441
|
-
return
|
|
2526
|
+
return getNodeEdges(buildBaseTransport(this.httpConfig), c, id, o);
|
|
1442
2527
|
}
|
|
1443
|
-
async
|
|
1444
|
-
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);
|
|
1445
2535
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
2536
|
+
async graphSearch(c, r) {
|
|
2537
|
+
this.ensureInitialized();
|
|
2538
|
+
return graphSearch(buildBaseTransport(this.httpConfig), c, r);
|
|
2539
|
+
}
|
|
2540
|
+
// Search
|
|
1449
2541
|
async search(c, q, o) {
|
|
1450
2542
|
this.ensureInitialized();
|
|
1451
|
-
return search(this.
|
|
2543
|
+
return search(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1452
2544
|
}
|
|
1453
|
-
async searchBatch(
|
|
2545
|
+
async searchBatch(c, s) {
|
|
1454
2546
|
this.ensureInitialized();
|
|
1455
|
-
return searchBatch(this.
|
|
2547
|
+
return searchBatch(buildSearchTransport(this.httpConfig), c, s);
|
|
1456
2548
|
}
|
|
1457
2549
|
async textSearch(c, q, o) {
|
|
1458
2550
|
this.ensureInitialized();
|
|
1459
|
-
return textSearch(this.
|
|
2551
|
+
return textSearch(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1460
2552
|
}
|
|
1461
2553
|
async hybridSearch(c, v, t, o) {
|
|
1462
2554
|
this.ensureInitialized();
|
|
1463
|
-
return hybridSearch(this.
|
|
2555
|
+
return hybridSearch(buildSearchTransport(this.httpConfig), c, v, t, o);
|
|
1464
2556
|
}
|
|
1465
2557
|
async multiQuerySearch(c, v, o) {
|
|
1466
2558
|
this.ensureInitialized();
|
|
1467
|
-
return multiQuerySearch(this.
|
|
2559
|
+
return multiQuerySearch(buildSearchTransport(this.httpConfig), c, v, o);
|
|
1468
2560
|
}
|
|
1469
2561
|
async searchIds(c, q, o) {
|
|
1470
2562
|
this.ensureInitialized();
|
|
1471
|
-
return searchIds(this.
|
|
2563
|
+
return searchIds(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1472
2564
|
}
|
|
1473
|
-
//
|
|
1474
|
-
// Query — delegates to query-backend.ts
|
|
1475
|
-
// ==========================================================================
|
|
2565
|
+
// Query
|
|
1476
2566
|
async query(c, q, p, o) {
|
|
1477
2567
|
this.ensureInitialized();
|
|
1478
|
-
return query(this.
|
|
2568
|
+
return query(buildQueryTransport(this.httpConfig), c, q, p, o);
|
|
1479
2569
|
}
|
|
1480
|
-
async queryExplain(q, p) {
|
|
2570
|
+
async queryExplain(q, p, o) {
|
|
1481
2571
|
this.ensureInitialized();
|
|
1482
|
-
return queryExplain(this.
|
|
2572
|
+
return queryExplain(buildQueryTransport(this.httpConfig), q, p, o);
|
|
1483
2573
|
}
|
|
1484
|
-
async collectionSanity(
|
|
2574
|
+
async collectionSanity(c) {
|
|
1485
2575
|
this.ensureInitialized();
|
|
1486
|
-
return collectionSanity(this.
|
|
2576
|
+
return collectionSanity(buildQueryTransport(this.httpConfig), c);
|
|
1487
2577
|
}
|
|
1488
|
-
//
|
|
1489
|
-
|
|
1490
|
-
// ==========================================================================
|
|
1491
|
-
async addEdge(collection, edge) {
|
|
2578
|
+
// Scroll
|
|
2579
|
+
async scroll(c, r) {
|
|
1492
2580
|
this.ensureInitialized();
|
|
1493
|
-
return
|
|
2581
|
+
return scroll(buildCrudTransport(this.httpConfig), c, r);
|
|
1494
2582
|
}
|
|
1495
|
-
|
|
2583
|
+
// Graph
|
|
2584
|
+
async addEdge(c, e) {
|
|
1496
2585
|
this.ensureInitialized();
|
|
1497
|
-
return
|
|
2586
|
+
return addEdge(buildCrudTransport(this.httpConfig), c, e);
|
|
1498
2587
|
}
|
|
1499
|
-
async
|
|
2588
|
+
async getEdges(c, o) {
|
|
1500
2589
|
this.ensureInitialized();
|
|
1501
|
-
return
|
|
2590
|
+
return getEdges(buildCrudTransport(this.httpConfig), c, o);
|
|
1502
2591
|
}
|
|
1503
|
-
async
|
|
2592
|
+
async traverseGraph(c, r) {
|
|
1504
2593
|
this.ensureInitialized();
|
|
1505
|
-
return
|
|
2594
|
+
return traverseGraph(buildCrudTransport(this.httpConfig), c, r);
|
|
1506
2595
|
}
|
|
1507
|
-
async
|
|
2596
|
+
async traverseParallel(c, r) {
|
|
1508
2597
|
this.ensureInitialized();
|
|
1509
|
-
return
|
|
2598
|
+
return traverseParallel(buildCrudTransport(this.httpConfig), c, r);
|
|
1510
2599
|
}
|
|
1511
|
-
|
|
1512
|
-
// Index — delegates to index-backend.ts
|
|
1513
|
-
// ==========================================================================
|
|
1514
|
-
async createIndex(collection, options) {
|
|
2600
|
+
async getNodeDegree(c, id) {
|
|
1515
2601
|
this.ensureInitialized();
|
|
1516
|
-
return
|
|
2602
|
+
return getNodeDegree(buildCrudTransport(this.httpConfig), c, id);
|
|
1517
2603
|
}
|
|
1518
|
-
async
|
|
2604
|
+
async createGraphCollection(n, c) {
|
|
1519
2605
|
this.ensureInitialized();
|
|
1520
|
-
return
|
|
2606
|
+
return createGraphCollection(buildCrudTransport(this.httpConfig), n, c);
|
|
1521
2607
|
}
|
|
1522
|
-
|
|
2608
|
+
// Index
|
|
2609
|
+
async createIndex(c, o) {
|
|
1523
2610
|
this.ensureInitialized();
|
|
1524
|
-
return
|
|
2611
|
+
return createIndex(buildCrudTransport(this.httpConfig), c, o);
|
|
1525
2612
|
}
|
|
1526
|
-
async
|
|
2613
|
+
async listIndexes(c) {
|
|
1527
2614
|
this.ensureInitialized();
|
|
1528
|
-
return
|
|
2615
|
+
return listIndexes(buildCrudTransport(this.httpConfig), c);
|
|
1529
2616
|
}
|
|
1530
|
-
|
|
1531
|
-
// Admin — delegates to admin-backend.ts
|
|
1532
|
-
// ==========================================================================
|
|
1533
|
-
async getCollectionStats(collection) {
|
|
2617
|
+
async hasIndex(c, l, p) {
|
|
1534
2618
|
this.ensureInitialized();
|
|
1535
|
-
return
|
|
2619
|
+
return hasIndex(buildCrudTransport(this.httpConfig), c, l, p);
|
|
1536
2620
|
}
|
|
1537
|
-
async
|
|
2621
|
+
async dropIndex(c, l, p) {
|
|
1538
2622
|
this.ensureInitialized();
|
|
1539
|
-
return
|
|
2623
|
+
return dropIndex(buildCrudTransport(this.httpConfig), c, l, p);
|
|
1540
2624
|
}
|
|
1541
|
-
|
|
2625
|
+
// Admin
|
|
2626
|
+
async getCollectionStats(c) {
|
|
1542
2627
|
this.ensureInitialized();
|
|
1543
|
-
return
|
|
2628
|
+
return getCollectionStats(buildCrudTransport(this.httpConfig), c);
|
|
1544
2629
|
}
|
|
1545
|
-
|
|
1546
|
-
// Streaming / PQ — delegates to streaming-backend.ts
|
|
1547
|
-
// ==========================================================================
|
|
1548
|
-
async trainPq(collection, options) {
|
|
2630
|
+
async analyzeCollection(c) {
|
|
1549
2631
|
this.ensureInitialized();
|
|
1550
|
-
return
|
|
2632
|
+
return analyzeCollection(buildCrudTransport(this.httpConfig), c);
|
|
1551
2633
|
}
|
|
1552
|
-
async
|
|
2634
|
+
async getCollectionConfig(c) {
|
|
2635
|
+
this.ensureInitialized();
|
|
2636
|
+
return getCollectionConfig(buildCrudTransport(this.httpConfig), c);
|
|
2637
|
+
}
|
|
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) {
|
|
2644
|
+
this.ensureInitialized();
|
|
2645
|
+
return streamInsert(buildStreamingTransport(this.httpConfig), c, d);
|
|
2646
|
+
}
|
|
2647
|
+
async streamUpsertPoints(c, d) {
|
|
1553
2648
|
this.ensureInitialized();
|
|
1554
|
-
return
|
|
2649
|
+
return streamUpsertPoints(buildStreamingTransport(this.httpConfig), c, d);
|
|
1555
2650
|
}
|
|
1556
|
-
//
|
|
1557
|
-
|
|
1558
|
-
// ==========================================================================
|
|
1559
|
-
async storeSemanticFact(collection, entry) {
|
|
2651
|
+
// Agent Memory
|
|
2652
|
+
async storeSemanticFact(c, e) {
|
|
1560
2653
|
this.ensureInitialized();
|
|
1561
|
-
return storeSemanticFact(this.
|
|
2654
|
+
return storeSemanticFact(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
|
|
1562
2655
|
}
|
|
1563
|
-
async searchSemanticMemory(
|
|
1564
|
-
|
|
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);
|
|
1565
2659
|
}
|
|
1566
|
-
async recordEpisodicEvent(
|
|
2660
|
+
async recordEpisodicEvent(c, e) {
|
|
1567
2661
|
this.ensureInitialized();
|
|
1568
|
-
return recordEpisodicEvent(this.
|
|
2662
|
+
return recordEpisodicEvent(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
|
|
1569
2663
|
}
|
|
1570
|
-
async recallEpisodicEvents(
|
|
1571
|
-
|
|
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);
|
|
1572
2667
|
}
|
|
1573
|
-
async storeProceduralPattern(
|
|
2668
|
+
async storeProceduralPattern(c, p) {
|
|
1574
2669
|
this.ensureInitialized();
|
|
1575
|
-
return storeProceduralPattern(this.
|
|
2670
|
+
return storeProceduralPattern(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, p);
|
|
1576
2671
|
}
|
|
1577
|
-
async matchProceduralPatterns(
|
|
1578
|
-
|
|
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);
|
|
1579
2675
|
}
|
|
1580
2676
|
};
|
|
1581
2677
|
|
|
@@ -1615,7 +2711,7 @@ var AgentMemoryClient = class {
|
|
|
1615
2711
|
}
|
|
1616
2712
|
};
|
|
1617
2713
|
|
|
1618
|
-
// src/client.ts
|
|
2714
|
+
// src/client/validation.ts
|
|
1619
2715
|
function requireNonEmptyString(value, label) {
|
|
1620
2716
|
if (!value || typeof value !== "string") {
|
|
1621
2717
|
throw new ValidationError(`${label} must be a non-empty string`);
|
|
@@ -1634,13 +2730,187 @@ function validateDocsBatch(docs, validateDoc) {
|
|
|
1634
2730
|
validateDoc(doc);
|
|
1635
2731
|
}
|
|
1636
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
|
|
1637
2913
|
var VelesDB = class {
|
|
1638
|
-
/**
|
|
1639
|
-
* Create a new VelesDB client
|
|
1640
|
-
*
|
|
1641
|
-
* @param config - Client configuration
|
|
1642
|
-
* @throws {ValidationError} If configuration is invalid
|
|
1643
|
-
*/
|
|
1644
2914
|
constructor(config) {
|
|
1645
2915
|
this.initialized = false;
|
|
1646
2916
|
this.validateConfig(config);
|
|
@@ -1668,10 +2938,7 @@ var VelesDB = class {
|
|
|
1668
2938
|
throw new ValidationError(`Unknown backend: ${config.backend}`);
|
|
1669
2939
|
}
|
|
1670
2940
|
}
|
|
1671
|
-
/**
|
|
1672
|
-
* Initialize the client
|
|
1673
|
-
* Must be called before any other operations
|
|
1674
|
-
*/
|
|
2941
|
+
/** Initialize the client. Must be called before any other operations. */
|
|
1675
2942
|
async init() {
|
|
1676
2943
|
if (this.initialized) {
|
|
1677
2944
|
return;
|
|
@@ -1679,9 +2946,7 @@ var VelesDB = class {
|
|
|
1679
2946
|
await this.backend.init();
|
|
1680
2947
|
this.initialized = true;
|
|
1681
2948
|
}
|
|
1682
|
-
/**
|
|
1683
|
-
* Check if client is initialized
|
|
1684
|
-
*/
|
|
2949
|
+
/** Check if client is initialized. */
|
|
1685
2950
|
isInitialized() {
|
|
1686
2951
|
return this.initialized;
|
|
1687
2952
|
}
|
|
@@ -1690,12 +2955,9 @@ var VelesDB = class {
|
|
|
1690
2955
|
throw new ValidationError("Client not initialized. Call init() first.");
|
|
1691
2956
|
}
|
|
1692
2957
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
* @param name - Collection name
|
|
1697
|
-
* @param config - Collection configuration
|
|
1698
|
-
*/
|
|
2958
|
+
// ========================================================================
|
|
2959
|
+
// Collection CRUD
|
|
2960
|
+
// ========================================================================
|
|
1699
2961
|
async createCollection(name, config) {
|
|
1700
2962
|
this.ensureInitialized();
|
|
1701
2963
|
requireNonEmptyString(name, "Collection name");
|
|
@@ -1705,329 +2967,149 @@ var VelesDB = class {
|
|
|
1705
2967
|
}
|
|
1706
2968
|
await this.backend.createCollection(name, config);
|
|
1707
2969
|
}
|
|
1708
|
-
/**
|
|
1709
|
-
* Create a metadata-only collection (no vectors, just payload data)
|
|
1710
|
-
*
|
|
1711
|
-
* Useful for storing reference data that can be JOINed with vector collections.
|
|
1712
|
-
*
|
|
1713
|
-
* @param name - Collection name
|
|
1714
|
-
*
|
|
1715
|
-
* @example
|
|
1716
|
-
* ```typescript
|
|
1717
|
-
* await db.createMetadataCollection('products');
|
|
1718
|
-
* await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
|
|
1719
|
-
* ```
|
|
1720
|
-
*/
|
|
1721
2970
|
async createMetadataCollection(name) {
|
|
1722
2971
|
this.ensureInitialized();
|
|
1723
2972
|
requireNonEmptyString(name, "Collection name");
|
|
1724
2973
|
await this.backend.createCollection(name, { collectionType: "metadata_only" });
|
|
1725
2974
|
}
|
|
1726
|
-
/**
|
|
1727
|
-
* Delete a collection
|
|
1728
|
-
*
|
|
1729
|
-
* @param name - Collection name
|
|
1730
|
-
*/
|
|
1731
2975
|
async deleteCollection(name) {
|
|
1732
2976
|
this.ensureInitialized();
|
|
1733
2977
|
await this.backend.deleteCollection(name);
|
|
1734
2978
|
}
|
|
1735
|
-
/**
|
|
1736
|
-
* Get collection information
|
|
1737
|
-
*
|
|
1738
|
-
* @param name - Collection name
|
|
1739
|
-
* @returns Collection info or null if not found
|
|
1740
|
-
*/
|
|
1741
2979
|
async getCollection(name) {
|
|
1742
2980
|
this.ensureInitialized();
|
|
1743
2981
|
return this.backend.getCollection(name);
|
|
1744
2982
|
}
|
|
1745
|
-
/**
|
|
1746
|
-
* List all collections
|
|
1747
|
-
*
|
|
1748
|
-
* @returns Array of collections
|
|
1749
|
-
*/
|
|
1750
2983
|
async listCollections() {
|
|
1751
2984
|
this.ensureInitialized();
|
|
1752
2985
|
return this.backend.listCollections();
|
|
1753
2986
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
* @param doc - Document to insert
|
|
1759
|
-
*/
|
|
1760
|
-
async insert(collection, doc) {
|
|
2987
|
+
// ========================================================================
|
|
2988
|
+
// Point CRUD
|
|
2989
|
+
// ========================================================================
|
|
2990
|
+
async upsert(collection, doc) {
|
|
1761
2991
|
this.ensureInitialized();
|
|
1762
|
-
|
|
1763
|
-
await this.backend.
|
|
2992
|
+
validateDocument(doc, this.config);
|
|
2993
|
+
await this.backend.upsert(collection, doc);
|
|
1764
2994
|
}
|
|
1765
|
-
|
|
1766
|
-
* Insert multiple vector documents
|
|
1767
|
-
*
|
|
1768
|
-
* @param collection - Collection name
|
|
1769
|
-
* @param docs - Documents to insert
|
|
1770
|
-
*/
|
|
1771
|
-
async insertBatch(collection, docs) {
|
|
2995
|
+
async upsertBatch(collection, docs) {
|
|
1772
2996
|
this.ensureInitialized();
|
|
1773
|
-
validateDocsBatch(docs, (doc) =>
|
|
1774
|
-
await this.backend.
|
|
2997
|
+
validateDocsBatch(docs, (doc) => validateDocument(doc, this.config));
|
|
2998
|
+
await this.backend.upsertBatch(collection, docs);
|
|
1775
2999
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
requireVector(doc.vector, "Vector");
|
|
1781
|
-
this.validateRestPointId(doc.id);
|
|
3000
|
+
async delete(collection, id) {
|
|
3001
|
+
this.ensureInitialized();
|
|
3002
|
+
validateRestPointId(id, this.config);
|
|
3003
|
+
return this.backend.delete(collection, id);
|
|
1782
3004
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
);
|
|
1788
|
-
}
|
|
3005
|
+
async get(collection, id) {
|
|
3006
|
+
this.ensureInitialized();
|
|
3007
|
+
validateRestPointId(id, this.config);
|
|
3008
|
+
return this.backend.get(collection, id);
|
|
1789
3009
|
}
|
|
1790
|
-
|
|
1791
|
-
* Search for similar vectors
|
|
1792
|
-
*
|
|
1793
|
-
* @param collection - Collection name
|
|
1794
|
-
* @param query - Query vector
|
|
1795
|
-
* @param options - Search options
|
|
1796
|
-
* @returns Search results sorted by relevance
|
|
1797
|
-
*/
|
|
1798
|
-
async search(collection, query2, options) {
|
|
3010
|
+
async isEmpty(collection) {
|
|
1799
3011
|
this.ensureInitialized();
|
|
1800
|
-
|
|
1801
|
-
return this.backend.search(collection, query2, options);
|
|
3012
|
+
return this.backend.isEmpty(collection);
|
|
1802
3013
|
}
|
|
1803
|
-
|
|
1804
|
-
* Search for multiple vectors in parallel
|
|
1805
|
-
*
|
|
1806
|
-
* @param collection - Collection name
|
|
1807
|
-
* @param searches - List of search queries
|
|
1808
|
-
* @returns List of search results for each query
|
|
1809
|
-
*/
|
|
1810
|
-
async searchBatch(collection, searches) {
|
|
3014
|
+
async flush(collection) {
|
|
1811
3015
|
this.ensureInitialized();
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
3016
|
+
await this.backend.flush(collection);
|
|
3017
|
+
}
|
|
3018
|
+
async close() {
|
|
3019
|
+
if (this.initialized) {
|
|
3020
|
+
await this.backend.close();
|
|
3021
|
+
this.initialized = false;
|
|
1817
3022
|
}
|
|
1818
|
-
return this.backend.searchBatch(collection, searches);
|
|
1819
3023
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
* @param id - Document ID
|
|
1825
|
-
* @returns true if deleted, false if not found
|
|
1826
|
-
*/
|
|
1827
|
-
async delete(collection, id) {
|
|
3024
|
+
// ========================================================================
|
|
3025
|
+
// Search & Query -- delegates to client/search-methods.ts
|
|
3026
|
+
// ========================================================================
|
|
3027
|
+
async search(collection, query3, options) {
|
|
1828
3028
|
this.ensureInitialized();
|
|
1829
|
-
this.
|
|
1830
|
-
return this.backend.delete(collection, id);
|
|
3029
|
+
return search2(this.backend, collection, query3, options);
|
|
1831
3030
|
}
|
|
1832
|
-
|
|
1833
|
-
* Get a vector by ID
|
|
1834
|
-
*
|
|
1835
|
-
* @param collection - Collection name
|
|
1836
|
-
* @param id - Document ID
|
|
1837
|
-
* @returns Document or null if not found
|
|
1838
|
-
*/
|
|
1839
|
-
async get(collection, id) {
|
|
3031
|
+
async searchBatch(collection, searches) {
|
|
1840
3032
|
this.ensureInitialized();
|
|
1841
|
-
this.
|
|
1842
|
-
return this.backend.get(collection, id);
|
|
3033
|
+
return searchBatch2(this.backend, collection, searches);
|
|
1843
3034
|
}
|
|
1844
|
-
|
|
1845
|
-
* Perform full-text search using BM25
|
|
1846
|
-
*
|
|
1847
|
-
* @param collection - Collection name
|
|
1848
|
-
* @param query - Text query
|
|
1849
|
-
* @param options - Search options (k, filter)
|
|
1850
|
-
* @returns Search results sorted by BM25 score
|
|
1851
|
-
*/
|
|
1852
|
-
async textSearch(collection, query2, options) {
|
|
3035
|
+
async textSearch(collection, query3, options) {
|
|
1853
3036
|
this.ensureInitialized();
|
|
1854
|
-
|
|
1855
|
-
return this.backend.textSearch(collection, query2, options);
|
|
3037
|
+
return textSearch2(this.backend, collection, query3, options);
|
|
1856
3038
|
}
|
|
1857
|
-
/**
|
|
1858
|
-
* Perform hybrid search combining vector similarity and BM25 text search
|
|
1859
|
-
*
|
|
1860
|
-
* @param collection - Collection name
|
|
1861
|
-
* @param vector - Query vector
|
|
1862
|
-
* @param textQuery - Text query for BM25
|
|
1863
|
-
* @param options - Search options (k, vectorWeight, filter)
|
|
1864
|
-
* @returns Search results sorted by fused score
|
|
1865
|
-
*/
|
|
1866
3039
|
async hybridSearch(collection, vector, textQuery, options) {
|
|
1867
3040
|
this.ensureInitialized();
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
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);
|
|
1871
3046
|
}
|
|
1872
|
-
/**
|
|
1873
|
-
* Execute a VelesQL multi-model query (EPIC-031 US-011)
|
|
1874
|
-
*
|
|
1875
|
-
* Supports hybrid vector + graph queries with VelesQL syntax.
|
|
1876
|
-
*
|
|
1877
|
-
* @param collection - Collection name
|
|
1878
|
-
* @param queryString - VelesQL query string
|
|
1879
|
-
* @param params - Query parameters (vectors, scalars)
|
|
1880
|
-
* @param options - Query options (timeout, streaming)
|
|
1881
|
-
* @returns Query response with results and execution stats
|
|
1882
|
-
*
|
|
1883
|
-
* @example
|
|
1884
|
-
* ```typescript
|
|
1885
|
-
* const response = await db.query('docs', `
|
|
1886
|
-
* MATCH (d:Doc) WHERE vector NEAR $q LIMIT 20
|
|
1887
|
-
* `, { q: queryVector });
|
|
1888
|
-
*
|
|
1889
|
-
* for (const r of response.results) {
|
|
1890
|
-
* console.log(`ID ${r.id}, title: ${r.title}`);
|
|
1891
|
-
* }
|
|
1892
|
-
* ```
|
|
1893
|
-
*/
|
|
1894
3047
|
async query(collection, queryString, params, options) {
|
|
1895
3048
|
this.ensureInitialized();
|
|
1896
|
-
|
|
1897
|
-
requireNonEmptyString(queryString, "Query string");
|
|
1898
|
-
return this.backend.query(collection, queryString, params, options);
|
|
3049
|
+
return query2(this.backend, collection, queryString, params, options);
|
|
1899
3050
|
}
|
|
1900
|
-
|
|
1901
|
-
* Explain the execution plan for a VelesQL query without running it
|
|
1902
|
-
*
|
|
1903
|
-
* @param queryString - VelesQL query string to explain
|
|
1904
|
-
* @param params - Optional query parameters (vectors, scalars)
|
|
1905
|
-
* @returns Explain response with the query execution plan
|
|
1906
|
-
*/
|
|
1907
|
-
async queryExplain(queryString, params) {
|
|
3051
|
+
async queryExplain(queryString, params, options) {
|
|
1908
3052
|
this.ensureInitialized();
|
|
1909
|
-
|
|
1910
|
-
return this.backend.queryExplain(queryString, params);
|
|
3053
|
+
return queryExplain2(this.backend, queryString, params, options);
|
|
1911
3054
|
}
|
|
1912
3055
|
async collectionSanity(collection) {
|
|
1913
3056
|
this.ensureInitialized();
|
|
1914
|
-
|
|
1915
|
-
return this.backend.collectionSanity(collection);
|
|
3057
|
+
return collectionSanity2(this.backend, collection);
|
|
1916
3058
|
}
|
|
1917
|
-
|
|
1918
|
-
* Multi-query fusion search combining results from multiple query vectors
|
|
1919
|
-
*
|
|
1920
|
-
* Ideal for RAG pipelines using Multiple Query Generation (MQG).
|
|
1921
|
-
*
|
|
1922
|
-
* @param collection - Collection name
|
|
1923
|
-
* @param vectors - Array of query vectors
|
|
1924
|
-
* @param options - Search options (k, fusion strategy, fusionParams, filter)
|
|
1925
|
-
* @returns Fused search results
|
|
1926
|
-
*
|
|
1927
|
-
* @example
|
|
1928
|
-
* ```typescript
|
|
1929
|
-
* // RRF fusion (default)
|
|
1930
|
-
* const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
|
|
1931
|
-
* k: 10,
|
|
1932
|
-
* fusion: 'rrf',
|
|
1933
|
-
* fusionParams: { k: 60 }
|
|
1934
|
-
* });
|
|
1935
|
-
*
|
|
1936
|
-
* // Weighted fusion
|
|
1937
|
-
* const results = await db.multiQuerySearch('docs', [emb1, emb2], {
|
|
1938
|
-
* k: 10,
|
|
1939
|
-
* fusion: 'weighted',
|
|
1940
|
-
* fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
|
|
1941
|
-
* });
|
|
1942
|
-
* ```
|
|
1943
|
-
*/
|
|
1944
|
-
async multiQuerySearch(collection, vectors, options) {
|
|
3059
|
+
async scroll(collection, request2) {
|
|
1945
3060
|
this.ensureInitialized();
|
|
1946
|
-
|
|
1947
|
-
throw new ValidationError("Vectors must be a non-empty array");
|
|
1948
|
-
}
|
|
1949
|
-
for (const v of vectors) {
|
|
1950
|
-
requireVector(v, "Each vector");
|
|
1951
|
-
}
|
|
1952
|
-
return this.backend.multiQuerySearch(collection, vectors, options);
|
|
3061
|
+
return scroll2(this.backend, collection, request2);
|
|
1953
3062
|
}
|
|
1954
|
-
/**
|
|
1955
|
-
* Train Product Quantization on a collection
|
|
1956
|
-
*
|
|
1957
|
-
* @param collection - Collection name
|
|
1958
|
-
* @param options - PQ training options (m, k, opq)
|
|
1959
|
-
* @returns Server response message
|
|
1960
|
-
*/
|
|
1961
3063
|
async trainPq(collection, options) {
|
|
1962
3064
|
this.ensureInitialized();
|
|
1963
|
-
return this.backend
|
|
3065
|
+
return trainPq2(this.backend, collection, options);
|
|
1964
3066
|
}
|
|
1965
|
-
/**
|
|
1966
|
-
* Stream-insert documents with backpressure support
|
|
1967
|
-
*
|
|
1968
|
-
* Sends documents sequentially to respect server backpressure.
|
|
1969
|
-
* Throws BackpressureError on 429 responses.
|
|
1970
|
-
*
|
|
1971
|
-
* @param collection - Collection name
|
|
1972
|
-
* @param docs - Documents to insert
|
|
1973
|
-
*/
|
|
1974
3067
|
async streamInsert(collection, docs) {
|
|
1975
3068
|
this.ensureInitialized();
|
|
1976
|
-
|
|
1977
|
-
await this.backend.streamInsert(collection, docs);
|
|
3069
|
+
return streamInsert2(this.backend, this.config, collection, docs);
|
|
1978
3070
|
}
|
|
1979
|
-
|
|
1980
|
-
* Check if a collection is empty
|
|
1981
|
-
*
|
|
1982
|
-
* @param collection - Collection name
|
|
1983
|
-
* @returns true if empty, false otherwise
|
|
1984
|
-
*/
|
|
1985
|
-
async isEmpty(collection) {
|
|
3071
|
+
async streamUpsertPoints(collection, docs) {
|
|
1986
3072
|
this.ensureInitialized();
|
|
1987
|
-
return this.backend.
|
|
3073
|
+
return streamUpsertPoints2(this.backend, this.config, collection, docs);
|
|
1988
3074
|
}
|
|
1989
|
-
|
|
1990
|
-
* Flush pending changes to disk
|
|
1991
|
-
*
|
|
1992
|
-
* @param collection - Collection name
|
|
1993
|
-
*/
|
|
1994
|
-
async flush(collection) {
|
|
3075
|
+
async searchIds(collection, query3, options) {
|
|
1995
3076
|
this.ensureInitialized();
|
|
1996
|
-
|
|
3077
|
+
return searchIds2(this.backend, collection, query3, options);
|
|
1997
3078
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
async
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
this.initialized = false;
|
|
2005
|
-
}
|
|
3079
|
+
// ========================================================================
|
|
3080
|
+
// Admin / Stats -- delegates to client/search-methods.ts
|
|
3081
|
+
// ========================================================================
|
|
3082
|
+
async rebuildIndex(collection) {
|
|
3083
|
+
this.ensureInitialized();
|
|
3084
|
+
return rebuildIndex2(this.backend, collection);
|
|
2006
3085
|
}
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
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);
|
|
2012
3109
|
}
|
|
2013
3110
|
// ========================================================================
|
|
2014
3111
|
// Index Management (EPIC-009)
|
|
2015
3112
|
// ========================================================================
|
|
2016
|
-
/**
|
|
2017
|
-
* Create a property index for O(1) equality lookups or O(log n) range queries
|
|
2018
|
-
*
|
|
2019
|
-
* @param collection - Collection name
|
|
2020
|
-
* @param options - Index configuration (label, property, indexType)
|
|
2021
|
-
*
|
|
2022
|
-
* @example
|
|
2023
|
-
* ```typescript
|
|
2024
|
-
* // Create hash index for fast email lookups
|
|
2025
|
-
* await db.createIndex('users', { label: 'Person', property: 'email' });
|
|
2026
|
-
*
|
|
2027
|
-
* // Create range index for timestamp queries
|
|
2028
|
-
* await db.createIndex('events', { label: 'Event', property: 'timestamp', indexType: 'range' });
|
|
2029
|
-
* ```
|
|
2030
|
-
*/
|
|
2031
3113
|
async createIndex(collection, options) {
|
|
2032
3114
|
this.ensureInitialized();
|
|
2033
3115
|
if (!options.label || !options.property) {
|
|
@@ -2035,208 +3117,89 @@ var VelesDB = class {
|
|
|
2035
3117
|
}
|
|
2036
3118
|
await this.backend.createIndex(collection, options);
|
|
2037
3119
|
}
|
|
2038
|
-
/**
|
|
2039
|
-
* List all indexes on a collection
|
|
2040
|
-
*
|
|
2041
|
-
* @param collection - Collection name
|
|
2042
|
-
* @returns Array of index information
|
|
2043
|
-
*/
|
|
2044
3120
|
async listIndexes(collection) {
|
|
2045
3121
|
this.ensureInitialized();
|
|
2046
3122
|
return this.backend.listIndexes(collection);
|
|
2047
3123
|
}
|
|
2048
|
-
/**
|
|
2049
|
-
* Check if an index exists
|
|
2050
|
-
*
|
|
2051
|
-
* @param collection - Collection name
|
|
2052
|
-
* @param label - Node label
|
|
2053
|
-
* @param property - Property name
|
|
2054
|
-
* @returns true if index exists
|
|
2055
|
-
*/
|
|
2056
3124
|
async hasIndex(collection, label, property) {
|
|
2057
3125
|
this.ensureInitialized();
|
|
2058
3126
|
return this.backend.hasIndex(collection, label, property);
|
|
2059
3127
|
}
|
|
2060
|
-
/**
|
|
2061
|
-
* Drop an index
|
|
2062
|
-
*
|
|
2063
|
-
* @param collection - Collection name
|
|
2064
|
-
* @param label - Node label
|
|
2065
|
-
* @param property - Property name
|
|
2066
|
-
* @returns true if index was dropped, false if it didn't exist
|
|
2067
|
-
*/
|
|
2068
3128
|
async dropIndex(collection, label, property) {
|
|
2069
3129
|
this.ensureInitialized();
|
|
2070
3130
|
return this.backend.dropIndex(collection, label, property);
|
|
2071
3131
|
}
|
|
2072
3132
|
// ========================================================================
|
|
2073
|
-
// Knowledge Graph
|
|
3133
|
+
// Knowledge Graph -- delegates to client/graph-methods.ts
|
|
2074
3134
|
// ========================================================================
|
|
2075
|
-
/**
|
|
2076
|
-
* Add an edge to the collection's knowledge graph
|
|
2077
|
-
*
|
|
2078
|
-
* @param collection - Collection name
|
|
2079
|
-
* @param edge - Edge to add (id, source, target, label, properties)
|
|
2080
|
-
*
|
|
2081
|
-
* @example
|
|
2082
|
-
* ```typescript
|
|
2083
|
-
* await db.addEdge('social', {
|
|
2084
|
-
* id: 1,
|
|
2085
|
-
* source: 100,
|
|
2086
|
-
* target: 200,
|
|
2087
|
-
* label: 'FOLLOWS',
|
|
2088
|
-
* properties: { since: '2024-01-01' }
|
|
2089
|
-
* });
|
|
2090
|
-
* ```
|
|
2091
|
-
*/
|
|
2092
3135
|
async addEdge(collection, edge) {
|
|
2093
3136
|
this.ensureInitialized();
|
|
2094
|
-
|
|
2095
|
-
throw new ValidationError("Edge label is required and must be a string");
|
|
2096
|
-
}
|
|
2097
|
-
if (typeof edge.source !== "number" || typeof edge.target !== "number") {
|
|
2098
|
-
throw new ValidationError("Edge source and target must be numbers");
|
|
2099
|
-
}
|
|
2100
|
-
await this.backend.addEdge(collection, edge);
|
|
3137
|
+
return addEdge2(this.backend, collection, edge);
|
|
2101
3138
|
}
|
|
2102
|
-
/**
|
|
2103
|
-
* Get edges from the collection's knowledge graph
|
|
2104
|
-
*
|
|
2105
|
-
* @param collection - Collection name
|
|
2106
|
-
* @param options - Query options (filter by label)
|
|
2107
|
-
* @returns Array of edges
|
|
2108
|
-
*
|
|
2109
|
-
* @example
|
|
2110
|
-
* ```typescript
|
|
2111
|
-
* // Get all edges with label "FOLLOWS"
|
|
2112
|
-
* const edges = await db.getEdges('social', { label: 'FOLLOWS' });
|
|
2113
|
-
* ```
|
|
2114
|
-
*/
|
|
2115
3139
|
async getEdges(collection, options) {
|
|
2116
3140
|
this.ensureInitialized();
|
|
2117
|
-
return this.backend
|
|
3141
|
+
return getEdges2(this.backend, collection, options);
|
|
2118
3142
|
}
|
|
2119
|
-
|
|
2120
|
-
// Graph Traversal (EPIC-016 US-050)
|
|
2121
|
-
// ========================================================================
|
|
2122
|
-
/**
|
|
2123
|
-
* Traverse the graph using BFS or DFS from a source node
|
|
2124
|
-
*
|
|
2125
|
-
* @param collection - Collection name
|
|
2126
|
-
* @param request - Traversal request options
|
|
2127
|
-
* @returns Traversal response with results and stats
|
|
2128
|
-
*
|
|
2129
|
-
* @example
|
|
2130
|
-
* ```typescript
|
|
2131
|
-
* // BFS traversal from node 100
|
|
2132
|
-
* const result = await db.traverseGraph('social', {
|
|
2133
|
-
* source: 100,
|
|
2134
|
-
* strategy: 'bfs',
|
|
2135
|
-
* maxDepth: 3,
|
|
2136
|
-
* limit: 100,
|
|
2137
|
-
* relTypes: ['FOLLOWS', 'KNOWS']
|
|
2138
|
-
* });
|
|
2139
|
-
*
|
|
2140
|
-
* for (const node of result.results) {
|
|
2141
|
-
* console.log(`Reached node ${node.targetId} at depth ${node.depth}`);
|
|
2142
|
-
* }
|
|
2143
|
-
* ```
|
|
2144
|
-
*/
|
|
2145
|
-
async traverseGraph(collection, request) {
|
|
3143
|
+
async traverseGraph(collection, request2) {
|
|
2146
3144
|
this.ensureInitialized();
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
}
|
|
2153
|
-
return this.backend.traverseGraph(collection, request);
|
|
3145
|
+
return traverseGraph2(this.backend, collection, request2);
|
|
3146
|
+
}
|
|
3147
|
+
async traverseParallel(collection, request2) {
|
|
3148
|
+
this.ensureInitialized();
|
|
3149
|
+
return traverseParallel2(this.backend, collection, request2);
|
|
2154
3150
|
}
|
|
2155
|
-
/**
|
|
2156
|
-
* Get the in-degree and out-degree of a node
|
|
2157
|
-
*
|
|
2158
|
-
* @param collection - Collection name
|
|
2159
|
-
* @param nodeId - Node ID
|
|
2160
|
-
* @returns Degree response with inDegree and outDegree
|
|
2161
|
-
*
|
|
2162
|
-
* @example
|
|
2163
|
-
* ```typescript
|
|
2164
|
-
* const degree = await db.getNodeDegree('social', 100);
|
|
2165
|
-
* console.log(`In: ${degree.inDegree}, Out: ${degree.outDegree}`);
|
|
2166
|
-
* ```
|
|
2167
|
-
*/
|
|
2168
3151
|
async getNodeDegree(collection, nodeId) {
|
|
2169
3152
|
this.ensureInitialized();
|
|
2170
|
-
|
|
2171
|
-
throw new ValidationError("Node ID must be a number");
|
|
2172
|
-
}
|
|
2173
|
-
return this.backend.getNodeDegree(collection, nodeId);
|
|
3153
|
+
return getNodeDegree2(this.backend, collection, nodeId);
|
|
2174
3154
|
}
|
|
2175
|
-
// ========================================================================
|
|
2176
|
-
// Graph Collection Management (Phase 8)
|
|
2177
|
-
// ========================================================================
|
|
2178
|
-
/**
|
|
2179
|
-
* Create a graph collection
|
|
2180
|
-
*
|
|
2181
|
-
* @param name - Collection name
|
|
2182
|
-
* @param config - Optional graph collection configuration
|
|
2183
|
-
*/
|
|
2184
3155
|
async createGraphCollection(name, config) {
|
|
2185
3156
|
this.ensureInitialized();
|
|
2186
|
-
|
|
2187
|
-
await this.backend.createGraphCollection(name, config);
|
|
3157
|
+
return createGraphCollection2(this.backend, name, config);
|
|
2188
3158
|
}
|
|
2189
|
-
|
|
2190
|
-
* Get collection statistics (requires prior analyze)
|
|
2191
|
-
*
|
|
2192
|
-
* @param collection - Collection name
|
|
2193
|
-
* @returns Statistics or null if not yet analyzed
|
|
2194
|
-
*/
|
|
2195
|
-
async getCollectionStats(collection) {
|
|
3159
|
+
async matchQuery(collection, queryString, params, options) {
|
|
2196
3160
|
this.ensureInitialized();
|
|
2197
|
-
return this.backend
|
|
3161
|
+
return matchQuery2(this.backend, collection, queryString, params, options);
|
|
2198
3162
|
}
|
|
2199
|
-
|
|
2200
|
-
* Analyze a collection to compute statistics
|
|
2201
|
-
*
|
|
2202
|
-
* @param collection - Collection name
|
|
2203
|
-
* @returns Computed statistics
|
|
2204
|
-
*/
|
|
2205
|
-
async analyzeCollection(collection) {
|
|
3163
|
+
async removeEdge(collection, edgeId) {
|
|
2206
3164
|
this.ensureInitialized();
|
|
2207
|
-
return this.backend
|
|
3165
|
+
return removeEdge2(this.backend, collection, edgeId);
|
|
2208
3166
|
}
|
|
2209
|
-
|
|
2210
|
-
* Get collection configuration
|
|
2211
|
-
*
|
|
2212
|
-
* @param collection - Collection name
|
|
2213
|
-
* @returns Collection configuration details
|
|
2214
|
-
*/
|
|
2215
|
-
async getCollectionConfig(collection) {
|
|
3167
|
+
async getEdgeCount(collection) {
|
|
2216
3168
|
this.ensureInitialized();
|
|
2217
|
-
return this.backend
|
|
3169
|
+
return getEdgeCount2(this.backend, collection);
|
|
2218
3170
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
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) {
|
|
2228
3188
|
this.ensureInitialized();
|
|
2229
|
-
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;
|
|
2230
3199
|
}
|
|
2231
3200
|
// ========================================================================
|
|
2232
3201
|
// Agent Memory (Phase 8)
|
|
2233
3202
|
// ========================================================================
|
|
2234
|
-
/**
|
|
2235
|
-
* Create an agent memory interface
|
|
2236
|
-
*
|
|
2237
|
-
* @param config - Optional agent memory configuration
|
|
2238
|
-
* @returns AgentMemoryClient instance
|
|
2239
|
-
*/
|
|
2240
3203
|
agentMemory(config) {
|
|
2241
3204
|
this.ensureInitialized();
|
|
2242
3205
|
return new AgentMemoryClient(this.backend, config);
|
|
@@ -2336,6 +3299,16 @@ var VelesQLBuilder = class _VelesQLBuilder {
|
|
|
2336
3299
|
*
|
|
2337
3300
|
* @param condition - WHERE condition
|
|
2338
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
|
+
* ```
|
|
2339
3312
|
*/
|
|
2340
3313
|
where(condition, params) {
|
|
2341
3314
|
const newParams = params ? { ...this.state.params, ...params } : this.state.params;
|
|
@@ -2544,16 +3517,205 @@ var VelesQLBuilder = class _VelesQLBuilder {
|
|
|
2544
3517
|
function velesql() {
|
|
2545
3518
|
return new VelesQLBuilder();
|
|
2546
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
|
+
};
|
|
2547
3664
|
export {
|
|
2548
3665
|
AgentMemoryClient,
|
|
3666
|
+
AllocationFailedError,
|
|
2549
3667
|
BackpressureError,
|
|
3668
|
+
CollectionExistsError,
|
|
3669
|
+
CollectionNotFoundError,
|
|
3670
|
+
ColumnStoreError,
|
|
3671
|
+
ConfigError,
|
|
2550
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,
|
|
2551
3692
|
NotFoundError,
|
|
3693
|
+
OverflowError,
|
|
3694
|
+
PointNotFoundError,
|
|
3695
|
+
QueryError,
|
|
3696
|
+
REST_CAPABILITIES,
|
|
2552
3697
|
RestBackend,
|
|
3698
|
+
SchemaValidationError,
|
|
3699
|
+
SearchNotSupportedError,
|
|
3700
|
+
SerializationError,
|
|
3701
|
+
SnapshotBuildFailedError,
|
|
3702
|
+
SparseIndexError,
|
|
3703
|
+
StorageError,
|
|
3704
|
+
TrainingFailedError,
|
|
3705
|
+
VELES_ERROR_CODES,
|
|
2553
3706
|
ValidationError,
|
|
3707
|
+
VectorNotAllowedError,
|
|
3708
|
+
VectorRequiredError,
|
|
2554
3709
|
VelesDB,
|
|
2555
3710
|
VelesDBError,
|
|
3711
|
+
VelesError,
|
|
2556
3712
|
VelesQLBuilder,
|
|
3713
|
+
WASM_CAPABILITIES,
|
|
2557
3714
|
WasmBackend,
|
|
3715
|
+
f,
|
|
3716
|
+
isTypedFilter,
|
|
3717
|
+
normalizeFilter,
|
|
3718
|
+
parseVelesError,
|
|
3719
|
+
searchQualityToMode,
|
|
2558
3720
|
velesql
|
|
2559
3721
|
};
|