@wiscale/velesdb-sdk 0.8.4 → 0.8.8

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 CHANGED
@@ -144,6 +144,50 @@ Delete a vector by ID. Returns `true` if deleted.
144
144
 
145
145
  Get a vector by ID. Returns `null` if not found.
146
146
 
147
+ ### `db.textSearch(collection, query, options)` (v0.8.5+)
148
+
149
+ Full-text search using BM25 algorithm.
150
+
151
+ ```typescript
152
+ const results = await db.textSearch('docs', 'machine learning', { k: 10 });
153
+ ```
154
+
155
+ ### `db.hybridSearch(collection, vector, textQuery, options)` (v0.8.5+)
156
+
157
+ Combined vector + text search with RRF fusion.
158
+
159
+ ```typescript
160
+ const results = await db.hybridSearch(
161
+ 'docs',
162
+ queryVector,
163
+ 'machine learning',
164
+ { k: 10, vectorWeight: 0.7 } // 0.7 = 70% vector, 30% text
165
+ );
166
+ ```
167
+
168
+ ### `db.query(queryString, params)` (v0.8.5+)
169
+
170
+ Execute a VelesQL query.
171
+
172
+ ```typescript
173
+ // Simple query
174
+ const results = await db.query(
175
+ "SELECT * FROM documents WHERE category = 'tech' LIMIT 10"
176
+ );
177
+
178
+ // With vector parameter
179
+ const results = await db.query(
180
+ "SELECT * FROM documents WHERE VECTOR NEAR $query LIMIT 5",
181
+ { query: [0.1, 0.2, ...] }
182
+ );
183
+
184
+ // Hybrid query
185
+ const results = await db.query(
186
+ "SELECT * FROM docs WHERE VECTOR NEAR $v AND content MATCH 'rust' LIMIT 10",
187
+ { v: queryVector }
188
+ );
189
+ ```
190
+
147
191
  ### `db.close()`
148
192
 
149
193
  Close the client and release resources.
package/dist/index.d.mts CHANGED
@@ -102,6 +102,25 @@ interface IVelesDBBackend {
102
102
  delete(collection: string, id: string | number): Promise<boolean>;
103
103
  /** Get a vector by ID */
104
104
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
105
+ /** Search for multiple vectors in batch */
106
+ searchBatch(collection: string, searches: Array<{
107
+ vector: number[] | Float32Array;
108
+ k?: number;
109
+ filter?: Record<string, unknown>;
110
+ }>): Promise<SearchResult[][]>;
111
+ /** Full-text search using BM25 */
112
+ textSearch(collection: string, query: string, options?: {
113
+ k?: number;
114
+ filter?: Record<string, unknown>;
115
+ }): Promise<SearchResult[]>;
116
+ /** Hybrid search combining vector and text */
117
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
118
+ k?: number;
119
+ vectorWeight?: number;
120
+ filter?: Record<string, unknown>;
121
+ }): Promise<SearchResult[]>;
122
+ /** Execute VelesQL query */
123
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
105
124
  /** Close/cleanup the backend */
106
125
  close(): Promise<void>;
107
126
  }
@@ -215,6 +234,18 @@ declare class VelesDB {
215
234
  * @returns Search results sorted by relevance
216
235
  */
217
236
  search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
237
+ /**
238
+ * Search for multiple vectors in parallel
239
+ *
240
+ * @param collection - Collection name
241
+ * @param searches - List of search queries
242
+ * @returns List of search results for each query
243
+ */
244
+ searchBatch(collection: string, searches: Array<{
245
+ vector: number[] | Float32Array;
246
+ k?: number;
247
+ filter?: Record<string, unknown>;
248
+ }>): Promise<SearchResult[][]>;
218
249
  /**
219
250
  * Delete a vector by ID
220
251
  *
@@ -231,6 +262,40 @@ declare class VelesDB {
231
262
  * @returns Document or null if not found
232
263
  */
233
264
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
265
+ /**
266
+ * Perform full-text search using BM25
267
+ *
268
+ * @param collection - Collection name
269
+ * @param query - Text query
270
+ * @param options - Search options (k, filter)
271
+ * @returns Search results sorted by BM25 score
272
+ */
273
+ textSearch(collection: string, query: string, options?: {
274
+ k?: number;
275
+ filter?: Record<string, unknown>;
276
+ }): Promise<SearchResult[]>;
277
+ /**
278
+ * Perform hybrid search combining vector similarity and BM25 text search
279
+ *
280
+ * @param collection - Collection name
281
+ * @param vector - Query vector
282
+ * @param textQuery - Text query for BM25
283
+ * @param options - Search options (k, vectorWeight, filter)
284
+ * @returns Search results sorted by fused score
285
+ */
286
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
287
+ k?: number;
288
+ vectorWeight?: number;
289
+ filter?: Record<string, unknown>;
290
+ }): Promise<SearchResult[]>;
291
+ /**
292
+ * Execute a VelesQL query
293
+ *
294
+ * @param queryString - VelesQL query string
295
+ * @param params - Optional query parameters
296
+ * @returns Query results
297
+ */
298
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
234
299
  /**
235
300
  * Close the client and release resources
236
301
  */
