duckdb 0.4.1-dev98.0 → 0.5.1-dev5.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.
package/Makefile CHANGED
@@ -7,10 +7,10 @@ src/duckdb.cpp:
7
7
  npm install --build-from-source
8
8
 
9
9
  build: ./node_modules src/duckdb.cpp
10
- ./node_modules/.bin/node-pre-gyp build --loglevel=silent
10
+ ./node_modules/.bin/node-pre-gyp build -j max --loglevel=silent
11
11
 
12
12
  debug: ./node_modules src/duckdb.cpp
13
- ./node_modules/.bin/node-pre-gyp build --debug --verbose
13
+ ./node_modules/.bin/node-pre-gyp build -j max --debug --verbose
14
14
 
15
15
  clean:
16
16
  @rm -rf ./build
package/binding.gyp CHANGED
@@ -5,6 +5,7 @@
5
5
  "sources": [
6
6
  "src/duckdb_node.cpp",
7
7
  "src/database.cpp",
8
+ "src/data_chunk.cpp",
8
9
  "src/connection.cpp",
9
10
  "src/statement.cpp",
10
11
  "src/utils.cpp",
@@ -20,18 +21,20 @@
20
21
  ],
21
22
  "cflags_cc": [
22
23
  "-frtti",
23
- "-fexceptions"
24
+ "-fexceptions",
25
+ "-Wno-redundant-move",
24
26
  ],
25
27
  "cflags_cc!": [
26
- "-fno-rrti"
28
+ "-fno-rrti",
27
29
  "-fno-exceptions",
28
30
  ],
29
31
  "cflags": [
30
32
  "-frtti",
31
- "-fexceptions"
33
+ "-fexceptions",
34
+ "-Wno-redundant-move",
32
35
  ],
33
36
  "cflags!": [
34
- "-fno-rrti"
37
+ "-fno-rrti",
35
38
  "-fno-exceptions",
36
39
  ],
37
40
  "xcode_settings": {
@@ -40,7 +43,7 @@
40
43
  "CLANG_CXX_LIBRARY": "libc++",
41
44
  "MACOSX_DEPLOYMENT_TARGET": "10.15",
42
45
  'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
43
- 'OTHER_CFLAGS' : ['-fexceptions', '-frtti']
46
+ 'OTHER_CFLAGS' : ['-fexceptions', '-frtti', '-Wno-redundant-move']
44
47
 
45
48
  },
