@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/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 (!warnedArrayLiteral && options.warnOnStringArrayLiteral) {
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
- const session = new DuckDBSession(this.client, this.dialect, this.schema, this.options);
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
- const result = await transaction(tx);
635
- await tx.execute(sql`commit`);
636
- return result;
637
- } catch (error) {
638
- await tx.execute(sql`rollback`);
639
- throw error;
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 drizzle(client, config = {}) {
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
- return new DuckDBDatabase(dialect, session, schema);
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
- constructor(dialect, session, schema) {
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
  };
@@ -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
+ };
@@ -1,2 +1 @@
1
1
  export declare function adaptArrayOperators(query: string): string;
2
- export declare function queryAdapter(query: string): string;
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { aliasFields } from './sql/selection.ts';
2
- export { adaptArrayOperators, queryAdapter } from './sql/query-rewriters.ts';
2
+ export { adaptArrayOperators } from './sql/query-rewriters.ts';
3
3
  export { mapResultRow } from './sql/result-mapper.ts';
@@ -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;
@@ -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.3",
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,