@leonardovida-md/drizzle-neo-duckdb 1.1.1 → 1.1.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.
package/src/session.ts CHANGED
@@ -26,13 +26,20 @@ import type {
26
26
  } from './client.ts';
27
27
  import {
28
28
  executeArrowOnClient,
29
+ executeArraysOnClient,
29
30
  executeInBatches,
31
+ executeInBatchesRaw,
30
32
  executeOnClient,
31
33
  prepareParams,
34
+ type ExecuteBatchesRawChunk,
32
35
  type ExecuteInBatchesOptions,
33
36
  } from './client.ts';
34
37
  import { isPool } from './client.ts';
35
38
  import type { DuckDBConnection } from '@duckdb/node-api';
39
+ import type {
40
+ PreparedStatementCacheConfig,
41
+ RewriteArraysMode,
42
+ } from './options.ts';
36
43
 
37
44
  export type { DuckDBClientLike, RowData } from './client.ts';
38
45
 
@@ -46,6 +53,18 @@ function isSavepointSyntaxError(error: unknown): boolean {
46
53
  );
47
54
  }
48
55
 
56
+ function rewriteQuery(
57
+ mode: RewriteArraysMode,
58
+ query: string
59
+ ): { sql: string; rewritten: boolean } {
60
+ if (mode === 'never') {
61
+ return { sql: query, rewritten: false };
62
+ }
63
+
64
+ const rewritten = adaptArrayOperators(query);
65
+ return { sql: rewritten, rewritten: rewritten !== query };
66
+ }
67
+
49
68
  export class DuckDBPreparedQuery<
50
69
  T extends PreparedQueryConfig,
51
70
  > extends PgPreparedQuery<T> {
@@ -62,8 +81,9 @@ export class DuckDBPreparedQuery<
62
81
  private customResultMapper:
63
82
  | ((rows: unknown[][]) => T['execute'])
64
83
  | undefined,
65
- private rewriteArrays: boolean,
84
+ private rewriteArraysMode: RewriteArraysMode,
66
85
  private rejectStringArrayLiterals: boolean,
86
+ private prepareCache: PreparedStatementCacheConfig | undefined,
67
87
  private warnOnStringArrayLiteral?: (sql: string) => void
68
88
  ) {
69
89
  super({ sql: queryString, params });
@@ -82,11 +102,12 @@ export class DuckDBPreparedQuery<
82
102
  : undefined,
83
103
  }
84
104
  );
85
- const rewrittenQuery = this.rewriteArrays
86
- ? adaptArrayOperators(this.queryString)
87
- : this.queryString;
105
+ const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
106
+ this.rewriteArraysMode,
107
+ this.queryString
108
+ );
88
109
 
89
- if (this.rewriteArrays && rewrittenQuery !== this.queryString) {
110
+ if (didRewrite) {
90
111
  this.logger.logQuery(
91
112
  `[duckdb] original query before array rewrite: ${this.queryString}`,
92
113
  params
@@ -98,19 +119,30 @@ export class DuckDBPreparedQuery<
98
119
  const { fields, joinsNotNullableMap, customResultMapper } =
99
120
  this as typeof this & { joinsNotNullableMap?: Record<string, boolean> };
100
121
 
101
- const rows = await executeOnClient(this.client, rewrittenQuery, params);
122
+ if (fields) {
123
+ const { rows } = await executeArraysOnClient(
124
+ this.client,
125
+ rewrittenQuery,
126
+ params,
127
+ { prepareCache: this.prepareCache }
128
+ );
129
+
130
+ if (rows.length === 0) {
131
+ return [] as T['execute'];
132
+ }
102
133
 
103
- if (rows.length === 0 || !fields) {
104
- return rows as T['execute'];
134
+ return customResultMapper
135
+ ? customResultMapper(rows)
136
+ : rows.map((row) =>
137
+ mapResultRow<T['execute']>(fields, row, joinsNotNullableMap)
138
+ );
105
139
  }
106
140
 
107
- const rowValues = rows.map((row) => Object.values(row));
141
+ const rows = await executeOnClient(this.client, rewrittenQuery, params, {
142
+ prepareCache: this.prepareCache,
143
+ });
108
144
 
109
- return customResultMapper
110
- ? customResultMapper(rowValues)
111
- : rowValues.map((row) =>
112
- mapResultRow<T['execute']>(fields, row, joinsNotNullableMap)
113
- );
145
+ return rows as T['execute'];
114
146
  }
115
147
 
116
148
  all(
@@ -126,8 +158,9 @@ export class DuckDBPreparedQuery<
126
158
 
127
159
  export interface DuckDBSessionOptions {
128
160
  logger?: Logger;
129
- rewriteArrays?: boolean;
161
+ rewriteArrays?: RewriteArraysMode;
130
162
  rejectStringArrayLiterals?: boolean;
163
+ prepareCache?: PreparedStatementCacheConfig;
131
164
  }
132
165
 
133
166
  export class DuckDBSession<
@@ -138,8 +171,9 @@ export class DuckDBSession<
138
171
 
139
172
  protected override dialect: DuckDBDialect;
140
173
  private logger: Logger;
141
- private rewriteArrays: boolean;
174
+ private rewriteArraysMode: RewriteArraysMode;
142
175
  private rejectStringArrayLiterals: boolean;
176
+ private prepareCache: PreparedStatementCacheConfig | undefined;
143
177
  private hasWarnedArrayLiteral = false;
144
178
  private rollbackOnly = false;
145
179
 
@@ -152,8 +186,14 @@ export class DuckDBSession<
152
186
  super(dialect);
153
187
  this.dialect = dialect;
154
188
  this.logger = options.logger ?? new NoopLogger();
155
- this.rewriteArrays = options.rewriteArrays ?? true;
189
+ this.rewriteArraysMode = options.rewriteArrays ?? 'auto';
156
190
  this.rejectStringArrayLiterals = options.rejectStringArrayLiterals ?? false;
191
+ this.prepareCache = options.prepareCache;
192
+ this.options = {
193
+ ...options,
194
+ rewriteArrays: this.rewriteArraysMode,
195
+ prepareCache: this.prepareCache,
196
+ };
157
197
  }
158
198
 
159
199
  prepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(
@@ -173,8 +213,9 @@ export class DuckDBSession<
173
213
  fields,
174
214
  isResponseInArrayMode,
175
215
  customResultMapper,
176
- this.rewriteArrays,
216
+ this.rewriteArraysMode,
177
217
  this.rejectStringArrayLiterals,
218
+ this.prepareCache,
178
219
  this.rejectStringArrayLiterals ? undefined : this.warnOnStringArrayLiteral
179
220
  );
180
221
  }
@@ -266,11 +307,12 @@ export class DuckDBSession<
266
307
  ? undefined
267
308
  : () => this.warnOnStringArrayLiteral(builtQuery.sql),
268
309
  });
