duckdb 0.4.1-dev19.0 → 0.4.1-dev1952.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,483 @@
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
+ * @arg sql
96
+ * @param {...*} params
97
+ * @param callback
98
+ * @return {void}
99
+ */
100
+ Connection.prototype.run = function (sql) {
12
101
  var statement = new Statement(this, sql);
13
102
  return statement.run.apply(statement, arguments);
14
103
  }
15
104
 
16
- Connection.prototype.all = function(sql) {
17
- var statement = new Statement(this,sql);
105
+ /**
106
+ * @arg sql
107
+ * @param {...*} params
108
+ * @param callback
109
+ * @return {void}
110
+ */
111
+ Connection.prototype.all = function (sql) {
112
+ var statement = new Statement(this, sql);
18
113
  return statement.all.apply(statement, arguments);
19
114
  }
20
115
 
21
- Connection.prototype.each = function(sql) {
116
+ /**
117
+ * @arg sql
118
+ * @param {...*} params
119
+ * @param callback
120
+ * @return {void}
121
+ */
122
+ Connection.prototype.each = function (sql) {
22
123
  var statement = new Statement(this, sql);
23
124
  return statement.each.apply(statement, arguments);
24
125
  }
25
126
 
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
127
+ /**
128
+ * @arg sql
129
+ * @param {...*} params
130
+ * @yields row chunks
131
+ */
132
+ Connection.prototype.stream = async function* (sql) {
133
+ const statement = new Statement(this, sql);
134
+ const queryResult = await statement.stream.apply(statement, arguments);
135
+ for await (const result of queryResult) {
136
+ yield result;
50
137
  }
51
138
  }
52
139
 
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) {
140
+ /**
141
+ * Register a User Defined Function
142
+ *
143
+ * @arg name
144
+ * @arg return_type
145
+ * @arg fun
146
+ * @return {void}
147
+ * @note this follows the wasm udfs somewhat but is simpler because we can pass data much more cleanly
148
+ */
149
+ Connection.prototype.register = function (name, return_type, fun) {
55
150
  // TODO what if this throws an error somewhere? do we need a try/catch?
56
- return this.register_bulk(name, return_type, function(descr) {
151
+ return this.register_bulk(name, return_type, function (desc) {
57
152
  try {
58
- const data_arr = [];
59
- const validity_arr = [];
153
+ // Build an argument resolver
154
+ const buildResolver = (arg) => {
155
+ let validity = arg.validity || null;
156
+ switch (arg.physicalType) {
157
+ case 'STRUCT': {
158
+ const tmp = {};
159
+ const children = [];
160
+ for (let j = 0; j < (arg.children.length || 0); ++j) {
161
+ const attr = arg.children[j];
162
+ const child = buildResolver(attr);
163
+ children.push((row) => {
164
+ tmp[attr.name] = child(row);
165
+ });
166
+ }
167
+ if (validity != null) {
168
+ return (row) => {
169
+ if (!validity[row]) {
170
+ return null;
171
+ }
172
+ for (const resolver of children) {
173
+ resolver(row);
174
+ }
175
+ return tmp;
176
+ };
177
+ } else {
178
+ return (row) => {
179
+ for (const resolver of children) {
180
+ resolver(row);
181
+ }
182
+ return tmp;
183
+ };
184
+ }
185
+ }
186
+ default: {
187
+ if (arg.data === undefined) {
188
+ throw new Error(
189
+ 'malformed data view, expected data buffer for argument of type: ' + arg.physicalType,
190
+ );
191
+ }
192
+ const data = arg.data;
193
+ if (validity != null) {
194
+ return (row) => (!validity[row] ? null : data[row]);
195
+ } else {
196
+ return (row) => data[row];
197
+ }
198
+ }
199
+ }
200
+ };
60
201
 
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));
202
+ // Translate argument data
203
+ const argResolvers = [];
204
+ for (let i = 0; i < desc.args.length; ++i) {
205
+ argResolvers.push(buildResolver(desc.args[i]));
206
+ }
207
+ const args = [];
208
+ for (let i = 0; i < desc.args.length; ++i) {
209
+ args.push(null);
65
210
  }
66
211
 
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
- }
212
+ // Return type
213
+ desc.ret.validity = new Uint8Array(desc.rows);
214
+ switch (desc.ret.physicalType) {
215
+ case 'INT8':
216
+ desc.ret.data = new Int8Array(desc.rows);
77
217
  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
- }
218
+ case 'INT16':
219
+ desc.ret.data = new Int16Array(desc.rows);
84
220
  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
- }
221
+ case 'INT32':
222
+ desc.ret.data = new Int32Array(desc.rows);
91
223
  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
- }
224
+ case 'DOUBLE':
225
+ desc.ret.data = new Float64Array(desc.rows);
226
+ break;
227
+ case 'DATE64':
228
+ case 'TIME64':
229
+ case 'TIMESTAMP':
230
+ case 'INT64':
231
+ desc.ret.data = new BigInt64Array(desc.rows);
232
+ break;
233
+ case 'UINT64':
234
+ desc.ret.data = new BigUint64Array(desc.rows);
235
+ break;
236
+ case 'BLOB':
237
+ case 'VARCHAR':
238
+ desc.ret.data = new Array(desc.rows);
98
239
  break;
99
- default:
100
- throw "Unsupported argument count";
101
240
  }
102
- } catch(error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
241
+
242
+ // Call the function
243
+ for (let i = 0; i < desc.rows; ++i) {
244
+ for (let j = 0; j < desc.args.length; ++j) {
245
+ args[j] = argResolvers[j](i);
246
+ }
247
+ const res = fun(...args);
248
+ desc.ret.data[i] = res;
249
+ desc.ret.validity[i] = res === undefined || res === null ? 0 : 1;
250
+ }
251
+ } catch (error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
252
+ console.log(desc.ret);
103
253
  msg = error;
104
254
  if (typeof error == 'object' && 'message' in error) {
105
255
  msg = error.message
106
256
  }
107
- throw {name: 'DuckDB-UDF-Exception', message : msg};
257
+ throw { name: 'DuckDB-UDF-Exception', message: msg };
108
258
  }
109
259
  })
