@leonardovida-md/drizzle-neo-duckdb 1.0.3 → 1.1.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/README.md +20 -5
- package/dist/client.d.ts +7 -1
- package/dist/columns.d.ts +1 -1
- package/dist/driver.d.ts +33 -1
- package/dist/duckdb-introspect.mjs +211 -37
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.mjs +319 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +202 -36
- package/dist/introspect.d.ts +1 -0
- package/dist/pool.d.ts +22 -0
- package/dist/sql/query-rewriters.d.ts +0 -1
- package/dist/utils.d.ts +1 -1
- package/dist/value-wrappers-core.d.ts +42 -0
- package/dist/value-wrappers.d.ts +2 -98
- package/package.json +6 -2
- package/src/client.ts +43 -5
- package/src/columns.ts +1 -1
- package/src/driver.ts +191 -7
- package/src/helpers.ts +18 -0
- package/src/index.ts +1 -0
- package/src/introspect.ts +24 -23
- package/src/migrator.ts +1 -1
- package/src/olap.ts +1 -0
- package/src/pool.ts +104 -0
- package/src/session.ts +36 -10
- package/src/sql/query-rewriters.ts +2 -49
- package/src/utils.ts +1 -1
- package/src/value-wrappers-core.ts +156 -0
- package/src/value-wrappers.ts +44 -213
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/driver.ts
|
|
2
|
+
import { DuckDBInstance as DuckDBInstance2 } from "@duckdb/node-api";
|
|
2
3
|
import { entityKind as entityKind3 } from "drizzle-orm/entity";
|
|
3
4
|
import { DefaultLogger } from "drizzle-orm/logger";
|
|
4
5
|
import { PgDatabase } from "drizzle-orm/pg-core/db";
|
|
@@ -15,10 +16,6 @@ import { PgPreparedQuery, PgSession } from "drizzle-orm/pg-core/session";
|
|
|
15
16
|
import { fillPlaceholders, sql } from "drizzle-orm/sql/sql";
|
|
16
17
|
|
|
17
18
|
// src/sql/query-rewriters.ts
|
|
18
|
-
var tableIdPropSelectionRegex = new RegExp([
|
|
19
|
-
`("(.+)"\\."(.+)")`,
|
|
20
|
-
`(\\s+as\\s+'?(.+?)'?\\.'?(.+?)'?)?`
|
|
21
|
-
].join(""), "i");
|
|
22
19
|
function adaptArrayOperators(query) {
|
|
23
20
|
const operators = [
|
|
24
21
|
{ token: "@>", fn: "array_has_all" },
|
|
@@ -35,6 +32,8 @@ function adaptArrayOperators(query) {
|
|
|
35
32
|
let inString = false;
|
|
36
33
|
for (;idx >= 0; idx--) {
|
|
37
34
|
const ch = source[idx];
|
|
35
|
+
if (ch === undefined)
|
|
36
|
+
break;
|
|
38
37
|
if (ch === "'" && source[idx - 1] !== "\\") {
|
|
39
38
|
inString = !inString;
|
|
40
39
|
}
|
|
@@ -62,6 +61,8 @@ function adaptArrayOperators(query) {
|
|
|
62
61
|
let inString = false;
|
|
63
62
|
for (;idx < source.length; idx++) {
|
|
64
63
|
const ch = source[idx];
|
|
64
|
+
if (ch === undefined)
|
|
65
|
+
break;
|
|
65
66
|
if (ch === "'" && source[idx - 1] !== "\\") {
|
|
66
67
|
inString = !inString;
|
|
67
68
|
}
|
|
@@ -317,6 +318,8 @@ import {
|
|
|
317
318
|
timestampValue,
|
|
318
319
|
timestampTZValue
|
|
319
320
|
} from "@duckdb/node-api";
|
|
321
|
+
|
|
322
|
+
// src/value-wrappers-core.ts
|
|
320
323
|
var DUCKDB_VALUE_MARKER = Symbol.for("drizzle-duckdb:value");
|
|
321
324
|
function isDuckDBWrapper(value) {
|
|
322
325
|
return value !== null && typeof value === "object" && DUCKDB_VALUE_MARKER in value && value[DUCKDB_VALUE_MARKER] === true;
|
|
@@ -377,6 +380,8 @@ function wrapJson(data) {
|
|
|
377
380
|
data
|
|
378
381
|
};
|
|
379
382
|
}
|
|
383
|
+
|
|
384
|
+
// src/value-wrappers.ts
|
|
380
385
|
function dateToMicros(value) {
|
|
381
386
|
if (value instanceof Date) {
|
|
382
387
|
return BigInt(value.getTime()) * 1000n;
|
|
@@ -434,6 +439,9 @@ function wrapperToNodeApiValue(wrapper, toValue) {
|
|
|
434
439
|
}
|
|
435
440
|
|
|
436
441
|
// src/client.ts
|
|
442
|
+
function isPool(client) {
|
|
443
|
+
return typeof client.acquire === "function";
|
|
444
|
+
}
|
|
437
445
|
function isPgArrayLiteral(value) {
|
|
438
446
|
return value.startsWith("{") && value.endsWith("}");
|
|
439
447
|
}
|
|
@@ -445,15 +453,13 @@ function parsePgArrayLiteral(value) {
|
|
|
445
453
|
return value;
|
|
446
454
|
}
|
|
447
455
|
}
|
|
448
|
-
var warnedArrayLiteral = false;
|
|
449
456
|
function prepareParams(params, options = {}) {
|
|
450
457
|
return params.map((param) => {
|
|
451
458
|
if (typeof param === "string" && isPgArrayLiteral(param)) {
|
|
452
459
|
if (options.rejectStringArrayLiterals) {
|
|
453
460
|
throw new Error("Stringified array literals are not supported. Use duckDbList()/duckDbArray() or pass native arrays.");
|
|
454
461
|
}
|
|
455
|
-
if (
|
|
456
|
-
warnedArrayLiteral = true;
|
|
462
|
+
if (options.warnOnStringArrayLiteral) {
|
|
457
463
|
options.warnOnStringArrayLiteral();
|
|
458
464
|
}
|
|
459
465
|
return parsePgArrayLiteral(param);
|
|
@@ -510,6 +516,14 @@ async function closeClientConnection(connection) {
|
|
|
510
516
|
}
|
|
511
517
|
}
|
|
512
518
|
async function executeOnClient(client, query, params) {
|
|
519
|
+
if (isPool(client)) {
|
|
520
|
+
const connection = await client.acquire();
|
|
521
|
+
try {
|
|
522
|
+
return await executeOnClient(connection, query, params);
|
|
523
|
+
} finally {
|
|
524
|
+
await client.release(connection);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
513
527
|
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
514
528
|
const result = await client.run(query, values);
|
|
515
529
|
const rows = await result.getRowsJS();
|
|
@@ -518,6 +532,15 @@ async function executeOnClient(client, query, params) {
|
|
|
518
532
|
return rows ? mapRowsToObjects(uniqueColumns, rows) : [];
|
|
519
533
|
}
|
|
520
534
|
async function* executeInBatches(client, query, params, options = {}) {
|
|
535
|
+
if (isPool(client)) {
|
|
536
|
+
const connection = await client.acquire();
|
|
537
|
+
try {
|
|
538
|
+
yield* executeInBatches(connection, query, params, options);
|
|
539
|
+
return;
|
|
540
|
+
} finally {
|
|
541
|
+
await client.release(connection);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
521
544
|
const rowsPerChunk = options.rowsPerChunk && options.rowsPerChunk > 0 ? options.rowsPerChunk : 1e5;
|
|
522
545
|
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
523
546
|
const result = await client.stream(query, values);
|
|
@@ -539,6 +562,14 @@ async function* executeInBatches(client, query, params, options = {}) {
|
|
|
539
562
|
}
|
|
540
563
|
}
|
|
541
564
|
async function executeArrowOnClient(client, query, params) {
|
|
565
|
+
if (isPool(client)) {
|
|
566
|
+
const connection = await client.acquire();
|
|
567
|
+
try {
|
|
568
|
+
return await executeArrowOnClient(connection, query, params);
|
|
569
|
+
} finally {
|
|
570
|
+
await client.release(connection);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
542
573
|
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
543
574
|
const result = await client.run(query, values);
|
|
544
575
|
const maybeArrow = result.toArrow ?? result.getArrowTable;
|
|
@@ -627,16 +658,30 @@ class DuckDBSession extends PgSession {
|
|
|
627
658
|
return new DuckDBPreparedQuery(this.client, this.dialect, query.sql, query.params, this.logger, fields, isResponseInArrayMode, customResultMapper, this.rewriteArrays, this.rejectStringArrayLiterals, this.rejectStringArrayLiterals ? undefined : this.warnOnStringArrayLiteral);
|
|
628
659
|
}
|
|
629
660
|
async transaction(transaction) {
|
|
630
|
-
|
|
661
|
+
let pinnedConnection;
|
|
662
|
+
let pool;
|
|
663
|
+
let clientForTx = this.client;
|
|
664
|
+
if (isPool(this.client)) {
|
|
665
|
+
pool = this.client;
|
|
666
|
+
pinnedConnection = await pool.acquire();
|
|
667
|
+
clientForTx = pinnedConnection;
|
|
668
|
+
}
|
|
669
|
+
const session = new DuckDBSession(clientForTx, this.dialect, this.schema, this.options);
|
|
631
670
|
const tx = new DuckDBTransaction(this.dialect, session, this.schema);
|
|
632
|
-
await tx.execute(sql`BEGIN TRANSACTION;`);
|
|
633
671
|
try {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
672
|
+
await tx.execute(sql`BEGIN TRANSACTION;`);
|
|
673
|
+
try {
|
|
674
|
+
const result = await transaction(tx);
|
|
675
|
+
await tx.execute(sql`commit`);
|
|
676
|
+
return result;
|
|
677
|
+
} catch (error) {
|
|
678
|
+
await tx.execute(sql`rollback`);
|
|
679
|
+
throw error;
|
|
680
|
+
}
|
|
681
|
+
} finally {
|
|
682
|
+
if (pinnedConnection && pool) {
|
|
683
|
+
await pool.release(pinnedConnection);
|
|
684
|
+
}
|
|
640
685
|
}
|
|
641
686
|
}
|
|
642
687
|
warnOnStringArrayLiteral = (query) => {
|
|
@@ -884,6 +929,72 @@ class DuckDBSelectBuilder extends PgSelectBuilder {
|
|
|
884
929
|
}
|
|
885
930
|
}
|
|
886
931
|
|
|
932
|
+
// src/pool.ts
|
|
933
|
+
import { DuckDBConnection } from "@duckdb/node-api";
|
|
934
|
+
var POOL_PRESETS = {
|
|
935
|
+
pulse: 4,
|
|
936
|
+
standard: 6,
|
|
937
|
+
jumbo: 8,
|
|
938
|
+
mega: 12,
|
|
939
|
+
giga: 16,
|
|
940
|
+
local: 8,
|
|
941
|
+
memory: 4
|
|
942
|
+
};
|
|
943
|
+
function resolvePoolSize(pool) {
|
|
944
|
+
if (pool === false)
|
|
945
|
+
return false;
|
|
946
|
+
if (pool === undefined)
|
|
947
|
+
return 4;
|
|
948
|
+
if (typeof pool === "string")
|
|
949
|
+
return POOL_PRESETS[pool];
|
|
950
|
+
return pool.size ?? 4;
|
|
951
|
+
}
|
|
952
|
+
function createDuckDBConnectionPool(instance, options = {}) {
|
|
953
|
+
const size = options.size && options.size > 0 ? options.size : 4;
|
|
954
|
+
const idle = [];
|
|
955
|
+
const waiting = [];
|
|
956
|
+
let total = 0;
|
|
957
|
+
let closed = false;
|
|
958
|
+
const acquire = async () => {
|
|
959
|
+
if (closed) {
|
|
960
|
+
throw new Error("DuckDB connection pool is closed");
|
|
961
|
+
}
|
|
962
|
+
if (idle.length > 0) {
|
|
963
|
+
return idle.pop();
|
|
964
|
+
}
|
|
965
|
+
if (total < size) {
|
|
966
|
+
total += 1;
|
|
967
|
+
return await DuckDBConnection.create(instance);
|
|
968
|
+
}
|
|
969
|
+
return await new Promise((resolve) => {
|
|
970
|
+
waiting.push(resolve);
|
|
971
|
+
});
|
|
972
|
+
};
|
|
973
|
+
const release = async (connection) => {
|
|
974
|
+
if (closed) {
|
|
975
|
+
await closeClientConnection(connection);
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const waiter = waiting.shift();
|
|
979
|
+
if (waiter) {
|
|
980
|
+
waiter(connection);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
idle.push(connection);
|
|
984
|
+
};
|
|
985
|
+
const close = async () => {
|
|
986
|
+
closed = true;
|
|
987
|
+
const toClose = idle.splice(0, idle.length);
|
|
988
|
+
await Promise.all(toClose.map((conn) => closeClientConnection(conn)));
|
|
989
|
+
};
|
|
990
|
+
return {
|
|
991
|
+
acquire,
|
|
992
|
+
release,
|
|
993
|
+
close,
|
|
994
|
+
size
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
|
|
887
998
|
// src/driver.ts
|
|
888
999
|
class DuckDBDriver {
|
|
889
1000
|
client;
|
|
@@ -903,7 +1014,14 @@ class DuckDBDriver {
|
|
|
903
1014
|
});
|
|
904
1015
|
}
|
|
905
1016
|
}
|
|
906
|
-
function
|
|
1017
|
+
function isConfigObject(data) {
|
|
1018
|
+
if (typeof data !== "object" || data === null)
|
|
1019
|
+
return false;
|
|
1020
|
+
if (data.constructor?.name !== "Object")
|
|
1021
|
+
return false;
|
|
1022
|
+
return "connection" in data || "client" in data || "pool" in data || "schema" in data || "logger" in data;
|
|
1023
|
+
}
|
|
1024
|
+
function createFromClient(client, config = {}, instance) {
|
|
907
1025
|
const dialect = new DuckDBDialect;
|
|
908
1026
|
const logger = config.logger === true ? new DefaultLogger : config.logger || undefined;
|
|
909
1027
|
let schema;
|
|
@@ -921,17 +1039,60 @@ function drizzle(client, config = {}) {
|
|
|
921
1039
|
rejectStringArrayLiterals: config.rejectStringArrayLiterals
|
|
922
1040
|
});
|
|
923
1041
|
const session = driver.createSession(schema);
|
|
924
|
-
|
|
1042
|
+
const db = new DuckDBDatabase(dialect, session, schema, client, instance);
|
|
1043
|
+
return db;
|
|
1044
|
+
}
|
|
1045
|
+
async function createFromConnectionString(path, instanceOptions, config = {}) {
|
|
1046
|
+
const instance = await DuckDBInstance2.create(path, instanceOptions);
|
|
1047
|
+
const poolSize = resolvePoolSize(config.pool);
|
|
1048
|
+
if (poolSize === false) {
|
|
1049
|
+
const connection = await instance.connect();
|
|
1050
|
+
return createFromClient(connection, config, instance);
|
|
1051
|
+
}
|
|
1052
|
+
const pool = createDuckDBConnectionPool(instance, { size: poolSize });
|
|
1053
|
+
return createFromClient(pool, config, instance);
|
|
1054
|
+
}
|
|
1055
|
+
function drizzle(clientOrConfigOrPath, config) {
|
|
1056
|
+
if (typeof clientOrConfigOrPath === "string") {
|
|
1057
|
+
return createFromConnectionString(clientOrConfigOrPath, undefined, config);
|
|
1058
|
+
}
|
|
1059
|
+
if (isConfigObject(clientOrConfigOrPath)) {
|
|
1060
|
+
const configObj = clientOrConfigOrPath;
|
|
1061
|
+
if ("connection" in configObj) {
|
|
1062
|
+
const connConfig = configObj;
|
|
1063
|
+
const { connection, ...restConfig } = connConfig;
|
|
1064
|
+
if (typeof connection === "string") {
|
|
1065
|
+
return createFromConnectionString(connection, undefined, restConfig);
|
|
1066
|
+
}
|
|
1067
|
+
return createFromConnectionString(connection.path, connection.options, restConfig);
|
|
1068
|
+
}
|
|
1069
|
+
if ("client" in configObj) {
|
|
1070
|
+
const clientConfig = configObj;
|
|
1071
|
+
const { client: clientValue, ...restConfig } = clientConfig;
|
|
1072
|
+
return createFromClient(clientValue, restConfig);
|
|
1073
|
+
}
|
|
1074
|
+
throw new Error("Invalid drizzle config: either connection or client must be provided");
|
|
1075
|
+
}
|
|
1076
|
+
return createFromClient(clientOrConfigOrPath, config);
|
|
925
1077
|
}
|
|
926
1078
|
|
|
927
1079
|
class DuckDBDatabase extends PgDatabase {
|
|
928
1080
|
dialect;
|
|
929
1081
|
session;
|
|
930
1082
|
static [entityKind3] = "DuckDBDatabase";
|
|
931
|
-
|
|
1083
|
+
$client;
|
|
1084
|
+
$instance;
|
|
1085
|
+
constructor(dialect, session, schema, client, instance) {
|
|
932
1086
|
super(dialect, session, schema);
|
|
933
1087
|
this.dialect = dialect;
|
|
934
1088
|
this.session = session;
|
|
1089
|
+
this.$client = client;
|
|
1090
|
+
this.$instance = instance;
|
|
1091
|
+
}
|
|
1092
|
+
async close() {
|
|
1093
|
+
if (isPool(this.$client) && this.$client.close) {
|
|
1094
|
+
await this.$client.close();
|
|
1095
|
+
}
|
|
935
1096
|
}
|
|
936
1097
|
select(fields) {
|
|
937
1098
|
const selectedFields = fields ? aliasFields(fields) : undefined;
|
|
@@ -1220,7 +1381,7 @@ async function migrate(db, config) {
|
|
|
1220
1381
|
// src/introspect.ts
|
|
1221
1382
|
import { sql as sql5 } from "drizzle-orm";
|
|
1222
1383
|
var SYSTEM_SCHEMAS = new Set(["information_schema", "pg_catalog"]);
|
|
1223
|
-
var DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb";
|
|
1384
|
+
var DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb/helpers";
|
|
1224
1385
|
async function introspect(db, opts = {}) {
|
|
1225
1386
|
const database = await resolveDatabase(db, opts.database, opts.allDatabases);
|
|
1226
1387
|
const schemas = await resolveSchemas(db, database, opts.schemas);
|
|
@@ -1556,6 +1717,22 @@ function mapDuckDbType(column, imports, options) {
|
|
|
1556
1717
|
imports.pgCore.add("doublePrecision");
|
|
1557
1718
|
return { builder: `doublePrecision(${columnName(column.name)})` };
|
|
1558
1719
|
}
|
|
1720
|
+
const arrayMatch = /^(.*)\[(\d+)\]$/.exec(upper);
|
|
1721
|
+
if (arrayMatch) {
|
|
1722
|
+
imports.local.add("duckDbArray");
|
|
1723
|
+
const [, base, length] = arrayMatch;
|
|
1724
|
+
return {
|
|
1725
|
+
builder: `duckDbArray(${columnName(column.name)}, ${JSON.stringify(base)}, ${Number(length)})`
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
const listMatch = /^(.*)\[\]$/.exec(upper);
|
|
1729
|
+
if (listMatch) {
|
|
1730
|
+
imports.local.add("duckDbList");
|
|
1731
|
+
const [, base] = listMatch;
|
|
1732
|
+
return {
|
|
1733
|
+
builder: `duckDbList(${columnName(column.name)}, ${JSON.stringify(base)})`
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1559
1736
|
if (upper.startsWith("CHAR(") || upper === "CHAR") {
|
|
1560
1737
|
imports.pgCore.add("char");
|
|
1561
1738
|
const length = column.characterLength;
|
|
@@ -1596,22 +1773,6 @@ function mapDuckDbType(column, imports, options) {
|
|
|
1596
1773
|
imports.local.add("duckDbBlob");
|
|
1597
1774
|
return { builder: `duckDbBlob(${columnName(column.name)})` };
|
|
1598
1775
|
}
|
|
1599
|
-
const arrayMatch = /^(.*)\[(\d+)\]$/.exec(upper);
|
|
1600
|
-
if (arrayMatch) {
|
|
1601
|
-
imports.local.add("duckDbArray");
|
|
1602
|
-
const [, base, length] = arrayMatch;
|
|
1603
|
-
return {
|
|
1604
|
-
builder: `duckDbArray(${columnName(column.name)}, ${JSON.stringify(base)}, ${Number(length)})`
|
|
1605
|
-
};
|
|
1606
|
-
}
|
|
1607
|
-
const listMatch = /^(.*)\[\]$/.exec(upper);
|
|
1608
|
-
if (listMatch) {
|
|
1609
|
-
imports.local.add("duckDbList");
|
|
1610
|
-
const [, base] = listMatch;
|
|
1611
|
-
return {
|
|
1612
|
-
builder: `duckDbList(${columnName(column.name)}, ${JSON.stringify(base)})`
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
1776
|
if (upper.startsWith("STRUCT")) {
|
|
1616
1777
|
imports.local.add("duckDbStruct");
|
|
1617
1778
|
const inner = upper.replace(/^STRUCT\s*\(/i, "").replace(/\)$/, "");
|
|
@@ -1891,6 +2052,7 @@ export {
|
|
|
1891
2052
|
sumN,
|
|
1892
2053
|
sumDistinctN,
|
|
1893
2054
|
rowNumber,
|
|
2055
|
+
resolvePoolSize,
|
|
1894
2056
|
rank,
|
|
1895
2057
|
prepareParams,
|
|
1896
2058
|
percentileCont,
|
|
@@ -1899,6 +2061,7 @@ export {
|
|
|
1899
2061
|
median,
|
|
1900
2062
|
lead,
|
|
1901
2063
|
lag,
|
|
2064
|
+
isPool,
|
|
1902
2065
|
isDuckDBWrapper,
|
|
1903
2066
|
introspect,
|
|
1904
2067
|
executeOnClient,
|
|
@@ -1920,15 +2083,18 @@ export {
|
|
|
1920
2083
|
duckDbArray,
|
|
1921
2084
|
drizzle,
|
|
1922
2085
|
denseRank,
|
|
2086
|
+
createDuckDBConnectionPool,
|
|
1923
2087
|
countN,
|
|
1924
2088
|
closeClientConnection,
|
|
1925
2089
|
avgN,
|
|
1926
2090
|
anyValue,
|
|
2091
|
+
POOL_PRESETS,
|
|
1927
2092
|
OlapBuilder,
|
|
1928
2093
|
DuckDBTransaction,
|
|
1929
2094
|
DuckDBSession,
|
|
1930
2095
|
DuckDBPreparedQuery,
|
|
1931
2096
|
DuckDBDriver,
|
|
1932
2097
|
DuckDBDatabase,
|
|
1933
|
-
DUCKDB_VALUE_MARKER
|
|
2098
|
+
DUCKDB_VALUE_MARKER,
|
|
2099
|
+
DEFAULT_IMPORT_BASE
|
|
1934
2100
|
};
|
package/dist/introspect.d.ts
CHANGED
|
@@ -61,5 +61,6 @@ export interface IntrospectResult {
|
|
|
61
61
|
relationsTs?: string;
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
export declare const DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb/helpers";
|
|
64
65
|
export declare function introspect(db: DuckDBDatabase, opts?: IntrospectOptions): Promise<IntrospectResult>;
|
|
65
66
|
export {};
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
2
|
+
import { type DuckDBConnectionPool } from './client.ts';
|
|
3
|
+
/** Pool size presets for different MotherDuck instance types */
|
|
4
|
+
export type PoolPreset = 'pulse' | 'standard' | 'jumbo' | 'mega' | 'giga' | 'local' | 'memory';
|
|
5
|
+
/** Pool sizes optimized for each MotherDuck instance type */
|
|
6
|
+
export declare const POOL_PRESETS: Record<PoolPreset, number>;
|
|
7
|
+
export interface DuckDBPoolConfig {
|
|
8
|
+
/** Maximum concurrent connections. Defaults to 4. */
|
|
9
|
+
size?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolve pool configuration to a concrete size.
|
|
13
|
+
* Returns false if pooling is disabled.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolvePoolSize(pool: DuckDBPoolConfig | PoolPreset | false | undefined): number | false;
|
|
16
|
+
export interface DuckDBConnectionPoolOptions {
|
|
17
|
+
/** Maximum concurrent connections. Defaults to 4. */
|
|
18
|
+
size?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function createDuckDBConnectionPool(instance: DuckDBInstance, options?: DuckDBConnectionPoolOptions): DuckDBConnectionPool & {
|
|
21
|
+
size: number;
|
|
22
|
+
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DuckDB wrapper value helpers that are safe for client-side bundles.
|
|
3
|
+
* These utilities only tag values; conversion to native bindings lives
|
|
4
|
+
* in value-wrappers.ts to avoid pulling @duckdb/node-api into browsers.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DUCKDB_VALUE_MARKER: unique symbol;
|
|
7
|
+
export type DuckDBValueKind = 'list' | 'array' | 'struct' | 'map' | 'timestamp' | 'blob' | 'json';
|
|
8
|
+
export interface DuckDBValueWrapper<TKind extends DuckDBValueKind = DuckDBValueKind, TData = unknown> {
|
|
9
|
+
readonly [DUCKDB_VALUE_MARKER]: true;
|
|
10
|
+
readonly kind: TKind;
|
|
11
|
+
readonly data: TData;
|
|
12
|
+
}
|
|
13
|
+
export interface ListValueWrapper extends DuckDBValueWrapper<'list', unknown[]> {
|
|
14
|
+
readonly elementType?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ArrayValueWrapper extends DuckDBValueWrapper<'array', unknown[]> {
|
|
17
|
+
readonly elementType?: string;
|
|
18
|
+
readonly fixedLength?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface StructValueWrapper extends DuckDBValueWrapper<'struct', Record<string, unknown>> {
|
|
21
|
+
readonly schema?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export interface MapValueWrapper extends DuckDBValueWrapper<'map', Record<string, unknown>> {
|
|
24
|
+
readonly valueType?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface TimestampValueWrapper extends DuckDBValueWrapper<'timestamp', Date | string> {
|
|
27
|
+
readonly withTimezone: boolean;
|
|
28
|
+
readonly precision?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface BlobValueWrapper extends DuckDBValueWrapper<'blob', Buffer | Uint8Array> {
|
|
31
|
+
}
|
|
32
|
+
export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {
|
|
33
|
+
}
|
|
34
|
+
export type AnyDuckDBValueWrapper = ListValueWrapper | ArrayValueWrapper | StructValueWrapper | MapValueWrapper | TimestampValueWrapper | BlobValueWrapper | JsonValueWrapper;
|
|
35
|
+
export declare function isDuckDBWrapper(value: unknown): value is AnyDuckDBValueWrapper;
|
|
36
|
+
export declare function wrapList(data: unknown[], elementType?: string): ListValueWrapper;
|
|
37
|
+
export declare function wrapArray(data: unknown[], elementType?: string, fixedLength?: number): ArrayValueWrapper;
|
|
38
|
+
export declare function wrapStruct(data: Record<string, unknown>, schema?: Record<string, string>): StructValueWrapper;
|
|
39
|
+
export declare function wrapMap(data: Record<string, unknown>, valueType?: string): MapValueWrapper;
|
|
40
|
+
export declare function wrapTimestamp(data: Date | string, withTimezone: boolean, precision?: number): TimestampValueWrapper;
|
|
41
|
+
export declare function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper;
|
|
42
|
+
export declare function wrapJson(data: unknown): JsonValueWrapper;
|
package/dist/value-wrappers.d.ts
CHANGED
|
@@ -1,104 +1,8 @@
|
|
|
1
1
|
import { type DuckDBValue } from '@duckdb/node-api';
|
|
2
|
-
|
|
3
|
-
* Symbol used to identify wrapped DuckDB values for native binding.
|
|
4
|
-
* Uses Symbol.for() to ensure cross-module compatibility.
|
|
5
|
-
*/
|
|
6
|
-
export declare const DUCKDB_VALUE_MARKER: unique symbol;
|
|
7
|
-
/**
|
|
8
|
-
* Type identifier for each wrapper kind.
|
|
9
|
-
*/
|
|
10
|
-
export type DuckDBValueKind = 'list' | 'array' | 'struct' | 'map' | 'timestamp' | 'blob' | 'json';
|
|
11
|
-
/**
|
|
12
|
-
* Base interface for all tagged DuckDB value wrappers.
|
|
13
|
-
*/
|
|
14
|
-
export interface DuckDBValueWrapper<TKind extends DuckDBValueKind = DuckDBValueKind, TData = unknown> {
|
|
15
|
-
readonly [DUCKDB_VALUE_MARKER]: true;
|
|
16
|
-
readonly kind: TKind;
|
|
17
|
-
readonly data: TData;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* List wrapper - maps to DuckDBListValue
|
|
21
|
-
*/
|
|
22
|
-
export interface ListValueWrapper extends DuckDBValueWrapper<'list', unknown[]> {
|
|
23
|
-
readonly elementType?: string;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Array wrapper (fixed size) - maps to DuckDBArrayValue
|
|
27
|
-
*/
|
|
28
|
-
export interface ArrayValueWrapper extends DuckDBValueWrapper<'array', unknown[]> {
|
|
29
|
-
readonly elementType?: string;
|
|
30
|
-
readonly fixedLength?: number;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Struct wrapper - maps to DuckDBStructValue
|
|
34
|
-
*/
|
|
35
|
-
export interface StructValueWrapper extends DuckDBValueWrapper<'struct', Record<string, unknown>> {
|
|
36
|
-
readonly schema?: Record<string, string>;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Map wrapper - maps to DuckDBMapValue
|
|
40
|
-
*/
|
|
41
|
-
export interface MapValueWrapper extends DuckDBValueWrapper<'map', Record<string, unknown>> {
|
|
42
|
-
readonly valueType?: string;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Timestamp wrapper - maps to DuckDBTimestampValue or DuckDBTimestampTZValue
|
|
46
|
-
*/
|
|
47
|
-
export interface TimestampValueWrapper extends DuckDBValueWrapper<'timestamp', Date | string> {
|
|
48
|
-
readonly withTimezone: boolean;
|
|
49
|
-
readonly precision?: number;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Blob wrapper - maps to DuckDBBlobValue
|
|
53
|
-
*/
|
|
54
|
-
export interface BlobValueWrapper extends DuckDBValueWrapper<'blob', Buffer | Uint8Array> {
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* JSON wrapper - delays JSON.stringify() to binding time.
|
|
58
|
-
* DuckDB stores JSON as VARCHAR internally.
|
|
59
|
-
*/
|
|
60
|
-
export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Union of all wrapper types for exhaustive type checking.
|
|
64
|
-
*/
|
|
65
|
-
export type AnyDuckDBValueWrapper = ListValueWrapper | ArrayValueWrapper | StructValueWrapper | MapValueWrapper | TimestampValueWrapper | BlobValueWrapper | JsonValueWrapper;
|
|
66
|
-
/**
|
|
67
|
-
* Type guard to check if a value is a tagged DuckDB wrapper.
|
|
68
|
-
* Optimized for fast detection in the hot path.
|
|
69
|
-
*/
|
|
70
|
-
export declare function isDuckDBWrapper(value: unknown): value is AnyDuckDBValueWrapper;
|
|
71
|
-
/**
|
|
72
|
-
* Create a list wrapper for variable-length lists.
|
|
73
|
-
*/
|
|
74
|
-
export declare function wrapList(data: unknown[], elementType?: string): ListValueWrapper;
|
|
75
|
-
/**
|
|
76
|
-
* Create an array wrapper for fixed-length arrays.
|
|
77
|
-
*/
|
|
78
|
-
export declare function wrapArray(data: unknown[], elementType?: string, fixedLength?: number): ArrayValueWrapper;
|
|
79
|
-
/**
|
|
80
|
-
* Create a struct wrapper for named field structures.
|
|
81
|
-
*/
|
|
82
|
-
export declare function wrapStruct(data: Record<string, unknown>, schema?: Record<string, string>): StructValueWrapper;
|
|
83
|
-
/**
|
|
84
|
-
* Create a map wrapper for key-value maps.
|
|
85
|
-
*/
|
|
86
|
-
export declare function wrapMap(data: Record<string, unknown>, valueType?: string): MapValueWrapper;
|
|
87
|
-
/**
|
|
88
|
-
* Create a timestamp wrapper.
|
|
89
|
-
*/
|
|
90
|
-
export declare function wrapTimestamp(data: Date | string, withTimezone: boolean, precision?: number): TimestampValueWrapper;
|
|
91
|
-
/**
|
|
92
|
-
* Create a blob wrapper for binary data.
|
|
93
|
-
*/
|
|
94
|
-
export declare function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper;
|
|
95
|
-
/**
|
|
96
|
-
* Create a JSON wrapper that delays JSON.stringify() to binding time.
|
|
97
|
-
* This ensures consistent handling with other wrapped types.
|
|
98
|
-
*/
|
|
99
|
-
export declare function wrapJson(data: unknown): JsonValueWrapper;
|
|
2
|
+
import { type AnyDuckDBValueWrapper } from './value-wrappers-core.ts';
|
|
100
3
|
/**
|
|
101
4
|
* Convert a wrapper to a DuckDB Node API value.
|
|
102
5
|
* Uses exhaustive switch for compile-time safety.
|
|
103
6
|
*/
|
|
104
7
|
export declare function wrapperToNodeApiValue(wrapper: AnyDuckDBValueWrapper, toValue: (v: unknown) => DuckDBValue): DuckDBValue;
|
|
8
|
+
export { DUCKDB_VALUE_MARKER, isDuckDBWrapper, wrapArray, wrapBlob, wrapJson, wrapList, wrapMap, wrapStruct, wrapTimestamp, type AnyDuckDBValueWrapper, type DuckDBValueWrapper, type ArrayValueWrapper, type BlobValueWrapper, type JsonValueWrapper, type ListValueWrapper, type MapValueWrapper, type StructValueWrapper, type TimestampValueWrapper, type DuckDBValueKind, } from './value-wrappers-core.ts';
|
package/package.json
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
"module": "./dist/index.mjs",
|
|
4
4
|
"main": "./dist/index.mjs",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
|
-
"version": "1.0
|
|
6
|
+
"version": "1.1.0",
|
|
7
7
|
"description": "A drizzle ORM client for use with DuckDB. Based on drizzle's Postgres client.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "bun build --target=node ./src/index.ts --outfile=./dist/index.mjs --packages=external && bun build --target=node ./src/bin/duckdb-introspect.ts --outfile=./dist/duckdb-introspect.mjs --packages=external && bun run build:declarations",
|
|
10
|
+
"build": "bun build --target=node ./src/index.ts --outfile=./dist/index.mjs --packages=external && bun build --target=node ./src/helpers.ts --outfile=./dist/helpers.mjs --packages=external && bun build --target=node ./src/bin/duckdb-introspect.ts --outfile=./dist/duckdb-introspect.mjs --packages=external && bun run build:declarations",
|
|
11
11
|
"build:declarations": "tsc --emitDeclarationOnly --project tsconfig.types.json",
|
|
12
12
|
"test": "vitest",
|
|
13
13
|
"t": "vitest --watch --ui",
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"types": "./dist/index.d.ts",
|
|
49
49
|
"import": "./dist/index.mjs"
|
|
50
50
|
},
|
|
51
|
+
"./helpers": {
|
|
52
|
+
"types": "./dist/helpers.d.ts",
|
|
53
|
+
"import": "./dist/helpers.mjs"
|
|
54
|
+
},
|
|
51
55
|
"./package.json": "./package.json"
|
|
52
56
|
},
|
|
53
57
|
"sideEffects": false,
|