@duckdbfan/drizzle-duckdb 0.0.7 → 1.3.2

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.
Files changed (55) hide show
  1. package/README.md +349 -62
  2. package/dist/bin/duckdb-introspect.d.ts +2 -0
  3. package/dist/client.d.ts +42 -0
  4. package/dist/columns.d.ts +100 -9
  5. package/dist/dialect.d.ts +27 -2
  6. package/dist/driver.d.ts +53 -37
  7. package/dist/duckdb-introspect.mjs +2890 -0
  8. package/dist/helpers.d.ts +1 -0
  9. package/dist/helpers.mjs +360 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.mjs +3015 -228
  12. package/dist/introspect.d.ts +74 -0
  13. package/dist/migrator.d.ts +3 -2
  14. package/dist/olap.d.ts +46 -0
  15. package/dist/operators.d.ts +8 -0
  16. package/dist/options.d.ts +7 -0
  17. package/dist/pool.d.ts +30 -0
  18. package/dist/select-builder.d.ts +31 -0
  19. package/dist/session.d.ts +33 -8
  20. package/dist/sql/ast-transformer.d.ts +33 -0
  21. package/dist/sql/result-mapper.d.ts +9 -0
  22. package/dist/sql/selection.d.ts +2 -0
  23. package/dist/sql/visitors/array-operators.d.ts +5 -0
  24. package/dist/sql/visitors/column-qualifier.d.ts +10 -0
  25. package/dist/sql/visitors/generate-series-alias.d.ts +13 -0
  26. package/dist/sql/visitors/union-with-hoister.d.ts +11 -0
  27. package/dist/utils.d.ts +2 -5
  28. package/dist/value-wrappers-core.d.ts +42 -0
  29. package/dist/value-wrappers.d.ts +8 -0
  30. package/package.json +53 -16
  31. package/src/bin/duckdb-introspect.ts +181 -0
  32. package/src/client.ts +528 -0
  33. package/src/columns.ts +420 -65
  34. package/src/dialect.ts +111 -15
  35. package/src/driver.ts +266 -180
  36. package/src/helpers.ts +18 -0
  37. package/src/index.ts +8 -1
  38. package/src/introspect.ts +935 -0
  39. package/src/migrator.ts +10 -5
  40. package/src/olap.ts +190 -0
  41. package/src/operators.ts +27 -0
  42. package/src/options.ts +25 -0
  43. package/src/pool.ts +274 -0
  44. package/src/select-builder.ts +110 -0
  45. package/src/session.ts +306 -66
  46. package/src/sql/ast-transformer.ts +170 -0
  47. package/src/sql/result-mapper.ts +303 -0
  48. package/src/sql/selection.ts +60 -0
  49. package/src/sql/visitors/array-operators.ts +214 -0
  50. package/src/sql/visitors/column-qualifier.ts +586 -0
  51. package/src/sql/visitors/generate-series-alias.ts +291 -0
  52. package/src/sql/visitors/union-with-hoister.ts +106 -0
  53. package/src/utils.ts +2 -222
  54. package/src/value-wrappers-core.ts +168 -0
  55. package/src/value-wrappers.ts +165 -0
package/src/driver.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { entityKind, is } from 'drizzle-orm/entity';
1
+ import { DuckDBInstance } from '@duckdb/node-api';
2
+ import { entityKind } from 'drizzle-orm/entity';
2
3
  import type { Logger } from 'drizzle-orm/logger';
3
4
  import { DefaultLogger } from 'drizzle-orm/logger';
4
5
  import { PgDatabase } from 'drizzle-orm/pg-core/db';
5
- import { PgDialect } from 'drizzle-orm/pg-core/dialect';
6
+ import type { SelectedFields } from 'drizzle-orm/pg-core/query-builders';
7
+ import type { PgSession } from 'drizzle-orm/pg-core';
6
8
  import {
7
9
  createTableRelationsHelpers,
8
10
  extractTablesRelationalConfig,
@@ -10,104 +12,115 @@ import {
10
12
  type RelationalSchemaConfig,
11
13
  type TablesRelationalConfig,
12
14
  } from 'drizzle-orm/relations';
13
- import {
14
- getTableColumns,
15
- type DrizzleConfig,
16
- type DrizzleTypeError,
17
- } from 'drizzle-orm/utils';
15
+ import { type DrizzleConfig } from 'drizzle-orm/utils';
16
+ import type { SQL } from 'drizzle-orm/sql/sql';
18
17
  import type {
19
- DuckDBClient,
18
+ DuckDBClientLike,
20
19
  DuckDBQueryResultHKT,
21
20
  DuckDBTransaction,
22
- } from './session';
21
+ } from './session.ts';
23
22
  import { DuckDBSession } from './session.ts';
