@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/README.md +44 -85
- package/dist/client.d.ts +15 -1
- package/dist/columns.d.ts +3 -2
- package/dist/driver.d.ts +7 -3
- package/dist/duckdb-introspect.mjs +262 -50
- package/dist/helpers.mjs +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +288 -50
- package/dist/options.d.ts +10 -0
- package/dist/session.d.ts +11 -5
- package/package.json +1 -1
- package/src/client.ts +300 -40
- package/src/columns.ts +51 -4
- package/src/driver.ts +30 -5
- package/src/index.ts +1 -0
- package/src/options.ts +40 -0
- package/src/session.ts +108 -26
- package/src/sql/query-rewriters.ts +8 -0
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
|
|
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 =
|
|
86
|
-
|
|
87
|
-
|
|
105
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
|
|
106
|
+
this.rewriteArraysMode,
|
|
107
|
+
this.queryString
|
|
108
|
+
);
|
|
88
109
|
|
|
89
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
134
|
+
return customResultMapper
|
|
135
|
+
? customResultMapper(rows)
|
|
136
|
+
: rows.map((row) =>
|
|
137
|
+
mapResultRow<T['execute']>(fields, row, joinsNotNullableMap)
|
|
138
|
+
);
|
|
105
139
|
}
|
|
106
140
|
|
|
107
|
-
const
|
|
141
|
+
const rows = await executeOnClient(this.client, rewrittenQuery, params, {
|
|
142
|
+
prepareCache: this.prepareCache,
|
|
143
|
+
});
|
|
108
144
|
|
|
109
|
-
return
|
|
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?:
|
|
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
|
|
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.
|
|
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.
|
|
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 =
|
|
270
|
-
|
|
271
|
-
|
|
310
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
|
|
311
|
+
this.rewriteArraysMode,
|
|
312
|
+
builtQuery.sql
|
|
313
|
+
);
|
|
272
314
|
|
|
273
|
-
if (
|
|
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 =
|
|
301
|
-
|
|
302
|
-
|
|
372
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(
|
|
373
|
+
this.rewriteArraysMode,
|
|
374
|
+
builtQuery.sql
|
|
375
|
+
);
|
|
303
376
|
|
|
304
|
-
if (
|
|
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;
|