46
49
  "msvs_settings": {
package/lib/duckdb.js CHANGED
@@ -1,159 +1,502 @@
1
+ /**
2
+ * @module duckdb
3
+ * @summary these jsdoc annotations are still a work in progress - feedback and suggestions are welcome!
4
+ */
5
+
1
6
  var duckdb = require('./duckdb-binding.js');
2
7
  module.exports = exports = duckdb;
3
8
 
9
+ /**
10
+ * Check that errno attribute equals this to check for a duckdb error
11
+ * @constant {number}
12
+ */
13
+ var ERROR = duckdb.ERROR;
14
+
15
+ /**
16
+ * Open database in readonly mode
17
+ * @constant {number}
18
+ */
19
+ var OPEN_READONLY = duckdb.OPEN_READONLY;
20
+ /**
21
+ * Currently ignored
22
+ * @constant {number}
23
+ */
24
+ var OPEN_READWRITE = duckdb.OPEN_READWRITE;
25
+ /**
26
+ * Currently ignored
27
+ * @constant {number}
28
+ */
29
+ var OPEN_CREATE = duckdb.OPEN_CREATE;
30
+ /**
31
+ * Currently ignored
32
+ * @constant {number}
33
+ */
34
+ var OPEN_FULLMUTEX = duckdb.OPEN_FULLMUTEX;
35
+ /**
36
+ * Currently ignored
37
+ * @constant {number}
38
+ */
39
+ var OPEN_SHAREDCACHE = duckdb.OPEN_SHAREDCACHE;
40
+ /**
41
+ * Currently ignored
42
+ * @constant {number}
43
+ */
44
+ var OPEN_PRIVATECACHE = duckdb.OPEN_PRIVATECACHE;
4
45
 
5
46
  // some wrappers for compatibilities sake
47
+ /**
48
+ * Main database interface
49
+ */
6
50
  var Database = duckdb.Database;
51
+ /**
52
+ * @class
53
+ */
7
54
  var Connection = duckdb.Connection;
55
+ /**
56
+ * @class
57
+ */
8
58
  var Statement = duckdb.Statement;
59
+ /**
60
+ * @class
61
+ */
62
+ var QueryResult = duckdb.QueryResult;
63
+
64
+ /**
65
+ * @method
66
+ * @return data chunk
67
+ */
68
+ QueryResult.prototype.nextChunk;
69
+
70
+ /**
71
+ * @name asyncIterator
72
+ * @memberof module:duckdb~QueryResult
73
+ * @method
74
+ * @instance
75
+ * @yields data chunks
76
+ */
77
+ QueryResult.prototype[Symbol.asyncIterator] = async function*() {
78
+ let prefetch = this.nextChunk();
79
+ while (true) {
80
+ const chunk = await prefetch;
81
+ // Null chunk indicates end of stream
82
+ if (!chunk) {
83
+ return;
84
+ }
85
+ // Prefetch the next chunk while we're iterating
86
+ prefetch = this.nextChunk();
87
+ for (const row of chunk) {
88
+ yield row;
89
+ }
90
+ }
91
+ }
9
92
 
10
93
 
11
- Connection.prototype.run = function(sql) {
94
+ /**
95
+ * Run a SQL statement and trigger a callback when done
96
+ * @arg sql
97
+ * @param {...*} params
98
+ * @param callback
99
+ * @return {void}
100
+ */
101
+ Connection.prototype.run = function (sql) {
12
102
  var statement = new Statement(this, sql);
13
103
  return statement.run.apply(statement, arguments);
14
104
  }
15
105
 
16
- Connection.prototype.all = function(sql) {
17
- var statement = new Statement(this,sql);
106
+ /**
107
+ * Run a SQL query and triggers the callback once for all result rows
108
+ * @arg sql
109
+ * @param {...*} params
110
+ * @param callback
111
+ * @return {void}
112
+ */
113
+ Connection.prototype.all = function (sql) {
114
+ var statement = new Statement(this, sql);
18
115
  return statement.all.apply(statement, arguments);
19
116
  }
20
117
 
21
- Connection.prototype.each = function(sql) {
118
+ /**
119
+ * Runs a SQL query and triggers the callback for each result row
120
+ * @arg sql
121
+ * @param {...*} params
122
+ * @param callback
123
+ * @return {void}
124
+ */
125
+ Connection.prototype.each = function (sql) {
22
126
  var statement = new Statement(this, sql);
23
127
  return statement.each.apply(statement, arguments);
24
128
  }
25
129
 
26
- function ptr_to_arr(buffer, ptype, n) {
27
- // TODO can we create those on the C++ side of things already?
28
- switch(ptype) {
29
- case 'BOOL':
30
- case 'UINT8':
31
- return new Uint8Array(buffer.buffer, 0, n);
32
- case 'INT8':
33
- return new Int8Array(buffer.buffer, 0, n);
34
- case 'INT16':
35
- return new Int16Array(buffer.buffer, 0, n);
36
- case 'UINT16':
37
- return new UInt16Array(buffer.buffer, 0, n);
38
- case 'INT32':
39
- return new Int32Array(buffer.buffer, 0, n);
40
- case 'UINT32':
41
- return new UInt32Array(buffer.buffer, 0, n);
42
- case 'FLOAT':
43
- return new Float32Array(buffer.buffer, 0, n);
44
- case 'DOUBLE':
45
- return new Float64Array(buffer.buffer, 0, n);
46
- case 'VARCHAR': // we already have created a string array on the C++ side for this
47
- return buffer;
48
- default:
49
- return new Array<string>(0); // cough
130
+ /**
131
+ * @arg sql
132
+ * @param {...*} params
133
+ * @yields row chunks
134
+ */
135
+ Connection.prototype.stream = async function* (sql) {
136
+ const statement = new Statement(this, sql);
137
+ const queryResult = await statement.stream.apply(statement, arguments);
138
+ for await (const result of queryResult) {
139
+ yield result;
50
140
  }
51
141
  }
52
142
 
53
- // this follows the wasm udfs somewhat but is simpler because we can pass data much more cleanly
54
- Connection.prototype.register = function(name, return_type, fun) {
143
+ /**
144
+ * Register a User Defined Function
145
+ *
146
+ * @arg name
147
+ * @arg return_type
148
+ * @arg fun
149
+ * @return {void}
150
+ * @note this follows the wasm udfs somewhat but is simpler because we can pass data much more cleanly
151
+ */
152
+ Connection.prototype.register = function (name, return_type, fun) {
55
153
  // TODO what if this throws an error somewhere? do we need a try/catch?
56
- return this.register_bulk(name, return_type, function(descr) {
154
+ return this.register_bulk(name, return_type, function (desc) {
57
155
  try {
58
- const data_arr = [];
59
- const validity_arr = [];
156
+ // Build an argument resolver
157
+ const buildResolver = (arg) => {
158
+ let validity = arg.validity || null;
159
+ switch (arg.physicalType) {
160
+ case 'STRUCT': {
161
+ const tmp = {};
162
+ const children = [];
163
+ for (let j = 0; j < (arg.children.length || 0); ++j) {
164
+ const attr = arg.children[j];
165
+ const child = buildResolver(attr);
166
+ children.push((row) => {
167
+ tmp[attr.name] = child(row);
168
+ });
169
+ }
170
+ if (validity != null) {
171
+ return (row) => {
172
+ if (!validity[row]) {
173
+ return null;
174
+ }
175
+ for (const resolver of children) {
176
+ resolver(row);
177
+ }
178
+ return tmp;
179
+ };
180
+ } else {
181
+ return (row) => {
182
+ for (const resolver of children) {
183
+ resolver(row);
184
+ }
185
+ return tmp;
186
+ };
187
+ }
188
+ }
189
+ default: {
190
+ if (arg.data === undefined) {
191
+ throw new Error(
192
+ 'malformed data view, expected data buffer for argument of type: ' + arg.physicalType,
193
+ );
194
+ }
195
+ const data = arg.data;
196
+ if (validity != null) {
197
+ return (row) => (!validity[row] ? null : data[row]);
198
+ } else {
199
+ return (row) => data[row];
200
+ }
201
+ }
202
+ }
203
+ };
60
204
 
61
- for (const idx in descr.args) {
62
- const arg = descr.args[idx];
63
- validity_arr.push(arg.data_buffers[arg.validity_buffer]);
64
- data_arr.push(ptr_to_arr(arg.data_buffers[arg.data_buffer], arg.physical_type, descr.rows));
205
+ // Translate argument data
206
+ const argResolvers = [];
207
+ for (let i = 0; i < desc.args.length; ++i) {
208
+ argResolvers.push(buildResolver(desc.args[i]));
209
+ }
210
+ const args = [];
211
+ for (let i = 0; i < desc.args.length; ++i) {
212
+ args.push(null);
65
213
  }
66
214
 
67
- const out_data = ptr_to_arr(descr.ret.data_buffers[descr.ret.data_buffer], descr.ret.physical_type, descr.rows);
68
- const out_validity = descr.ret.data_buffers[descr.ret.validity_buffer];
69
-
70
- switch (descr.args.length) {
71
- case 0:
72
- for (let i = 0; i < descr.rows; ++i) {
73
- const res = fun();
74
- out_data[i] = res;
75
- out_validity[i] = res == undefined || res == null ? 0 : 1;
76
- }
215
+ // Return type
216
+ desc.ret.validity = new Uint8Array(desc.rows);
217
+ switch (desc.ret.physicalType) {
218
+ case 'INT8':
219
+ desc.ret.data = new Int8Array(desc.rows);
77
220
  break;
78
- case 1:
79
- for (let i = 0; i < descr.rows; ++i) {
80
- const res = fun(validity_arr[0][i] ? data_arr[0][i] : undefined);
81
- out_data[i] = res;
82
- out_validity[i] = res == undefined || res == null ? 0 : 1;
83
- }
221
+ case 'INT16':
222
+ desc.ret.data = new Int16Array(desc.rows);
84
223
  break;
85
- case 2:
86
- for (let i = 0; i < descr.rows; ++i) {
87
- const res = fun(validity_arr[0][i] ? data_arr[0][i] : undefined, validity_arr[1][i] ? data_arr[1][i] : undefined);
88
- out_data[i] = res;
89
- out_validity[i] = res == undefined || res == null ? 0 : 1;
90
- }
224
+ case 'INT32':
225
+ desc.ret.data = new Int32Array(desc.rows);
91
226
  break;
92
- case 3:
93
- for (let i = 0; i < descr.rows; ++i) {
94
- const res = fun(validity_arr[0][i] ? data_arr[0][i] : undefined, validity_arr[1][i] ? data_arr[1][i] : undefined, validity_arr[2][i] ? data_arr[2][i] : undefined);
95
- out_data[i] = res;
96
- out_validity[i] = res == undefined || res == null ? 0 : 1;
97
- }
227
+ case 'DOUBLE':
228
+ desc.ret.data = new Float64Array(desc.rows);
229
+ break;
230
+ case 'DATE64':
231
+ case 'TIME64':
232
+ case 'TIMESTAMP':
233
+ case 'INT64':
234
+ desc.ret.data = new BigInt64Array(desc.rows);
235
+ break;
236
+ case 'UINT64':
237
+ desc.ret.data = new BigUint64Array(desc.rows);
238
+ break;
239
+ case 'BLOB':
240
+ case 'VARCHAR':
241
+ desc.ret.data = new Array(desc.rows);
98
242
  break;
99
- default:
100
- throw "Unsupported argument count";
101
243
  }
102
- } catch(error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
244
+
245
+ // Call the function
246
+ for (let i = 0; i < desc.rows; ++i) {
247
+ for (let j = 0; j < desc.args.length; ++j) {
248
+ args[j] = argResolvers[j](i);
249
+ }
250
+ const res = fun(...args);
251
+ desc.ret.data[i] = res;
252
+ desc.ret.validity[i] = res === undefined || res === null ? 0 : 1;
253
+ }
254
+ } catch (error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
255
+ console.log(desc.ret);
103
256
  msg = error;
104
257
  if (typeof error == 'object' && 'message' in error) {
105
258
  msg = error.message
106
259
  }
107
- throw {name: 'DuckDB-UDF-Exception', message : msg};
260
+ throw { name: 'DuckDB-UDF-Exception', message: msg };
108
261
  }
109
262
  })
110
263
  }
111
264
 
112
- default_connection = function(o) {
265
+ /**
266
+ * Prepare a SQL query for execution
267
+ * @method
268
+ * @arg sql
269
+ * @param {...*} params
270
+ * @param callback
271
+ * @return {Statement}
272
+ */
273
+ Connection.prototype.prepare;
274
+ /**
275
+ * Execute a SQL query
276
+ * @method
277
+ * @arg sql
278
+ * @param {...*} params
279
+ * @param callback
280
+ * @return {void}
281
+ */
282
+ Connection.prototype.exec;
283
+ /**
284
+ * Register a User Defined Function
285
+ *
286
+ * @method
287
+ * @arg name
288
+ * @arg return_type
289
+ * @param callback
290
+ * @return {void}
291
+ */
292
+ Connection.prototype.register_bulk;
293
+ /**
294
+ * Unregister a User Defined Function
295
+ *
296
+ * @method
297
+ * @arg name
298
+ * @arg return_type
299
+ * @param callback
300
+ * @return {void}
301
+ */
302
+ Connection.prototype.unregister;
303
+
304
+ var default_connection = function (o) {
113
305
  if (o.default_connection == undefined) {
114
306
  o.default_connection = new duckdb.Connection(o);
115
307
  }
116
- return(o.default_connection);
308
+ return o.default_connection;
117
309
  }
118
310
 
119
- Database.prototype.prepare = function() {
311
+
312
+ /**
313
+ * Closes database instance
314
+ * @method
315
+ * @param callback
316
+ * @return {void}
317
+ */
318
+ Database.prototype.close = function() {
319
+ this.default_connection = null
320
+ this.close_internal.apply(this, arguments);
321
+ };
322
+
323
+ /**
324
+ * Internal method. Do not use, call Connection#close instead
325
+ * @method
326
+ * @param callback
327
+ * @return {void}
328
+ */
329
+ Database.prototype.close_internal;
330
+
331
+ /**
332
+ * Triggers callback when all scheduled database tasks have completed.
333
+ * @method
334
+ * @param callback
335
+ * @return {void}
336
+ */
337
+ Database.prototype.wait;
338
+
339
+ /**
340
+ * TODO: what does this do?
341
+ * @method
342
+ * @param callback
343
+ * @return {void}
344
+ */
345
+ Database.prototype.serialize;
346
+
347
+ /**
348
+ * TODO: what does this do?
349
+ * @method
350
+ * @param callback
351
+ * @return {void}
352
+ */
353
+ Database.prototype.parallelize;
354
+
355
+ /**
356
+ * Create a new database connection
357
+ * @method
358
+ * @arg path the database to connect to, either a file path, or `:memory:`
359
+ * @return {Connection}
360
+ */
361
+ Database.prototype.connect;
362
+
363
+ /**
364
+ * Supposedly interrupt queries, but currently does not do anything.
365
+ * @method
366
+ * @param callback
367
+ * @return {void}
368
+ */
369
+ Database.prototype.interrupt;
370
+
371
+ /**
372
+ * Prepare a SQL query for execution
373
+ * @arg sql
374
+ * @return {Statement}
375
+ */
376
+ Database.prototype.prepare = function () {
120
377
  return default_connection(this).prepare.apply(this.default_connection, arguments);
121
378
  }
122
379
 
123
- Database.prototype.run = function() {
380
+ /**
381
+ * Convenience method for Connection#run using a built-in default connection
382
+ * @arg sql
383
+ * @param {...*} params
384
+ * @param callback
385
+ * @return {void}
386
+ */
387
+ Database.prototype.run = function () {
124
388
  default_connection(this).run.apply(this.default_connection, arguments);
125
389
  return this;
126
390
  }
127
391
 
128
- Database.prototype.each = function() {
392
+ /**
393
+ * Convenience method for Connection#each using a built-in default connection
394
+ * @arg sql
395
+ * @param {...*} params
396
+ * @param callback
397
+ * @return {void}
398
+ */
399
+ Database.prototype.each = function () {
129
400
  default_connection(this).each.apply(this.default_connection, arguments);
130
401
  return this;
131
402
  }
132
403
 
133
- Database.prototype.all = function() {
404
+ /**
405
+ * Convenience method for Connection#apply using a built-in default connection
406
+ * @arg sql
407
+ * @param {...*} params
408
+ * @param callback
409
+ * @return {void}
410
+ */
411
+ Database.prototype.all = function () {
134
412
  default_connection(this).all.apply(this.default_connection, arguments);
135
413
  return this;
136
414
  }
137
415
 
138
- Database.prototype.exec = function() {
416
+ /**
417
+ * Convenience method for Connection#exec using a built-in default connection
418
+ * @arg sql
419
+ * @param {...*} params
420
+ * @param callback
421
+ * @return {void}
422
+ */
423
+ Database.prototype.exec = function () {
139
424
  default_connection(this).exec.apply(this.default_connection, arguments);
140
425
  return this;
141
426
  }
142
427
 
143
- Database.prototype.register = function() {
428
+ /**
429
+ * Convenience method for Connection#register using a built-in default connection
430
+ * @arg name
431
+ * @arg return_type
432
+ * @arg fun
433
+ * @return {this}
434
+ */
435
+ Database.prototype.register = function () {
144
436
  default_connection(this).register.apply(this.default_connection, arguments);
145
437
  return this;
146
438
  }
147
439
 
148
- Database.prototype.unregister = function() {
440
+ /**
441
+ * Convenience method for Connection#unregister using a built-in default connection
442
+ * @arg name
443
+ * @return {this}
444
+ */
445
+ Database.prototype.unregister = function () {
149
446
  default_connection(this).unregister.apply(this.default_connection, arguments);
150
447
  return this;
151
448
  }
152
449
 
153
- Database.prototype.get = function() {
450
+ /**
451
+ * Not implemented
452
+ */
453
+ Database.prototype.get = function () {
154
454
  throw "get() is not implemented because it's evil";
155
455
  }
156
456
 
157
- Statement.prototype.get = function() {
457
+ /**
458
+ * Not implemented
459
+ */
460
+ Statement.prototype.get = function () {
158
461
  throw "get() is not implemented because it's evil";
159
462
  }
463
+
464
+ /**
465
+ * @method
466
+ * @arg sql
467
+ * @param {...*} params
468
+ * @param callback
469
+ * @return {void}
470
+ */
471
+ Statement.prototype.run;
472
+ /**
473
+ * @method
474
+ * @arg sql
475
+ * @param {...*} params
476
+ * @param callback
477
+ * @return {void}
478
+ */
479
+ Statement.prototype.all;
480
+ /**
481
+ * @method
482
+ * @arg sql
483
+ * @param {...*} params
484
+ * @param callback
485
+ * @return {void}
486
+ */
487
+ Statement.prototype.each;
488
+ /**
489
+ * @method
490
+ * @arg sql
491
+ * @param {...*} params
492
+ * @param callback
493
+ * @return {void}
494
+ */
495
+ Statement.prototype.finalize
496
+ /**
497
+ * @method
498
+ * @arg sql
499
+ * @param {...*} params
500
+ * @yield callback
501
+ */
502
+ Statement.prototype.stream;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
- "version": "0.4.1-dev98.0",
4
+ "version": "0.5.1-dev5.0",
5
5
  "description": "DuckDB node.js API",
6
6
  "gypfile": true,
7
7
  "dependencies": {
@@ -26,6 +26,8 @@
26
26
  },
27
27
  "devDependencies": {
28
28
  "aws-sdk": "^2.790.0",
29
+ "chai": "^4.3.6",
30
+ "jsdoc3-parser": "^2.0.0",
29
31
  "mocha": "^8.3.0"
30
32
  },
31
33
  "repository": {