@uwdata/mosaic-duckdb 0.21.1 → 0.23.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/bin/to-arrow.js +2 -1
- package/dist/src/DuckDB.d.ts +62 -16
- package/dist/src/DuckDB.d.ts.map +1 -1
- package/dist/src/data-server.d.ts.map +1 -1
- package/dist/src/load/arrow.d.ts +1 -1
- package/dist/src/load/arrow.d.ts.map +1 -1
- package/package.json +10 -6
- package/src/DuckDB.js +89 -82
- package/src/data-server.js +3 -2
- package/src/load/arrow.js +14 -11
- package/src/merge-buffers.js +0 -13
package/bin/to-arrow.js
CHANGED
package/dist/src/DuckDB.d.ts
CHANGED
|
@@ -1,22 +1,68 @@
|
|
|
1
1
|
export class DuckDB {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @param {string} path
|
|
4
|
+
* @param {Record<string, string>} config
|
|
5
|
+
* @param {string} initStatements
|
|
6
|
+
*/
|
|
7
|
+
constructor(path?: string, config?: Record<string, string>, initStatements?: string);
|
|
8
|
+
/** @type {Promise<void>} */
|
|
9
|
+
_init: Promise<void>;
|
|
10
|
+
/** @type {DuckDBInstance | undefined} */
|
|
11
|
+
db: DuckDBInstance | undefined;
|
|
12
|
+
/** @type {DuckDBConnection | undefined} */
|
|
13
|
+
con: DuckDBConnection | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} path
|
|
16
|
+
* @param {Record<string, string>} config
|
|
17
|
+
* @param {string} initStatements
|
|
18
|
+
*/
|
|
19
|
+
_initialize(path: string, config: Record<string, string>, initStatements: string): Promise<void>;
|
|
20
|
+
close(): void;
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} sql
|
|
23
|
+
* @returns {Promise<DuckDBStatement>}
|
|
24
|
+
*/
|
|
25
|
+
prepare(sql: string): Promise<DuckDBStatement>;
|
|
26
|
+
/**
|
|
27
|
+
* @param {string | { toString(): string }} sql
|
|
28
|
+
* @returns {Promise<this>}
|
|
29
|
+
*/
|
|
30
|
+
exec(sql: string | {
|
|
31
|
+
toString(): string;
|
|
32
|
+
}): Promise<this>;
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} sql
|
|
35
|
+
* @returns {Promise<Record<string, Json>[]>}
|
|
36
|
+
*/
|
|
37
|
+
query(sql: string): Promise<Record<string, Json>[]>;
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} sql
|
|
40
|
+
* @returns {Promise<Uint8Array[]>}
|
|
41
|
+
*/
|
|
42
|
+
arrowBuffer(sql: string): Promise<Uint8Array[]>;
|
|
11
43
|
}
|
|
12
44
|
export class DuckDBStatement {
|
|
13
|
-
|
|
14
|
-
statement:
|
|
45
|
+
/** @param {DuckDBPreparedStatement} statement */
|
|
46
|
+
constructor(statement: DuckDBPreparedStatement);
|
|
47
|
+
/** @type {DuckDBPreparedStatement} */
|
|
48
|
+
statement: DuckDBPreparedStatement;
|
|
15
49
|
finalize(): void;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
/** @param {DuckDBValue[]} [params] */
|
|
51
|
+
run(params?: DuckDBValue[]): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* @param {DuckDBValue[]} [params]
|
|
54
|
+
* @returns {Promise<this>}
|
|
55
|
+
*/
|
|
56
|
+
exec(params?: DuckDBValue[]): Promise<this>;
|
|
57
|
+
/**
|
|
58
|
+
* @param {DuckDBValue[]} [params]
|
|
59
|
+
* @returns {Promise<Record<string, Json>[]>}
|
|
60
|
+
*/
|
|
61
|
+
query(params?: DuckDBValue[]): Promise<Record<string, Json>[]>;
|
|
20
62
|
}
|
|
21
|
-
import
|
|
63
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
64
|
+
import type { DuckDBConnection } from '@duckdb/node-api';
|
|
65
|
+
import type { Json } from '@duckdb/node-api';
|
|
66
|
+
import type { DuckDBPreparedStatement } from '@duckdb/node-api';
|
|
67
|
+
import type { DuckDBValue } from '@duckdb/node-api';
|
|
22
68
|
//# sourceMappingURL=DuckDB.d.ts.map
|
package/dist/src/DuckDB.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DuckDB.d.ts","sourceRoot":"","sources":["../../src/DuckDB.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DuckDB.d.ts","sourceRoot":"","sources":["../../src/DuckDB.js"],"names":[],"mappings":"AAcA;IAQE;;;;OAIG;IACH,mBAJW,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,mBACtB,MAAM,EAQhB;IAlBD,4BAA4B;IAC5B,OADW,OAAO,CAAC,IAAI,CAAC,CAClB;IACN,yCAAyC;IACzC,IADW,cAAc,GAAG,SAAS,CAClC;IACH,2CAA2C;IAC3C,KADW,gBAAgB,GAAG,SAAS,CACnC;IAeJ;;;;OAIG;IACH,kBAJW,MAAM,UACN,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,kBACtB,MAAM,iBAMhB;IAED,cAGC;IAED;;;OAGG;IACH,aAHW,MAAM,GACJ,OAAO,CAAC,eAAe,CAAC,CAMpC;IAED;;;OAGG;IACH,UAHW,MAAM,GAAG;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAMzB;IAED;;;OAGG;IACH,WAHW,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAM3C;IAED;;;OAGG;IACH,iBAHW,MAAM,GACJ,OAAO,CAAC,UAAU,EAAE,CAAC,CAQjC;CAEF;AAED;IAIE,iDAAiD;IACjD,uBADY,uBAAuB,EAGlC;IAND,sCAAsC;IACtC,WADW,uBAAuB,CACxB;IAOV,iBAEC;IAED,sCAAsC;IACtC,aADY,WAAW,EAAE,iBAIxB;IAED;;;OAGG;IACH,cAHW,WAAW,EAAE,GACX,OAAO,CAAC,IAAI,CAAC,CAMzB;IAED;;;OAGG;IACH,eAHW,WAAW,EAAE,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAM3C;CACF;+BArI8B,kBAAkB;sCAEiC,kBAAkB;0BAAlB,kBAAkB;6CAAlB,kBAAkB;iCAAlB,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-server.d.ts","sourceRoot":"","sources":["../../src/data-server.js"],"names":[],"mappings":"AAOA;;;;;yEAgBC;AA6CD,yDAqBgB,QAAG,EAAE,SAAI,mBAwCxB;
|
|
1
|
+
{"version":3,"file":"data-server.d.ts","sourceRoot":"","sources":["../../src/data-server.js"],"names":[],"mappings":"AAOA;;;;;yEAgBC;AA6CD,yDAqBgB,QAAG,EAAE,SAAI,mBAwCxB;AAyBD;;;;;EAmBC;iBA7KgB,WAAW"}
|
package/dist/src/load/arrow.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function loadArrow(db: any, tableName: any, buffer: any): Promise<
|
|
1
|
+
export function loadArrow(db: any, tableName: any, buffer: any): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=arrow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrow.d.ts","sourceRoot":"","sources":["../../../src/load/arrow.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"arrow.d.ts","sourceRoot":"","sources":["../../../src/load/arrow.js"],"names":[],"mappings":"AAKA,+EAWC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uwdata/mosaic-duckdb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "A Promise-based DuckDB API and Node.js data server.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"duckdb",
|
|
@@ -36,12 +36,16 @@
|
|
|
36
36
|
"lint": "eslint src test",
|
|
37
37
|
"server": "node bin/run-server.js",
|
|
38
38
|
"test": "vitest run",
|
|
39
|
-
"prepublishOnly": "
|
|
39
|
+
"prepublishOnly": "pnpm run test && pnpm run lint && tsc --build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"ws": "^8.
|
|
42
|
+
"@duckdb/node-api": "~1.4.4-r.3",
|
|
43
|
+
"@uwdata/mosaic-sql": "^0.23.0",
|
|
44
|
+
"ws": "^8.20.0"
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^25.5.0",
|
|
48
|
+
"@uwdata/flechette": "^2.3.0"
|
|
49
|
+
},
|
|
50
|
+
"gitHead": "8d153a15b9b1c69130d5384ecd59aa634e3f90b3"
|
|
47
51
|
}
|
package/src/DuckDB.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
2
|
+
|
|
3
|
+
/** @import { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue, Json } from '@duckdb/node-api' */
|
|
3
4
|
|
|
4
5
|
const TEMP_DIR = '.duckdb';
|
|
5
6
|
|
|
@@ -12,116 +13,122 @@ const DEFAULT_INIT_STATEMENTS = [
|
|
|
12
13
|
].join(';\n');
|
|
13
14
|
|
|
14
15
|
export class DuckDB {
|
|
16
|
+
/** @type {Promise<void>} */
|
|
17
|
+
_init;
|
|
18
|
+
/** @type {DuckDBInstance | undefined} */
|
|
19
|
+
db;
|
|
20
|
+
/** @type {DuckDBConnection | undefined} */
|
|
21
|
+
con;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} path
|
|
25
|
+
* @param {Record<string, string>} config
|
|
26
|
+
* @param {string} initStatements
|
|
27
|
+
*/
|
|
15
28
|
constructor(
|
|
16
29
|
path = ':memory:',
|
|
17
30
|
config = {},
|
|
18
31
|
initStatements = DEFAULT_INIT_STATEMENTS
|
|
19
32
|
) {
|
|
20
|
-
this.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
this._init = this._initialize(path, config, initStatements);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} path
|
|
38
|
+
* @param {Record<string, string>} config
|
|
39
|
+
* @param {string} initStatements
|
|
40
|
+
*/
|
|
41
|
+
async _initialize(path, config, initStatements) {
|
|
42
|
+
this.db = await DuckDBInstance.create(path, config);
|
|
43
|
+
this.con = await this.db.connect();
|
|
44
|
+
await this.con.run(initStatements);
|
|
24
45
|
}
|
|
25
46
|
|
|
26
47
|
close() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (err) {
|
|
30
|
-
reject(err);
|
|
31
|
-
} else {
|
|
32
|
-
resolve(this);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
});
|
|
48
|
+
this.con?.closeSync();
|
|
49
|
+
this.db?.closeSync();
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
/**
|
|
53
|
+
* @param {string} sql
|
|
54
|
+
* @returns {Promise<DuckDBStatement>}
|
|
55
|
+
*/
|
|
56
|
+
async prepare(sql) {
|
|
57
|
+
await this._init;
|
|
58
|
+
const stmt = await this.con.prepare(sql);
|
|
59
|
+
return new DuckDBStatement(stmt);
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
51
|
-
});
|
|
62
|
+
/**
|
|
63
|
+
* @param {string | { toString(): string }} sql
|
|
64
|
+
* @returns {Promise<this>}
|
|
65
|
+
*/
|
|
66
|
+
async exec(sql) {
|
|
67
|
+
await this._init;
|
|
68
|
+
await this.con.run(String(sql));
|
|
69
|
+
return this;
|
|
52
70
|
}
|
|
53
71
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
});
|
|
63
|
-
});
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} sql
|
|
74
|
+
* @returns {Promise<Record<string, Json>[]>}
|
|
75
|
+
*/
|
|
76
|
+
async query(sql) {
|
|
77
|
+
await this._init;
|
|
78
|
+
const reader = await this.con.runAndReadAll(sql);
|
|
79
|
+
return reader.getRowObjectsJson();
|
|
64
80
|
}
|
|
65
81
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
82
|
+
/**
|
|
83
|
+
* @param {string} sql
|
|
84
|
+
* @returns {Promise<Uint8Array[]>}
|
|
85
|
+
*/
|
|
86
|
+
async arrowBuffer(sql) {
|
|
87
|
+
await this._init;
|
|
88
|
+
const reader = await this.con.runAndReadAll(
|
|
89
|
+
`SELECT * FROM to_arrow_ipc((${sql}))`
|
|
90
|
+
);
|
|
91
|
+
return /** @type {Uint8Array[]} */ (reader.getColumnsJS()[0]) ?? [];
|
|
76
92
|
}
|
|
93
|
+
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
export class DuckDBStatement {
|
|
97
|
+
/** @type {DuckDBPreparedStatement} */
|
|
98
|
+
statement;
|
|
99
|
+
|
|
100
|
+
/** @param {DuckDBPreparedStatement} statement */
|
|
80
101
|
constructor(statement) {
|
|
81
102
|
this.statement = statement;
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
finalize() {
|
|
85
|
-
this.statement.
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
run(params) {
|
|
89
|
-
this.statement.run(...params);
|
|
106
|
+
this.statement.destroySync();
|
|
90
107
|
}
|
|
91
108
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
reject(err);
|
|
97
|
-
} else {
|
|
98
|
-
resolve(this);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
});
|
|
109
|
+
/** @param {DuckDBValue[]} [params] */
|
|
110
|
+
async run(params) {
|
|
111
|
+
if (params?.length) this.statement.bind(params);
|
|
112
|
+
await this.statement.run();
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
});
|
|
113
|
-
});
|
|
115
|
+
/**
|
|
116
|
+
* @param {DuckDBValue[]} [params]
|
|
117
|
+
* @returns {Promise<this>}
|
|
118
|
+
*/
|
|
119
|
+
async exec(params) {
|
|
120
|
+
if (params?.length) this.statement.bind(params);
|
|
121
|
+
await this.statement.run();
|
|
122
|
+
return this;
|
|
114
123
|
}
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
125
|
-
});
|
|
125
|
+
/**
|
|
126
|
+
* @param {DuckDBValue[]} [params]
|
|
127
|
+
* @returns {Promise<Record<string, Json>[]>}
|
|
128
|
+
*/
|
|
129
|
+
async query(params) {
|
|
130
|
+
if (params?.length) this.statement.bind(params);
|
|
131
|
+
const reader = await this.statement.runAndReadAll();
|
|
132
|
+
return reader.getRowObjectsJson();
|
|
126
133
|
}
|
|
127
134
|
}
|
package/src/data-server.js
CHANGED
|
@@ -133,7 +133,8 @@ function httpResponse(res) {
|
|
|
133
133
|
return {
|
|
134
134
|
arrow(data) {
|
|
135
135
|
res.setHeader('Content-Type', 'application/vnd.apache.arrow.stream');
|
|
136
|
-
res.
|
|
136
|
+
for (const chunk of data) res.write(chunk);
|
|
137
|
+
res.end();
|
|
137
138
|
},
|
|
138
139
|
json(data) {
|
|
139
140
|
res.setHeader('Content-Type', 'application/json');
|
|
@@ -157,7 +158,7 @@ export function socketResponse(ws) {
|
|
|
157
158
|
|
|
158
159
|
return {
|
|
159
160
|
arrow(data) {
|
|
160
|
-
ws.send(data, BINARY);
|
|
161
|
+
ws.send(Buffer.concat(data), BINARY);
|
|
161
162
|
},
|
|
162
163
|
json(data) {
|
|
163
164
|
ws.send(JSON.stringify(data), STRING);
|
package/src/load/arrow.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
1
|
+
import { readFile, writeFile, unlink } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
2
5
|
|
|
3
6
|
export async function loadArrow(db, tableName, buffer) {
|
|
4
|
-
const arrowData =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
-
}
|
|
7
|
+
const arrowData = Array.isArray(buffer) ? Buffer.concat(buffer)
|
|
8
|
+
: ArrayBuffer.isView(buffer) ? Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
9
|
+
: await readFile(buffer);
|
|
10
|
+
const tempFile = join(tmpdir(), `mosaic_${randomBytes(8).toString('hex')}.arrow`);
|
|
11
|
+
await writeFile(tempFile, arrowData);
|
|
12
|
+
try {
|
|
13
|
+
await db.exec(`CREATE OR REPLACE TABLE "${tableName}" AS SELECT * FROM '${tempFile}'`);
|
|
14
|
+
} finally {
|
|
15
|
+
await unlink(tempFile).catch(() => {});
|
|
16
|
+
}
|
|
14
17
|
}
|
package/src/merge-buffers.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export function mergeBuffers(buffers) {
|
|
2
|
-
const len = buffers.reduce((a, b) => a + (b ? b.length : 0), 0);
|
|
3
|
-
const buf = new Uint8Array(len);
|
|
4
|
-
|
|
5
|
-
for (let i = 0, offset = 0; i < buffers.length; ++i) {
|
|
6
|
-
if (buffers[i]) {
|
|
7
|
-
buf.set(buffers[i], offset);
|
|
8
|
-
offset += buffers[i].length;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return buf;
|
|
13
|
-
}
|