24
23
  import { DuckDBDialect } from './dialect.ts';
25
-
24
+ import { DuckDBSelectBuilder } from './select-builder.ts';
25
+ import { aliasFields } from './sql/selection.ts';
26
+ import type {
27
+ ExecuteBatchesRawChunk,
28
+ ExecuteInBatchesOptions,
29
+ RowData,
30
+ } from './client.ts';
31
+ import { closeClientConnection, isPool } from './client.ts';
26
32
  import {
27
- PgSelectBase,
28
- PgSelectBuilder,
29
- type CreatePgSelectFromBuilderMode,
30
- type SelectedFields,
31
- type TableLikeHasEmptySelection,
32
- } from 'drizzle-orm/pg-core/query-builders';
33
+ createDuckDBConnectionPool,
34
+ resolvePoolSize,
35
+ type DuckDBPoolConfig,
36
+ type PoolPreset,
37
+ } from './pool.ts';
33
38
  import {
34
- PgColumn,
35
- PgTable,
36
- type PgSession,
37
- type PgTransactionConfig,
38
- } from 'drizzle-orm/pg-core';
39
- import { sql, SQL, type ColumnsSelection } from 'drizzle-orm/sql/sql';
40
- import { Column } from 'drizzle-orm/column';
41
- import { Subquery, ViewBaseConfig, type SQLWrapper } from 'drizzle-orm';
42
- import { PgViewBase } from 'drizzle-orm/pg-core/view-base';
43
- import type {
44
- GetSelectTableName,
45
- GetSelectTableSelection,
46
- } from 'drizzle-orm/query-builders/select.types';
47
- import { aliasFields } from './utils.ts';
39
+ resolvePrepareCacheOption,
40
+ type PreparedStatementCacheConfig,
41
+ type PrepareCacheOption,
42
+ } from './options.ts';
48
43
 
49
44
  export interface PgDriverOptions {
50
45
  logger?: Logger;
46
+ rejectStringArrayLiterals?: boolean;
47
+ prepareCache?: PreparedStatementCacheConfig;
51
48
  }
52
49
 
53
- const selectionRegex = /select\s+(.+)\s+from/i;
54
- const aliasRegex = /as\s+(.+)$/i;
55
-
56
50
  export class DuckDBDriver {
57
51
  static readonly [entityKind]: string = 'DuckDBDriver';
58
52
 
59
53
  constructor(
60
- private client: DuckDBClient,
54
+ private client: DuckDBClientLike,
61
55
  private dialect: DuckDBDialect,
62
56
  private options: PgDriverOptions = {}
63
- ) {
64
- // const clientProxy = new Proxy(client, {
65
- // get(target, prop, receiver) {
66
- // if (prop === 'all') {
67
- // return (query: string, params: Parameters<typeof target.all>) => {
68
- // // DuckDB names returned variables differently than Postgres
69
- // // so we need to remap them to match the Postgres names
70
- // const selection = selectionRegex.exec(query);
71
- // if (selection?.length !== 2) {
72
- // return target.all(query, params);
73
- // }
74
- // const fields = selection[1].split(',').map((field) => {});
75
- // return target.all(query, params);
76
- // };
77
- // }
78
- // return Reflect.get(target, prop, receiver);
79
- // },
80
- // });
81
- }
57
+ ) {}
82
58
 
83
59
  createSession(
84
60
  schema: RelationalSchemaConfig<TablesRelationalConfig> | undefined
85
61
  ): DuckDBSession<Record<string, unknown>, TablesRelationalConfig> {
86
62
  return new DuckDBSession(this.client, this.dialect, schema, {
87
63
  logger: this.options.logger,
64
+ rejectStringArrayLiterals: this.options.rejectStringArrayLiterals,
65
+ prepareCache: this.options.prepareCache,
88
66
  });
89
67
  }
90
68
  }
91
69
 
92
- // Need to work around omitted internal types from drizzle...
93
- // interface DuckDBDatabaseInternal<
94
- // TSchema extends Record<string, unknown> = Record<string, never>
95
- // > extends PgDatabase<DuckDBQueryResultHKT, TSchema> {
96
- // dialect: PgDialect;
97
- // session: DuckDBSession<Record<string, unknown>, TablesRelationalConfig>;
98
- // }
70
+ /** Connection configuration when using path-based connection */
71
+ export interface DuckDBConnectionConfig {
72
+ /** Database path: ':memory:', './file.duckdb', 'md:', 'md:database' */
73
+ path: string;
74
+ /** DuckDB instance options (e.g., motherduck_token) */
75
+ options?: Record<string, string>;
76
+ }
99
77
 
