@lancedb/lancedb 0.5.2 → 0.7.1

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.
Files changed (89) hide show
  1. package/Cargo.toml +3 -3
  2. package/biome.json +19 -3
  3. package/dist/arrow.d.ts +41 -8
  4. package/dist/arrow.js +4 -4
  5. package/dist/connection.d.ts +49 -29
  6. package/dist/connection.js +21 -73
  7. package/dist/embedding/embedding_function.d.ts +9 -1
  8. package/dist/embedding/embedding_function.js +6 -0
  9. package/dist/embedding/openai.d.ts +6 -5
  10. package/dist/embedding/openai.js +4 -2
  11. package/dist/embedding/registry.d.ts +6 -11
  12. package/dist/index.d.ts +51 -3
  13. package/dist/index.js +28 -4
  14. package/dist/merge.d.ts +54 -0
  15. package/dist/merge.js +64 -0
  16. package/dist/native.d.ts +29 -3
  17. package/dist/native.js +26 -9
  18. package/dist/query.d.ts +33 -10
  19. package/dist/query.js +100 -13
  20. package/dist/remote/client.d.ts +28 -0
  21. package/dist/remote/client.js +172 -0
  22. package/dist/remote/connection.d.ts +25 -0
  23. package/dist/remote/connection.js +110 -0
  24. package/dist/remote/index.d.ts +3 -0
  25. package/dist/remote/index.js +9 -0
  26. package/dist/remote/table.d.ts +42 -0
  27. package/dist/remote/table.js +179 -0
  28. package/dist/sanitize.d.ts +3 -2
  29. package/dist/sanitize.js +55 -1
  30. package/dist/table.d.ts +105 -30
  31. package/dist/table.js +94 -237
  32. package/dist/util.d.ts +14 -0
  33. package/dist/util.js +65 -0
  34. package/examples/ann_indexes.ts +49 -0
  35. package/examples/basic.ts +149 -0
  36. package/examples/embedding.ts +83 -0
  37. package/examples/filtering.ts +34 -0
  38. package/examples/jsconfig.json +27 -0
  39. package/examples/package-lock.json +79 -0
  40. package/examples/package.json +18 -0
  41. package/examples/search.ts +37 -0
  42. package/lancedb/arrow.ts +80 -23
  43. package/lancedb/connection.ts +107 -92
  44. package/lancedb/embedding/embedding_function.ts +12 -1
  45. package/lancedb/embedding/openai.ts +11 -6
  46. package/lancedb/embedding/registry.ts +34 -22
  47. package/lancedb/index.ts +101 -2
  48. package/lancedb/merge.ts +70 -0
  49. package/lancedb/query.ts +114 -28
  50. package/lancedb/remote/client.ts +221 -0
  51. package/lancedb/remote/connection.ts +201 -0
  52. package/lancedb/remote/index.ts +3 -0
  53. package/lancedb/remote/table.ts +226 -0
  54. package/lancedb/sanitize.ts +73 -1
  55. package/lancedb/table.ts +320 -132
  56. package/lancedb/util.ts +69 -0
  57. package/native.d.ts +208 -0
  58. package/nodejs-artifacts/arrow.d.ts +41 -8
  59. package/nodejs-artifacts/arrow.js +4 -4
  60. package/nodejs-artifacts/connection.d.ts +49 -29
  61. package/nodejs-artifacts/connection.js +21 -73
  62. package/nodejs-artifacts/embedding/embedding_function.d.ts +9 -1
  63. package/nodejs-artifacts/embedding/embedding_function.js +6 -0
  64. package/nodejs-artifacts/embedding/openai.d.ts +6 -5
  65. package/nodejs-artifacts/embedding/openai.js +4 -2
  66. package/nodejs-artifacts/embedding/registry.d.ts +6 -11
  67. package/nodejs-artifacts/index.d.ts +51 -3
  68. package/nodejs-artifacts/index.js +28 -4
  69. package/nodejs-artifacts/merge.d.ts +54 -0
  70. package/nodejs-artifacts/merge.js +64 -0
  71. package/nodejs-artifacts/native.d.ts +29 -3
  72. package/nodejs-artifacts/native.js +26 -9
  73. package/nodejs-artifacts/query.d.ts +33 -10
  74. package/nodejs-artifacts/query.js +100 -13
  75. package/nodejs-artifacts/remote/client.d.ts +28 -0
  76. package/nodejs-artifacts/remote/client.js +172 -0
  77. package/nodejs-artifacts/remote/connection.d.ts +25 -0
  78. package/nodejs-artifacts/remote/connection.js +110 -0
  79. package/nodejs-artifacts/remote/index.d.ts +3 -0
  80. package/nodejs-artifacts/remote/index.js +9 -0
  81. package/nodejs-artifacts/remote/table.d.ts +42 -0
  82. package/nodejs-artifacts/remote/table.js +179 -0
  83. package/nodejs-artifacts/sanitize.d.ts +3 -2
  84. package/nodejs-artifacts/sanitize.js +55 -1
  85. package/nodejs-artifacts/table.d.ts +105 -30
  86. package/nodejs-artifacts/table.js +94 -237
  87. package/nodejs-artifacts/util.d.ts +14 -0
  88. package/nodejs-artifacts/util.js +65 -0
  89. package/package.json +25 -11
