@lancedb/lancedb 0.5.1 → 0.7.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.
Files changed (91) hide show
  1. package/Cargo.toml +3 -3
  2. package/biome.json +19 -3
  3. package/dist/arrow.d.ts +42 -7
  4. package/dist/arrow.js +6 -5
  5. package/dist/connection.d.ts +55 -29
  6. package/dist/connection.js +22 -74
  7. package/dist/embedding/embedding_function.d.ts +11 -3
  8. package/dist/embedding/embedding_function.js +36 -12
  9. package/dist/embedding/openai.d.ts +6 -5
  10. package/dist/embedding/openai.js +4 -2
  11. package/dist/embedding/registry.d.ts +10 -11
  12. package/dist/embedding/registry.js +4 -0
  13. package/dist/index.d.ts +51 -3
  14. package/dist/index.js +28 -4
  15. package/dist/merge.d.ts +54 -0
  16. package/dist/merge.js +64 -0
  17. package/dist/native.d.ts +34 -7
  18. package/dist/native.js +26 -9
  19. package/dist/query.d.ts +51 -16
  20. package/dist/query.js +122 -21
  21. package/dist/remote/client.d.ts +28 -0
  22. package/dist/remote/client.js +172 -0
  23. package/dist/remote/connection.d.ts +25 -0
  24. package/dist/remote/connection.js +110 -0
  25. package/dist/remote/index.d.ts +3 -0
  26. package/dist/remote/index.js +9 -0
  27. package/dist/remote/table.d.ts +42 -0
  28. package/dist/remote/table.js +179 -0
  29. package/dist/sanitize.d.ts +3 -2
  30. package/dist/sanitize.js +55 -1
  31. package/dist/table.d.ts +116 -25
  32. package/dist/table.js +117 -233
  33. package/dist/util.d.ts +14 -0
  34. package/dist/util.js +65 -0
  35. package/examples/ann_indexes.ts +49 -0
  36. package/examples/basic.ts +149 -0
  37. package/examples/embedding.ts +83 -0
  38. package/examples/filtering.ts +34 -0
  39. package/examples/jsconfig.json +27 -0
  40. package/examples/package-lock.json +79 -0
  41. package/examples/package.json +18 -0
  42. package/examples/search.ts +37 -0
  43. package/lancedb/arrow.ts +87 -24
  44. package/lancedb/connection.ts +115 -92
  45. package/lancedb/embedding/embedding_function.ts +48 -16
  46. package/lancedb/embedding/openai.ts +11 -6
  47. package/lancedb/embedding/registry.ts +38 -22
  48. package/lancedb/index.ts +101 -2
  49. package/lancedb/merge.ts +70 -0
  50. package/lancedb/query.ts +168 -39
  51. package/lancedb/remote/client.ts +221 -0
  52. package/lancedb/remote/connection.ts +201 -0
  53. package/lancedb/remote/index.ts +3 -0
  54. package/lancedb/remote/table.ts +226 -0
  55. package/lancedb/sanitize.ts +73 -1
  56. package/lancedb/table.ts +344 -101
  57. package/lancedb/util.ts +69 -0
  58. package/native.d.ts +208 -0
  59. package/nodejs-artifacts/arrow.d.ts +42 -7
  60. package/nodejs-artifacts/arrow.js +6 -5
  61. package/nodejs-artifacts/connection.d.ts +55 -29
  62. package/nodejs-artifacts/connection.js +22 -74
  63. package/nodejs-artifacts/embedding/embedding_function.d.ts +11 -3
  64. package/nodejs-artifacts/embedding/embedding_function.js +36 -12
  65. package/nodejs-artifacts/embedding/openai.d.ts +6 -5
  66. package/nodejs-artifacts/embedding/openai.js +4 -2
  67. package/nodejs-artifacts/embedding/registry.d.ts +10 -11
  68. package/nodejs-artifacts/embedding/registry.js +4 -0
  69. package/nodejs-artifacts/index.d.ts +51 -3
  70. package/nodejs-artifacts/index.js +28 -4
  71. package/nodejs-artifacts/merge.d.ts +54 -0
  72. package/nodejs-artifacts/merge.js +64 -0
  73. package/nodejs-artifacts/native.d.ts +34 -7
  74. package/nodejs-artifacts/native.js +26 -9
  75. package/nodejs-artifacts/query.d.ts +51 -16
  76. package/nodejs-artifacts/query.js +122 -21
  77. package/nodejs-artifacts/remote/client.d.ts +28 -0
  78. package/nodejs-artifacts/remote/client.js +172 -0
  79. package/nodejs-artifacts/remote/connection.d.ts +25 -0
  80. package/nodejs-artifacts/remote/connection.js +110 -0
  81. package/nodejs-artifacts/remote/index.d.ts +3 -0
  82. package/nodejs-artifacts/remote/index.js +9 -0
  83. package/nodejs-artifacts/remote/table.d.ts +42 -0
  84. package/nodejs-artifacts/remote/table.js +179 -0
  85. package/nodejs-artifacts/sanitize.d.ts +3 -2
  86. package/nodejs-artifacts/sanitize.js +55 -1
  87. package/nodejs-artifacts/table.d.ts +116 -25
  88. package/nodejs-artifacts/table.js +117 -233
  89. package/nodejs-artifacts/util.d.ts +14 -0
  90. package/nodejs-artifacts/util.js +65 -0
  91. package/package.json +25 -11