100
- // export type DuckDBDatabase<
101
- // TSchema extends Record<string, unknown> = Record<string, never>
102
- // > = DuckDBDatabaseInternal<TSchema>;
78
+ export interface DuckDBDrizzleConfig<
79
+ TSchema extends Record<string, unknown> = Record<string, never>,
80
+ > extends DrizzleConfig<TSchema> {
81
+ rejectStringArrayLiterals?: boolean;
82
+ prepareCache?: PrepareCacheOption;
83
+ /** Pool configuration. Use preset name, size config, or false to disable. */
84
+ pool?: DuckDBPoolConfig | PoolPreset | false;
85
+ }
103
86
 
104
- export function drizzle<
105
- TSchema extends Record<string, unknown> = Record<string, never>
87
+ export interface DuckDBDrizzleConfigWithConnection<
88
+ TSchema extends Record<string, unknown> = Record<string, never>,
89
+ > extends DuckDBDrizzleConfig<TSchema> {
90
+ /** Connection string or config object */
91
+ connection: string | DuckDBConnectionConfig;
92
+ }
93
+
94
+ export interface DuckDBDrizzleConfigWithClient<
95
+ TSchema extends Record<string, unknown> = Record<string, never>,
96
+ > extends DuckDBDrizzleConfig<TSchema> {
97
+ /** Explicit client (connection or pool) */
98
+ client: DuckDBClientLike;
99
+ }
100
+
101
+ /** Check if a value looks like a config object (not a client) */
102
+ function isConfigObject(data: unknown): data is Record<string, unknown> {
103
+ if (typeof data !== 'object' || data === null) return false;
104
+ if (data.constructor?.name !== 'Object') return false;
105
+ return (
106
+ 'connection' in data ||
107
+ 'client' in data ||
108
+ 'pool' in data ||
109
+ 'schema' in data ||
110
+ 'logger' in data
111
+ );
112
+ }
113
+
114
+ /** Internal: create database from a client (connection or pool) */
115
+ function createFromClient<
116
+ TSchema extends Record<string, unknown> = Record<string, never>,
106
117
  >(
107
- client: DuckDBClient,
108
- config: DrizzleConfig<TSchema> = {}
118
+ client: DuckDBClientLike,
119
+ config: DuckDBDrizzleConfig<TSchema> = {},
120
+ instance?: DuckDBInstance
109
121
  ): DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>> {
110
122
  const dialect = new DuckDBDialect();
123
+ const prepareCache = resolvePrepareCacheOption(config.prepareCache);
111
124
 
112
125
  const logger =
113
126
  config.logger === true ? new DefaultLogger() : config.logger || undefined;
@@ -126,148 +139,221 @@ export function drizzle<
126
139
  };
127
140
  }
128
141
 
129
- const driver = new DuckDBDriver(client, dialect, { logger });
142
+ const driver = new DuckDBDriver(client, dialect, {
143
+ logger,
144
+ rejectStringArrayLiterals: config.rejectStringArrayLiterals,
145
+ prepareCache,
146
+ });
130
147
  const session = driver.createSession(schema);
131
148
 
