@duckdb/node-api 1.2.1-alpha.16 → 1.2.1-alpha.17

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 (62) hide show
  1. package/README.md +205 -10
  2. package/lib/DuckDBAppender.d.ts +2 -2
  3. package/lib/DuckDBAppender.js +4 -4
  4. package/lib/DuckDBConnection.d.ts +4 -4
  5. package/lib/DuckDBConnection.js +10 -6
  6. package/lib/DuckDBDataChunk.d.ts +12 -4
  7. package/lib/DuckDBDataChunk.js +64 -6
  8. package/lib/DuckDBInstance.d.ts +2 -0
  9. package/lib/DuckDBInstance.js +9 -9
  10. package/lib/DuckDBInstanceCache.d.ts +8 -0
  11. package/lib/DuckDBInstanceCache.js +28 -0
  12. package/lib/DuckDBResult.d.ts +15 -1
  13. package/lib/DuckDBResult.js +62 -9
  14. package/lib/DuckDBResultReader.d.ts +15 -1
  15. package/lib/DuckDBResultReader.js +42 -5
  16. package/lib/DuckDBType.d.ts +9 -0
  17. package/lib/DuckDBType.js +61 -0
  18. package/lib/DuckDBValueConverter.d.ts +1 -3
  19. package/lib/DuckDBValueConverters.d.ts +47 -0
  20. package/lib/DuckDBValueConverters.js +214 -0
  21. package/lib/JS.d.ts +3 -0
  22. package/lib/JS.js +2 -0
  23. package/lib/JSDuckDBValueConverter.d.ts +3 -0
  24. package/lib/JSDuckDBValueConverter.js +46 -0
  25. package/lib/Json.d.ts +3 -0
  26. package/lib/Json.js +2 -0
  27. package/lib/JsonDuckDBValueConverter.d.ts +3 -0
  28. package/lib/JsonDuckDBValueConverter.js +46 -0
  29. package/lib/conversion/stringFromBlob.d.ts +2 -0
  30. package/lib/conversion/stringFromBlob.js +28 -2
  31. package/lib/convertColumnsFromChunks.d.ts +1 -1
  32. package/lib/convertColumnsFromChunks.js +1 -1
  33. package/lib/convertColumnsObjectFromChunks.d.ts +1 -1
  34. package/lib/convertColumnsObjectFromChunks.js +1 -1
  35. package/lib/convertRowObjectsFromChunks.d.ts +1 -1
  36. package/lib/convertRowObjectsFromChunks.js +1 -1
  37. package/lib/convertRowsFromChunks.d.ts +1 -1
  38. package/lib/createConfig.d.ts +2 -0
  39. package/lib/createConfig.js +19 -0
  40. package/lib/createDuckDBValueConverter.d.ts +3 -0
  41. package/lib/createDuckDBValueConverter.js +15 -0
  42. package/lib/duckdb.d.ts +8 -3
  43. package/lib/duckdb.js +10 -5
  44. package/lib/getColumnsFromChunks.js +2 -8
  45. package/lib/getColumnsObjectFromChunks.js +2 -11
  46. package/lib/getRowObjectsFromChunks.js +1 -8
  47. package/lib/getRowsFromChunks.js +1 -1
  48. package/lib/values/DuckDBBitValue.d.ts +1 -1
  49. package/lib/values/DuckDBBitValue.js +13 -2
  50. package/lib/values/DuckDBDateValue.d.ts +1 -1
  51. package/lib/values/DuckDBDateValue.js +5 -2
  52. package/lib/values/DuckDBDecimalValue.d.ts +1 -1
  53. package/lib/values/DuckDBDecimalValue.js +3 -0
  54. package/lib/values/DuckDBTimeValue.d.ts +1 -1
  55. package/lib/values/DuckDBTimeValue.js +5 -2
  56. package/lib/values/DuckDBTimestampTZValue.d.ts +1 -1
  57. package/lib/values/DuckDBTimestampTZValue.js +5 -2
  58. package/lib/values/DuckDBTimestampValue.d.ts +1 -1
  59. package/lib/values/DuckDBTimestampValue.js +5 -2
  60. package/package.json +2 -2
  61. package/lib/DuckDBValueToJsonConverter.d.ts +0 -10
  62. package/lib/DuckDBValueToJsonConverter.js +0 -101
