@duckdb/node-api 1.1.2-alpha.1 → 1.1.2-alpha.2

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
@@ -1,5 +1,328 @@
1
1
  # DuckDB Node API
2
2
 
3
- API for using DuckDB in Node.
3
+ An API for using [DuckDB](https://duckdb.org/) in [Node](https://nodejs.org/).
4
4
 
5
- [Documentation](https://github.com/duckdb/duckdb-node-neo)
5
+ This is a high-level API meant for applications. It depends on low-level bindings that adhere closely to [DuckDB's C API](https://duckdb.org/docs/api/c/overview), available separately as [@duckdb/duckdb-bindings](https://www.npmjs.com/package/@duckdb/node-bindings).
6
+
7
+ ## Features
8
+
9
+ ### Main differences from [duckdb-node](https://www.npmjs.com/package/duckdb)
10
+ - Native support for Promises; no need for separate [duckdb-async](https://www.npmjs.com/package/duckdb-async) wrapper.
11
+ - DuckDB-specific API; not based on the [SQLite Node API](https://www.npmjs.com/package/sqlite3).
12
+ - Lossless & efficent support for values of all [DuckDB data types](https://duckdb.org/docs/sql/data_types/overview).
13
+ - Wraps [released DuckDB binaries](https://github.com/duckdb/duckdb/releases) instead of rebuilding DuckDB.
14
+ - Built on [DuckDB's C API](https://duckdb.org/docs/api/c/overview); exposes more functionality.
15
+
16
+ ### Roadmap
17
+
18
+ Some features are not yet complete:
19
+ - Friendlier APIs for consuming advanced data types and values, especially converting them to strings.
20
+ - Appending and binding advanced data types. (Additional DuckDB C API support needed.)
21
+ - Writing to data chunk vectors. (Directly writing to binary buffers is challenging to support using the Node Addon API.)
22
+ - User-defined types & functions. (Support for this was added to the DuckDB C API in v1.1.0.)
23
+ - Profiling info (Added in v1.1.0)
24
+ - Table description (Added in v1.1.0)
25
+ - APIs for Arrow. (This part of the DuckDB C API is [deprecated](https://github.com/duckdb/duckdb/blob/e791508e9bc2eb84bc87eb794074f4893093b743/src/include/duckdb.h#L3760).)
26
+
27
+ ### Supported Platforms
28
+
29
+ - Linux x64
30
+ - Mac OS X (Darwin) arm64 (Apple Silicon)
31
+ - Windows (Win32) x64
32
+
33
+ ## Examples
34
+
35
+ ### Get Basic Information
36
+
37
+ ```ts
38
+ import duckdb from '@duckdb/node-api';
39
+
40
+ console.log(duckdb.version());
41
+
42
+ console.log(duckdb.configurationOptionDescriptions());
43
+ ```
44
+
45
+ ### Create Instance
46
+
47
+ ```ts
48
+ import { DuckDBInstance } from '@duckdb/node-api';
49
+ ```
50
+
51
+ Create with an in-memory database:
52
+ ```ts
53
+ const instance = await DuckDBInstance.create(':memory:');
54
+ ```
55
+
56
+ Equivalent to the above:
57
+ ```ts
58
+ const instance = await DuckDBInstance.create();
59
+ ```
60
+
61
+ Read from and write to a database file, which is created if needed:
62
+ ```ts
63
+ const instance = await DuckDBInstance.create('my_duckdb.db');
64
+ ```
65
+
66
+ Set configuration options:
67
+ ```ts
68
+ const instance = await DuckDBInstance.create('my_duckdb.db', { threads: '4' });
69
+ ```
70
+
71
+ Dispose:
72
+ ```ts
73
+ await instance.dispose();
74
+ ```
75
+
76
+ ### Connect
77
+
78
+ ```ts
79
+ const connection = await instance.connect();
80
+ ```
81
+
82
+ Dispose:
83
+ ```ts
84
+ await connection.dispose();
85
+ ```
86
+
87
+ ### Run SQL
88
+
89
+ ```ts
90
+ const result = await connection.run('from test_all_types()');
91
+ ```
92
+
93
+ Dispose:
94
+ ```ts
95
+ result.dispose();
96
+ ```
97
+
98
+ ### Parameterize SQL
99
+
100
+ ```ts
101
+ const prepared = await connection.prepare('select $1, $2');
102
+ prepared.bindVarchar(1, 'duck');
103
+ prepared.bindInteger(2, 42);
104
+ const result = await prepared.run();
105
+ ```
106
+
107
+ Dispose:
108
+ ```ts
109
+ result.dispose();
110
+ prepared.dispose();
111
+ ```
112
+
113
+ ### Inspect Result
114
+
115
+ Get column names and types:
116
+ ```ts
117
+ const columnNames = [];
118
+ const columnTypes = [];
119
+ const columnCount = result.columnCount;
120
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
121
+ const columnName = result.columnName(columnIndex);
122
+ const columnType = result.columnType(columnIndex);
123
+ columnNames.push(columnName);
124
+ columnTypes.push(columnType);
125
+ }
126
+ ```
127
+
128
+ Fetch data chunks:
129
+ ```ts
130
+ const chunks = [];
131
+ while (true) {
132
+ const chunk = await result.fetchChunk();
133
+ if (chunk.rowCount === 0) {
134
+ break;
135
+ }
136
+ chunks.push(chunk);
137
+ }
138
+ ```
139
+
140
+ Read column data:
141
+ ```ts
142
+ const columns = [];
143
+ const columnCount = result.columnCount;
144
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
145
+ const columnValues = [];
146
+ const columnVector = chunk.getColumn(columnIndex);
147
+ const itemCount = columnVector.itemCount;
148
+ for (let itemIndex = 0; itemIndex < itemCount; itemIndex++) {
149
+ const value = columnVector.getItem(itemIndex);
150
+ columnValues.push(value);
151
+ }
152
+ columns.push(columnValues);
153
+ }
154
+ ```
155
+
156
+ Dispose data chunk:
157
+ ```ts
158
+ chunk.dispose();
159
+ ```
160
+
161
+ ### Inspect Data Types
162
+
163
+ ```ts
164
+ import { DuckDBTypeId } from '@duckdb/node-api';
165
+
166
+ function typeToString(dataType) {
167
+ switch (dataType.typeId) {
168
+ case DuckDBTypeId.ARRAY:
169
+ return `${typeToString(dataType.valueType)}[${dataType.length}]`;
170
+ case DuckDBTypeId.DECIMAL:
171
+ return `DECIMAL(${dataType.width},${dataType.scale})`;
172
+ case DuckDBTypeId.ENUM:
173
+ return `ENUM(${dataType.values.map(
174
+ value => `'${value.replace(`'`, `''`)}'`
175
+ ).join(', ')})`;
176
+ case DuckDBTypeId.LIST:
177
+ return `${typeToString(dataType.valueType)}[]`;
178
+ case DuckDBTypeId.MAP:
179
+ return `MAP(${typeToString(dataType.keyType)}, ${typeToString(dataType.valueType)})`;
180
+ case DuckDBTypeId.STRUCT:
181
+ return `STRUCT(${dataType.entries.map(
182
+ entry => `"${entry.name.replace(`"`, `""`)}" ${typeToString(entry.valueType)}`
183
+ ).join(', ')})`;
184
+ case DuckDBTypeId.UNION:
185
+ return `UNION(${dataType.alternatives.map(
186
+ alt => `"${alt.tag.replace(`"`, `""`)}" ${typeToString(alt.valueType)}`
187
+ ).join(', ')})`;
188
+ default:
189
+ return DuckDBTypeId[dataType.typeId];
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### Inspect Data Values
195
+
196
+ ```ts
197
+ import { DuckDBTypeId } from '@duckdb/node-api';
198
+
199
+ function valueToString(value, dataType) {
200
+ switch (dataType.typeId) {
201
+ case DuckDBTypeId.ARRAY:
202
+ return value
203
+ ? `[${Array.from({ length: dataType.length }).map(
204
+ (_, i) => valueToString(value.getItem(i), dataType.valueType)
205
+ ).join(', ')}]`
206
+ : 'null';
207
+ case DuckDBTypeId.DECIMAL:
208
+ return JSON.stringify(value, replacer);
209
+ case DuckDBTypeId.INTERVAL:
210
+ return JSON.stringify(value, replacer);
211
+ case DuckDBTypeId.LIST:
212
+ return value
213
+ ? `[${Array.from({ length: value.itemCount }).map(
214
+ (_, i) => valueToString(value.getItem(i), dataType.valueType)
215
+ ).join(', ')}]`
216
+ : 'null';
217
+ case DuckDBTypeId.MAP:
218
+ return value
219
+ ? `{ ${value.map(
220
+ (entry) => `${valueToString(entry.key, dataType.keyType)}=${valueToString(entry.value, dataType.valueType)}`
221
+ ).join(', ')} }`
222
+ : 'null';
223
+ case DuckDBTypeId.STRUCT:
224
+ return value
225
+ ? `{ ${value.map(
226
+ (entry, i) => `'${entry.name.replace(`'`, `''`)}': ${valueToString(entry.value, dataType.entries[i].valueType)}`
227
+ ).join(', ')} }`
228
+ : 'null';
229
+ case DuckDBTypeId.TIME_TZ:
230
+ return JSON.stringify(value, replacer);
231
+ case DuckDBTypeId.UNION:
232
+ return value
233
+ ? valueToString(value.value, dataType.alternatives.find((alt) => alt.tag === value.tag).valueType)
234
+ : 'null';
235
+ default:
236
+ return String(value);
237
+ }
238
+ }
239
+
240
+ function replacer(key, value) {
241
+ return typeof value === "bigint" ? { $bigint: value.toString() } : value;
242
+ }
243
+ ```
244
+
245
+ ### Append To Table
246
+
247
+ ```ts
248
+ const createTableResult = await connection.run(`create or replace table target_table(i integer, v varchar)`);
249
+ createTableResult.dispose();
250
+
251
+ const appender = await connection.createAppender('main', 'target_table');
252
+ try {
253
+ appender.appendInteger(42);
254
+ appender.appendVarchar('duck');
255
+ appender.endRow();
256
+ appender.appendInteger(123);
257
+ appender.appendVarchar('mallard');
258
+ appender.endRow();
259
+ appender.flush();
260
+ appender.appendInteger(17);
261
+ appender.appendVarchar('goose');
262
+ appender.endRow();
263
+ appender.close(); // also flushes
264
+ } finally {
265
+ appender.dispose();
266
+ }
267
+ ```
268
+
269
+ ### Extract Statements
270
+
271
+ ```ts
272
+ const extractedStatements = await connection.extractStatements(`
273
+ create or replace table numbers as from range(?);
274
+ from numbers where range < ?;
275
+ drop table numbers;
276
+ `);
277
+ const parameterValues = [10, 7];
278
+ try {
279
+ const statementCount = extractedStatements.count;
280
+ for (let statementIndex = 0; statementIndex < statementCount; statementIndex++) {
281
+ const prepared = await extractedStatements.prepare(statementIndex);
282
+ try {
283
+ let parameterCount = prepared.parameterCount;
284
+ for (let parameterIndex = 1; parameterIndex <= parameterCount; parameterIndex++) {
285
+ prepared.bindInteger(parameterIndex, parameterValues.shift());
286
+ }
287
+ const result = await prepared.run();
288
+ // ...
289
+ result.dispose();
290
+ } finally {
291
+ prepared.dispose();
292
+ }
293
+ }
294
+ } finally {
295
+ extractedStatements.dispose();
296
+ }
297
+ ```
298
+
299
+ ### Control Evaluation
300
+
301
+ ```ts
302
+ import { DuckDBPendingResultState } from '@duckdb/node-api';
303
+
304
+ async function sleep(ms) {
305
+ return new Promise((resolve) => {
306
+ setTimeout(resolve, ms);
307
+ });
308
+ }
309
+
310
+ const prepared = await connection.prepare('from range(10_000_000)');
311
+ try {
312
+ const pending = prepared.start();
313
+ try {
314
+ while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) {
315
+ console.log('not ready');
316
+ await sleep(1);
317
+ }
318
+ console.log('ready');
319
+ const result = await pending.getResult();
320
+ // ...
321
+ result.dispose();
322
+ } finally {
323
+ pending.dispose();
324
+ }
325
+ } finally {
326
+ prepared.dispose();
327
+ }
328
+ ```
@@ -16,7 +16,7 @@ class DuckDBInstance {
16
16
  const config = node_bindings_1.default.create_config();
17
17
  try {
18
18
  for (const optionName in options) {
19
- const optionValue = options[optionName];
19
+ const optionValue = String(options[optionName]);
20
20
  node_bindings_1.default.set_config(config, optionName, optionValue);
21
21
  }
22
22
  return new DuckDBInstance(await node_bindings_1.default.open(path, config));
package/lib/enums.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import duckdb from '@duckdb/node-bindings';
2
- type ResultReturnType = duckdb.ResultType;
3
- type StatementType = duckdb.StatementType;
4
- export type { ResultReturnType, StatementType };
2
+ export type ResultReturnType = duckdb.ResultType;
3
+ export declare const ResultReturnType: typeof duckdb.ResultType;
4
+ export type StatementType = duckdb.StatementType;
5
+ export declare const StatementType: typeof duckdb.StatementType;
package/lib/enums.js CHANGED
@@ -1,2 +1,9 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StatementType = exports.ResultReturnType = void 0;
7
+ const node_bindings_1 = __importDefault(require("@duckdb/node-bindings"));
8
+ exports.ResultReturnType = node_bindings_1.default.ResultType;
9
+ exports.StatementType = node_bindings_1.default.StatementType;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@duckdb/node-api",
3
- "version": "1.1.2-alpha.1",
3
+ "version": "1.1.2-alpha.2",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "dependencies": {
7
- "@duckdb/node-bindings": "1.1.2-alpha.1"
7
+ "@duckdb/node-bindings": "1.1.2-alpha.2"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",