@@ -267,8 +332,23 @@ declare class WasmBackend implements IVelesDBBackend {
267
332
  insert(collectionName: string, doc: VectorDocument): Promise<void>;
268
333
  insertBatch(collectionName: string, docs: VectorDocument[]): Promise<void>;
269
334
  search(collectionName: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
335
+ searchBatch(collectionName: string, searches: Array<{
336
+ vector: number[] | Float32Array;
337
+ k?: number;
338
+ filter?: Record<string, unknown>;
339
+ }>): Promise<SearchResult[][]>;
270
340
  delete(collectionName: string, id: string | number): Promise<boolean>;
271
341
  get(collectionName: string, id: string | number): Promise<VectorDocument | null>;
342
+ textSearch(_collection: string, _query: string, _options?: {
343
+ k?: number;
344
+ filter?: Record<string, unknown>;
345
+ }): Promise<SearchResult[]>;
346
+ hybridSearch(_collection: string, _vector: number[] | Float32Array, _textQuery: string, _options?: {
347
+ k?: number;
348
+ vectorWeight?: number;
349
+ filter?: Record<string, unknown>;
350
+ }): Promise<SearchResult[]>;
351
+ query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
272
352
  close(): Promise<void>;
273
353
  private toNumericId;
274
354
  }
@@ -301,8 +381,23 @@ declare class RestBackend implements IVelesDBBackend {
301
381
  insert(collection: string, doc: VectorDocument): Promise<void>;
302
382
  insertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
303
383
  search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
384
+ searchBatch(collection: string, searches: Array<{
385
+ vector: number[] | Float32Array;
386
+ k?: number;
387
+ filter?: Record<string, unknown>;
388
+ }>): Promise<SearchResult[][]>;
304
389
  delete(collection: string, id: string | number): Promise<boolean>;
305
390
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
391
+ textSearch(collection: string, query: string, options?: {
392
+ k?: number;
393
+ filter?: Record<string, unknown>;
394
+ }): Promise<SearchResult[]>;
395
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
396
+ k?: number;
397
+ vectorWeight?: number;
398
+ filter?: Record<string, unknown>;
399
+ }): Promise<SearchResult[]>;
400
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
306
401
  close(): Promise<void>;
307
402
  }
308
403
 
package/dist/index.d.ts CHANGED
@@ -102,6 +102,25 @@ interface IVelesDBBackend {
102
102
  delete(collection: string, id: string | number): Promise<boolean>;
103
103
  /** Get a vector by ID */
104
104
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
105
+ /** Search for multiple vectors in batch */
106
+ searchBatch(collection: string, searches: Array<{
107
+ vector: number[] | Float32Array;
108
+ k?: number;
109
+ filter?: Record<string, unknown>;
110
+ }>): Promise<SearchResult[][]>;
111
+ /** Full-text search using BM25 */
112
+ textSearch(collection: string, query: string, options?: {
113
+ k?: number;
114
+ filter?: Record<string, unknown>;
115
+ }): Promise<SearchResult[]>;
116
+ /** Hybrid search combining vector and text */
117
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
118
+ k?: number;
119
+ vectorWeight?: number;
120
+ filter?: Record<string, unknown>;
121
+ }): Promise<SearchResult[]>;
122
+ /** Execute VelesQL query */
123
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
105
124
  /** Close/cleanup the backend */
106
125
  close(): Promise<void>;
107
126
  }