132
- return new DuckDBDatabase(dialect, session, schema) as DuckDBDatabase<
133
- TSchema,
134
- ExtractTablesWithRelations<TSchema>
135
- >;
149
+ const db = new DuckDBDatabase(dialect, session, schema, client, instance);
150
+ return db as DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>;
151
+ }
152
+
153
+ /** Internal: create database from a connection string */
154
+ async function createFromConnectionString<
155
+ TSchema extends Record<string, unknown> = Record<string, never>,
156
+ >(
157
+ path: string,
158
+ instanceOptions: Record<string, string> | undefined,
159
+ config: DuckDBDrizzleConfig<TSchema> = {}
160
+ ): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>> {
161
+ const instance = await DuckDBInstance.create(path, instanceOptions);
162
+ const poolSize = resolvePoolSize(config.pool);
163
+
164
+ if (poolSize === false) {
165
+ const connection = await instance.connect();
166
+ return createFromClient(connection, config, instance);
167
+ }
168
+
169
+ const pool = createDuckDBConnectionPool(instance, { size: poolSize });
170
+ return createFromClient(pool, config, instance);
171
+ }
172
+
173
+ // Overload 1: Connection string (async, auto-pools)
174
+ export function drizzle<
175
+ TSchema extends Record<string, unknown> = Record<string, never>,
176
+ >(
177
+ connectionString: string
178
+ ): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
179
+
180
+ // Overload 2: Connection string + config (async, auto-pools)
181
+ export function drizzle<
182
+ TSchema extends Record<string, unknown> = Record<string, never>,
183
+ >(
184
+ connectionString: string,
185
+ config: DuckDBDrizzleConfig<TSchema>
186
+ ): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
187
+
188
+ // Overload 3: Config with connection (async, auto-pools)
189
+ export function drizzle<
190
+ TSchema extends Record<string, unknown> = Record<string, never>,
191
+ >(
192
+ config: DuckDBDrizzleConfigWithConnection<TSchema>
193
+ ): Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>>;
194
+
195
+ // Overload 4: Config with explicit client (sync)
196
+ export function drizzle<
197
+ TSchema extends Record<string, unknown> = Record<string, never>,
198
+ >(
199
+ config: DuckDBDrizzleConfigWithClient<TSchema>
200
+ ): DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>;
201
+
202
+ // Overload 5: Explicit client (sync, backward compatible)
203
+ export function drizzle<
204
+ TSchema extends Record<string, unknown> = Record<string, never>,
205
+ >(
206
+ client: DuckDBClientLike,
207
+ config?: DuckDBDrizzleConfig<TSchema>
208
+ ): DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>;
209
+
210
+ // Implementation
211
+ export function drizzle<
212
+ TSchema extends Record<string, unknown> = Record<string, never>,
213
+ >(
214
+ clientOrConfigOrPath:
215
+ | string
216
+ | DuckDBClientLike
217
+ | DuckDBDrizzleConfigWithConnection<TSchema>
218
+ | DuckDBDrizzleConfigWithClient<TSchema>,
219
+ config?: DuckDBDrizzleConfig<TSchema>
220
+ ):
221
+ | DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>
222
+ | Promise<DuckDBDatabase<TSchema, ExtractTablesWithRelations<TSchema>>> {
223
+ // String path -> async with auto-pool
224
+ if (typeof clientOrConfigOrPath === 'string') {
225
+ return createFromConnectionString(clientOrConfigOrPath, undefined, config);
226
+ }
227
+
228
+ // Config object with connection or client
229
+ if (isConfigObject(clientOrConfigOrPath)) {
230
+ const configObj = clientOrConfigOrPath as
231
+ | DuckDBDrizzleConfigWithConnection<TSchema>
232
+ | DuckDBDrizzleConfigWithClient<TSchema>;
233
+
234
+ if ('connection' in configObj) {
235
+ const connConfig =
236
+ configObj as DuckDBDrizzleConfigWithConnection<TSchema>;
237
+ const { connection, ...restConfig } = connConfig;
238
+ if (typeof connection === 'string') {
239
+ return createFromConnectionString(
240
+ connection,
241
+ undefined,
242
+ restConfig as DuckDBDrizzleConfig<TSchema>
243
+ );
244
+ }
245
+ return createFromConnectionString(
246
+ connection.path,
247
+ connection.options,
248
+ restConfig as DuckDBDrizzleConfig<TSchema>
249
+ );
250
+ }
251
+
252
+ if ('client' in configObj) {
253
+ const clientConfig = configObj as DuckDBDrizzleConfigWithClient<TSchema>;
254
+ const { client: clientValue, ...restConfig } = clientConfig;
255
+ return createFromClient(
256
+ clientValue,
257
+ restConfig as DuckDBDrizzleConfig<TSchema>
258
+ );
259
+ }
260
+
261
+ throw new Error(
262
+ 'Invalid drizzle config: either connection or client must be provided'
263
+ );
264
+ }
265
+
266
+ // Direct client (backward compatible)
267
+ return createFromClient(clientOrConfigOrPath as DuckDBClientLike, config);
136
268
  }
137
269
 
138
270
  export class DuckDBDatabase<
139
271
  TFullSchema extends Record<string, unknown> = Record<string, never>,