110
260
  }
111
261
 
112
- default_connection = function(o) {
262
+ /**
263
+ * @method
264
+ * @arg sql
265
+ * @param {...*} params
266
+ * @param callback
267
+ * @return {Statement}
268
+ */
269
+ Connection.prototype.prepare;
270
+ /**
271
+ * @method
272
+ * @arg sql
273
+ * @param {...*} params
274
+ * @param callback
275
+ * @return {void}
276
+ */
277
+ Connection.prototype.exec;
278
+ /**
279
+ * Register a User Defined Function
280
+ *
281
+ * @method
282
+ * @arg name
283
+ * @arg return_type
284
+ * @param callback
285
+ * @return {void}
286
+ */
287
+ Connection.prototype.register_bulk;
288
+ /**
289
+ * Unregister a User Defined Function
290
+ *
291
+ * @method
292
+ * @arg name
293
+ * @arg return_type
294
+ * @param callback
295
+ * @return {void}
296
+ */
297
+ Connection.prototype.unregister;
298
+
299
+ default_connection = function (o) {
113
300
  if (o.default_connection == undefined) {
114
301
  o.default_connection = new duckdb.Connection(o);
115
302
  }
116
- return(o.default_connection);
303
+ return o.default_connection;
117
304
  }
118
305
 
119
- Database.prototype.prepare = function() {
306
+
307
+ /**
308
+ * @method
309
+ * @param callback
310
+ * @return {void}
311
+ */
312
+ Database.prototype.close;
313
+
314
+ /**
315
+ * @method
316
+ * @param callback
317
+ * TODO: what does this do?
318
+ * @return {void}
319
+ */
320
+ Database.prototype.wait;
321
+
322
+ /**
323
+ * TODO: what does this do?
324
+ * @method
325
+ * @param callback
326
+ * @return {void}
327
+ */
328
+ Database.prototype.serialize;
329
+
330
+ /**
331
+ * TODO: what does this do?
332
+ * @method
333
+ * @param callback
334
+ * @return {void}
335
+ */
336
+ Database.prototype.parallelize;
337
+
338
+ /**
339
+ * @method
340
+ * @arg path the database to connect to, either a file path, or `:memory:`
341
+ * @return {Connection}
342
+ */
343
+ Database.prototype.connect;
344
+
345
+ /**
346
+ * TODO: what does this do?
347
+ * @method
348
+ * @param callback
349
+ * @return {void}
350
+ */
351
+ Database.prototype.interrupt;
352
+
353
+ /**
354
+ * @arg sql
355
+ * @return {Statement}
356
+ */
357
+ Database.prototype.prepare = function () {
120
358
  return default_connection(this).prepare.apply(this.default_connection, arguments);
121
359
  }
122
360
 
123
- Database.prototype.run = function() {
361
+ /**
362
+ * @arg sql
363
+ * @param {...*} params
364
+ * @param callback
365
+ * @return {void}
366
+ */
367
+ Database.prototype.run = function () {
124
368
  default_connection(this).run.apply(this.default_connection, arguments);
125
369
  return this;
126
370
  }
127
371
 
128
- Database.prototype.each = function() {
372
+ /**
373
+ * @arg sql
374
+ * @param {...*} params
375
+ * @param callback
376
+ * @return {void}
377
+ */
378
+ Database.prototype.each = function () {
129
379
  default_connection(this).each.apply(this.default_connection, arguments);
130
380
  return this;
131
381
  }
132
382
 
133
- Database.prototype.all = function() {
383
+ /**
384
+ * @arg sql
385
+ * @param {...*} params
386
+ * @param callback
387
+ * @return {void}
388
+ */
389
+ Database.prototype.all = function () {
134
390
  default_connection(this).all.apply(this.default_connection, arguments);
135
391
  return this;
136
392
  }
137
393
 
138
- Database.prototype.exec = function() {
394
+ /**
395
+ * @arg sql
396
+ * @param {...*} params
397
+ * @param callback
398
+ * @return {void}
399
+ */
400
+ Database.prototype.exec = function () {
139
401
  default_connection(this).exec.apply(this.default_connection, arguments);
140
402
  return this;
141
403
  }
142
404
 
143
- Database.prototype.register = function() {
405
+ /**
406
+ * Register a User Defined Function
407
+ *
408
+ * Convenience method for Connection#register
409
+ * @arg name
410
+ * @arg return_type
411
+ * @arg fun
412
+ * @return {this}
413
+ */
414
+ Database.prototype.register = function () {
144
415
  default_connection(this).register.apply(this.default_connection, arguments);
145
416
  return this;
146
417
  }
147
418
 
148
- Database.prototype.unregister = function() {
419
+ /**
420
+ * Unregister a User Defined Function
421
+ *
422
+ * Convenience method for Connection#unregister
423
+ * @arg name
424
+ * @return {this}
425
+ */
426
+ Database.prototype.unregister = function () {
149
427
  default_connection(this).unregister.apply(this.default_connection, arguments);
150
428
  return this;
151
429
  }
152
430
 
153
- Database.prototype.get = function() {
431
+ /**
432
+ * Not implemented
433
+ */
434
+ Database.prototype.get = function () {
154
435
  throw "get() is not implemented because it's evil";
155
436
  }
156
437
 
157
- Statement.prototype.get = function() {
438
+ /**
439
+ * Not implemented
440
+ */
441
+ Statement.prototype.get = function () {
158
442
  throw "get() is not implemented because it's evil";
159
443
  }
444
+
445
+ /**
446
+ * @method
447
+ * @arg sql
448
+ * @param {...*} params
449
+ * @param callback
450
+ * @return {void}
451
+ */
452
+ Statement.prototype.run;
453
+ /**
454
+ * @method
455
+ * @arg sql
456
+ * @param {...*} params
457
+ * @param callback
458
+ * @return {void}
459
+ */
460
+ Statement.prototype.all;
461
+ /**
462
+ * @method
463
+ * @arg sql
464
+ * @param {...*} params
465
+ * @param callback
466
+ * @return {void}
467
+ */
468
+ Statement.prototype.each;
469
+ /**
470
+ * @method
471
+ * @arg sql
472
+ * @param {...*} params
473
+ * @param callback
474
+ * @return {void}
475
+ */
476
+ Statement.prototype.finalize
477
+ /**
478
+ * @method
479
+ * @arg sql
480
+ * @param {...*} params
481
+ * @yield callback
482
+ */
483
+ 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-dev19.0",
4
+ "version": "0.4.1-dev1952.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": {