@@ -215,6 +234,18 @@ declare class VelesDB {
215
234
  * @returns Search results sorted by relevance
216
235
  */
217
236
  search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
237
+ /**
238
+ * Search for multiple vectors in parallel
239
+ *
240
+ * @param collection - Collection name
241
+ * @param searches - List of search queries
242
+ * @returns List of search results for each query
243
+ */
244
+ searchBatch(collection: string, searches: Array<{
245
+ vector: number[] | Float32Array;
246
+ k?: number;
247
+ filter?: Record<string, unknown>;
248
+ }>): Promise<SearchResult[][]>;
218
249
  /**
219
250
  * Delete a vector by ID
220
251
  *
@@ -231,6 +262,40 @@ declare class VelesDB {
231
262
  * @returns Document or null if not found
232
263
  */
233
264
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
265
+ /**
266
+ * Perform full-text search using BM25
267
+ *
268
+ * @param collection - Collection name
269
+ * @param query - Text query
270
+ * @param options - Search options (k, filter)
271
+ * @returns Search results sorted by BM25 score
272
+ */
273
+ textSearch(collection: string, query: string, options?: {
274
+ k?: number;
275
+ filter?: Record<string, unknown>;
276
+ }): Promise<SearchResult[]>;
277
+ /**
278
+ * Perform hybrid search combining vector similarity and BM25 text search
279
+ *
280
+ * @param collection - Collection name
281
+ * @param vector - Query vector
282
+ * @param textQuery - Text query for BM25
283
+ * @param options - Search options (k, vectorWeight, filter)
284
+ * @returns Search results sorted by fused score
285
+ */
286
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
287
+ k?: number;
288
+ vectorWeight?: number;
289
+ filter?: Record<string, unknown>;
290
+ }): Promise<SearchResult[]>;
291
+ /**
292
+ * Execute a VelesQL query
293
+ *
294
+ * @param queryString - VelesQL query string
295
+ * @param params - Optional query parameters
296
+ * @returns Query results
297
+ */
298
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
234
299
  /**
235
300
  * Close the client and release resources
236
301
  */
@@ -267,8 +332,23 @@ declare class WasmBackend implements IVelesDBBackend {
267
332
  insert(collectionName: string, doc: VectorDocument): Promise<void>;
268
333
  insertBatch(collectionName: string, docs: VectorDocument[]): Promise<void>;
269
334
  search(collectionName: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
335
+ searchBatch(collectionName: string, searches: Array<{
336
+ vector: number[] | Float32Array;
337
+ k?: number;
338
+ filter?: Record<string, unknown>;
339
+ }>): Promise<SearchResult[][]>;
270
340
  delete(collectionName: string, id: string | number): Promise<boolean>;
271
341
  get(collectionName: string, id: string | number): Promise<VectorDocument | null>;
342
+ textSearch(_collection: string, _query: string, _options?: {
343
+ k?: number;
344
+ filter?: Record<string, unknown>;
345
+ }): Promise<SearchResult[]>;
346
+ hybridSearch(_collection: string, _vector: number[] | Float32Array, _textQuery: string, _options?: {
347
+ k?: number;
348
+ vectorWeight?: number;
349
+ filter?: Record<string, unknown>;
350
+ }): Promise<SearchResult[]>;
351
+ query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
272
352
  close(): Promise<void>;
273
353
  private toNumericId;
274
354
  }
@@ -301,8 +381,23 @@ declare class RestBackend implements IVelesDBBackend {
301
381
  insert(collection: string, doc: VectorDocument): Promise<void>;
302
382
  insertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
303
383
  search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
384
+ searchBatch(collection: string, searches: Array<{
385
+ vector: number[] | Float32Array;
386
+ k?: number;
387
+ filter?: Record<string, unknown>;
388
+ }>): Promise<SearchResult[][]>;
304
389
  delete(collection: string, id: string | number): Promise<boolean>;
305
390
  get(collection: string, id: string | number): Promise<VectorDocument | null>;
391
+ textSearch(collection: string, query: string, options?: {
392
+ k?: number;
393
+ filter?: Record<string, unknown>;
394
+ }): Promise<SearchResult[]>;
395
+ hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
396
+ k?: number;
397
+ vectorWeight?: number;
398
+ filter?: Record<string, unknown>;
399
+ }): Promise<SearchResult[]>;
400
+ query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
306
401
  close(): Promise<void>;
307
402
  }
308
403
 
package/dist/index.js CHANGED
@@ -209,6 +209,14 @@ var WasmBackend = class {
209
209
  );
210
210
  }
211
211
  const k = options?.k ?? 10;