package/lancedb/table.ts CHANGED
@@ -17,20 +17,30 @@ import {
17
17
  Data,
18
18
  IntoVector,
19
19
  Schema,
20
+ TableLike,
20
21
  fromDataToBuffer,
22
+ fromTableToBuffer,
23
+ fromTableToStreamBuffer,
24
+ isArrowTable,
25
+ makeArrowTable,
21
26
  tableFromIPC,
22
27
  } from "./arrow";
28
+ import { CreateTableOptions } from "./connection";
23
29
 
24
30
  import { EmbeddingFunctionConfig, getRegistry } from "./embedding/registry";
25
31
  import { IndexOptions } from "./indices";
32
+ import { MergeInsertBuilder } from "./merge";
26
33
  import {
27
34
  AddColumnsSql,
28
35
  ColumnAlteration,
29
36
  IndexConfig,
37
+ IndexStatistics,
30
38
  OptimizeStats,
31
39
  Table as _NativeTable,
32
40
  } from "./native";
33
41
  import { Query, VectorQuery } from "./query";
42
+ import { sanitizeTable } from "./sanitize";
43
+ import { IntoSql, toSQL } from "./util";
34
44
  export { IndexConfig } from "./native";
35
45
 
36
46
  /**
@@ -88,19 +98,15 @@ export interface OptimizeOptions {
88
98
  * Closing a table is optional. It not closed, it will be closed when it is garbage
89
99
  * collected.
90
100
  */