package/README.md CHANGED
@@ -25,9 +25,12 @@ Some features are not yet complete:
25
25
  - Table description
26
26
  - APIs for Arrow
27
27
 
28
+ See the [issues list on GitHub](https://github.com/duckdb/duckdb-node-neo/issues)
29
+ for the most up-to-date roadmap.
30
+
28
31
  ### Supported Platforms
29
32
 
30
- - Linux arm64 (experimental)
33
+ - Linux arm64
31
34
  - Linux x64
32
35
  - Mac OS X (Darwin) arm64 (Apple Silicon)
33
36
  - Mac OS X (Darwin) x64 (Intel)
@@ -45,6 +48,17 @@ console.log(duckdb.version());
45
48
  console.log(duckdb.configurationOptionDescriptions());
46
49
  ```
47
50
 
51
+ ### Connect
52
+
53
+ ```ts
54
+ import { DuckDBConnection } from '@duckdb/node-api';
55
+
56
+ const connection = await DuckDBConnection.create();
57
+ ```
58
+
59
+ This uses the default instance.
60
+ For advanced usage, you can create instances explicitly.
61
+
48
62
  ### Create Instance
49
63
 
50
64
  ```ts
@@ -66,14 +80,33 @@ Read from and write to a database file, which is created if needed:
66
80
  const instance = await DuckDBInstance.create('my_duckdb.db');
67
81
  ```
68
82
 
69
- Set configuration options:
83
+ Set [configuration options](https://duckdb.org/docs/stable/configuration/overview.html#configuration-reference):
70
84
  ```ts
71
85
  const instance = await DuckDBInstance.create('my_duckdb.db', {
72
86
  threads: '4'
73
87
  });
74
88
  ```
75
89
 
76
- ### Connect
90
+ ### Instance Cache
91
+
92
+ Multiple instances in the same process should not
93
+ attach the same database.
94
+
95
+ To prevent this, an instance cache can be used:
96
+ ```ts
97
+ const instance = await DuckDBInstance.fromCache('my_duckdb.db');
98
+ ```
99
+
100
+ This uses the default instance cache. For advanced usage, you can create
101
+ instance caches explicitly:
102
+ ```ts
103
+ import { DuckDBInstanceCache } from '@duckdb/node-api';
104
+
105
+ const cache = new DuckDBInstanceCache();
106
+ const instance = await cache.getOrCreateInstance('my_duckdb.db');
107
+ ```
108
+
109
+ ### Connect to Instance
77
110
 
78
111
  ```ts
79
112
  const connection = await instance.connect();
@@ -150,6 +183,36 @@ const result = await connection.run('select $a, $b, $c', {
150
183
  });
151
184
  ```
152
185
 
186
+ ### Specifying Values
187
+
188
+ Values of many data types are represented using one of the JS primitives
189
+ `boolean`, `number`, `bigint`, or `string`.
190
+ Also, any type can have `null` values.
191
+
192
+ Values of some data types need to be constructed using special functions.
193
+ These are:
194
+
195
+ | Type | Function |
196
+ | ---- | -------- |
197
+ | `ARRAY` | `arrayValue` |
198
+ | `BIT` | `bitValue` |
199
+ | `BLOB` | `blobValue` |
200
+ | `DATE` | `dateValue` |
201
+ | `DECIMAL` | `decimalValue` |
202
+ | `INTERVAL` | `intervalValue` |
203
+ | `LIST` | `listValue` |
204
+ | `MAP` | `mapValue` |
205
+ | `STRUCT` | `structValue` |
206
+ | `TIME` | `timeValue` |
207
+ | `TIMETZ` | `timeTZValue` |
208
+ | `TIMESTAMP` | `timestampValue` |
209
+ | `TIMESTAMPTZ` | `timestampTZValue` |
210
+ | `TIMESTAMP_S` | `timestampSecondsValue` |
211
+ | `TIMESTAMP_MS` | `timestampMillisValue` |
212
+ | `TIMESTAMP_NS` | `timestampNanosValue` |
213
+ | `UNION` | `unionValue` |
214
+ | `UUID` | `uuidValue` |
215
+
153
216
  ### Stream Results
154
217
 
155
218
  Streaming results evaluate lazily when rows are read.
@@ -221,13 +284,21 @@ const columnsObject = reader.getColumnsObject();
221
284
  // { i: [0, 1, 2], n: [10, 11, 12] }
222
285
  ```
223
286
 
224
- ### Convert Result Data to JSON
287
+ ### Convert Result Data
288
+
289
+ By default, data values that cannot be represented as JS built-ins
290
+ are returned as specialized JS objects; see `Inspect Data Values` below.
225
291
 
226
- By default, data values that cannot be represented as JS primitives
227
- are returned as rich JS objects; see `Inspect Data Values` below.
292
+ To retrieve data in a different form, such as JS built-ins or values that
293
+ can be losslessly serialized to JSON, use the `JS` or `Json` forms of the
294
+ above result data methods.
228
295
 
229
- To retrieve data in a form that can be losslessly serialized to JSON,
230
- use the `Json` forms of the above result data methods:
296
+ Custom converters can be supplied as well. See the implementations of
297
+ [JSDuckDBValueConverter](https://github.com/duckdb/duckdb-node-neo/blob/main/api/src/JSDuckDBValueConverter.ts)
298
+ and [JsonDuckDBValueConverters](https://github.com/duckdb/duckdb-node-neo/blob/main/api/src/JsonDuckDBValueConverter.ts)
299
+ for how to do this.
300
+
301
+ Examples (using the `Json` forms):
231
302
 
232
303
  ```ts
233
304
  const reader = await connection.runAndReadAll(
@@ -375,6 +446,127 @@ const columnsObject = reader.getColumnsObjectJson();
375
446
  // }
376
447
  ```
377
448
 
449
+ Column names and types can also be serialized to JSON:
450
+ ```ts
451
+ const columnNamesAndTypes = reader.columnNamesAndTypesJson();
452
+ // {
453
+ // "columnNames": [
454
+ // "int_array",
455
+ // "struct",
456
+ // "map",
457
+ // "union"
458
+ // ],
459
+ // "columnTypes": [
460
+ // {
461
+ // "typeId": 24,
462
+ // "valueType": {
463
+ // "typeId": 4
464
+ // }
465
+ // },
466
+ // {
467
+ // "typeId": 25,
468
+ // "entryNames": [
469
+ // "a",
470
+ // "b"
471
+ // ],
472
+ // "entryTypes": [
473
+ // {
474
+ // "typeId": 4
475
+ // },
476
+ // {
477
+ // "typeId": 17
478
+ // }
479
+ // ]
480
+ // },
481
+ // {
482
+ // "typeId": 26,
483
+ // "keyType": {
484
+ // "typeId": 17
485
+ // },
486
+ // "valueType": {
487
+ // "typeId": 17
488
+ // }
489
+ // },
490
+ // {
491
+ // "typeId": 28,
492
+ // "memberTags": [
493
+ // "name",
494
+ // "age"
495
+ // ],
496
+ // "memberTypes": [
497
+ // {
498
+ // "typeId": 17
499
+ // },
500
+ // {
501
+ // "typeId": 3
502
+ // }
503
+ // ]
504
+ // }
505
+ // ]
506
+ // }
507
+
508
+ const columnNameAndTypeObjects = reader.columnNameAndTypeObjectsJson();
509
+ // [
510
+ // {
511
+ // "columnName": "int_array",
512
+ // "columnType": {
513
+ // "typeId": 24,
514
+ // "valueType": {
515
+ // "typeId": 4
516
+ // }
517
+ // }
518
+ // },
519
+ // {
520
+ // "columnName": "struct",
521
+ // "columnType": {
522
+ // "typeId": 25,
523
+ // "entryNames": [
524
+ // "a",
525
+ // "b"
526
+ // ],
527
+ // "entryTypes": [
528
+ // {
529
+ // "typeId": 4
530
+ // },
531
+ // {
532
+ // "typeId": 17
533
+ // }
534
+ // ]
535
+ // }
536
+ // },
537
+ // {
538
+ // "columnName": "map",
539
+ // "columnType": {
540
+ // "typeId": 26,
541
+ // "keyType": {
542
+ // "typeId": 17
543
+ // },
544
+ // "valueType": {
545
+ // "typeId": 17
546
+ // }
547
+ // }
548
+ // },
549
+ // {
550
+ // "columnName": "union",
551
+ // "columnType": {
552
+ // "typeId": 28,
553
+ // "memberTags": [
554
+ // "name",
555
+ // "age"
556
+ // ],
557
+ // "memberTypes": [
558
+ // {
559
+ // "typeId": 17
560
+ // },
561
+ // {
562
+ // "typeId": 3
563
+ // }
564
+ // ]
565
+ // }
566
+ // }
567
+ // ]
568
+ ```
569
+
378
570
  ### Fetch Chunks
379
571
 
380
572
  Fetch all chunks:
@@ -409,11 +601,12 @@ Get chunk data:
409
601
  ```ts
410
602
  const rows = chunk.getRows();
411
603
 
412
- const rowObjects = chunk.getRowObjects();
604
+ const rowObjects = chunk.getRowObjects(result.deduplicatedColumnNames());
413
605
 
414
606
  const columns = chunk.getColumns();
415
607
 
416
- const columnsObject = chunk.getColumnsObject();
608
+ const columnsObject =
609
+ chunk.getColumnsObject(result.deduplicatedColumnNames());
417
610
  ```
418
611
 
419
612
  Get chunk data (one value at a time)
@@ -688,6 +881,8 @@ appender.appendDataChunk(chunk);
688
881
  appender.flush();
689
882
  ```
690
883
 
884
+ See "Specifying Values" above for how to supply values to the appender.
885
+
691
886
  ### Extract Statements
692
887
 
693
888
  ```ts
@@ -5,8 +5,8 @@ import { DuckDBArrayValue, DuckDBBitValue, DuckDBDateValue, DuckDBDecimalValue,
5
5
  export declare class DuckDBAppender {
6
6
  private readonly appender;
7
7
  constructor(appender: duckdb.Appender);
8
- close(): void;
9
- flush(): void;
8
+ closeSync(): void;
9
+ flushSync(): void;
10
10
  get columnCount(): number;
11
11
  columnType(columnIndex: number): DuckDBType;
12
12
  endRow(): void;
@@ -13,11 +13,11 @@ class DuckDBAppender {
13
13
  constructor(appender) {
14
14
  this.appender = appender;
15
15
  }
16
- close() {
17
- node_bindings_1.default.appender_close(this.appender);
16
+ closeSync() {
17
+ node_bindings_1.default.appender_close_sync(this.appender);
18
18
  }
19
- flush() {
20
- node_bindings_1.default.appender_flush(this.appender);
19
+ flushSync() {
20
+ node_bindings_1.default.appender_flush_sync(this.appender);
21
21
  }
22
22
  get columnCount() {
23
23
  return node_bindings_1.default.appender_column_count(this.appender);
@@ -12,10 +12,10 @@ import { DuckDBValue } from './values';
12
12
  export declare class DuckDBConnection {
13
13
  private readonly connection;
14
14
  constructor(connection: duckdb.Connection);
15
- static create(instance: DuckDBInstance): Promise<DuckDBConnection>;
16
- /** Same as disconnect. */
17
- close(): void;
18
- disconnect(): void;
15
+ static create(instance?: DuckDBInstance): Promise<DuckDBConnection>;
16
+ /** Same as disconnectSync. */
17
+ closeSync(): void;
18
+ disconnectSync(): void;
19
19
  interrupt(): void;
20
20
  get progress(): duckdb.QueryProgress;
21
21
  run(sql: string, values?: DuckDBValue[] | Record<string, DuckDBValue>, types?: DuckDBType[] | Record<string, DuckDBType | undefined>): Promise<DuckDBMaterializedResult>;
@@ -7,6 +7,7 @@ exports.DuckDBConnection = void 0;
7
7
  const node_bindings_1 = __importDefault(require("@duckdb/node-bindings"));
8
8
  const DuckDBAppender_1 = require("./DuckDBAppender");
9
9
  const DuckDBExtractedStatements_1 = require("./DuckDBExtractedStatements");
10
+ const DuckDBInstance_1 = require("./DuckDBInstance");
10
11
  const DuckDBMaterializedResult_1 = require("./DuckDBMaterializedResult");
11
12
  const DuckDBPreparedStatement_1 = require("./DuckDBPreparedStatement");
12
13
  const DuckDBResultReader_1 = require("./DuckDBResultReader");
@@ -16,14 +17,17 @@ class DuckDBConnection {
16
17
  this.connection = connection;
17
18
  }
18
19
  static async create(instance) {
19
- return instance.connect();
20
+ if (instance) {
21
+ return instance.connect();
22
+ }
23
+ return (await DuckDBInstance_1.DuckDBInstance.fromCache()).connect();
20
24
  }
21
- /** Same as disconnect. */
22
- close() {
23
- return this.disconnect();
25
+ /** Same as disconnectSync. */
26
+ closeSync() {
27
+ return this.disconnectSync();
24
28
  }
25
- disconnect() {
26
- return node_bindings_1.default.disconnect(this.connection);
29
+ disconnectSync() {
30
+ return node_bindings_1.default.disconnect_sync(this.connection);
27
31
  }
28
32
  interrupt() {
29
33
  node_bindings_1.default.interrupt(this.connection);
@@ -14,20 +14,28 @@ export declare class DuckDBDataChunk {
14
14
  set rowCount(count: number);
15
15
  getColumnVector(columnIndex: number): DuckDBVector;
16
16
  visitColumnValues(columnIndex: number, visitValue: (value: DuckDBValue, rowIndex: number, columnIndex: number, type: DuckDBType) => void): void;
17
+ appendColumnValues(columnIndex: number, values: DuckDBValue[]): void;
17
18
  getColumnValues(columnIndex: number): DuckDBValue[];
18
- convertColumnValues<T>(columnIndex: number, converter: DuckDBValueConverter<T>): T[];
19
+ convertColumnValues<T>(columnIndex: number, converter: DuckDBValueConverter<T>): (T | null)[];
19
20
  setColumnValues(columnIndex: number, values: readonly DuckDBValue[]): void;
20
21
  visitColumns(visitColumn: (column: DuckDBValue[], columnIndex: number, type: DuckDBType) => void): void;
22
+ appendToColumns(columns: (DuckDBValue[] | undefined)[]): void;
21
23
  getColumns(): DuckDBValue[][];
22
- convertColumns<T>(converter: DuckDBValueConverter<T>): T[][];
24
+ convertColumns<T>(converter: DuckDBValueConverter<T>): (T | null)[][];
23
25
  setColumns(columns: readonly (readonly DuckDBValue[])[]): void;
26
+ appendToColumnsObject(columnNames: readonly string[], columnsObject: Record<string, DuckDBValue[] | undefined>): void;
27
+ getColumnsObject(columnNames: readonly string[]): Record<string, DuckDBValue[]>;
24
28
  visitColumnMajor(visitValue: (value: DuckDBValue, rowIndex: number, columnIndex: number, type: DuckDBType) => void): void;
25
29
  visitRowValues(rowIndex: number, visitValue: (value: DuckDBValue, rowIndex: number, columnIndex: number, type: DuckDBType) => void): void;
30
+ appendRowValues(rowIndex: number, values: DuckDBValue[]): void;
26
31
  getRowValues(rowIndex: number): DuckDBValue[];
27
- convertRowValues<T>(rowIndex: number, converter: DuckDBValueConverter<T>): T[];
32
+ convertRowValues<T>(rowIndex: number, converter: DuckDBValueConverter<T>): (T | null)[];
28
33
  visitRows(visitRow: (row: DuckDBValue[], rowIndex: number) => void): void;
34
+ appendToRows(rows: DuckDBValue[][]): void;
29
35
  getRows(): DuckDBValue[][];
30
- convertRows<T>(converter: DuckDBValueConverter<T>): T[][];
36
+ convertRows<T>(converter: DuckDBValueConverter<T>): (T | null)[][];
31
37
  setRows(rows: readonly (readonly DuckDBValue[])[]): void;
38
+ appendToRowObjects(columnNames: readonly string[], rowObjects: Record<string, DuckDBValue>[]): void;
39
+ getRowObjects(columnNames: readonly string[]): Record<string, DuckDBValue>[];
32
40
  visitRowMajor(visitValue: (value: DuckDBValue, rowIndex: number, columnIndex: number, type: DuckDBType) => void): void;
33
41
  }
@@ -46,15 +46,17 @@ class DuckDBDataChunk {
46
46
  visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, type);
47
47
  }
48
48
  }
49
+ appendColumnValues(columnIndex, values) {
50
+ this.visitColumnValues(columnIndex, (value) => values.push(value));
51
+ }
49
52
  getColumnValues(columnIndex) {
50
53
  const values = [];
51
- this.visitColumnValues(columnIndex, (value) => values.push(value));
54
+ this.appendColumnValues(columnIndex, values);
52
55
  return values;
53
56
  }
54
57
  convertColumnValues(columnIndex, converter) {
55
58
  const convertedValues = [];
56
- const type = this.getColumnVector(columnIndex).type;
57
- this.visitColumnValues(columnIndex, (value) => convertedValues.push(converter.convertValue(value, type)));
59
+ this.visitColumnValues(columnIndex, (value, _r, _c, type) => convertedValues.push(converter(value, type, converter)));
58
60
  return convertedValues;
59
61
  }
60
62
  setColumnValues(columnIndex, values) {
@@ -73,6 +75,17 @@ class DuckDBDataChunk {
73
75
  visitColumn(this.getColumnValues(columnIndex), columnIndex, this.getColumnVector(columnIndex).type);
74
76
  }
75
77
  }
78
+ appendToColumns(columns) {
79
+ const columnCount = this.columnCount;
80
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
81
+ let column = columns[columnIndex];
82
+ if (!column) {
83
+ column = [];
84
+ columns[columnIndex] = column;
85
+ }
86
+ this.appendColumnValues(columnIndex, column);
87
+ }
88
+ }
76
89
  getColumns() {
77
90
  const columns = [];
78
91
  this.visitColumns((column) => columns.push(column));
@@ -94,6 +107,26 @@ class DuckDBDataChunk {
94
107
  this.setColumnValues(columnIndex, columns[columnIndex]);
95
108
  }
96
109
  }
110
+ appendToColumnsObject(columnNames, columnsObject) {
111
+ const columnCount = this.columnCount;
112
+ if (columnNames.length !== columnCount) {
113
+ throw new Error(`Provided number of column names (${columnNames.length}) does not match column count (${this.columnCount})`);
114
+ }
115
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
116
+ const columnName = columnNames[columnIndex];
117
+ let columnValues = columnsObject[columnName];
118
+ if (!columnValues) {
119
+ columnValues = [];
120
+ columnsObject[columnName] = columnValues;
121
+ }
122
+ this.appendColumnValues(columnIndex, columnValues);
123
+ }
124
+ }
125
+ getColumnsObject(columnNames) {
126
+ const columnsObject = {};
127
+ this.appendToColumnsObject(columnNames, columnsObject);
128
+ return columnsObject;
129
+ }
97
130
  visitColumnMajor(visitValue) {
98
131
  const columnCount = this.columnCount;
99
132
  for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
@@ -107,14 +140,17 @@ class DuckDBDataChunk {
107
140
  visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, vector.type);
108
141
  }
109
142
  }
143
+ appendRowValues(rowIndex, values) {
144
+ this.visitRowValues(rowIndex, (value) => values.push(value));
145
+ }
110
146
  getRowValues(rowIndex) {
111
147
  const values = [];
112
- this.visitRowValues(rowIndex, (value) => values.push(value));
148
+ this.appendRowValues(rowIndex, values);
113
149
  return values;
114
150
  }
115
151
  convertRowValues(rowIndex, converter) {
116
152
  const convertedValues = [];
117
- this.visitRowValues(rowIndex, (value, _, columnIndex) => convertedValues.push(converter.convertValue(value, this.getColumnVector(columnIndex).type)));
153
+ this.visitRowValues(rowIndex, (value, _, columnIndex) => convertedValues.push(converter(value, this.getColumnVector(columnIndex).type, converter)));
118
154
  return convertedValues;
119
155
  }
120
156
  visitRows(visitRow) {
@@ -123,9 +159,12 @@ class DuckDBDataChunk {
123
159
  visitRow(this.getRowValues(rowIndex), rowIndex);
124
160
  }
125
161
  }
162
+ appendToRows(rows) {
163
+ this.visitRows((row) => rows.push(row));
164
+ }
126
165
  getRows() {
127
166
  const rows = [];
128
- this.visitRows((row) => rows.push(row));
167
+ this.appendToRows(rows);
129
168
  return rows;
130
169
  }
131
170
  convertRows(converter) {
@@ -147,6 +186,25 @@ class DuckDBDataChunk {
147
186
  vector.flush();
148
187
  }
149
188
  }
189
+ appendToRowObjects(columnNames, rowObjects) {
190
+ const columnCount = this.columnCount;
191
+ if (columnNames.length !== columnCount) {
192
+ throw new Error(`Provided number of column names (${columnNames.length}) does not match column count (${this.columnCount})`);
193
+ }
194
+ const rowCount = this.rowCount;
195
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
196
+ let rowObject = {};
197
+ this.visitRowValues(rowIndex, (value, _, columnIndex) => {
198
+ rowObject[columnNames[columnIndex]] = value;
199
+ });
200
+ rowObjects.push(rowObject);
201
+ }
202
+ }
203
+ getRowObjects(columnNames) {
204
+ const rowObjects = [];
205
+ this.appendToRowObjects(columnNames, rowObjects);
206
+ return rowObjects;
207
+ }
150
208
  visitRowMajor(visitValue) {
151
209
  const rowCount = this.rowCount;
152
210
  const columnCount = this.columnCount;
@@ -4,5 +4,7 @@ export declare class DuckDBInstance {
4
4
  private readonly db;
5
5
  constructor(db: duckdb.Database);
6
6
  static create(path?: string, options?: Record<string, string>): Promise<DuckDBInstance>;
7
+ static fromCache(path?: string, options?: Record<string, string>): Promise<DuckDBInstance>;
7
8
  connect(): Promise<DuckDBConnection>;
9
+ closeSync(): void;
8
10
  }
@@ -5,26 +5,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DuckDBInstance = void 0;
7
7
  const node_bindings_1 = __importDefault(require("@duckdb/node-bindings"));
8
+ const createConfig_1 = require("./createConfig");
8
9
  const DuckDBConnection_1 = require("./DuckDBConnection");
10
+ const DuckDBInstanceCache_1 = require("./DuckDBInstanceCache");
9
11
  class DuckDBInstance {
10
12
  db;
11
13
  constructor(db) {
12
14
  this.db = db;
13
15
  }
14
16
  static async create(path, options) {
15
- const config = node_bindings_1.default.create_config();
16
- // Set the default duckdb_api value for the api. Can be overridden.
17
- node_bindings_1.default.set_config(config, 'duckdb_api', 'node-neo-api');
18
- if (options) {
19
- for (const optionName in options) {
20
- const optionValue = String(options[optionName]);
21
- node_bindings_1.default.set_config(config, optionName, optionValue);
22
- }
23
- }
17
+ const config = (0, createConfig_1.createConfig)(options);
24
18
  return new DuckDBInstance(await node_bindings_1.default.open(path, config));
25
19
  }
20
+ static async fromCache(path, options) {
21
+ return DuckDBInstanceCache_1.DuckDBInstanceCache.singleton.getOrCreateInstance(path, options);
22
+ }
26
23
  async connect() {
27
24
  return new DuckDBConnection_1.DuckDBConnection(await node_bindings_1.default.connect(this.db));
28
25
  }
26
+ closeSync() {
27
+ node_bindings_1.default.close_sync(this.db);
28
+ }
29
29
  }
30
30
  exports.DuckDBInstance = DuckDBInstance;
@@ -0,0 +1,8 @@
1
+ import { DuckDBInstance } from './DuckDBInstance';
2
+ export declare class DuckDBInstanceCache {
3
+ private readonly cache;
4
+ constructor();
5
+ getOrCreateInstance(path?: string, options?: Record<string, string>): Promise<DuckDBInstance>;
6
+ private static singletonInstance;
7
+ static get singleton(): DuckDBInstanceCache;
8
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DuckDBInstanceCache = void 0;
7
+ const node_bindings_1 = __importDefault(require("@duckdb/node-bindings"));
8
+ const DuckDBInstance_1 = require("./DuckDBInstance");
9
+ const createConfig_1 = require("./createConfig");
10
+ class DuckDBInstanceCache {
11
+ cache;
12
+ constructor() {
13
+ this.cache = node_bindings_1.default.create_instance_cache();
14
+ }
15
+ async getOrCreateInstance(path, options) {
16
+ const config = (0, createConfig_1.createConfig)(options);
17
+ const db = await node_bindings_1.default.get_or_create_from_cache(this.cache, path, config);
18
+ return new DuckDBInstance_1.DuckDBInstance(db);
19
+ }
20
+ static singletonInstance;
21
+ static get singleton() {
22
+ if (!DuckDBInstanceCache.singletonInstance) {
23
+ DuckDBInstanceCache.singletonInstance = new DuckDBInstanceCache();
24
+ }
25
+ return DuckDBInstanceCache.singletonInstance;
26
+ }
27
+ }
28
+ exports.DuckDBInstanceCache = DuckDBInstanceCache;
@@ -3,7 +3,9 @@ import { DuckDBDataChunk } from './DuckDBDataChunk';
3
3
  import { DuckDBLogicalType } from './DuckDBLogicalType';
4
4
  import { DuckDBType } from './DuckDBType';
5
5
  import { DuckDBTypeId } from './DuckDBTypeId';
6
- import { Json } from './DuckDBValueToJsonConverter';
6
+ import { DuckDBValueConverter } from './DuckDBValueConverter';
7
+ import { JS } from './JS';
8
+ import { Json } from './Json';
7
9
  import { ResultReturnType, StatementType } from './enums';
8
10
  import { DuckDBValue } from './values';
9
11
  export declare class DuckDBResult {
@@ -18,17 +20,29 @@ export declare class DuckDBResult {
18
20
  columnTypeId(columnIndex: number): DuckDBTypeId;
19
21
  columnLogicalType(columnIndex: number): DuckDBLogicalType;
20
22
  columnType(columnIndex: number): DuckDBType;
23
+ columnTypeJson(columnIndex: number): Json;
21
24
  columnTypes(): DuckDBType[];
25
+ columnTypesJson(): Json;
26
+ columnNamesAndTypesJson(): Json;
27
+ columnNameAndTypeObjectsJson(): Json;
22
28
  get isStreaming(): boolean;
23
29
  get rowsChanged(): number;
24
30
  fetchChunk(): Promise<DuckDBDataChunk | null>;
25
31
  fetchAllChunks(): Promise<DuckDBDataChunk[]>;
26
32
  getColumns(): Promise<DuckDBValue[][]>;
33
+ convertColumns<T>(converter: DuckDBValueConverter<T>): Promise<(T | null)[][]>;
34
+ getColumnsJS(): Promise<JS[][]>;
27
35
  getColumnsJson(): Promise<Json[][]>;
28
36
  getColumnsObject(): Promise<Record<string, DuckDBValue[]>>;
37
+ convertColumnsObject<T>(converter: DuckDBValueConverter<T>): Promise<Record<string, (T | null)[]>>;
38
+ getColumnsObjectJS(): Promise<Record<string, JS[]>>;
29
39
  getColumnsObjectJson(): Promise<Record<string, Json[]>>;
30
40
  getRows(): Promise<DuckDBValue[][]>;
41
+ convertRows<T>(converter: DuckDBValueConverter<T>): Promise<(T | null)[][]>;
42
+ getRowsJS(): Promise<JS[][]>;
31
43
  getRowsJson(): Promise<Json[][]>;
32
44
  getRowObjects(): Promise<Record<string, DuckDBValue>[]>;
45
+ convertRowObjects<T>(converter: DuckDBValueConverter<T>): Promise<Record<string, T | null>[]>;
46
+ getRowObjectsJS(): Promise<Record<string, JS>[]>;
33
47
  getRowObjectsJson(): Promise<Record<string, Json>[]>;
34
48
  }