212
+ if (options?.filter) {
213
+ const results = collection.store.search_with_filter(queryVector, k, options.filter);
214
+ return results.map((r) => ({
215
+ id: String(r.id),
216
+ score: r.score,
217
+ payload: r.payload || collection.payloads.get(String(r.id))
218
+ }));
219
+ }
212
220
  const rawResults = collection.store.search(queryVector, k);
213
221
  return rawResults.map(([id, score]) => {
214
222
  const stringId = String(id);
@@ -223,6 +231,14 @@ var WasmBackend = class {
223
231
  return result;
224
232
  });
225
233
  }
234
+ async searchBatch(collectionName, searches) {
235
+ this.ensureInitialized();
236
+ const results = [];
237
+ for (const s of searches) {
238
+ results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
239
+ }
240
+ return results;
241
+ }
226
242
  async delete(collectionName, id) {
227
243
  this.ensureInitialized();
228
244
  const collection = this.collections.get(collectionName);
@@ -253,6 +269,24 @@ var WasmBackend = class {
253
269
  payload
254
270
  };
255
271
  }
272
+ async textSearch(_collection, _query, _options) {
273
+ throw new VelesDBError(
274
+ "Text search is not supported in WASM backend. Use REST backend for BM25 search.",
275
+ "NOT_SUPPORTED"
276
+ );
277
+ }
278
+ async hybridSearch(_collection, _vector, _textQuery, _options) {
279
+ throw new VelesDBError(
280
+ "Hybrid search is not supported in WASM backend. Use REST backend for hybrid search.",
281
+ "NOT_SUPPORTED"
282
+ );
283
+ }
284
+ async query(_queryString, _params) {
285
+ throw new VelesDBError(
286
+ "VelesQL queries are not supported in WASM backend. Use REST backend for query support.",
287
+ "NOT_SUPPORTED"
288
+ );
289
+ }
256
290
  async close() {
257
291
  for (const [, data] of this.collections) {
258
292
  data.store.free();
@@ -453,6 +487,26 @@ var RestBackend = class {
453
487
  }
454
488
  return response.data ?? [];
455
489
  }
490
+ async searchBatch(collection, searches) {
491
+ this.ensureInitialized();
492
+ const formattedSearches = searches.map((s) => ({
493
+ vector: s.vector instanceof Float32Array ? Array.from(s.vector) : s.vector,
494
+ top_k: s.k ?? 10,
495
+ filter: s.filter
496
+ }));
497
+ const response = await this.request(
498
+ "POST",
499
+ `/collections/${encodeURIComponent(collection)}/search/batch`,
500
+ { searches: formattedSearches }
501
+ );
502
+ if (response.error) {
503
+ if (response.error.code === "NOT_FOUND") {
504
+ throw new NotFoundError(`Collection '${collection}'`);
505
+ }
506
+ throw new VelesDBError(response.error.message, response.error.code);
507
+ }
508
+ return response.data?.results.map((r) => r.results) ?? [];
509
+ }
456
510
  async delete(collection, id) {
457
511
  this.ensureInitialized();
458
512
  const response = await this.request(
@@ -481,6 +535,62 @@ var RestBackend = class {
481
535
  }
482
536
  return response.data ?? null;
483
537
  }
538
+ async textSearch(collection, query, options) {
539
+ this.ensureInitialized();
540
+ const response = await this.request(
541
+ "POST",
542
+ `/collections/${encodeURIComponent(collection)}/search/text`,
543
+ {
544
+ query,
545
+ top_k: options?.k ?? 10,
546
+ filter: options?.filter
547
+ }
548
+ );
549
+ if (response.error) {
550
+ if (response.error.code === "NOT_FOUND") {
551
+ throw new NotFoundError(`Collection '${collection}'`);
552
+ }
553
+ throw new VelesDBError(response.error.message, response.error.code);
554
+ }
555
+ return response.data?.results ?? [];
556
+ }
557
+ async hybridSearch(collection, vector, textQuery, options) {
558
+ this.ensureInitialized();
559
+ const queryVector = vector instanceof Float32Array ? Array.from(vector) : vector;
560
+ const response = await this.request(
561
+ "POST",
562
+ `/collections/${encodeURIComponent(collection)}/search/hybrid`,
563
+ {
564
+ vector: queryVector,
565
+ query: textQuery,
566
+ top_k: options?.k ?? 10,
567
+ vector_weight: options?.vectorWeight ?? 0.5,
568
+ filter: options?.filter
569
+ }
570
+ );
571
+ if (response.error) {
572
+ if (response.error.code === "NOT_FOUND") {
573
+ throw new NotFoundError(`Collection '${collection}'`);
574
+ }
575
+ throw new VelesDBError(response.error.message, response.error.code);
576
+ }
577
+ return response.data?.results ?? [];
578
+ }
579
+ async query(queryString, params) {
580
+ this.ensureInitialized();
581
+ const response = await this.request(
582
+ "POST",
583
+ "/query",
584
+ {
585
+ query: queryString,
586
+ params: params ?? {}
587
+ }
588
+ );
589
+ if (response.error) {
590
+ throw new VelesDBError(response.error.message, response.error.code);
591
+ }
592
+ return response.data?.results ?? [];
593
+ }
484
594
  async close() {
485
595
  this._initialized = false;
486
596
  }
@@ -640,6 +750,25 @@ var VelesDB = class {
640
750
  }
641
751
  return this.backend.search(collection, query, options);
642
752
  }
753
+ /**
754
+ * Search for multiple vectors in parallel
755
+ *
756
+ * @param collection - Collection name
757
+ * @param searches - List of search queries
758
+ * @returns List of search results for each query
759
+ */
760
+ async searchBatch(collection, searches) {
761
+ this.ensureInitialized();
762
+ if (!Array.isArray(searches)) {
763
+ throw new ValidationError("Searches must be an array");
764
+ }
765
+ for (const s of searches) {
766
+ if (!s.vector || !Array.isArray(s.vector) && !(s.vector instanceof Float32Array)) {
767
+ throw new ValidationError("Each search must have a vector (array or Float32Array)");
768
+ }
769
+ }
770
+ return this.backend.searchBatch(collection, searches);
771
+ }
643
772
  /**
644
773
  * Delete a vector by ID
645
774
  *
@@ -662,6 +791,54 @@ var VelesDB = class {
662
791
  this.ensureInitialized();
663
792
  return this.backend.get(collection, id);
664
793
  }
794
+ /**
795
+ * Perform full-text search using BM25
796
+ *
797
+ * @param collection - Collection name
798
+ * @param query - Text query
799
+ * @param options - Search options (k, filter)
800
+ * @returns Search results sorted by BM25 score
801
+ */
802
+ async textSearch(collection, query, options) {
803
+ this.ensureInitialized();
804
+ if (!query || typeof query !== "string") {
805
+ throw new ValidationError("Query must be a non-empty string");
806
+ }
807
+ return this.backend.textSearch(collection, query, options);
808
+ }
809
+ /**
810
+ * Perform hybrid search combining vector similarity and BM25 text search
811
+ *
812
+ * @param collection - Collection name
813
+ * @param vector - Query vector
814
+ * @param textQuery - Text query for BM25
815
+ * @param options - Search options (k, vectorWeight, filter)
816
+ * @returns Search results sorted by fused score
817
+ */
818
+ async hybridSearch(collection, vector, textQuery, options) {
819
+ this.ensureInitialized();
820
+ if (!vector || !Array.isArray(vector) && !(vector instanceof Float32Array)) {
821
+ throw new ValidationError("Vector must be an array or Float32Array");
822
+ }
823
+ if (!textQuery || typeof textQuery !== "string") {
824
+ throw new ValidationError("Text query must be a non-empty string");
825
+ }
826
+ return this.backend.hybridSearch(collection, vector, textQuery, options);
827
+ }
828
+ /**
829
+ * Execute a VelesQL query
830
+ *
831
+ * @param queryString - VelesQL query string
832
+ * @param params - Optional query parameters
833
+ * @returns Query results
834
+ */
835
+ async query(queryString, params) {
836
+ this.ensureInitialized();
837
+ if (!queryString || typeof queryString !== "string") {
838
+ throw new ValidationError("Query string must be a non-empty string");
839
+ }
840
+ return this.backend.query(queryString, params);
841
+ }
665
842
  /**
666
843
  * Close the client and release resources
667
844
  */
package/dist/index.mjs CHANGED
@@ -167,6 +167,14 @@ var WasmBackend = class {
167
167
  );
168
168
  }
