@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 CHANGED
@@ -7,7 +7,7 @@
7
7
  [![npm version](https://img.shields.io/npm/v/@leonardovida-md/drizzle-neo-duckdb)](https://www.npmjs.com/package/@leonardovida-md/drizzle-neo-duckdb)
8
8
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
9
9
 
10
- [Documentation](https://leonardovida-md.github.io/drizzle-neo-duckdb/) • [Examples](./example) • [Contributing](#contributing)
10
+ [Documentation](https://leonardovida.github.io/drizzle-neo-duckdb/) • [LLM Context](https://leonardovida.github.io/drizzle-neo-duckdb/llms.txt) • [Examples](./example) • [Contributing](#contributing)
11
11
 
12
12
  </div>
13
13
 
@@ -19,6 +19,8 @@ Works with local DuckDB files, in-memory databases, and [MotherDuck](https://mot
19
19
 
20
20
  > **Status:** Experimental. Core query building, migrations, and type inference work well. Some DuckDB-specific types and edge cases are still being refined.
21
21
 
22
+ Docs tip: every docs page has a **Markdown (raw)** button for LLM-friendly source.
23
+
22
24
  ## Installation
23
25
 
24
26
  ```bash
@@ -188,7 +190,20 @@ const products = pgTable('products', {
188
190
  });
189
191
  ```
190
192
 
191
- See [Column Types Documentation](https://leonardovida-md.github.io/drizzle-neo-duckdb/api/columns) for complete reference.
193
+ See [Column Types Documentation](https://leonardovida.github.io/drizzle-neo-duckdb/api/columns) for complete reference.
194
+
195
+ ### Client-Safe Imports (schemas, drizzle-zod, trpc)
196
+
197
+ When generated schemas are consumed in client bundles, import the helpers from the browser-safe subpath to avoid pulling the native DuckDB bindings:
198
+
199
+ ```typescript
200
+ import {
201
+ duckDbJson,
202
+ duckDbList,
203
+ } from '@leonardovida-md/drizzle-neo-duckdb/helpers';
204
+ ```
205
+
206
+ The introspection CLI now emits this import path by default. You can still override `importBasePath` if you need the old root import.
192
207
 
193
208
  ## Querying
194
209
 
@@ -275,7 +290,7 @@ import { migrate } from '@leonardovida-md/drizzle-neo-duckdb';
275
290
  await migrate(db, { migrationsFolder: './drizzle' });
276
291
  ```
277
292
 
278
- Migration metadata is stored in `drizzle.__drizzle_migrations` by default. See [Migrations Documentation](https://leonardovida-md.github.io/drizzle-neo-duckdb/guide/migrations) for configuration options.
293
+ Migration metadata is stored in `drizzle.__drizzle_migrations` by default. See [Migrations Documentation](https://leonardovida.github.io/drizzle-neo-duckdb/guide/migrations) for configuration options.
279
294
 
280
295
  ## Schema Introspection
281
296
 
@@ -300,7 +315,7 @@ const result = await introspect(db, {
300
315
  console.log(result.files.schemaTs);
301
316
  ```
302
317
 
303
- See [Introspection Documentation](https://leonardovida-md.github.io/drizzle-neo-duckdb/guide/introspection) for all options.
318
+ See [Introspection Documentation](https://leonardovida.github.io/drizzle-neo-duckdb/guide/introspection) for all options.
304
319
 
305
320
  ## Configuration Options
306
321
 
@@ -333,7 +348,7 @@ This connector aims for compatibility with Drizzle's Postgres driver but has som
333
348
  | Prepared statements | No statement caching |
334
349
  | Streaming results | Materialized by default; use `executeBatches()` for chunks |
335
350
 
336
- See [Limitations Documentation](https://leonardovida-md.github.io/drizzle-neo-duckdb/guide/limitations) for details.
351
+ See [Limitations Documentation](https://leonardovida.github.io/drizzle-neo-duckdb/guide/limitations) for details.
337
352
 
338
353
  ## Examples
339
354
 
package/dist/client.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import { type DuckDBConnection } from '@duckdb/node-api';
2
- export type DuckDBClientLike = DuckDBConnection;
2
+ export type DuckDBClientLike = DuckDBConnection | DuckDBConnectionPool;
3
3
  export type RowData = Record<string, unknown>;
4
+ export interface DuckDBConnectionPool {
5
+ acquire(): Promise<DuckDBConnection>;
6
+ release(connection: DuckDBConnection): void | Promise<void>;
7
+ close?(): Promise<void> | void;
8
+ }
9
+ export declare function isPool(client: DuckDBClientLike): client is DuckDBConnectionPool;
4
10
  export interface PrepareParamsOptions {
5
11
  rejectStringArrayLiterals?: boolean;
6
12
  warnOnStringArrayLiteral?: () => void;
package/dist/columns.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type SQL } from 'drizzle-orm';
2
2
  import type { SQLWrapper } from 'drizzle-orm/sql/sql';
3
- import { type ListValueWrapper, type ArrayValueWrapper, type MapValueWrapper, type BlobValueWrapper, type JsonValueWrapper } from './value-wrappers.ts';
3
+ import { type ListValueWrapper, type ArrayValueWrapper, type MapValueWrapper, type BlobValueWrapper, type JsonValueWrapper } from './value-wrappers-core.ts';
4
4
  type IntColType = 'SMALLINT' | 'INTEGER' | 'BIGINT' | 'HUGEINT' | 'USMALLINT' | 'UINTEGER' | 'UBIGINT' | 'UHUGEINT' | 'INT' | 'INT16' | 'INT32' | 'INT64' | 'INT128' | 'LONG' | 'VARINT';
5
5
  type FloatColType = 'FLOAT' | 'DOUBLE';
6
6
  type StringColType = 'STRING' | 'VARCHAR' | 'TEXT';
package/dist/driver.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { DuckDBInstance } from '@duckdb/node-api';
1
2
  import { entityKind } from 'drizzle-orm/entity';
2
3
  import type { Logger } from 'drizzle-orm/logger';
3
4
  import { PgDatabase } from 'drizzle-orm/pg-core/db';
@@ -10,6 +11,7 @@ import { DuckDBSession } from './session.ts';
10
11
  import { DuckDBDialect } from './dialect.ts';
11
12
  import { DuckDBSelectBuilder } from './select-builder.ts';
12
13
  import type { ExecuteInBatchesOptions, RowData } from './client.ts';
14
+ import { type DuckDBPoolConfig, type PoolPreset } from './pool.ts';
13
15
  export interface PgDriverOptions {
14
16
  logger?: Logger;
15
17
  rewriteArrays?: boolean;
@@ -23,16 +25,46 @@ export declare class DuckDBDriver {
23
25
  constructor(client: DuckDBClientLike, dialect: DuckDBDialect, options?: PgDriverOptions);
24
26
  createSession(schema: RelationalSchemaConfig<TablesRelationalConfig> | undefined): DuckDBSession<Record<string, unknown>, TablesRelationalConfig>;
25
27
  }
28
+ /** Connection configuration when using path-based connection */
29
+ export interface DuckDBConnectionConfig {
30
+ /** Database path: ':memory:', './file.duckdb', 'md:', 'md:database' */
31
+ path: string;
32
+ /** DuckDB instance options (e.g., motherduck_token) */
33
+ options?: Record<string, string>;
34
+ }
26
35
  export interface DuckDBDrizzleConfig<TSchema extends Record<string, unknown> = Record<string, never>> extends DrizzleConfig<TSchema> {
27
36
  rewriteArrays?: boolean;
28
37
  rejectStringArrayLiterals?: boolean;
38
+ /** Pool configuration. Use preset name, size config, or false to disable. */
39
+ pool?: DuckDBPoolConfig | PoolPreset | false;
40
+ }
41
+ export interface DuckDBDrizzleConfigWithConnection<TSchema extends Record<string, unknown> = Record<string, never>> extends DuckDBDrizzleConfig<TSchema> {
42
+ /** Connection string or config object */
43
+ connection: string | DuckDBConnectionConfig;
44
+ }
45
+ export interface DuckDBDrizzleConfigWithClient<TSchema extends Record<string, unknown> = Record<string, never>> extends DuckDBDrizzleConfig<TSchema> {
46
+ /** Explicit client (connection or pool) */
47
+ client: DuckDBClientLike;
29
48
  }
49
+ export declare function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(connectionString: string): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
50
+ export declare function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(connectionString: string, config: DuckDBDrizzleConfig<TSchema>): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
51
+ export declare function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(config: DuckDBDrizzleConfigWithConnection<TSchema>): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
52
+ export declare function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(config: DuckDBDrizzleConfigWithClient<TSchema>): DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>;
30
53
  export declare function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(client: DuckDBClientLike, config?: DuckDBDrizzleConfig<TSchema>): DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>;
31
54
  export declare class DuckDBDatabase<TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> extends PgDatabase<DuckDBQueryResultHKT, TFullSchema, TSchema> {
32
55
  readonly dialect: DuckDBDialect;
33
56
  readonly session: DuckDBSession<TFullSchema, TSchema>;
34
57
  static readonly [entityKind]: string;
35
- constructor(dialect: DuckDBDialect, session: DuckDBSession<TFullSchema, TSchema>, schema: RelationalSchemaConfig<TSchema> | undefined);
58
+ /** The underlying connection or pool */
59
+ readonly $client: DuckDBClientLike;
60
+ /** The DuckDB instance (when created from connection string) */
61
+ readonly $instance?: DuckDBInstance;
62
+ constructor(dialect: DuckDBDialect, session: DuckDBSession<TFullSchema, TSchema>, schema: RelationalSchemaConfig<TSchema> | undefined, client: DuckDBClientLike, instance?: DuckDBInstance);
63
+ /**
64
+ * Close the database connection pool and instance.
65
+ * Should be called when shutting down the application.
66
+ */
67
+ close(): Promise<void>;
36
68
  select(): DuckDBSelectBuilder<undefined>;
37
69
  select<TSelection extends SelectedFields>(fields: TSelection): DuckDBSelectBuilder<TSelection>;
38
70
  executeBatches<T extends RowData = RowData>(query: SQL, options?: ExecuteInBatchesOptions): AsyncGenerator<T[], void, void>;
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/bin/duckdb-introspect.ts
4
- import { DuckDBInstance } from "@duckdb/node-api";
4
+ import { DuckDBInstance as DuckDBInstance3 } from "@duckdb/node-api";
5
5
  import { mkdir, writeFile } from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import process from "node:process";
8
8
 
9
9
  // src/driver.ts
10
+ import { DuckDBInstance as DuckDBInstance2 } from "@duckdb/node-api";
10
11
  import { entityKind as entityKind3 } from "drizzle-orm/entity";
11
12
  import { DefaultLogger } from "drizzle-orm/logger";
12
13
  import { PgDatabase } from "drizzle-orm/pg-core/db";
@@ -23,10 +24,6 @@ import { PgPreparedQuery, PgSession } from "drizzle-orm/pg-core/session";
23
24
  import { fillPlaceholders, sql } from "drizzle-orm/sql/sql";
24
25
 
25
26
  // src/sql/query-rewriters.ts
26
- var tableIdPropSelectionRegex = new RegExp([
27
- `("(.+)"\\."(.+)")`,
28
- `(\\s+as\\s+'?(.+?)'?\\.'?(.+?)'?)?`
29
- ].join(""), "i");
30
27
  function adaptArrayOperators(query) {
31
28
  const operators = [
32
29
  { token: "@>", fn: "array_has_all" },
@@ -43,6 +40,8 @@ function adaptArrayOperators(query) {
43
40
  let inString = false;
44
41
  for (;idx >= 0; idx--) {
45
42
  const ch = source[idx];
43
+ if (ch === undefined)
44
+ break;
46
45
  if (ch === "'" && source[idx - 1] !== "\\") {
47
46
  inString = !inString;
48
47
  }
@@ -70,6 +69,8 @@ function adaptArrayOperators(query) {
70
69
  let inString = false;
71
70
  for (;idx < source.length; idx++) {
72
71
  const ch = source[idx];
72
+ if (ch === undefined)
73
+ break;
73
74
  if (ch === "'" && source[idx - 1] !== "\\") {
74
75
  inString = !inString;
75
76
  }
@@ -325,7 +326,11 @@ import {
325
326
  timestampValue,
326
327
  timestampTZValue
327
328
  } from "@duckdb/node-api";
329
+
330
+ // src/value-wrappers-core.ts
328
331
  var DUCKDB_VALUE_MARKER = Symbol.for("drizzle-duckdb:value");
332
+
333
+ // src/value-wrappers.ts
329
334
  function dateToMicros(value) {
330
335
  if (value instanceof Date) {
331
336
  return BigInt(value.getTime()) * 1000n;
@@ -383,6 +388,9 @@ function wrapperToNodeApiValue(wrapper, toValue) {
383
388
  }
384
389
 
385
390
  // src/client.ts
391
+ function isPool(client) {
392
+ return typeof client.acquire === "function";
393
+ }
386
394
  function isPgArrayLiteral(value) {
387
395
  return value.startsWith("{") && value.endsWith("}");
388
396
  }
@@ -394,15 +402,13 @@ function parsePgArrayLiteral(value) {
394
402
  return value;
395
403
  }
396
404
  }
397
- var warnedArrayLiteral = false;
398
405
  function prepareParams(params, options = {}) {
399
406
  return params.map((param) => {
400
407
  if (typeof param === "string" && isPgArrayLiteral(param)) {
401
408
  if (options.rejectStringArrayLiterals) {
402
409
  throw new Error("Stringified array literals are not supported. Use duckDbList()/duckDbArray() or pass native arrays.");
403
410
  }
404
- if (!warnedArrayLiteral && options.warnOnStringArrayLiteral) {
405
- warnedArrayLiteral = true;
411
+ if (options.warnOnStringArrayLiteral) {
406
412
  options.warnOnStringArrayLiteral();
407
413
  }
408
414
  return parsePgArrayLiteral(param);
@@ -445,7 +451,28 @@ function mapRowsToObjects(columns, rows) {
445
451
  return obj;
446
452
  });
447
453
  }
454
+ async function closeClientConnection(connection) {
455
+ if ("close" in connection && typeof connection.close === "function") {
456
+ await connection.close();
457
+ return;
458
+ }
459
+ if ("closeSync" in connection && typeof connection.closeSync === "function") {
460
+ connection.closeSync();
461
+ return;
462
+ }
463
+ if ("disconnectSync" in connection && typeof connection.disconnectSync === "function") {
464
+ connection.disconnectSync();
465
+ }
466
+ }
448
467
  async function executeOnClient(client, query, params) {
468
+ if (isPool(client)) {
469
+ const connection = await client.acquire();
470
+ try {
471
+ return await executeOnClient(connection, query, params);
472
+ } finally {
473
+ await client.release(connection);
474
+ }
475
+ }
449
476
  const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
450
477
  const result = await client.run(query, values);
451
478
  const rows = await result.getRowsJS();
@@ -454,6 +481,15 @@ async function executeOnClient(client, query, params) {
454
481
  return rows ? mapRowsToObjects(uniqueColumns, rows) : [];
455
482
  }
456
483
  async function* executeInBatches(client, query, params, options = {}) {
484
+ if (isPool(client)) {
485
+ const connection = await client.acquire();
486
+ try {
487
+ yield* executeInBatches(connection, query, params, options);
488
+ return;
489
+ } finally {
490
+ await client.release(connection);
491
+ }
492
+ }
457
493
  const rowsPerChunk = options.rowsPerChunk && options.rowsPerChunk > 0 ? options.rowsPerChunk : 1e5;
458
494
  const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
459
495
  const result = await client.stream(query, values);
@@ -475,6 +511,14 @@ async function* executeInBatches(client, query, params, options = {}) {
475
511
  }
476
512
  }
477
513
  async function executeArrowOnClient(client, query, params) {
514
+ if (isPool(client)) {
515
+ const connection = await client.acquire();
516
+ try {
517
+ return await executeArrowOnClient(connection, query, params);
518
+ } finally {
519
+ await client.release(connection);
520
+ }
521
+ }
478
522
  const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
479
523
  const result = await client.run(query, values);
480
524
  const maybeArrow = result.toArrow ?? result.getArrowTable;
@@ -563,16 +607,30 @@ class DuckDBSession extends PgSession {
563
607
  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);
564
608
  }
565
609
  async transaction(transaction) {
566
- const session = new DuckDBSession(this.client, this.dialect, this.schema, this.options);
610
+ let pinnedConnection;
611
+ let pool;
612
+ let clientForTx = this.client;
613
+ if (isPool(this.client)) {
614
+ pool = this.client;
615
+ pinnedConnection = await pool.acquire();
616
+ clientForTx = pinnedConnection;
617
+ }
618
+ const session = new DuckDBSession(clientForTx, this.dialect, this.schema, this.options);
567
619
  const tx = new DuckDBTransaction(this.dialect, session, this.schema);
568
- await tx.execute(sql`BEGIN TRANSACTION;`);
569
620
  try {
570
- const result = await transaction(tx);
571
- await tx.execute(sql`commit`);
572
- return result;
573
- } catch (error) {
574
- await tx.execute(sql`rollback`);
575
- throw error;
621
+ await tx.execute(sql`BEGIN TRANSACTION;`);
622
+ try {
623
+ const result = await transaction(tx);
624
+ await tx.execute(sql`commit`);
625
+ return result;
626
+ } catch (error) {
627
+ await tx.execute(sql`rollback`);
628
+ throw error;
629
+ }
630
+ } finally {
631
+ if (pinnedConnection && pool) {
632
+ await pool.release(pinnedConnection);
633
+ }
576
634
  }
577
635
  }
578
636
  warnOnStringArrayLiteral = (query) => {
@@ -820,6 +878,72 @@ class DuckDBSelectBuilder extends PgSelectBuilder {
820
878
  }
821
879
  }
822
880
 
881
+ // src/pool.ts
882
+ import { DuckDBConnection } from "@duckdb/node-api";
883
+ var POOL_PRESETS = {
884
+ pulse: 4,
885
+ standard: 6,
886
+ jumbo: 8,
887
+ mega: 12,
888
+ giga: 16,
889
+ local: 8,
890
+ memory: 4
891
+ };
892
+ function resolvePoolSize(pool) {
893
+ if (pool === false)
894
+ return false;
895
+ if (pool === undefined)
896
+ return 4;
897
+ if (typeof pool === "string")
898
+ return POOL_PRESETS[pool];
899
+ return pool.size ?? 4;
900
+ }
901
+ function createDuckDBConnectionPool(instance, options = {}) {
902
+ const size = options.size && options.size > 0 ? options.size : 4;
903
+ const idle = [];
904
+ const waiting = [];
905
+ let total = 0;
906
+ let closed = false;
907
+ const acquire = async () => {
908
+ if (closed) {
909
+ throw new Error("DuckDB connection pool is closed");
910
+ }
911
+ if (idle.length > 0) {
912
+ return idle.pop();
913
+ }
914
+ if (total < size) {
915
+ total += 1;
916
+ return await DuckDBConnection.create(instance);
917
+ }
918
+ return await new Promise((resolve) => {
919
+ waiting.push(resolve);
920
+ });
921
+ };
922
+ const release = async (connection) => {
923
+ if (closed) {
924
+ await closeClientConnection(connection);
925
+ return;
926
+ }
927
+ const waiter = waiting.shift();
928
+ if (waiter) {
929
+ waiter(connection);
930
+ return;
931
+ }
932
+ idle.push(connection);
933
+ };
934
+ const close = async () => {
935
+ closed = true;
936
+ const toClose = idle.splice(0, idle.length);
937
+ await Promise.all(toClose.map((conn) => closeClientConnection(conn)));
938
+ };
939
+ return {
940
+ acquire,
941
+ release,
942
+ close,
943
+ size
944
+ };
945
+ }
946
+
823
947
  // src/driver.ts
824
948
  class DuckDBDriver {
825
949
  client;
@@ -839,7 +963,14 @@ class DuckDBDriver {
839
963
  });
840
964
  }
841
965
  }
842
- function drizzle(client, config = {}) {
966
+ function isConfigObject(data) {
967
+ if (typeof data !== "object" || data === null)
968
+ return false;
969
+ if (data.constructor?.name !== "Object")
970
+ return false;
971
+ return "connection" in data || "client" in data || "pool" in data || "schema" in data || "logger" in data;
972
+ }
973
+ function createFromClient(client, config = {}, instance) {
843
974
  const dialect = new DuckDBDialect;
844
975
  const logger = config.logger === true ? new DefaultLogger : config.logger || undefined;
845
976
  let schema;
@@ -857,17 +988,60 @@ function drizzle(client, config = {}) {
857
988
  rejectStringArrayLiterals: config.rejectStringArrayLiterals
858
989
  });
859
990
  const session = driver.createSession(schema);
860
- return new DuckDBDatabase(dialect, session, schema);
991
+ const db = new DuckDBDatabase(dialect, session, schema, client, instance);
992
+ return db;
993
+ }
994
+ async function createFromConnectionString(path, instanceOptions, config = {}) {
995
+ const instance = await DuckDBInstance2.create(path, instanceOptions);
996
+ const poolSize = resolvePoolSize(config.pool);
997
+ if (poolSize === false) {
998
+ const connection = await instance.connect();
999
+ return createFromClient(connection, config, instance);
1000
+ }
1001
+ const pool = createDuckDBConnectionPool(instance, { size: poolSize });
1002
+ return createFromClient(pool, config, instance);
1003
+ }
1004
+ function drizzle(clientOrConfigOrPath, config) {
1005
+ if (typeof clientOrConfigOrPath === "string") {
1006
+ return createFromConnectionString(clientOrConfigOrPath, undefined, config);
1007
+ }
1008
+ if (isConfigObject(clientOrConfigOrPath)) {
1009
+ const configObj = clientOrConfigOrPath;
1010
+ if ("connection" in configObj) {
1011
+ const connConfig = configObj;
1012
+ const { connection, ...restConfig } = connConfig;
1013
+ if (typeof connection === "string") {
1014
+ return createFromConnectionString(connection, undefined, restConfig);
1015
+ }
1016
+ return createFromConnectionString(connection.path, connection.options, restConfig);
1017
+ }
1018
+ if ("client" in configObj) {
1019
+ const clientConfig = configObj;
1020
+ const { client: clientValue, ...restConfig } = clientConfig;
1021
+ return createFromClient(clientValue, restConfig);
1022
+ }
1023
+ throw new Error("Invalid drizzle config: either connection or client must be provided");
1024
+ }
1025
+ return createFromClient(clientOrConfigOrPath, config);
861
1026
  }
862
1027
 
863
1028
  class DuckDBDatabase extends PgDatabase {
864
1029
  dialect;
865
1030
  session;
866
1031
  static [entityKind3] = "DuckDBDatabase";
867
- constructor(dialect, session, schema) {
1032
+ $client;
1033
+ $instance;
1034
+ constructor(dialect, session, schema, client, instance) {
868
1035
  super(dialect, session, schema);
869
1036
  this.dialect = dialect;
870
1037
  this.session = session;
1038
+ this.$client = client;
1039
+ this.$instance = instance;
1040
+ }
1041
+ async close() {
1042
+ if (isPool(this.$client) && this.$client.close) {
1043
+ await this.$client.close();
1044
+ }
871
1045
  }
872
1046
  select(fields) {
873
1047
  const selectedFields = fields ? aliasFields(fields) : undefined;
@@ -891,7 +1065,7 @@ class DuckDBDatabase extends PgDatabase {
891
1065
  // src/introspect.ts
892
1066
  import { sql as sql4 } from "drizzle-orm";
893
1067
  var SYSTEM_SCHEMAS = new Set(["information_schema", "pg_catalog"]);
894
- var DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb";
1068
+ var DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb/helpers";
895
1069
  async function introspect(db, opts = {}) {
896
1070
  const database = await resolveDatabase(db, opts.database, opts.allDatabases);
897
1071
  const schemas = await resolveSchemas(db, database, opts.schemas);
@@ -1227,6 +1401,22 @@ function mapDuckDbType(column, imports, options) {
1227
1401
  imports.pgCore.add("doublePrecision");
1228
1402
  return { builder: `doublePrecision(${columnName(column.name)})` };
1229
1403
  }
1404
+ const arrayMatch = /^(.*)\[(\d+)\]$/.exec(upper);
1405
+ if (arrayMatch) {
1406
+ imports.local.add("duckDbArray");
1407
+ const [, base, length] = arrayMatch;
1408
+ return {
1409
+ builder: `duckDbArray(${columnName(column.name)}, ${JSON.stringify(base)}, ${Number(length)})`
1410
+ };
1411
+ }
1412
+ const listMatch = /^(.*)\[\]$/.exec(upper);
1413
+ if (listMatch) {
1414
+ imports.local.add("duckDbList");
1415
+ const [, base] = listMatch;
1416
+ return {
1417
+ builder: `duckDbList(${columnName(column.name)}, ${JSON.stringify(base)})`
1418
+ };
1419
+ }
1230
1420
  if (upper.startsWith("CHAR(") || upper === "CHAR") {
1231
1421
  imports.pgCore.add("char");
1232
1422
  const length = column.characterLength;
@@ -1267,22 +1457,6 @@ function mapDuckDbType(column, imports, options) {
1267
1457
  imports.local.add("duckDbBlob");
1268
1458
  return { builder: `duckDbBlob(${columnName(column.name)})` };
1269
1459
  }
1270
- const arrayMatch = /^(.*)\[(\d+)\]$/.exec(upper);
1271
- if (arrayMatch) {
1272
- imports.local.add("duckDbArray");
1273
- const [, base, length] = arrayMatch;
1274
- return {
1275
- builder: `duckDbArray(${columnName(column.name)}, ${JSON.stringify(base)}, ${Number(length)})`
1276
- };
1277
- }
1278
- const listMatch = /^(.*)\[\]$/.exec(upper);
1279
- if (listMatch) {
1280
- imports.local.add("duckDbList");
1281
- const [, base] = listMatch;
1282
- return {
1283
- builder: `duckDbList(${columnName(column.name)}, ${JSON.stringify(base)})`
1284
- };
1285
- }
1286
1460
  if (upper.startsWith("STRUCT")) {
1287
1461
  imports.local.add("duckDbStruct");
1288
1462
  const inner = upper.replace(/^STRUCT\s*\(/i, "").replace(/\)$/, "");
@@ -1531,7 +1705,7 @@ async function main() {
1531
1705
  throw new Error("Missing required --url");
1532
1706
  }
1533
1707
  const instanceOptions = options.url.startsWith("md:") && process.env.MOTHERDUCK_TOKEN ? { motherduck_token: process.env.MOTHERDUCK_TOKEN } : undefined;
1534
- const instance = await DuckDBInstance.create(options.url, instanceOptions);
1708
+ const instance = await DuckDBInstance3.create(options.url, instanceOptions);
1535
1709
  const connection = await instance.connect();
1536
1710
  const db = drizzle(connection);
1537
1711
  try {
@@ -0,0 +1 @@
1
+ export { duckDbList, duckDbArray, duckDbMap, duckDbStruct, duckDbJson, duckDbBlob, duckDbInet, duckDbInterval, duckDbTimestamp, duckDbDate, duckDbTime, duckDbArrayContains, duckDbArrayContained, duckDbArrayOverlaps, } from './columns.ts';