140
- TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>
272
+ TSchema extends TablesRelationalConfig =
273
+ ExtractTablesWithRelations<TFullSchema>,
141
274
  > extends PgDatabase<DuckDBQueryResultHKT, TFullSchema, TSchema> {
142
275
  static readonly [entityKind]: string = 'DuckDBDatabase';
143
276
 
277
+ /** The underlying connection or pool */
278
+ readonly $client: DuckDBClientLike;
279
+
280
+ /** The DuckDB instance (when created from connection string) */
281
+ readonly $instance?: DuckDBInstance;
282
+
144
283
  constructor(
145
284
  readonly dialect: DuckDBDialect,
146
285
  readonly session: DuckDBSession<TFullSchema, TSchema>,
147
- schema: RelationalSchemaConfig<TSchema> | undefined
286
+ schema: RelationalSchemaConfig<TSchema> | undefined,
287
+ client: DuckDBClientLike,
288
+ instance?: DuckDBInstance
148
289
  ) {
149
290
  super(dialect, session, schema);
291
+ this.$client = client;
292
+ this.$instance = instance;
150
293
  }
151
294
 
152
- select(): PgSelectBuilder<undefined>;
153
- select<TSelection extends SelectedFields>(
154
- fields: TSelection
155
- ): PgSelectBuilder<TSelection>;
156
- select(fields?: SelectedFields): PgSelectBuilder<SelectedFields | undefined> {
157
- if (!fields) {
158
- // iterate over all fields and do the same as below (may have to extend/override `.from()`)
159
-
160
- return new DuckDBSelectBuilder({
161
- fields: fields ?? undefined,
162
- session: this.session as unknown as PgSession<DuckDBQueryResultHKT>,
163
- dialect: this.dialect,
164
- });
295
+ /**
296
+ * Close the database connection pool and instance.
297
+ * Should be called when shutting down the application.
298
+ */
299
+ async close(): Promise<void> {
300
+ if (isPool(this.$client) && this.$client.close) {
301
+ await this.$client.close();
302
+ }
303
+ if (!isPool(this.$client)) {
304
+ await closeClientConnection(this.$client);
305
+ }
306
+ if (this.$instance) {
307
+ const maybeClosable = this.$instance as unknown as {
308
+ close?: () => Promise<void> | void;
309
+ closeSync?: () => void;
310
+ };
311
+ if (typeof maybeClosable.close === 'function') {
312
+ await maybeClosable.close();
313
+ } else if (typeof maybeClosable.closeSync === 'function') {
314
+ maybeClosable.closeSync();
315
+ }
165
316
  }
317
+ }
166
318
 
167
- const aliasedFields: SelectedFields = aliasFields(fields);
319
+ select(): DuckDBSelectBuilder<undefined>;
320
+ select<TSelection extends SelectedFields>(
321
+ fields: TSelection
322
+ ): DuckDBSelectBuilder<TSelection>;
323
+ select(
324
+ fields?: SelectedFields
325
+ ): DuckDBSelectBuilder<SelectedFields | undefined> {
326
+ const selectedFields = fields ? aliasFields(fields) : undefined;
168
327
 
328
+ // Cast needed: DuckDBSession is compatible but types don't align exactly with PgSession
169
329
  return new DuckDBSelectBuilder({
170
- fields: aliasedFields,
330
+ fields: selectedFields ?? undefined,
171
331
  session: this.session as unknown as PgSession<DuckDBQueryResultHKT>,
172
332
  dialect: this.dialect,
173
333
  });
174
334
  }
175
335
 
176
- override async transaction<T>(
177
- transaction: (tx: DuckDBTransaction<TFullSchema, TSchema>) => Promise<T>
178
- ): Promise<T> {
179
- return await this.session.transaction<T>(transaction);
336
+ executeBatches<T extends RowData = RowData>(
337
+ query: SQL,
338
+ options: ExecuteInBatchesOptions = {}
339
+ ): AsyncGenerator<T[], void, void> {
340
+ return this.session.executeBatches<T>(query, options);
180
341
  }
181
- }
182
-
183
- interface PgViewBaseInternal<
184
- TName extends string = string,
185
- TExisting extends boolean = boolean,
186
- TSelectedFields extends ColumnsSelection = ColumnsSelection
187
- > extends PgViewBase<TName, TExisting, TSelectedFields> {
188
- [ViewBaseConfig]?: {
189
- selectedFields: SelectedFields;
190
- };
191
- }
192
342
 
193
- export class DuckDBSelectBuilder<
194
- TSelection extends SelectedFields | undefined,
195
- TBuilderMode extends 'db' | 'qb' = 'db'
196
- > extends PgSelectBuilder<TSelection, TBuilderMode> {
197
- private _fields: TSelection;
198
- private _session: PgSession | undefined;
199
- private _dialect: DuckDBDialect;
200
- private _withList: Subquery[] = [];
201
- private _distinct:
202
- | boolean
203
- | {
204
- on: (PgColumn | SQLWrapper)[];
205
- }
206
- | undefined;
207
-
208
- constructor(config: {
209
- fields: TSelection;
210
- session: PgSession | undefined;
211
- dialect: PgDialect;
212
- withList?: Subquery[];
213
- distinct?:
214
- | boolean
215
- | {
216
- on: (PgColumn | SQLWrapper)[];
217
- };
218
- }) {
219
- super(config);
220
- this._fields = config.fields;
221
- this._session = config.session;
222
- this._dialect = config.dialect;
223
- if (config.withList) {
224
- this._withList = config.withList;
225
- }
226
- this._distinct = config.distinct;
343
+ executeBatchesRaw(
344
+ query: SQL,
345
+ options: ExecuteInBatchesOptions = {}
346
+ ): AsyncGenerator<ExecuteBatchesRawChunk, void, void> {
347
+ return this.session.executeBatchesRaw(query, options);
227
348
  }
228
349
 
229
- from<TFrom extends PgTable | Subquery | PgViewBaseInternal | SQL>(
230
- source: TableLikeHasEmptySelection<TFrom> extends true
231
- ? DrizzleTypeError<"Cannot reference a data-modifying statement subquery if it doesn't contain a `returning` clause">
232
- : TFrom
233
- ): CreatePgSelectFromBuilderMode<
234
- TBuilderMode,
235
- GetSelectTableName<TFrom>,
236
- TSelection extends undefined ? GetSelectTableSelection<TFrom> : TSelection,
237
- TSelection extends undefined ? 'single' : 'partial'
238
- > {
239
- const isPartialSelect = !!this._fields;
240
- const src = source as TFrom;
241
-
242
- let fields: SelectedFields;
243
- if (this._fields) {
244
- fields = this._fields;
245
- } else if (is(src, Subquery)) {
246
- // This is required to use the proxy handler to get the correct field values from the subquery
247
- fields = Object.fromEntries(
248
- Object.keys(src._.selectedFields).map((key) => [
249
- key,
250
- src[
251
- key as unknown as keyof typeof src
252
- ] as unknown as SelectedFields[string],
253
- ])
254
- );
255
- } else if (is(src, PgViewBase)) {
256
- fields = src[ViewBaseConfig]?.selectedFields as SelectedFields;
257
- } else if (is(src, SQL)) {
258
- fields = {};
259
- } else {
260
- fields = aliasFields(getTableColumns<PgTable>(src), !isPartialSelect);
261
- }
350
+ executeArrow(query: SQL): Promise<unknown> {
351
+ return this.session.executeArrow(query);
352
+ }
262
353
 
263
- return new PgSelectBase({
264
- table: src,
265
- fields,
266
- isPartialSelect,
267
- session: this._session,
268
- dialect: this._dialect,
269
- withList: this._withList,
270
- distinct: this._distinct,
271
- }) as any;
354
+ override async transaction<T>(
355
+ transaction: (tx: DuckDBTransaction<TFullSchema, TSchema>) => Promise<T>
356
+ ): Promise<T> {
357
+ return await this.session.transaction<T>(transaction);
272
358
  }
273
359
  }
package/src/helpers.ts ADDED
@@ -0,0 +1,18 @@
1
+ // Client-safe entrypoint exposing schema builder utilities without pulling
2
+ // the DuckDB Node API bindings. Intended for generated schemas and browser use.
3
+ export {
4
+ duckDbList,
5
+ duckDbArray,
6
+ duckDbMap,
7
+ duckDbStruct,
8
+ duckDbJson,
9
+ duckDbBlob,
10
+ duckDbInet,
11
+ duckDbInterval,
12
+ duckDbTimestamp,
13
+ duckDbDate,
14
+ duckDbTime,
15
+ duckDbArrayContains,
16
+ duckDbArrayContained,
17
+ duckDbArrayOverlaps,
18
+ } from './columns.ts';
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  export * from './driver.ts';
2
2
  export * from './session.ts';
3
3
  export * from './columns.ts';
4
- export * from './migrator.ts';
4
+ export * from './migrator.ts';
5
+ export * from './introspect.ts';
6
+ export * from './client.ts';
7
+ export * from './pool.ts';
8
+ export * from './olap.ts';
9
+ export * from './value-wrappers.ts';
10
+ export * from './options.ts';
11
+ export * from './operators.ts';