269
- const rewrittenQuery = this.rewriteArrays
270
- ? adaptArrayOperators(builtQuery.sql)
271
- : builtQuery.sql;
310
+ const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
311
+ this.rewriteArraysMode,
312
+ builtQuery.sql
313
+ );
272
314
 
273
- if (this.rewriteArrays && rewrittenQuery !== builtQuery.sql) {
315
+ if (didRewrite) {
274
316
  this.logger.logQuery(
275
317
  `[duckdb] original query before array rewrite: ${builtQuery.sql}`,
276
318
  params
@@ -287,6 +329,36 @@ export class DuckDBSession<
287
329
  ) as AsyncGenerator<GenericRowData<T>[], void, void>;
288
330
  }
289
331
 
332
+ executeBatchesRaw(
333
+ query: SQL,
334
+ options: ExecuteInBatchesOptions = {}
335
+ ): AsyncGenerator<ExecuteBatchesRawChunk, void, void> {
336
+ this.dialect.resetPgJsonFlag();
337
+ const builtQuery = this.dialect.sqlToQuery(query);
338
+ this.dialect.assertNoPgJsonColumns();
339
+ const params = prepareParams(builtQuery.params, {
340
+ rejectStringArrayLiterals: this.rejectStringArrayLiterals,
341
+ warnOnStringArrayLiteral: this.rejectStringArrayLiterals
342
+ ? undefined
343
+ : () => this.warnOnStringArrayLiteral(builtQuery.sql),
344
+ });
345
+ const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
346
+ this.rewriteArraysMode,
347
+ builtQuery.sql
348
+ );
349
+
350
+ if (didRewrite) {
351
+ this.logger.logQuery(
352
+ `[duckdb] original query before array rewrite: ${builtQuery.sql}`,
353
+ params
354
+ );
355
+ }
356
+
357
+ this.logger.logQuery(rewrittenQuery, params);
358
+
359
+ return executeInBatchesRaw(this.client, rewrittenQuery, params, options);
360
+ }
361
+
290
362
  async executeArrow(query: SQL): Promise<unknown> {
291
363
  this.dialect.resetPgJsonFlag();
292
364
  const builtQuery = this.dialect.sqlToQuery(query);
@@ -297,11 +369,12 @@ export class DuckDBSession<
297
369
  ? undefined
298
370
  : () => this.warnOnStringArrayLiteral(builtQuery.sql),
299
371
  });
300
- const rewrittenQuery = this.rewriteArrays
301
- ? adaptArrayOperators(builtQuery.sql)
302
- : builtQuery.sql;
372
+ const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
373
+ this.rewriteArraysMode,
374
+ builtQuery.sql
375
+ );
303
376
 
304
- if (this.rewriteArrays && rewrittenQuery !== builtQuery.sql) {
377
+ if (didRewrite) {
305
378
  this.logger.logQuery(
306
379
  `[duckdb] original query before array rewrite: ${builtQuery.sql}`,
307
380
  params
@@ -377,6 +450,15 @@ export class DuckDBTransaction<
377
450
  return (this as unknown as Tx).session.executeBatches<T>(query, options);
378
451
  }
379
452
 
453
+ executeBatchesRaw(
454
+ query: SQL,
455
+ options: ExecuteInBatchesOptions = {}
456
+ ): AsyncGenerator<ExecuteBatchesRawChunk, void, void> {
457
+ // Cast needed: PgTransaction doesn't expose session property in public API
458
+ type Tx = DuckDBTransactionWithInternals<TFullSchema, TSchema>;
459
+ return (this as unknown as Tx).session.executeBatchesRaw(query, options);
460
+ }
461
+
380
462
  executeArrow(query: SQL): Promise<unknown> {
381
463
  // Cast needed: PgTransaction doesn't expose session property in public API
382
464
  type Tx = DuckDBTransactionWithInternals<TFullSchema, TSchema>;
@@ -171,6 +171,14 @@ function walkRight(
171
171
  }
172
172
 
173
173
  export function adaptArrayOperators(query: string): string {
174
+ if (
175
+ query.indexOf('@>') === -1 &&
176
+ query.indexOf('<@') === -1 &&
177
+ query.indexOf('&&') === -1
178
+ ) {
179
+ return query;
180
+ }
181
+
174
182
  let rewritten = query;
175
183
  let scrubbed = scrubForRewrite(query);
176
184
  let searchStart = 0;