91
- export class Table {
92
- private readonly inner: _NativeTable;
93
-
94
- /** Construct a Table. Internal use only. */
95
- constructor(inner: _NativeTable) {
96
- this.inner = inner;
101
+ export abstract class Table {
102
+ [Symbol.for("nodejs.util.inspect.custom")](): string {
103
+ return this.display();
97
104
  }
105
+ /** Returns the name of the table */
106
+ abstract get name(): string;
98
107
 
99
108
  /** Return true if the table has not been closed */
100
- isOpen(): boolean {
101
- return this.inner.isOpen();
102
- }
103
-
109
+ abstract isOpen(): boolean;
104
110
  /**
105
111
  * Close the table, releasing any underlying resources.
106
112
  *
@@ -108,48 +114,44 @@ export class Table {
108
114
  *
109
115
  * Any attempt to use the table after it is closed will result in an error.
110
116
  */
111
- close(): void {
112
- this.inner.close();
113
- }
114
-
117
+ abstract close(): void;
115
118
  /** Return a brief description of the table */
116
- display(): string {
117
- return this.inner.display();
118
- }
119
-
120
- async #getEmbeddingFunctions(): Promise<
121
- Map<string, EmbeddingFunctionConfig>
122
- > {
123
- const schema = await this.schema();
124
- const registry = getRegistry();
125
- return registry.parseFunctions(schema.metadata);
126
- }
127
-
119
+ abstract display(): string;
128
120
  /** Get the schema of the table. */
129
- async schema(): Promise<Schema> {
130
- const schemaBuf = await this.inner.schema();
131
- const tbl = tableFromIPC(schemaBuf);
132
- return tbl.schema;
133
- }
134
-
121
+ abstract schema(): Promise<Schema>;
135
122
  /**
136
123
  * Insert records into this Table.
137
124
  * @param {Data} data Records to be inserted into the Table
138
125
  */
139
- async add(data: Data, options?: Partial<AddDataOptions>): Promise<void> {
140
- const mode = options?.mode ?? "append";
141
- const schema = await this.schema();
142
- const registry = getRegistry();
143
- const functions = registry.parseFunctions(schema.metadata);
144
-
145
- const buffer = await fromDataToBuffer(
146
- data,
147
- functions.values().next().value,
148
- schema,
149
- );
150
- await this.inner.add(buffer, mode);
151
- }
152
-
126
+ abstract add(data: Data, options?: Partial<AddDataOptions>): Promise<void>;
127
+ /**
128
+ * Update existing records in the Table
129
+ * @param opts.values The values to update. The keys are the column names and the values
130
+ * are the values to set.
131
+ * @example
132
+ * ```ts
133
+ * table.update({where:"x = 2", values:{"vector": [10, 10]}})
134
+ * ```
135
+ */
136
+ abstract update(
137
+ opts: {
138
+ values: Map<string, IntoSql> | Record<string, IntoSql>;
139
+ } & Partial<UpdateOptions>,
140
+ ): Promise<void>;
141
+ /**
142
+ * Update existing records in the Table
143
+ * @param opts.valuesSql The values to update. The keys are the column names and the values
144
+ * are the values to set. The values are SQL expressions.
145
+ * @example
146
+ * ```ts
147
+ * table.update({where:"x = 2", valuesSql:{"x": "x + 1"}})
148
+ * ```
149
+ */
150
+ abstract update(
151
+ opts: {
152
+ valuesSql: Map<string, string> | Record<string, string>;
153
+ } & Partial<UpdateOptions>,
154
+ ): Promise<void>;
153
155
  /**
154
156
  * Update existing records in the Table
155
157
  *
@@ -175,30 +177,15 @@ export class Table {
175
177
  * @param {Partial<UpdateOptions>} options - additional options to control
176
178
  * the update behavior
177
179
  */
178
- async update(
180
+ abstract update(
179
181
  updates: Map<string, string> | Record<string, string>,
180
182
  options?: Partial<UpdateOptions>,
181
- ) {
182
- const onlyIf = options?.where;
183
- let columns: [string, string][];
184
- if (updates instanceof Map) {
185
- columns = Array.from(updates.entries());
186
- } else {
187
- columns = Object.entries(updates);
188
- }
189
- await this.inner.update(onlyIf, columns);
190
- }
183
+ ): Promise<void>;
191
184
 
192
185
  /** Count the total number of rows in the dataset. */
193
- async countRows(filter?: string): Promise<number> {
194
- return await this.inner.countRows(filter);
195
- }
196
-
186
+ abstract countRows(filter?: string): Promise<number>;
197
187
  /** Delete the rows that satisfy the predicate. */
198
- async delete(predicate: string): Promise<void> {
199
- await this.inner.delete(predicate);
200
- }
201
-
188
+ abstract delete(predicate: string): Promise<void>;
202
189
  /**
203
190
  * Create an index to speed up queries.
204
191
  *
@@ -206,6 +193,9 @@ export class Table {
206
193
  * Indices on vector columns will speed up vector searches.
207
194
  * Indices on scalar columns will speed up filtering (in both
208
195
  * vector and non-vector searches)
196
+ *
197
+ * @note We currently don't support custom named indexes,
198
+ * The index name will always be `${column}_idx`
209
199
  * @example
210
200
  * // If the column has a vector (fixed size list) data type then
211
201
  * // an IvfPq vector index will be created.
@@ -225,13 +215,10 @@ export class Table {
225
215
  * // Or create a Scalar index
226
216
  * await table.createIndex("my_float_col");
227
217
  */
228
- async createIndex(column: string, options?: Partial<IndexOptions>) {
229
- // Bit of a hack to get around the fact that TS has no package-scope.
230
- // biome-ignore lint/suspicious/noExplicitAny: skip
231
- const nativeIndex = (options?.config as any)?.inner;
232
- await this.inner.createIndex(nativeIndex, column, options?.replace);
233
- }
234
-
218
+ abstract createIndex(
219
+ column: string,
220
+ options?: Partial<IndexOptions>,
221
+ ): Promise<void>;
235
222
  /**
236
223
  * Create a {@link Query} Builder.
237
224
  *
@@ -282,44 +269,20 @@ export class Table {
282
269
  * }
283
270
  * @returns {Query} A builder that can be used to parameterize the query
284
271
  */
285
- query(): Query {
286
- return new Query(this.inner);
287
- }
288
-
272
+ abstract query(): Query;
289
273
  /**
290
274
  * Create a search query to find the nearest neighbors
291
275
  * of the given query vector
292
276
  * @param {string} query - the query. This will be converted to a vector using the table's provided embedding function
293
- * @rejects {Error} If no embedding functions are defined in the table
277
+ * @note If no embedding functions are defined in the table, this will error when collecting the results.
294
278
  */
295
- search(query: string): Promise<VectorQuery>;
279
+ abstract search(query: string): VectorQuery;
296
280
  /**
297
281
  * Create a search query to find the nearest neighbors
298
282
  * of the given query vector
299
283
  * @param {IntoVector} query - the query vector
300
284
  */
301
- search(query: IntoVector): VectorQuery;
302
- search(query: string | IntoVector): Promise<VectorQuery> | VectorQuery {
303
- if (typeof query !== "string") {
304
- return this.vectorSearch(query);
305
- } else {
306
- return this.#getEmbeddingFunctions().then(async (functions) => {
307
- // TODO: Support multiple embedding functions
308
- const embeddingFunc: EmbeddingFunctionConfig | undefined = functions
309
- .values()
310
- .next().value;
311
- if (!embeddingFunc) {
312
- return Promise.reject(
313
- new Error("No embedding functions are defined in the table"),
314
- );
315
- }
316
- const embeddings =
317
- await embeddingFunc.function.computeQueryEmbeddings(query);
318
- return this.query().nearestTo(embeddings);
319
- });
320
- }
321
- }
322
-
285
+ abstract search(query: IntoVector): VectorQuery;
323
286
  /**
324
287
  * Search the table with a given query vector.
325
288
  *
@@ -327,11 +290,7 @@ export class Table {
327
290
  * is the same thing as calling `nearestTo` on the builder returned
328
291
  * by `query`. @see {@link Query#nearestTo} for more details.
329
292
  */
330
- vectorSearch(vector: IntoVector): VectorQuery {
331
- return this.query().nearestTo(vector);
332
- }
333
-
334
- // TODO: Support BatchUDF
293
+ abstract vectorSearch(vector: IntoVector): VectorQuery;
335
294
  /**
336
295
  * Add new columns with defined values.
337
296
  * @param {AddColumnsSql[]} newColumnTransforms pairs of column names and
@@ -339,19 +298,14 @@ export class Table {
339
298
  * expressions will be evaluated for each row in the table, and can
340
299
  * reference existing columns in the table.
341
300
  */
342
- async addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void> {
343
- await this.inner.addColumns(newColumnTransforms);
344
- }
301
+ abstract addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void>;
345
302
 
346
303
  /**
347
304
  * Alter the name or nullability of columns.
348
305
  * @param {ColumnAlteration[]} columnAlterations One or more alterations to
349
306
  * apply to columns.
350
307
  */
351
- async alterColumns(columnAlterations: ColumnAlteration[]): Promise<void> {
352
- await this.inner.alterColumns(columnAlterations);
353
- }
354
-
308
+ abstract alterColumns(columnAlterations: ColumnAlteration[]): Promise<void>;
355
309
  /**
356
310
  * Drop one or more columns from the dataset
357
311
  *
@@ -363,15 +317,10 @@ export class Table {
363
317
  * be nested column references (e.g. "a.b.c") or top-level column names
364
318
  * (e.g. "a").
365
319
  */
366
- async dropColumns(columnNames: string[]): Promise<void> {
367
- await this.inner.dropColumns(columnNames);
368
- }
369
-
320
+ abstract dropColumns(columnNames: string[]): Promise<void>;
370
321
  /** Retrieve the version of the table */
371
- async version(): Promise<number> {
372
- return await this.inner.version();
373
- }
374
322
 
323
+ abstract version(): Promise<number>;
375
324
  /**
376
325
  * Checks out a specific version of the table _This is an in-place operation._
377
326
  *
@@ -397,19 +346,14 @@ export class Table {
397
346
  * console.log(await table.version()); // 2
398
347
  * ```
399
348
  */
400
- async checkout(version: number): Promise<void> {
401
- await this.inner.checkout(version);
402
- }
403
-
349
+ abstract checkout(version: number): Promise<void>;
404
350
  /**
405
351
  * Checkout the latest version of the table. _This is an in-place operation._
406
352
  *
407
353
  * The table will be set back into standard mode, and will track the latest
408
354
  * version of the table.
409
355
  */
410
- async checkoutLatest(): Promise<void> {
411
- await this.inner.checkoutLatest();
412
- }
356
+ abstract checkoutLatest(): Promise<void>;
413
357
 
414
358
  /**
415
359
  * Restore the table to the currently checked out version
@@ -423,10 +367,7 @@ export class Table {
423
367
  * Once the operation concludes the table will no longer be in a checked
424
368
  * out state and the read_consistency_interval, if any, will apply.
425
369
  */
426
- async restore(): Promise<void> {
427
- await this.inner.restore();
428
- }
429
-
370
+ abstract restore(): Promise<void>;
430
371
  /**
431
372
  * Optimize the on-disk data and indices for better performance.
432
373
  *
@@ -457,6 +398,243 @@ export class Table {
457
398
  * you have added or modified 100,000 or more records or run more than 20 data
458
399
  * modification operations.
459
400
  */
401
+ abstract optimize(options?: Partial<OptimizeOptions>): Promise<OptimizeStats>;
402
+ /** List all indices that have been created with {@link Table.createIndex} */
403
+ abstract listIndices(): Promise<IndexConfig[]>;
404
+ /** Return the table as an arrow table */
405
+ abstract toArrow(): Promise<ArrowTable>;
406
+
407
+ abstract mergeInsert(on: string | string[]): MergeInsertBuilder;
408
+
409
+ /** List all the stats of a specified index
410
+ *
411
+ * @param {string} name The name of the index.
412
+ * @returns {IndexStatistics | undefined} The stats of the index. If the index does not exist, it will return undefined
413
+ */
414
+ abstract indexStats(name: string): Promise<IndexStatistics | undefined>;
415
+
416
+ static async parseTableData(
417
+ data: Record<string, unknown>[] | TableLike,
418
+ options?: Partial<CreateTableOptions>,
419
+ streaming = false,
420
+ ) {
421
+ let mode: string = options?.mode ?? "create";
422
+ const existOk = options?.existOk ?? false;
423
+
424
+ if (mode === "create" && existOk) {
425
+ mode = "exist_ok";
426
+ }
427
+
428
+ let table: ArrowTable;
429
+ if (isArrowTable(data)) {
430
+ table = sanitizeTable(data);
431
+ } else {
432
+ table = makeArrowTable(data as Record<string, unknown>[], options);
433
+ }
434
+ if (streaming) {
435
+ const buf = await fromTableToStreamBuffer(
436
+ table,
437
+ options?.embeddingFunction,
438
+ options?.schema,
439
+ );
440
+ return { buf, mode };
441
+ } else {
442
+ const buf = await fromTableToBuffer(
443
+ table,
444
+ options?.embeddingFunction,
445
+ options?.schema,
446
+ );
447
+ return { buf, mode };
448
+ }
449
+ }
450
+ }
451
+
452
+ export class LocalTable extends Table {
453
+ private readonly inner: _NativeTable;
454
+
455
+ constructor(inner: _NativeTable) {
456
+ super();
457
+ this.inner = inner;
458
+ }
459
+ get name(): string {
460
+ return this.inner.name;
461
+ }
462
+ isOpen(): boolean {
463
+ return this.inner.isOpen();
464
+ }
465
+
466
+ close(): void {
467
+ this.inner.close();
468
+ }
469
+
470
+ display(): string {
471
+ return this.inner.display();
472
+ }
473
+
474
+ private async getEmbeddingFunctions(): Promise<
475
+ Map<string, EmbeddingFunctionConfig>
476
+ > {
477
+ const schema = await this.schema();
478
+ const registry = getRegistry();
479
+ return registry.parseFunctions(schema.metadata);
480
+ }
481
+
482
+ /** Get the schema of the table. */
483
+ async schema(): Promise<Schema> {
484
+ const schemaBuf = await this.inner.schema();
485
+ const tbl = tableFromIPC(schemaBuf);
486
+ return tbl.schema;
487
+ }
488
+
489
+ async add(data: Data, options?: Partial<AddDataOptions>): Promise<void> {
490
+ const mode = options?.mode ?? "append";
491
+ const schema = await this.schema();
492
+ const registry = getRegistry();
493
+ const functions = registry.parseFunctions(schema.metadata);
494
+
495
+ const buffer = await fromDataToBuffer(
496
+ data,
497
+ functions.values().next().value,
498
+ schema,
499
+ );
500
+ await this.inner.add(buffer, mode);
501
+ }
502
+
503
+ async update(
504
+ optsOrUpdates:
505
+ | (Map<string, string> | Record<string, string>)
506
+ | ({
507
+ values: Map<string, IntoSql> | Record<string, IntoSql>;
508
+ } & Partial<UpdateOptions>)
509
+ | ({
510
+ valuesSql: Map<string, string> | Record<string, string>;
511
+ } & Partial<UpdateOptions>),
512
+ options?: Partial<UpdateOptions>,
513
+ ) {
514
+ const isValues =
515
+ "values" in optsOrUpdates && typeof optsOrUpdates.values !== "string";
516
+ const isValuesSql =
517
+ "valuesSql" in optsOrUpdates &&
518
+ typeof optsOrUpdates.valuesSql !== "string";
519
+ const isMap = (obj: unknown): obj is Map<string, string> => {
520
+ return obj instanceof Map;
521
+ };
522
+
523
+ let predicate;
524
+ let columns: [string, string][];
525
+ switch (true) {
526
+ case isMap(optsOrUpdates):
527
+ columns = Array.from(optsOrUpdates.entries());
528
+ predicate = options?.where;
529
+ break;
530
+ case isValues && isMap(optsOrUpdates.values):
531
+ columns = Array.from(optsOrUpdates.values.entries()).map(([k, v]) => [
532
+ k,
533
+ toSQL(v),
534
+ ]);
535
+ predicate = optsOrUpdates.where;
536
+ break;
537
+ case isValues && !isMap(optsOrUpdates.values):
538
+ columns = Object.entries(optsOrUpdates.values).map(([k, v]) => [
539
+ k,
540
+ toSQL(v),
541
+ ]);
542
+ predicate = optsOrUpdates.where;
543
+ break;
544
+
545
+ case isValuesSql && isMap(optsOrUpdates.valuesSql):
546
+ columns = Array.from(optsOrUpdates.valuesSql.entries());
547
+ predicate = optsOrUpdates.where;
548
+ break;
549
+ case isValuesSql && !isMap(optsOrUpdates.valuesSql):
550
+ columns = Object.entries(optsOrUpdates.valuesSql).map(([k, v]) => [
551
+ k,
552
+ v,
553
+ ]);
554
+ predicate = optsOrUpdates.where;
555
+ break;
556
+ default:
557
+ columns = Object.entries(optsOrUpdates as Record<string, string>);
558
+ predicate = options?.where;
559
+ }
560
+ await this.inner.update(predicate, columns);
561
+ }
562
+
563
+ async countRows(filter?: string): Promise<number> {
564
+ return await this.inner.countRows(filter);
565
+ }
566
+
567
+ async delete(predicate: string): Promise<void> {
568
+ await this.inner.delete(predicate);
569
+ }
570
+
571
+ async createIndex(column: string, options?: Partial<IndexOptions>) {
572
+ // Bit of a hack to get around the fact that TS has no package-scope.
573
+ // biome-ignore lint/suspicious/noExplicitAny: skip
574
+ const nativeIndex = (options?.config as any)?.inner;
575
+ await this.inner.createIndex(nativeIndex, column, options?.replace);
576
+ }
577
+
578
+ query(): Query {
579
+ return new Query(this.inner);
580
+ }
581
+ search(query: string | IntoVector): VectorQuery {
582
+ if (typeof query !== "string") {
583
+ return this.vectorSearch(query);
584
+ } else {
585
+ const queryPromise = this.getEmbeddingFunctions().then(
586
+ async (functions) => {
587
+ // TODO: Support multiple embedding functions
588
+ const embeddingFunc: EmbeddingFunctionConfig | undefined = functions
589
+ .values()
590
+ .next().value;
591
+ if (!embeddingFunc) {
592
+ return Promise.reject(
593
+ new Error("No embedding functions are defined in the table"),
594
+ );
595
+ }
596
+ return await embeddingFunc.function.computeQueryEmbeddings(query);
597
+ },
598
+ );
599
+
600
+ return this.query().nearestTo(queryPromise);
601
+ }
602
+ }
603
+
604
+ vectorSearch(vector: IntoVector): VectorQuery {
605
+ return this.query().nearestTo(vector);
606
+ }
607
+
608
+ // TODO: Support BatchUDF
609
+
610
+ async addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void> {
611
+ await this.inner.addColumns(newColumnTransforms);
612
+ }
613
+
614
+ async alterColumns(columnAlterations: ColumnAlteration[]): Promise<void> {
615
+ await this.inner.alterColumns(columnAlterations);
616
+ }
617
+
618
+ async dropColumns(columnNames: string[]): Promise<void> {
619
+ await this.inner.dropColumns(columnNames);
620
+ }
621
+
622
+ async version(): Promise<number> {
623
+ return await this.inner.version();
624
+ }
625
+
626
+ async checkout(version: number): Promise<void> {
627
+ await this.inner.checkout(version);
628
+ }
629
+
630
+ async checkoutLatest(): Promise<void> {
631
+ await this.inner.checkoutLatest();
632
+ }
633
+
634
+ async restore(): Promise<void> {
635
+ await this.inner.restore();
636
+ }
637
+
460
638
  async optimize(options?: Partial<OptimizeOptions>): Promise<OptimizeStats> {
461
639
  let cleanupOlderThanMs;
462
640
  if (
@@ -469,13 +647,23 @@ export class Table {
469
647
  return await this.inner.optimize(cleanupOlderThanMs);
470
648
  }
471
649
 
472
- /** List all indices that have been created with {@link Table.createIndex} */
473
650
  async listIndices(): Promise<IndexConfig[]> {
474
651
  return await this.inner.listIndices();
475
652
  }
476
653
 
477
- /** Return the table as an arrow table */
478
654
  async toArrow(): Promise<ArrowTable> {
479
655
  return await this.query().toArrow();
480
656
  }
657
+
658
+ async indexStats(name: string): Promise<IndexStatistics | undefined> {
659
+ const stats = await this.inner.indexStats(name);
660
+ if (stats === null) {
661
+ return undefined;
662
+ }
663
+ return stats;
664
+ }
665
+ mergeInsert(on: string | string[]): MergeInsertBuilder {
666
+ on = Array.isArray(on) ? on : [on];
667
+ return new MergeInsertBuilder(this.inner.mergeInsert(on));
668
+ }
481
669
  }
@@ -0,0 +1,69 @@
1
+ export type IntoSql =
2
+ | string
3
+ | number
4
+ | boolean
5
+ | null
6
+ | Date
7
+ | ArrayBufferLike
8
+ | Buffer
9
+ | IntoSql[];
10
+
11
+ export function toSQL(value: IntoSql): string {
12
+ if (typeof value === "string") {
13
+ return `'${value.replace(/'/g, "''")}'`;
14
+ } else if (typeof value === "number") {
15
+ return value.toString();
16
+ } else if (typeof value === "boolean") {
17
+ return value ? "TRUE" : "FALSE";
18
+ } else if (value === null) {
19
+ return "NULL";
20
+ } else if (value instanceof Date) {
21
+ return `'${value.toISOString()}'`;
22
+ } else if (Array.isArray(value)) {
23
+ return `[${value.map(toSQL).join(", ")}]`;
24
+ } else if (Buffer.isBuffer(value)) {
25
+ return `X'${value.toString("hex")}'`;
26
+ } else if (value instanceof ArrayBuffer) {
27
+ return `X'${Buffer.from(value).toString("hex")}'`;
28
+ } else {
29
+ throw new Error(
30
+ `Unsupported value type: ${typeof value} value: (${value})`,
31
+ );
32
+ }
33
+ }
34
+
35
+ export class TTLCache {
36
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
37
+ private readonly cache: Map<string, { value: any; expires: number }>;
38
+
39
+ /**
40
+ * @param ttl Time to live in milliseconds
41
+ */
42
+ constructor(private readonly ttl: number) {
43
+ this.cache = new Map();
44
+ }
45
+
46
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
47
+ get(key: string): any | undefined {
48
+ const entry = this.cache.get(key);
49
+ if (entry === undefined) {
50
+ return undefined;
51
+ }
52
+
53
+ if (entry.expires < Date.now()) {
54
+ this.cache.delete(key);
55
+ return undefined;
56
+ }
57
+
58
+ return entry.value;
59
+ }
60
+
61
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
62
+ set(key: string, value: any): void {
63
+ this.cache.set(key, { value, expires: Date.now() + this.ttl });
64
+ }
65
+
66
+ delete(key: string): void {
67
+ this.cache.delete(key);
68
+ }
69
+ }