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