@ohos-ports/duckdb 0.0.0-stage → 1.4.2-beta.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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2018-2025 Stichting DuckDB Foundation
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,128 @@
1
- # Temporary Holding Version
1
+ > [!WARNING]
2
+ > The original DuckDB <> Node.js bindings in this package are deprecated in favor of the new and shiny `@duckdb/node-api` package. Currently, the plan is to release this package `duckdb-node` for the last time for the DuckDB 1.4.x (~Fall 2025) series but *not* for the DuckDB 1.5.x series (~Early 2026) any more. Please [contact](https://duckdblabs.com/contact/) DuckDB Labs if you absolutely require updates after that.
3
+
4
+ # DuckDB Node Bindings
5
+
6
+ This package provides a Node.js API for [DuckDB](https://github.com/duckdb/duckdb), the "SQLite for Analytics". The API for this client is somewhat compliant to the SQLite Node.js client for easier transition (and transition you must eventually).
7
+
8
+ Load the package and create a database object:
9
+
10
+ ```js
11
+ var duckdb = require('duckdb');
12
+
13
+ var db = new duckdb.Database(':memory:'); // or a file name for a persistent DB
14
+ ```
15
+
16
+ Then you can run a query:
17
+
18
+ ```js
19
+ db.all('SELECT 42 AS fortytwo', function(err, res) {
20
+ if (err) {
21
+ console.warn(err);
22
+ }
23
+ console.log(res[0].fortytwo)
24
+ });
25
+ ```
26
+
27
+ Other available methods are `each`, where the callback is invoked for each row, `run` to execute a single statement without results and `exec`, which can execute several SQL commands at once but also does not return results. All those commands can work with prepared statements, taking the values for the parameters as additional arguments. For example like so:
28
+
29
+ ```js
30
+ db.all('SELECT ?::INTEGER AS fortytwo, ?::STRING as hello', 42, 'Hello, World', function(err, res) {
31
+ if (err) {
32
+ console.warn(err);
33
+ }
34
+ console.log(res[0].fortytwo)
35
+ console.log(res[0].hello)
36
+ });
37
+ ```
38
+
39
+ However, these are all shorthands for something much more elegant. A database can have multiple `Connection`s, those are created using `db.connect()`.
40
+
41
+ ```js
42
+ var con = db.connect();
43
+ ```
44
+
45
+ You can create multiple connections, each with their own transaction context.
46
+
47
+
48
+ `Connection` objects also contain shorthands to directly call `run()`, `all()` and `each()` with parameters and callbacks, respectively, for example:
49
+
50
+ ```js
51
+ con.all('SELECT 42 AS fortytwo', function(err, res) {
52
+ if (err) {
53
+ console.warn(err);
54
+ }
55
+ console.log(res[0].fortytwo)
56
+ });
57
+ ```
58
+
59
+ From connections, you can create prepared statements (and only that) using `con.prepare()`:
60
+
61
+ ```js
62
+ var stmt = con.prepare('select ?::INTEGER as fortytwo');
63
+ ```
64
+
65
+ To execute this statement, you can call for example `all()` on the `stmt` object:
66
+
67
+ ```js
68
+ stmt.all(42, function(err, res) {
69
+ if (err) {
70
+ console.warn(err);
71
+ }
72
+ console.log(res[0].fortytwo)
73
+ });
74
+ ```
75
+
76
+ You can also execute the prepared statement multiple times. This is for example useful to fill a table with data:
77
+
78
+ ```js
79
+ con.run('CREATE TABLE a (i INTEGER)');
80
+ var stmt = con.prepare('INSERT INTO a VALUES (?)');
81
+ for (var i = 0; i < 10; i++) {
82
+ stmt.run(i);
83
+ }
84
+ stmt.finalize();
85
+ con.all('SELECT * FROM a', function(err, res) {
86
+ if (err) {
87
+ console.warn(err);
88
+ }
89
+ console.log(res)
90
+ });
91
+ ```
92
+
93
+ `prepare()` can also take a callback which gets the prepared statement as an argument:
94
+
95
+ ```js
96
+ var stmt = con.prepare('select ?::INTEGER as fortytwo', function(err, stmt) {
97
+ stmt.all(42, function(err, res) {
98
+ if (err) {
99
+ console.warn(err);
100
+ }
101
+ console.log(res[0].fortytwo)
102
+ });
103
+ });
104
+ ```
105
+
106
+ ## Supported Node versions
107
+ We actively support only LTS and In-Support Node versions, as per July 2023, they are: Node 18, Node 20 and Node 21. For OSX and Linux targets, also Node 22 is available.
108
+ Release schedule for Node.js can be checked here: https://github.com/nodejs/release#release-schedule.
109
+
110
+ We currently bundle and test DuckDB also for Node 12, 14, 16, 17 and 19. We plan of going so going forward as long as the tooling supports it.
111
+ As per July 2023, Node 15 has been removed from the supported versions.
112
+
113
+ ## Development
114
+
115
+ ### First install:
116
+
117
+ To install all the dev dependencies of the project, run `npm install` (this uses package.json)
118
+ You might want to add the `--ignore-scripts` option if you don't care about building the package for now and just want to install the dependencies.
119
+
120
+ ### Tests:
121
+ Tests are located in `test` and can be run with `npm test`
122
+ To run a single test, you can use `npm test -- --grep "name of test as given in describe"`
123
+
124
+ ### Additional notes:
125
+ To build the NodeJS package from source, when on Windows, requires the following extra steps:
126
+ - Set `OPENSSL_ROOT_DIR` to the root directory of an OpenSSL installation
127
+ - Supply the `STATIC_OPENSSL=1` option when executing `make`, or set `-DOPENSSL_USE_STATIC_LIBS=1` manually when calling `cmake`
2
128
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
package/duckdb.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/duckdb');
@@ -0,0 +1,4 @@
1
+ [diffend] Oversized file quarantined before diffing.
2
+ name: package/lib/binding/duckdb.node
3
+ size: 64145920 bytes
4
+ sha256: 27e61cfd99fa79d7f63005beaccc6b26e32e6263d4c20b685b0c3897565a4adc
@@ -0,0 +1,16 @@
1
+ // @ohos-ports/duckdb: vendored native binding loader (openharmony/arm64)
2
+ // The prebuilt, signed duckdb.node addon is shipped inside this package at
3
+ // lib/binding/duckdb.node, so no @mapbox/node-pre-gyp download/build step is
4
+ // needed at install time (upstream npm duckdb 404s its openharmony prebuilds).
5
+ var path = require('path');
6
+ var binding_path = path.join(__dirname, 'binding', 'duckdb.node');
7
+ var fs = require('fs');
8
+ if (!fs.existsSync(binding_path)) {
9
+ throw new Error(
10
+ '@ohos-ports/duckdb: native binding not found at ' + binding_path +
11
+ ' — this package ships a prebuilt openharmony/arm64 addon and does not support building from source at install time.'
12
+ );
13
+ }
14
+ var binding = require(binding_path);
15
+
16
+ module.exports = exports = binding;
@@ -0,0 +1,281 @@
1
+ /**
2
+ * TypeScript declarations for Node.JS bindings for DuckDb.
3
+ * See https://duckdb.org/docs/api/nodejs/overview for details
4
+ * on Node.JS API
5
+ */
6
+
7
+ export type ExceptionType =
8
+ | "Invalid" // invalid type
9
+ | "Out of Range" // value out of range error
10
+ | "Conversion" // conversion/casting error
11
+ | "Unknown Type" // unknown type
12
+ | "Decimal" // decimal related
13
+ | "Mismatch Type" // type mismatch
14
+ | "Divide by Zero" // divide by 0
15
+ | "Object Size" // object size exceeded
16
+ | "Invalid type" // incompatible for operation
17
+ | "Serialization" // serialization
18
+ | "TransactionContext" // transaction management
19
+ | "Not implemented" // method not implemented
20
+ | "Expression" // expression parsing
21
+ | "Catalog" // catalog related
22
+ | "Parser" // parser related
23
+ | "Binder" // binder related
24
+ | "Planner" // planner related
25
+ | "Scheduler" // scheduler related
26
+ | "Executor" // executor related
27
+ | "Constraint" // constraint related
28
+ | "Index" // index related
29
+ | "Stat" // stat related
30
+ | "Connection" // connection related
31
+ | "Syntax" // syntax related
32
+ | "Settings" // settings related
33
+ | "Optimizer" // optimizer related
34
+ | "NullPointer" // nullptr exception
35
+ | "IO" // IO exception
36
+ | "INTERRUPT" // interrupt
37
+ | "FATAL" // Fatal exceptions are non-recoverable and render the entire DB in an unusable state
38
+ | "INTERNAL" // Internal exceptions indicate something went wrong internally (i.e. bug in the code base)
39
+ | "Invalid Input" // Input or arguments error
40
+ | "Out of Memory" // out of memory
41
+ | "Permission" // insufficient permissions
42
+ | "Parameter Not Resolved" // parameter types could not be resolved
43
+ | "Parameter Not Allowed" // parameter types not allowed
44
+ | "Dependency" // dependency
45
+ | "Unknown"
46
+ | "HTTP"
47
+ ;
48
+
49
+ /**
50
+ * Standard error shape for DuckDB errors
51
+ */
52
+ export interface _DuckDbError extends Error {
53
+ errno: -1; // value of ERROR
54
+ code: 'DUCKDB_NODEJS_ERROR';
55
+ errorType: ExceptionType;
56
+ }
57
+
58
+ export interface HttpError extends _DuckDbError {
59
+ errorType: 'HTTP';
60
+ statusCode: number;
61
+ response: string;
62
+ reason: string;
63
+ headers: Record<string, string>;
64
+ }
65
+
66
+ export type DuckDbError = HttpError | _DuckDbError;
67
+
68
+ type Callback<T> = (err: DuckDbError | null, res: T) => void;
69
+
70
+ export type RowData = {
71
+ [columnName: string]: any;
72
+ };
73
+
74
+ export type TableData = RowData[];
75
+ export type ArrowIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
76
+ export type ArrowArray = Uint8Array[];
77
+
78
+ export class Connection {
79
+ constructor(db: Database, callback?: Callback<any>);
80
+
81
+ close(callback?: Callback<void>): void;
82
+
83
+ all(sql: string, ...args: [...any, Callback<TableData>] | []): void;
84
+ arrowIPCAll(sql: string, ...args: [...any, Callback<ArrowArray>] | []): void;
85
+ each(sql: string, ...args: [...any, Callback<RowData>] | []): void;
86
+ exec(sql: string, ...args: [...any, Callback<void>] | []): void;
87
+
88
+ prepare(sql: string, ...args: [...any, Callback<Statement>] | []): Statement;
89
+ run(sql: string, ...args: [...any, Callback<void>] | []): Statement;
90
+
91
+ register_udf(
92
+ name: string,
93
+ return_type: string,
94
+ fun: (...args: any[]) => any
95
+ ): void;
96
+
97
+ register_bulk(
98
+ name: string,
99
+ return_type: string,
100
+ fun: (...args: any[]) => any
101
+ ): void;
102
+ unregister_udf(name: string, callback: Callback<any>): void;
103
+
104
+ stream(sql: any, ...args: any[]): QueryResult;
105
+ arrowIPCStream(sql: any, ...args: any[]): Promise<IpcResultStreamIterator>;
106
+
107
+ register_buffer(name: string, array: ArrowIterable, force: boolean, callback?: Callback<void>): void;
108
+ unregister_buffer(name: string, callback?: Callback<void>): void;
109
+ }
110
+
111
+ export class QueryResult implements AsyncIterable<RowData> {
112
+ [Symbol.asyncIterator](): AsyncIterator<RowData>;
113
+ }
114
+
115
+ export class IpcResultStreamIterator implements AsyncIterator<Uint8Array>, AsyncIterable<Uint8Array> {
116
+ [Symbol.asyncIterator](): this;
117
+
118
+ next(...args: [] | [undefined]): Promise<IteratorResult<Uint8Array, any>>;
119
+
120
+ toArray(): Promise<ArrowArray>;
121
+ }
122
+
123
+ export interface ReplacementScanResult {
124
+ function: string;
125
+ parameters: Array<unknown>;
126
+ }
127
+
128
+ export type ReplacementScanCallback = (
129
+ table: string
130
+ ) => ReplacementScanResult | null;
131
+
132
+ export enum TokenType {
133
+ IDENTIFIER = 0,
134
+ NUMERIC_CONSTANT = 1,
135
+ STRING_CONSTANT = 2,
136
+ OPERATOR = 3,
137
+ KEYWORD = 4,
138
+ COMMENT = 5,
139
+ }
140
+
141
+ export interface ScriptTokens {
142
+ offsets: number[];
143
+ types: TokenType[];
144
+ }
145
+
146
+ export class Database {
147
+ constructor(path: string, accessMode?: number | Record<string,string>, callback?: Callback<any>);
148
+ constructor(path: string, callback?: Callback<any>);
149
+
150
+ close(callback?: Callback<void>): void;
151
+
152
+ connect(): Connection;
153
+
154
+ all(sql: string, ...args: [...any, Callback<TableData>] | []): this;
155
+ arrowIPCAll(sql: string, ...args: [...any, Callback<ArrowArray>] | []): void;
156
+ each(sql: string, ...args: [...any, Callback<RowData>] | []): this;
157
+ exec(sql: string, ...args: [...any, Callback<void>] | []): void;
158
+
159
+ prepare(sql: string, ...args: [...any, Callback<Statement>] | []): Statement;
160
+ run(sql: string, ...args: [...any, Callback<void>] | []): Statement;
161
+
162
+ register_udf(
163
+ name: string,
164
+ return_type: string,
165
+ fun: (...args: any[]) => any
166
+ ): void;
167
+ unregister_udf(name: string, callback: Callback<any>): void;
168
+
169
+ stream(sql: any, ...args: any[]): QueryResult;
170
+ arrowIPCStream(sql: any, ...args: any[]): Promise<IpcResultStreamIterator>;
171
+
172
+ serialize(done?: Callback<void>): void;
173
+ parallelize(done?: Callback<void>): void;
174
+ wait(done: Callback<void>): void;
175
+
176
+ get(columnName: string, cb: Callback<RowData>): void;
177
+ get(columnName: string, num: number, cb: Callback<RowData>): void;
178
+
179
+ interrupt(): void;
180
+
181
+ register_buffer(name: string, array: ArrowIterable, force: boolean, callback?: Callback<void>): void;
182
+
183
+ unregister_buffer(name: string, callback?: Callback<void>): void;
184
+
185
+ registerReplacementScan(
186
+ replacementScan: ReplacementScanCallback
187
+ ): Promise<void>;
188
+
189
+ tokenize(text: string): ScriptTokens;
190
+ }
191
+
192
+ export type GenericTypeInfo = {
193
+ id: string,
194
+ sql_type: string,
195
+ alias?: string,
196
+ }
197
+
198
+ export type StructTypeInfo = {
199
+ id: "STRUCT",
200
+ alias?: string,
201
+ sql_type: string,
202
+ children: TypeInfoChildren,
203
+ }
204
+
205
+ export type ListTypeInfo = {
206
+ id: "LIST",
207
+ alias?: string,
208
+ sql_type: string,
209
+ child: TypeInfo,
210
+ }
211
+
212
+ export type MapTypeInfo = {
213
+ id: "MAP",
214
+ alias?: string,
215
+ sql_type: string,
216
+ key: TypeInfo,
217
+ value: TypeInfo,
218
+ }
219
+
220
+ export type UnionTypeInfo = {
221
+ id: "UNION",
222
+ alias?: string,
223
+ sql_type: string,
224
+ children: TypeInfoChildren,
225
+ }
226
+
227
+ export type DecimalTypeInfo = {
228
+ id: "DECIMAL",
229
+ alias?: string,
230
+ sql_type: string,
231
+ width: number,
232
+ scale: number,
233
+ }
234
+
235
+ export type EnumTypeInfo = {
236
+ id: "ENUM",
237
+ alias?: string,
238
+ sql_type: string,
239
+ name: string,
240
+ values: string[],
241
+ }
242
+
243
+ export type TypeInfoChildren = { name: string, type: TypeInfo }[];
244
+
245
+ export type TypeInfo = GenericTypeInfo | StructTypeInfo | ListTypeInfo | MapTypeInfo | UnionTypeInfo | DecimalTypeInfo | EnumTypeInfo;
246
+
247
+ export type ColumnInfo = { name: string, type: TypeInfo };
248
+
249
+ export class Statement {
250
+ sql: string;
251
+
252
+ constructor(connection: Connection, sql: string);
253
+
254
+ all(...args: [...any, Callback<TableData>] | any[]): this;
255
+
256
+ arrowIPCAll(...args: [...any, Callback<ArrowArray>] | any[]): void;
257
+
258
+ each(...args: [...any, Callback<RowData>] | any[]): this;
259
+
260
+ finalize(callback?: Callback<void>): void;
261
+
262
+ run(...args: [...any, Callback<void>] | any[]): Statement;
263
+
264
+ columns(): ColumnInfo[];
265
+ }
266
+
267
+ export const ERROR: number;
268
+
269
+ export const OPEN_CREATE: number;
270
+
271
+ export const OPEN_FULLMUTEX: number;
272
+
273
+ export const OPEN_PRIVATECACHE: number;
274
+
275
+ export const OPEN_READONLY: number;
276
+
277
+ export const OPEN_READWRITE: number;
278
+
279
+ export const OPEN_SHAREDCACHE: number;
280
+
281
+ export const INTERRUPT: number;
package/lib/duckdb.js ADDED
@@ -0,0 +1,763 @@
1
+ /**
2
+ * @module duckdb
3
+ * @summary DuckDB is an embeddable SQL OLAP Database Management System
4
+ */
5
+
6
+ var duckdb = require('./duckdb-binding.js');
7
+ module.exports = exports = duckdb;
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;
45
+
46
+ // some wrappers for compatibilities sake
47
+ /**
48
+ * Main database interface
49
+ * @arg path - path to database file or :memory: for in-memory database
50
+ * @arg access_mode - access mode
51
+ * @arg config - the configuration object
52
+ * @arg callback - callback function
53
+ */
54
+ var Database = duckdb.Database;
55
+ /**
56
+ * @class
57
+ */
58
+ var Connection = duckdb.Connection;
59
+ /**
60
+ * @class
61
+ */
62
+ var Statement = duckdb.Statement;
63
+ /**
64
+ * @class
65
+ */
66
+ var QueryResult = duckdb.QueryResult;
67
+ /**
68
+ * Types of tokens return by `tokenize`.
69
+ */
70
+ var TokenType = duckdb.TokenType;
71
+
72
+ /**
73
+ * @method
74
+ * @return data chunk
75
+ */
76
+ QueryResult.prototype.nextChunk;
77
+
78
+ /**
79
+ * Function to fetch the next result blob of an Arrow IPC Stream in a zero-copy way.
80
+ * (requires arrow extension to be loaded)
81
+ *
82
+ * @method
83
+ * @return data chunk
84
+ */
85
+ QueryResult.prototype.nextIpcBuffer;
86
+
87
+ /**
88
+ * @name asyncIterator
89
+ * @memberof module:duckdb~QueryResult
90
+ * @method
91
+ * @instance
92
+ * @yields data chunks
93
+ */
94
+ QueryResult.prototype[Symbol.asyncIterator] = async function*() {
95
+ let prefetch = this.nextChunk();
96
+ while (true) {
97
+ const chunk = await prefetch;
98
+ // Null chunk indicates end of stream
99
+ if (!chunk) {
100
+ return;
101
+ }
102
+ // Prefetch the next chunk while we're iterating
103
+ prefetch = this.nextChunk();
104
+ for (const row of chunk) {
105
+ yield row;
106
+ }
107
+ }
108
+ }
109
+
110
+
111
+ /**
112
+ * Run a SQL statement and trigger a callback when done
113
+ * @arg sql
114
+ * @param {...*} params
115
+ * @param callback
116
+ * @return {void}
117
+ */
118
+ Connection.prototype.run = function (sql) {
119
+ var statement = new Statement(this, sql);
120
+ return statement.run.apply(statement, arguments);
121
+ }
122
+
123
+ /**
124
+ * Run a SQL query and triggers the callback once for all result rows
125
+ * @arg sql
126
+ * @param {...*} params
127
+ * @param callback
128
+ * @return {void}
129
+ */
130
+ Connection.prototype.all = function (sql) {
131
+ var statement = new Statement(this, sql);
132
+ return statement.all.apply(statement, arguments);
133
+ }
134
+
135
+ // Utility class for streaming Apache Arrow IPC
136
+ class IpcResultStreamIterator {
137
+ constructor(stream_result_p) {
138
+ this._depleted = false;
139
+ this.stream_result = stream_result_p;
140
+ }
141
+
142
+ async next() {
143
+ if (this._depleted) {
144
+ return { done: true, value: null };
145
+ }
146
+
147
+ const ipc_raw = await this.stream_result.nextIpcBuffer();
148
+ const res = new Uint8Array(ipc_raw);
149
+
150
+ this._depleted = res.length == 0;
151
+ return {
152
+ done: this._depleted,
153
+ value: res,
154
+ };
155
+ }
156
+
157
+ [Symbol.asyncIterator]() {
158
+ return this;
159
+ }
160
+
161
+ // Materialize the IPC stream into a list of Uint8Arrays
162
+ async toArray () {
163
+ const retval = []
164
+
165
+ for await (const ipc_buf of this) {
166
+ retval.push(ipc_buf);
167
+ }
168
+
169
+ // Push EOS message containing 4 bytes of 0
170
+ retval.push(new Uint8Array([0,0,0,0]));
171
+
172
+ return retval;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Run a SQL query and serialize the result into the Apache Arrow IPC format (requires arrow extension to be loaded)
178
+ * @arg sql
179
+ * @param {...*} params
180
+ * @param callback
181
+ * @return {void}
182
+ */
183
+ Connection.prototype.arrowIPCAll = function (sql) {
184
+ const query = "SELECT * FROM to_arrow_ipc((" + sql + "));";
185
+ var statement = new Statement(this, query);
186
+ return statement.arrowIPCAll.apply(statement, arguments);
187
+ }
188
+
189
+ /**
190
+ * Run a SQL query, returns a IpcResultStreamIterator that allows streaming the result into the Apache Arrow IPC format
191
+ * (requires arrow extension to be loaded)
192
+ *
193
+ * @arg sql
194
+ * @param {...*} params
195
+ * @param callback
196
+ * @return Promise<IpcResultStreamIterator>
197
+ */
198
+ Connection.prototype.arrowIPCStream = async function (sql) {
199
+ const query = "SELECT * FROM to_arrow_ipc((" + sql + "));";
200
+ const statement = new Statement(this, query);
201
+ return new IpcResultStreamIterator(await statement.stream.apply(statement, arguments));
202
+ }
203
+
204
+ /**
205
+ * Runs a SQL query and triggers the callback for each result row
206
+ * @arg sql
207
+ * @param {...*} params
208
+ * @param callback
209
+ * @return {void}
210
+ */
211
+ Connection.prototype.each = function (sql) {
212
+ var statement = new Statement(this, sql);
213
+ return statement.each.apply(statement, arguments);
214
+ }
215
+
216
+ /**
217
+ * @arg sql
218
+ * @param {...*} params
219
+ * @yields row chunks
220
+ */
221
+ Connection.prototype.stream = async function* (sql) {
222
+ const statement = new Statement(this, sql);
223
+ const queryResult = await statement.stream.apply(statement, arguments);
224
+ for await (const result of queryResult) {
225
+ yield result;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Register a User Defined Function
231
+ *
232
+ * @arg name
233
+ * @arg return_type
234
+ * @arg fun
235
+ * @return {void}
236
+ * @note this follows the wasm udfs somewhat but is simpler because we can pass data much more cleanly
237
+ */
238
+ Connection.prototype.register_udf = function (name, return_type, fun) {
239
+ // TODO what if this throws an error somewhere? do we need a try/catch?
240
+ return this.register_udf_bulk(name, return_type, function (desc) {
241
+ try {
242
+ // Build an argument resolver
243
+ const buildResolver = (arg) => {
244
+ let validity = arg.validity || null;
245
+ switch (arg.physicalType) {
246
+ case 'STRUCT': {
247
+ const tmp = {};
248
+ const children = [];
249
+ for (let j = 0; j < (arg.children.length || 0); ++j) {
250
+ const attr = arg.children[j];
251
+ const child = buildResolver(attr);
252
+ children.push((row) => {
253
+ tmp[attr.name] = child(row);
254
+ });
255
+ }
256
+ if (validity != null) {
257
+ return (row) => {
258
+ if (!validity[row]) {
259
+ return null;
260
+ }
261
+ for (const resolver of children) {
262
+ resolver(row);
263
+ }
264
+ return tmp;
265
+ };
266
+ } else {
267
+ return (row) => {
268
+ for (const resolver of children) {
269
+ resolver(row);
270
+ }
271
+ return tmp;
272
+ };
273
+ }
274
+ }
275
+ default: {
276
+ if (arg.data === undefined) {
277
+ throw new Error(
278
+ 'malformed data view, expected data buffer for argument of type: ' + arg.physicalType,
279
+ );
280
+ }
281
+ const data = arg.data;
282
+ if (validity != null) {
283
+ return (row) => (!validity[row] ? null : data[row]);
284
+ } else {
285
+ return (row) => data[row];
286
+ }
287
+ }
288
+ }
289
+ };
290
+
291
+ // Translate argument data
292
+ const argResolvers = [];
293
+ for (let i = 0; i < desc.args.length; ++i) {
294
+ argResolvers.push(buildResolver(desc.args[i]));
295
+ }
296
+ const args = [];
297
+ for (let i = 0; i < desc.args.length; ++i) {
298
+ args.push(null);
299
+ }
300
+
301
+ // Return type
302
+ desc.ret.validity = new Uint8Array(desc.rows);
303
+ switch (desc.ret.physicalType) {
304
+ case 'INT8':
305
+ desc.ret.data = new Int8Array(desc.rows);
306
+ break;
307
+ case 'INT16':
308
+ desc.ret.data = new Int16Array(desc.rows);
309
+ break;
310
+ case 'INT32':
311
+ desc.ret.data = new Int32Array(desc.rows);
312
+ break;
313
+ case 'DOUBLE':
314
+ desc.ret.data = new Float64Array(desc.rows);
315
+ break;
316
+ case 'DATE64':
317
+ case 'TIME64':
318
+ case 'TIMESTAMP':
319
+ case 'INT64':
320
+ desc.ret.data = new BigInt64Array(desc.rows);
321
+ break;
322
+ case 'UINT64':
323
+ desc.ret.data = new BigUint64Array(desc.rows);
324
+ break;
325
+ case 'BLOB':
326
+ case 'VARCHAR':
327
+ desc.ret.data = new Array(desc.rows);
328
+ break;
329
+ }
330
+
331
+ // Call the function
332
+ for (let i = 0; i < desc.rows; ++i) {
333
+ for (let j = 0; j < desc.args.length; ++j) {
334
+ args[j] = argResolvers[j](i);
335
+ }
336
+ const res = fun(...args);
337
+ desc.ret.data[i] = res;
338
+ desc.ret.validity[i] = res === undefined || res === null ? 0 : 1;
339
+ }
340
+ } catch (error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
341
+ msg = error;
342
+ if (typeof error == 'object' && 'message' in error) {
343
+ msg = error.message
344
+ }
345
+ throw { name: 'DuckDB-UDF-Exception', message: msg };
346
+ }
347
+ })
348
+ }
349
+
350
+ /**
351
+ * Prepare a SQL query for execution
352
+ * @method
353
+ * @arg sql
354
+ * @param {...*} params
355
+ * @param callback
356
+ * @return {Statement}
357
+ */
358
+ Connection.prototype.prepare;
359
+ /**
360
+ * Execute a SQL query
361
+ * @method
362
+ * @arg sql
363
+ * @param {...*} params
364
+ * @param callback
365
+ * @return {void}
366
+ */
367
+ Connection.prototype.exec;
368
+ /**
369
+ * Register a User Defined Function
370
+ *
371
+ * @method
372
+ * @arg name
373
+ * @arg return_type
374
+ * @param callback
375
+ * @return {void}
376
+ */
377
+ Connection.prototype.register_udf_bulk;
378
+ /**
379
+ * Unregister a User Defined Function
380
+ *
381
+ * @method
382
+ * @arg name
383
+ * @arg return_type
384
+ * @param callback
385
+ * @return {void}
386
+ */
387
+ Connection.prototype.unregister_udf;
388
+
389
+ var default_connection = function (o) {
390
+ if (o.default_connection == undefined) {
391
+ o.default_connection = new duckdb.Connection(o);
392
+ }
393
+ return o.default_connection;
394
+ }
395
+
396
+ /**
397
+ * Register a Buffer to be scanned using the Apache Arrow IPC scanner
398
+ * (requires arrow extension to be loaded)
399
+ *
400
+ * @method
401
+ * @arg name
402
+ * @arg array
403
+ * @arg force
404
+ * @param callback
405
+ * @return {void}
406
+ */
407
+ Connection.prototype.register_buffer;
408
+
409
+ /**
410
+ * Unregister the Buffer
411
+ *
412
+ * @method
413
+ * @arg name
414
+ * @param callback
415
+ * @return {void}
416
+ */
417
+ Connection.prototype.unregister_buffer;
418
+
419
+ /**
420
+ * Closes connection
421
+ * @method
422
+ * @param callback
423
+ * @return {void}
424
+ */
425
+ Connection.prototype.close;
426
+
427
+ /**
428
+ * Closes database instance
429
+ * @method
430
+ * @param callback
431
+ * @return {void}
432
+ */
433
+ Database.prototype.close = function() {
434
+ if (this.default_connection) {
435
+ this.default_connection.close(); // this queues up a job in the internals, which blocks the below close call
436
+ this.default_connection = null;
437
+ }
438
+ this.close_internal.apply(this, arguments);
439
+ };
440
+
441
+ /**
442
+ * Internal method. Do not use, call Connection#close instead
443
+ * @method
444
+ * @param callback
445
+ * @return {void}
446
+ */
447
+ Database.prototype.close_internal;
448
+
449
+ /**
450
+ * Triggers callback when all scheduled database tasks have completed.
451
+ * @method
452
+ * @param callback
453
+ * @return {void}
454
+ */
455
+ Database.prototype.wait;
456
+
457
+ /**
458
+ * Currently a no-op. Provided for SQLite compatibility
459
+ * @method
460
+ * @param callback
461
+ * @return {void}
462
+ */
463
+ Database.prototype.serialize;
464
+
465
+ /**
466
+ * Currently a no-op. Provided for SQLite compatibility
467
+ * @method
468
+ * @param callback
469
+ * @return {void}
470
+ */
471
+ Database.prototype.parallelize;
472
+
473
+ /**
474
+ * Create a new database connection
475
+ * @method
476
+ * @arg path the database to connect to, either a file path, or `:memory:`
477
+ * @return {Connection}
478
+ */
479
+ Database.prototype.connect;
480
+
481
+ /**
482
+ * Supposedly interrupt queries, but currently does not do anything.
483
+ * @method
484
+ * @param callback
485
+ * @return {void}
486
+ */
487
+ Database.prototype.interrupt;
488
+
489
+ /**
490
+ * Prepare a SQL query for execution
491
+ * @arg sql
492
+ * @return {Statement}
493
+ */
494
+ Database.prototype.prepare = function () {
495
+ return default_connection(this).prepare.apply(this.default_connection, arguments);
496
+ }
497
+
498
+ /**
499
+ * Convenience method for Connection#run using a built-in default connection
500
+ * @arg sql
501
+ * @param {...*} params
502
+ * @param callback
503
+ * @return {void}
504
+ */
505
+ Database.prototype.run = function () {
506
+ default_connection(this).run.apply(this.default_connection, arguments);
507
+ return this;
508
+ }
509
+
510
+ /**
511
+ * Convenience method for Connection#scanArrowIpc using a built-in default connection
512
+ * @arg sql
513
+ * @param {...*} params
514
+ * @param callback
515
+ * @return {void}
516
+ */
517
+ Database.prototype.scanArrowIpc = function () {
518
+ default_connection(this).scanArrowIpc.apply(this.default_connection, arguments);
519
+ return this;
520
+ }
521
+
522
+ /**
523
+ * @arg sql
524
+ * @param {...*} params
525
+ * @param callback
526
+ * @return {void}
527
+ */
528
+ Database.prototype.each = function () {
529
+ default_connection(this).each.apply(this.default_connection, arguments);
530
+ return this;
531
+ }
532
+
533
+
534
+ /**
535
+ * @arg sql
536
+ * @param {...*} params
537
+ * @yields row chunks
538
+ */
539
+ Database.prototype.stream = function() {
540
+ return default_connection(this).stream.apply(this.default_connection, arguments);
541
+ }
542
+
543
+
544
+ /**
545
+ * Convenience method for Connection#apply using a built-in default connection
546
+ * @arg sql
547
+ * @param {...*} params
548
+ * @param callback
549
+ * @return {void}
550
+ */
551
+ Database.prototype.all = function () {
552
+ default_connection(this).all.apply(this.default_connection, arguments);
553
+ return this;
554
+ }
555
+
556
+ /**
557
+ * Convenience method for Connection#arrowIPCAll using a built-in default connection
558
+ * @arg sql
559
+ * @param {...*} params
560
+ * @param callback
561
+ * @return {void}
562
+ */
563
+ Database.prototype.arrowIPCAll = function () {
564
+ default_connection(this).arrowIPCAll.apply(this.default_connection, arguments);
565
+ return this;
566
+ }
567
+
568
+ /**
569
+ * Convenience method for Connection#arrowIPCStream using a built-in default connection
570
+ * @arg sql
571
+ * @param {...*} params
572
+ * @param callback
573
+ * @return {void}
574
+ */
575
+ Database.prototype.arrowIPCStream = function () {
576
+ return default_connection(this).arrowIPCStream.apply(this.default_connection, arguments);
577
+ }
578
+
579
+ /**
580
+ * @arg sql
581
+ * @param {...*} params
582
+ * @param callback
583
+ * @return {void}
584
+ */
585
+ Database.prototype.exec = function () {
586
+ default_connection(this).exec.apply(this.default_connection, arguments);
587
+ return this;
588
+ }
589
+
590
+ /**
591
+ * Register a User Defined Function
592
+ *
593
+ * Convenience method for Connection#register_udf
594
+ * @arg name
595
+ * @arg return_type
596
+ * @arg fun
597
+ * @return {this}
598
+ */
599
+ Database.prototype.register_udf = function () {
600
+ default_connection(this).register_udf.apply(this.default_connection, arguments);
601
+ return this;
602
+ }
603
+
604
+ /**
605
+ * Register a buffer containing serialized data to be scanned from DuckDB.
606
+ *
607
+ * Convenience method for Connection#unregister_buffer
608
+ * @arg name
609
+ * @return {this}
610
+ */
611
+ Database.prototype.register_buffer = function () {
612
+ default_connection(this).register_buffer.apply(this.default_connection, arguments);
613
+ return this;
614
+ }
615
+
616
+ /**
617
+ * Unregister a Buffer
618
+ *
619
+ * Convenience method for Connection#unregister_buffer
620
+ * @arg name
621
+ * @return {this}
622
+ */
623
+ Database.prototype.unregister_buffer = function () {
624
+ default_connection(this).unregister_buffer.apply(this.default_connection, arguments);
625
+ return this;
626
+ }
627
+
628
+ /**
629
+ * Unregister a UDF
630
+ *
631
+ * Convenience method for Connection#unregister_udf
632
+ * @arg name
633
+ * @return {this}
634
+ */
635
+ Database.prototype.unregister_udf = function () {
636
+ default_connection(this).unregister_udf.apply(this.default_connection, arguments);
637
+ return this;
638
+ }
639
+
640
+ /**
641
+ * Register a table replace scan function
642
+ * @method
643
+ * @arg fun Replacement scan function
644
+ * @return {this}
645
+ */
646
+
647
+ Database.prototype.registerReplacementScan;
648
+
649
+ /**
650
+ * Return positions and types of tokens in given text
651
+ * @method
652
+ * @arg text
653
+ * @return {ScriptTokens}
654
+ */
655
+ Database.prototype.tokenize;
656
+
657
+ /**
658
+ * Not implemented
659
+ */
660
+ Database.prototype.get = function () {
661
+ throw "get() is not implemented because it's evil";
662
+ }
663
+
664
+ /**
665
+ * Not implemented
666
+ */
667
+ Statement.prototype.get = function () {
668
+ throw "get() is not implemented because it's evil";
669
+ }
670
+
671
+ /**
672
+ * @method
673
+ * @arg sql
674
+ * @param {...*} params
675
+ * @param callback
676
+ * @return {void}
677
+ */
678
+ Statement.prototype.run;
679
+ /**
680
+ * @method
681
+ * @arg sql
682
+ * @param {...*} params
683
+ * @param callback
684
+ * @return {void}
685
+ */
686
+ Statement.prototype.all;
687
+ /**
688
+ * @method
689
+ * @arg sql
690
+ * @param {...*} params
691
+ * @param callback
692
+ * @return {void}
693
+ */
694
+ Statement.prototype.arrowIPCAll;
695
+ /**
696
+ * @method
697
+ * @arg sql
698
+ * @param {...*} params
699
+ * @param callback
700
+ * @return {void}
701
+ */
702
+ Statement.prototype.each;
703
+ /**
704
+ * @method
705
+ * @arg sql
706
+ * @param {...*} params
707
+ * @param callback
708
+ * @return {void}
709
+ */
710
+ Statement.prototype.finalize
711
+ /**
712
+ * @method
713
+ * @arg sql
714
+ * @param {...*} params
715
+ * @yield callback
716
+ */
717
+ Statement.prototype.stream;
718
+
719
+ /**
720
+ * @field
721
+ * @returns sql contained in statement
722
+ */
723
+ Statement.prototype.sql;
724
+
725
+ /**
726
+ * @method
727
+ * @return {ColumnInfo[]} - Array of column names and types
728
+ */
729
+ Statement.prototype.columns;
730
+
731
+ /**
732
+ * @typedef ColumnInfo
733
+ * @type {object}
734
+ * @property {string} name - Column name
735
+ * @property {TypeInfo} type - Column type
736
+ */
737
+
738
+ /**
739
+ * @typedef TypeInfo
740
+ * @type {object}
741
+ * @property {string} id - Type ID
742
+ * @property {string} [alias] - SQL type alias
743
+ * @property {string} sql_type - SQL type name
744
+ */
745
+
746
+ /**
747
+ * @typedef DuckDbError
748
+ * @type {object}
749
+ * @property {number} errno - -1 for DuckDB errors
750
+ * @property {string} message - Error message
751
+ * @property {string} code - 'DUCKDB_NODEJS_ERROR' for DuckDB errors
752
+ * @property {string} errorType - DuckDB error type code (eg, HTTP, IO, Catalog)
753
+ */
754
+
755
+ /**
756
+ * @typedef HTTPError
757
+ * @type {object}
758
+ * @extends {DuckDbError}
759
+ * @property {number} statusCode - HTTP response status code
760
+ * @property {string} reason - HTTP response reason
761
+ * @property {string} response - HTTP response body
762
+ * @property {object} headers - HTTP headers
763
+ */
package/lib/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./duckdb');
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "@ohos-ports/duckdb",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.4.2-beta.0",
4
+ "description": "DuckDB node.js API (HarmonyOS openharmony/arm64 port with vendored prebuilt native binding; companion package of @ohos-ports/duckdb-async)",
5
+ "main": "./lib/duckdb.js",
6
+ "types": "./lib/duckdb.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "duckdb.js",
10
+ "LICENSE",
11
+ "README.md"
12
+ ],
13
+ "os": [
14
+ "openharmony"
15
+ ],
16
+ "cpu": [
17
+ "arm64"
18
+ ],
19
+ "scripts": {},
20
+ "dependencies": {},
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/ohos-ports/ohos-ports.git",
24
+ "directory": "ports/duckdb/1.4.2"
25
+ },
26
+ "keywords": [
27
+ "database",
28
+ "sql",
29
+ "duckdb",
30
+ "openharmony",
31
+ "harmonyos"
32
+ ],
33
+ "author": "Hannes Mühleisen",
34
+ "license": "MIT",
35
+ "bugs": {
36
+ "url": "https://github.com/ohos-ports/ohos-ports/issues"
37
+ },
38
+ "homepage": "https://github.com/ohos-ports/ohos-ports/tree/main/ports/duckdb/1.4.2",
39
+ "ohos-ports": {
40
+ "upstream": "duckdb@1.4.2",
41
+ "platform": "openharmony",
42
+ "arch": "arm64",
43
+ "native_artifact": "lib/binding/duckdb.node",
44
+ "content_delta": "statement.cpp each()-completion persistent-handle fix + exception hardening, compiled from source for openharmony/arm64 and signed; binding vendored in lib/binding (no node-pre-gyp download at install time)"
45
+ }
46
+ }