package/lancedb/table.ts CHANGED
@@ -12,20 +12,37 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
 
15
- import { Data, Schema, fromDataToBuffer, tableFromIPC } from "./arrow";
15
+ import {
16
+ Table as ArrowTable,
17
+ Data,
18
+ IntoVector,
19
+ Schema,
20
+ TableLike,
21
+ fromDataToBuffer,
22
+ fromTableToBuffer,
23
+ fromTableToStreamBuffer,
24
+ isArrowTable,
25
+ makeArrowTable,
26
+ tableFromIPC,
27
+ } from "./arrow";
28
+ import { CreateTableOptions } from "./connection";
16
29
 
17
- import { getRegistry } from "./embedding/registry";
30
+ import { EmbeddingFunctionConfig, getRegistry } from "./embedding/registry";
18
31
  import { IndexOptions } from "./indices";
32
+ import { MergeInsertBuilder } from "./merge";
19
33
  import {
20
34
  AddColumnsSql,
21
35
  ColumnAlteration,
22
36
  IndexConfig,
37
+ IndexStatistics,
23
38
  OptimizeStats,
24
39
  Table as _NativeTable,
25
40
  } from "./native";
26
41
  import { Query, VectorQuery } from "./query";
27
-
42
+ import { sanitizeTable } from "./sanitize";
43
+ import { IntoSql, toSQL } from "./util";
28
44
  export { IndexConfig } from "./native";
45
+
29
46
  /**
30
47
  * Options for adding data to a table.
31
48
  */