169
169
  const k = options?.k ?? 10;
170
+ if (options?.filter) {
171
+ const results = collection.store.search_with_filter(queryVector, k, options.filter);
172
+ return results.map((r) => ({
173
+ id: String(r.id),
174
+ score: r.score,
175
+ payload: r.payload || collection.payloads.get(String(r.id))
176
+ }));
177
+ }
170
178
  const rawResults = collection.store.search(queryVector, k);
171
179
  return rawResults.map(([id, score]) => {
172
180
  const stringId = String(id);
@@ -181,6 +189,14 @@ var WasmBackend = class {
181
189
  return result;
182
190
  });
183
191
  }
192
+ async searchBatch(collectionName, searches) {
193
+ this.ensureInitialized();
194
+ const results = [];
195
+ for (const s of searches) {
196
+ results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
197
+ }
198
+ return results;
199
+ }
184
200
  async delete(collectionName, id) {
185
201
  this.ensureInitialized();
186
202
  const collection = this.collections.get(collectionName);
@@ -211,6 +227,24 @@ var WasmBackend = class {
211
227
  payload
212
228
  };
213
229
  }
230
+ async textSearch(_collection, _query, _options) {
231
+ throw new VelesDBError(
232
+ "Text search is not supported in WASM backend. Use REST backend for BM25 search.",
233
+ "NOT_SUPPORTED"
234
+ );
235
+ }
236
+ async hybridSearch(_collection, _vector, _textQuery, _options) {
237
+ throw new VelesDBError(
238
+ "Hybrid search is not supported in WASM backend. Use REST backend for hybrid search.",
239
+ "NOT_SUPPORTED"
240
+ );
241
+ }
242
+ async query(_queryString, _params) {
243
+ throw new VelesDBError(
244
+ "VelesQL queries are not supported in WASM backend. Use REST backend for query support.",
245
+ "NOT_SUPPORTED"
246
+ );
247
+ }
214
248
  async close() {
215
249
  for (const [, data] of this.collections) {
216
250
  data.store.free();
@@ -411,6 +445,26 @@ var RestBackend = class {
411
445
  }
412
446
  return response.data ?? [];
413
447
  }
448
+ async searchBatch(collection, searches) {
449
+ this.ensureInitialized();
450
+ const formattedSearches = searches.map((s) => ({
451
+ vector: s.vector instanceof Float32Array ? Array.from(s.vector) : s.vector,
452
+ top_k: s.k ?? 10,
453
+ filter: s.filter
454
+ }));
455
+ const response = await this.request(
456
+ "POST",
457
+ `/collections/${encodeURIComponent(collection)}/search/batch`,
458
+ { searches: formattedSearches }
459
+ );
460
+ if (response.error) {
461
+ if (response.error.code === "NOT_FOUND") {
462
+ throw new NotFoundError(`Collection '${collection}'`);
463
+ }
464
+ throw new VelesDBError(response.error.message, response.error.code);
465
+ }
466
+ return response.data?.results.map((r) => r.results) ?? [];
467
+ }
414
468
  async delete(collection, id) {
415
469
  this.ensureInitialized();
416
470
  const response = await this.request(
@@ -439,6 +493,62 @@ var RestBackend = class {
439
493
  }
440
494
  return response.data ?? null;
441
495
  }
496
+ async textSearch(collection, query, options) {
497
+ this.ensureInitialized();
498
+ const response = await this.request(
499
+ "POST",
500
+ `/collections/${encodeURIComponent(collection)}/search/text`,
501
+ {
502
+ query,
503
+ top_k: options?.k ?? 10,
504
+ filter: options?.filter
505
+ }
506
+ );
507
+ if (response.error) {
508
+ if (response.error.code === "NOT_FOUND") {
509
+ throw new NotFoundError(`Collection '${collection}'`);
510
+ }
511
+ throw new VelesDBError(response.error.message, response.error.code);
512
+ }
513
+ return response.data?.results ?? [];
514
+ }
515
+ async hybridSearch(collection, vector, textQuery, options) {
516
+ this.ensureInitialized();
517
+ const queryVector = vector instanceof Float32Array ? Array.from(vector) : vector;
518
+ const response = await this.request(
519
+ "POST",
520
+ `/collections/${encodeURIComponent(collection)}/search/hybrid`,
521
+ {
522
+ vector: queryVector,
523
+ query: textQuery,
524
+ top_k: options?.k ?? 10,
525
+ vector_weight: options?.vectorWeight ?? 0.5,
526
+ filter: options?.filter
527
+ }
528
+ );
529
+ if (response.error) {
530
+ if (response.error.code === "NOT_FOUND") {
531
+ throw new NotFoundError(`Collection '${collection}'`);
532
+ }
533
+ throw new VelesDBError(response.error.message, response.error.code);
534
+ }
535
+ return response.data?.results ?? [];
536
+ }
537
+ async query(queryString, params) {
538
+ this.ensureInitialized();
539
+ const response = await this.request(
540
+ "POST",
541
+ "/query",
542
+ {
543
+ query: queryString,
544
+ params: params ?? {}
545
+ }
546
+ );
547
+ if (response.error) {
548
+ throw new VelesDBError(response.error.message, response.error.code);
549
+ }
550
+ return response.data?.results ?? [];
551
+ }
442
552
  async close() {
443
553
  this._initialized = false;
444
554
  }
@@ -598,6 +708,25 @@ var VelesDB = class {
598
708
  }
599
709
  return this.backend.search(collection, query, options);
600
710
  }
711
+ /**
712
+ * Search for multiple vectors in parallel
713
+ *
714
+ * @param collection - Collection name
715
+ * @param searches - List of search queries
716
+ * @returns List of search results for each query
717
+ */
718
+ async searchBatch(collection, searches) {
719
+ this.ensureInitialized();
720
+ if (!Array.isArray(searches)) {
721
+ throw new ValidationError("Searches must be an array");
722
+ }
723
+ for (const s of searches) {
724
+ if (!s.vector || !Array.isArray(s.vector) && !(s.vector instanceof Float32Array)) {
725
+ throw new ValidationError("Each search must have a vector (array or Float32Array)");
726
+ }
727
+ }
728
+ return this.backend.searchBatch(collection, searches);
729
+ }
601
730
  /**
602
731
  * Delete a vector by ID
603
732
  *
@@ -620,6 +749,54 @@ var VelesDB = class {
620
749
  this.ensureInitialized();
621
750
  return this.backend.get(collection, id);
622
751
  }
752
+ /**
753
+ * Perform full-text search using BM25
754
+ *
755
+ * @param collection - Collection name
756
+ * @param query - Text query
757
+ * @param options - Search options (k, filter)
758
+ * @returns Search results sorted by BM25 score
759
+ */
760
+ async textSearch(collection, query, options) {
761
+ this.ensureInitialized();
762
+ if (!query || typeof query !== "string") {
763
+ throw new ValidationError("Query must be a non-empty string");
764
+ }
765
+ return this.backend.textSearch(collection, query, options);
766
+ }
767
+ /**
768
+ * Perform hybrid search combining vector similarity and BM25 text search
769
+ *
770
+ * @param collection - Collection name
771
+ * @param vector - Query vector
772
+ * @param textQuery - Text query for BM25
773
+ * @param options - Search options (k, vectorWeight, filter)
774
+ * @returns Search results sorted by fused score
775
+ */
776
+ async hybridSearch(collection, vector, textQuery, options) {
777
+ this.ensureInitialized();
778
+ if (!vector || !Array.isArray(vector) && !(vector instanceof Float32Array)) {
779
+ throw new ValidationError("Vector must be an array or Float32Array");
780
+ }
781
+ if (!textQuery || typeof textQuery !== "string") {
782
+ throw new ValidationError("Text query must be a non-empty string");
783
+ }
784
+ return this.backend.hybridSearch(collection, vector, textQuery, options);
785
+ }
786
+ /**
787
+ * Execute a VelesQL query
788
+ *
789
+ * @param queryString - VelesQL query string
790
+ * @param params - Optional query parameters
791
+ * @returns Query results
792
+ */
793
+ async query(queryString, params) {
794
+ this.ensureInitialized();
795
+ if (!queryString || typeof queryString !== "string") {
796
+ throw new ValidationError("Query string must be a non-empty string");
797
+ }
798
+ return this.backend.query(queryString, params);
799
+ }
623
800
  /**
624
801
  * Close the client and release resources
625
802
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiscale/velesdb-sdk",
3
- "version": "0.8.4",
3
+ "version": "0.8.8",
4
4
  "description": "Official TypeScript SDK for VelesDB - Vector Search in Microseconds",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -63,7 +63,7 @@
63
63
  "vitest": "^4.0.16"
64
64
  },
65
65
  "dependencies": {
66
- "@wiscale/velesdb-wasm": "^0.6.0"
66
+ "@wiscale/velesdb-wasm": "^0.8.8"
67
67
  },
68
68
  "engines": {
69
69
  "node": ">=18.0.0"