@@ -81,19 +98,15 @@ export interface OptimizeOptions {
81
98
  * Closing a table is optional. It not closed, it will be closed when it is garbage
82
99
  * collected.
83
100
  */
84
- export class Table {
85
- private readonly inner: _NativeTable;
86
-
87
- /** Construct a Table. Internal use only. */
88
- constructor(inner: _NativeTable) {
89
- this.inner = inner;
101
+ export abstract class Table {
102
+ [Symbol.for("nodejs.util.inspect.custom")](): string {
103
+ return this.display();
90
104
  }
105
+ /** Returns the name of the table */
106
+ abstract get name(): string;
91
107
 
92
108
  /** Return true if the table has not been closed */
93
- isOpen(): boolean {
94
- return this.inner.isOpen();
95
- }
96
-
109
+ abstract isOpen(): boolean;
97
110
  /**
98
111
  * Close the table, releasing any underlying resources.
99
112
  *
@@ -101,39 +114,44 @@ export class Table {
101
114
  *
102
115
  * Any attempt to use the table after it is closed will result in an error.
103
116
  */
104
- close(): void {
105
- this.inner.close();
106
- }
107
-
117
+ abstract close(): void;
108
118
  /** Return a brief description of the table */
109
- display(): string {
110
- return this.inner.display();
111
- }
112
-
119
+ abstract display(): string;
113
120
  /** Get the schema of the table. */
114
- async schema(): Promise<Schema> {
115
- const schemaBuf = await this.inner.schema();
116
- const tbl = tableFromIPC(schemaBuf);
117
- return tbl.schema;
118
- }
119
-
121
+ abstract schema(): Promise<Schema>;
120
122
  /**
121
123
  * Insert records into this Table.
122
124
  * @param {Data} data Records to be inserted into the Table
123
125
  */
124
- async add(data: Data, options?: Partial<AddDataOptions>): Promise<void> {
125
- const mode = options?.mode ?? "append";
126
- const schema = await this.schema();
127
- const registry = getRegistry();
128
- const functions = registry.parseFunctions(schema.metadata);
129
-
130
- const buffer = await fromDataToBuffer(
131
- data,
132
- functions.values().next().value,
133
- );
134
- await this.inner.add(buffer, mode);
135
- }
136
-
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>;
137
155
  /**
138
156
  * Update existing records in the Table
139
157
  *
@@ -159,30 +177,15 @@ export class Table {
159
177
  * @param {Partial<UpdateOptions>} options - additional options to control
160
178
  * the update behavior
161
179
  */
162
- async update(
180
+ abstract update(
163
181
  updates: Map<string, string> | Record<string, string>,
164
182
  options?: Partial<UpdateOptions>,
165
- ) {
166
- const onlyIf = options?.where;
167
- let columns: [string, string][];
168
- if (updates instanceof Map) {
169
- columns = Array.from(updates.entries());
170
- } else {
171
- columns = Object.entries(updates);
172
- }
173
- await this.inner.update(onlyIf, columns);
174
- }
183
+ ): Promise<void>;
175
184
 
176
185
  /** Count the total number of rows in the dataset. */
177
- async countRows(filter?: string): Promise<number> {
178
- return await this.inner.countRows(filter);
179
- }
180
-
186
+ abstract countRows(filter?: string): Promise<number>;
181
187
  /** Delete the rows that satisfy the predicate. */
182
- async delete(predicate: string): Promise<void> {
183
- await this.inner.delete(predicate);
184
- }
185
-
188
+ abstract delete(predicate: string): Promise<void>;
186
189
  /**
187
190
  * Create an index to speed up queries.
188
191
  *
@@ -190,6 +193,9 @@ export class Table {
190
193
  * Indices on vector columns will speed up vector searches.
191
194
  * Indices on scalar columns will speed up filtering (in both
192
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`
193
199
  * @example
194
200
  * // If the column has a vector (fixed size list) data type then
195
201
  * // an IvfPq vector index will be created.
@@ -209,13 +215,10 @@ export class Table {
209
215
  * // Or create a Scalar index
210
216
  * await table.createIndex("my_float_col");
211
217
  */
212
- async createIndex(column: string, options?: Partial<IndexOptions>) {
213
- // Bit of a hack to get around the fact that TS has no package-scope.
214
- // biome-ignore lint/suspicious/noExplicitAny: skip
215
- const nativeIndex = (options?.config as any)?.inner;
216
- await this.inner.createIndex(nativeIndex, column, options?.replace);
217
- }
218
-
218
+ abstract createIndex(
219
+ column: string,
220
+ options?: Partial<IndexOptions>,
221
+ ): Promise<void>;
219
222
  /**
220
223
  * Create a {@link Query} Builder.
221
224
  *
@@ -266,10 +269,20 @@ export class Table {
266
269
  * }
267
270
  * @returns {Query} A builder that can be used to parameterize the query
268
271
  */
269
- query(): Query {
270
- return new Query(this.inner);
271
- }
272
-
272
+ abstract query(): Query;
273
+ /**
274
+ * Create a search query to find the nearest neighbors
275
+ * of the given query vector
276
+ * @param {string} query - the query. This will be converted to a vector using the table's provided embedding function
277
+ * @note If no embedding functions are defined in the table, this will error when collecting the results.
278
+ */
279
+ abstract search(query: string): VectorQuery;
280
+ /**
281
+ * Create a search query to find the nearest neighbors
282
+ * of the given query vector
283
+ * @param {IntoVector} query - the query vector
284
+ */
285
+ abstract search(query: IntoVector): VectorQuery;
273
286
  /**
274
287
  * Search the table with a given query vector.
275
288
  *
@@ -277,11 +290,7 @@ export class Table {
277
290
  * is the same thing as calling `nearestTo` on the builder returned
278
291
  * by `query`. @see {@link Query#nearestTo} for more details.
279
292
  */
280
- vectorSearch(vector: unknown): VectorQuery {
281
- return this.query().nearestTo(vector);
282
- }
283
-
284
- // TODO: Support BatchUDF
293
+ abstract vectorSearch(vector: IntoVector): VectorQuery;
285
294
  /**
286
295
  * Add new columns with defined values.
287
296
  * @param {AddColumnsSql[]} newColumnTransforms pairs of column names and
@@ -289,19 +298,14 @@ export class Table {
289
298
  * expressions will be evaluated for each row in the table, and can
290
299
  * reference existing columns in the table.
291
300
  */
292
- async addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void> {
293
- await this.inner.addColumns(newColumnTransforms);
294
- }
301
+ abstract addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void>;
295
302
 
296
303
  /**
297
304
  * Alter the name or nullability of columns.
298
305
  * @param {ColumnAlteration[]} columnAlterations One or more alterations to
299
306
  * apply to columns.
300
307
  */
301
- async alterColumns(columnAlterations: ColumnAlteration[]): Promise<void> {
302
- await this.inner.alterColumns(columnAlterations);
303
- }
304
-
308
+ abstract alterColumns(columnAlterations: ColumnAlteration[]): Promise<void>;
305
309
  /**
306
310
  * Drop one or more columns from the dataset
307
311
  *
@@ -313,15 +317,10 @@ export class Table {
313
317
  * be nested column references (e.g. "a.b.c") or top-level column names
314
318
  * (e.g. "a").
315
319
  */
316
- async dropColumns(columnNames: string[]): Promise<void> {
317
- await this.inner.dropColumns(columnNames);
318
- }
319
-
320
+ abstract dropColumns(columnNames: string[]): Promise<void>;
320
321
  /** Retrieve the version of the table */
321
- async version(): Promise<number> {
322
- return await this.inner.version();
323
- }
324
322
 
323
+ abstract version(): Promise<number>;
325
324
  /**
326
325
  * Checks out a specific version of the table _This is an in-place operation._
327
326
  *
@@ -347,19 +346,14 @@ export class Table {
347
346
  * console.log(await table.version()); // 2
348
347
  * ```
349
348
  */
350
- async checkout(version: number): Promise<void> {
351
- await this.inner.checkout(version);
352
- }
353
-
349
+ abstract checkout(version: number): Promise<void>;
354
350
  /**
355
351
  * Checkout the latest version of the table. _This is an in-place operation._
356
352
  *
357
353
  * The table will be set back into standard mode, and will track the latest
358
354
  * version of the table.
359
355
  */
360
- async checkoutLatest(): Promise<void> {
361
- await this.inner.checkoutLatest();
362
- }
356
+ abstract checkoutLatest(): Promise<void>;
363
357
 
364
358
  /**
365
359
  * Restore the table to the currently checked out version
@@ -373,10 +367,7 @@ export class Table {
373
367
  * Once the operation concludes the table will no longer be in a checked
374
368
  * out state and the read_consistency_interval, if any, will apply.
375
369
  */
376
- async restore(): Promise<void> {
377
- await this.inner.restore();
378
- }
379
-
370
+ abstract restore(): Promise<void>;
380
371
  /**
381
372
  * Optimize the on-disk data and indices for better performance.
382
373
  *
@@ -407,6 +398,243 @@ export class Table {
407
398
  * you have added or modified 100,000 or more records or run more than 20 data
408
399
  * modification operations.
409
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
+
410
638
  async optimize(options?: Partial<OptimizeOptions>): Promise<OptimizeStats> {
411
639
  let cleanupOlderThanMs;
412
640
  if (
@@ -419,8 +647,23 @@ export class Table {
419
647
  return await this.inner.optimize(cleanupOlderThanMs);
420
648
  }
421
649
 
422
- /** List all indices that have been created with {@link Table.createIndex} */
423
650
  async listIndices(): Promise<IndexConfig[]> {
424
651
  return await this.inner.listIndices();
425
652
  }
653
+
654
+ async toArrow(): Promise<ArrowTable> {
655
+ return await this.query().toArrow();
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
+ }
426
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
+ }