drizzle-databend 0.1.9 → 0.1.11

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,200 +1,45 @@
1
- // src/driver.ts
2
- import { Client } from "databend-driver";
3
- import { entityKind as entityKind3 } from "drizzle-orm/entity";
4
- import { DefaultLogger } from "drizzle-orm/logger";
5
- import { PgDatabase } from "drizzle-orm/pg-core/db";
6
- import {
7
- createTableRelationsHelpers,
8
- extractTablesRelationalConfig
9
- } from "drizzle-orm/relations";
10
-
11
- // src/session.ts
12
- import { entityKind } from "drizzle-orm/entity";
13
- import { NoopLogger } from "drizzle-orm/logger";
14
- import { PgTransaction } from "drizzle-orm/pg-core";
15
- import { PgPreparedQuery, PgSession } from "drizzle-orm/pg-core/session";
16
- import { fillPlaceholders, sql } from "drizzle-orm/sql/sql";
17
-
18
- // src/sql/result-mapper.ts
19
- import {
20
- Column,
21
- SQL,
22
- getTableName,
23
- is
24
- } from "drizzle-orm";
25
- import {
26
- PgCustomColumn,
27
- PgDate,
28
- PgDateString,
29
- PgTime,
30
- PgTimestamp,
31
- PgTimestampString
32
- } from "drizzle-orm/pg-core";
33
- function toDecoderInput(decoder, value) {
34
- return value;
35
- }
36
- function normalizeTimestampString(value, withTimezone) {
37
- if (value instanceof Date) {
38
- const iso = value.toISOString().replace("T", " ");
39
- return withTimezone ? iso.replace("Z", "+00") : iso.replace("Z", "");
40
- }
41
- if (typeof value === "string") {
42
- const normalized = value.replace("T", " ");
43
- if (withTimezone) {
44
- return normalized.includes("+") ? normalized : `${normalized}+00`;
45
- }
46
- return normalized.replace(/\+00$/, "");
47
- }
48
- return value;
49
- }
50
- function normalizeTimestamp(value, withTimezone) {
51
- if (value instanceof Date) {
52
- return value;
53
- }
54
- if (typeof value === "string") {
55
- const hasOffset = value.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(value.trim());
56
- const spaced = value.replace(" ", "T");
57
- const normalized = withTimezone || hasOffset ? spaced : `${spaced}+00`;
58
- return new Date(normalized);
59
- }
60
- return value;
61
- }
62
- function normalizeDateString(value) {
63
- if (value instanceof Date) {
64
- return value.toISOString().slice(0, 10);
65
- }
66
- if (typeof value === "string") {
67
- return value.slice(0, 10);
68
- }
69
- return value;
70
- }
71
- function normalizeDateValue(value) {
72
- if (value instanceof Date) {
73
- return value;
74
- }
75
- if (typeof value === "string") {
76
- return new Date(`${value.slice(0, 10)}T00:00:00Z`);
77
- }
78
- return value;
79
- }
80
- function normalizeTime(value) {
81
- if (typeof value === "bigint") {
82
- const totalMillis = Number(value) / 1000;
83
- const date = new Date(totalMillis);
84
- return date.toISOString().split("T")[1].replace("Z", "");
85
- }
86
- if (value instanceof Date) {
87
- return value.toISOString().split("T")[1].replace("Z", "");
88
- }
89
- return value;
90
- }
91
- function mapDriverValue(decoder, rawValue) {
92
- if (is(decoder, PgTimestampString)) {
93
- return decoder.mapFromDriverValue(toDecoderInput(decoder, normalizeTimestampString(rawValue, decoder.withTimezone)));
94
- }
95
- if (is(decoder, PgTimestamp)) {
96
- const normalized = normalizeTimestamp(rawValue, decoder.withTimezone);
97
- if (normalized instanceof Date) {
98
- return normalized;
99
- }
100
- return decoder.mapFromDriverValue(toDecoderInput(decoder, normalized));
101
- }
102
- if (is(decoder, PgDateString)) {
103
- return decoder.mapFromDriverValue(toDecoderInput(decoder, normalizeDateString(rawValue)));
104
- }
105
- if (is(decoder, PgDate)) {
106
- return decoder.mapFromDriverValue(toDecoderInput(decoder, normalizeDateValue(rawValue)));
107
- }
108
- if (is(decoder, PgTime)) {
109
- return decoder.mapFromDriverValue(toDecoderInput(decoder, normalizeTime(rawValue)));
110
- }
111
- return decoder.mapFromDriverValue(toDecoderInput(decoder, rawValue));
112
- }
113
- function mapResultRow(columns, row, joinsNotNullableMap) {
114
- const nullifyMap = {};
115
- const result = columns.reduce((acc, { path, field }, columnIndex) => {
116
- let decoder;
117
- if (is(field, Column)) {
118
- decoder = field;
119
- } else if (is(field, SQL)) {
120
- decoder = field.decoder;
121
- } else {
122
- const col = field.sql.queryChunks.find((chunk) => is(chunk, Column));
123
- if (is(col, PgCustomColumn)) {
124
- decoder = col;
125
- } else {
126
- decoder = field.sql.decoder;
127
- }
128
- }
129
- let node = acc;
130
- for (const [pathChunkIndex, pathChunk] of path.entries()) {
131
- if (pathChunkIndex < path.length - 1) {
132
- if (!(pathChunk in node)) {
133
- node[pathChunk] = {};
134
- }
135
- node = node[pathChunk];
136
- continue;
137
- }
138
- const rawValue = row[columnIndex];
139
- const value = node[pathChunk] = rawValue === null ? null : mapDriverValue(decoder, rawValue);
140
- if (joinsNotNullableMap && is(field, Column) && path.length === 2) {
141
- const objectName = path[0];
142
- if (!(objectName in nullifyMap)) {
143
- nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
144
- } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
145
- nullifyMap[objectName] = false;
146
- }
147
- continue;
148
- }
149
- if (joinsNotNullableMap && is(field, SQL.Aliased) && path.length === 2) {
150
- const col = field.sql.queryChunks.find((chunk) => is(chunk, Column));
151
- const tableName = col?.table && getTableName(col?.table);
152
- if (!tableName) {
153
- continue;
154
- }
155
- const objectName = path[0];
156
- if (!(objectName in nullifyMap)) {
157
- nullifyMap[objectName] = value === null ? tableName : false;
158
- continue;
159
- }
160
- if (nullifyMap[objectName] && nullifyMap[objectName] !== tableName) {
161
- nullifyMap[objectName] = false;
162
- }
163
- continue;
164
- }
165
- }
166
- return acc;
167
- }, {});
168
- if (joinsNotNullableMap && Object.keys(nullifyMap).length > 0) {
169
- for (const [objectName, tableName] of Object.entries(nullifyMap)) {
170
- if (typeof tableName === "string" && !joinsNotNullableMap[tableName]) {
171
- result[objectName] = null;
172
- }
173
- }
174
- }
175
- return result;
176
- }
177
-
178
- // src/session.ts
179
- import { TransactionRollbackError } from "drizzle-orm/errors";
180
-
181
1
  // src/client.ts
182
2
  function isPool(client) {
183
3
  return typeof client.acquire === "function";
184
4
  }
185
- function prepareParams(params) {
186
- return params.map((param) => {
187
- if (param === undefined)
188
- return null;
189
- if (param instanceof Date)
190
- return param.toISOString();
191
- if (typeof param === "bigint")
192
- return param.toString();
5
+ function prepareParams(params, typings) {
6
+ return params.map((param, i) => {
7
+ if (param === void 0) return null;
8
+ if (param instanceof Date) return param.toISOString().replace(/'/g, "''");
9
+ if (typeof param === "bigint") return param.toString();
10
+ if (typeof param === "string") {
11
+ const typing = typings?.[i];
12
+ if (typing === "decimal" && /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(param)) {
13
+ return Number(param);
14
+ }
15
+ return param.replace(/'/g, "''");
16
+ }
17
+ if (typeof param === "object" && param !== null) {
18
+ return JSON.stringify(param).replace(/'/g, "''");
19
+ }
193
20
  return param;
194
21
  });
195
22
  }
23
+ function isTransientError(error) {
24
+ if (!(error instanceof Error)) return false;
25
+ const msg = error.message?.toLowerCase() ?? "";
26
+ return msg.includes("connection closed") || msg.includes("econnreset") || msg.includes("epipe") || msg.includes("socket hang up") || msg.includes("connection refused");
27
+ }
28
+ async function withRetry(fn, maxRetries = 2) {
29
+ let lastError;
30
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
31
+ try {
32
+ return await fn();
33
+ } catch (error) {
34
+ lastError = error;
35
+ if (!isTransientError(error) || attempt === maxRetries) throw error;
36
+ await new Promise((r) => setTimeout(r, 100 * 2 ** attempt));
37
+ }
38
+ }
39
+ throw lastError;
40
+ }
196
41
  function deduplicateColumns(columns) {
197
- const counts = new Map;
42
+ const counts = /* @__PURE__ */ new Map();
198
43
  let hasDuplicates = false;
199
44
  for (const column of columns) {
200
45
  const next = (counts.get(column) ?? 0) + 1;
@@ -214,34 +59,38 @@ function deduplicateColumns(columns) {
214
59
  return count === 0 ? column : `${column}_${count}`;
215
60
  });
216
61
  }
217
- async function executeOnClient(client, query, params) {
62
+ async function executeOnClient(client, query, params, typings) {
218
63
  if (isPool(client)) {
219
- const connection = await client.acquire();
220
- try {
221
- return await executeOnClient(connection, query, params);
222
- } finally {
223
- await client.release(connection);
224
- }
64
+ return withRetry(async () => {
65
+ const connection = await client.acquire();
66
+ try {
67
+ return await executeOnClient(connection, query, params, typings);
68
+ } finally {
69
+ await client.release(connection);
70
+ }
71
+ });
225
72
  }
226
- const prepared = prepareParams(params);
227
- const paramValue = prepared.length > 0 ? prepared : undefined;
73
+ const prepared = prepareParams(params, typings);
74
+ const paramValue = prepared.length > 0 ? prepared : void 0;
228
75
  const rows = await client.queryAll(query, paramValue);
229
76
  if (!rows || rows.length === 0) {
230
77
  return [];
231
78
  }
232
79
  return rows.map((r) => r.data());
233
80
  }
234
- async function executeArraysOnClient(client, query, params) {
81
+ async function executeArraysOnClient(client, query, params, typings) {
235
82
  if (isPool(client)) {
236
- const connection = await client.acquire();
237
- try {
238
- return await executeArraysOnClient(connection, query, params);
239
- } finally {
240
- await client.release(connection);
241
- }
83
+ return withRetry(async () => {
84
+ const connection = await client.acquire();
85
+ try {
86
+ return await executeArraysOnClient(connection, query, params, typings);
87
+ } finally {
88
+ await client.release(connection);
89
+ }
90
+ });
242
91
  }
243
- const prepared = prepareParams(params);
244
- const paramValue = prepared.length > 0 ? prepared : undefined;
92
+ const prepared = prepareParams(params, typings);
93
+ const paramValue = prepared.length > 0 ? prepared : void 0;
245
94
  const iter = await client.queryIter(query, paramValue);
246
95
  const schema = iter.schema();
247
96
  const fields = schema.fields();
@@ -249,25 +98,25 @@ async function executeArraysOnClient(client, query, params) {
249
98
  const rows = [];
250
99
  while (true) {
251
100
  const row = await iter.next();
252
- if (row === null)
253
- break;
254
- if (row instanceof Error)
255
- throw row;
101
+ if (row === null) break;
102
+ if (row instanceof Error) throw row;
256
103
  rows.push(row.values());
257
104
  }
258
105
  return { columns, rows };
259
106
  }
260
- async function execOnClient(client, query, params) {
107
+ async function execOnClient(client, query, params, typings) {
261
108
  if (isPool(client)) {
262
- const connection = await client.acquire();
263
- try {
264
- return await execOnClient(connection, query, params);
265
- } finally {
266
- await client.release(connection);
267
- }
109
+ return withRetry(async () => {
110
+ const connection = await client.acquire();
111
+ try {
112
+ return await execOnClient(connection, query, params, typings);
113
+ } finally {
114
+ await client.release(connection);
115
+ }
116
+ });
268
117
  }
269
- const prepared = prepareParams(params);
270
- const paramValue = prepared.length > 0 ? prepared : undefined;
118
+ const prepared = prepareParams(params, typings);
119
+ const paramValue = prepared.length > 0 ? prepared : void 0;
271
120
  return await client.exec(query, paramValue);
272
121
  }
273
122
  async function closeClientConnection(connection) {
@@ -276,171 +125,155 @@ async function closeClientConnection(connection) {
276
125
  }
277
126
  }
278
127
 
279
- // src/session.ts
280
- class DatabendPreparedQuery extends PgPreparedQuery {
281
- client;
282
- queryString;
283
- params;
284
- logger;
285
- fields;
286
- _isResponseInArrayMode;
287
- customResultMapper;
288
- static [entityKind] = "DatabendPreparedQuery";
289
- constructor(client, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper) {
290
- super({ sql: queryString, params });
291
- this.client = client;
292
- this.queryString = queryString;
293
- this.params = params;
294
- this.logger = logger;
295
- this.fields = fields;
296
- this._isResponseInArrayMode = _isResponseInArrayMode;
297
- this.customResultMapper = customResultMapper;
128
+ // src/columns.ts
129
+ import { customType } from "drizzle-orm/pg-core";
130
+ var databendVariant = (name) => customType({
131
+ dataType() {
132
+ return "VARIANT";
133
+ },
134
+ toDriver(value) {
135
+ if (typeof value === "string") {
136
+ return value;
137
+ }
138
+ return JSON.stringify(value);
139
+ },
140
+ fromDriver(value) {
141
+ if (typeof value === "string") {
142
+ try {
143
+ return JSON.parse(value);
144
+ } catch {
145
+ return value;
146
+ }
147
+ }
148
+ return value;
298
149
  }
299
- async execute(placeholderValues = {}) {
300
- const params = prepareParams(fillPlaceholders(this.params, placeholderValues));
301
- this.logger.logQuery(this.queryString, params);
302
- const { fields, joinsNotNullableMap, customResultMapper } = this;
303
- if (fields) {
304
- const { rows: rows2 } = await executeArraysOnClient(this.client, this.queryString, params);
305
- if (rows2.length === 0) {
150
+ })(name);
151
+ var databendArray = (name, elementType) => customType({
152
+ dataType() {
153
+ return `ARRAY(${elementType})`;
154
+ },
155
+ toDriver(value) {
156
+ return value;
157
+ },
158
+ fromDriver(value) {
159
+ if (typeof value === "string") {
160
+ try {
161
+ return JSON.parse(value);
162
+ } catch {
306
163
  return [];
307
164
  }
308
- return customResultMapper ? customResultMapper(rows2) : rows2.map((row) => mapResultRow(fields, row, joinsNotNullableMap));
309
165
  }
310
- const rows = await executeOnClient(this.client, this.queryString, params);
311
- return rows;
312
- }
313
- all(placeholderValues = {}) {
314
- return this.execute(placeholderValues);
315
- }
316
- isResponseInArrayMode() {
317
- return this._isResponseInArrayMode;
318
- }
319
- }
320
-
321
- class DatabendSession extends PgSession {
322
- client;
323
- schema;
324
- options;
325
- static [entityKind] = "DatabendSession";
326
- dialect;
327
- logger;
328
- rollbackOnly = false;
329
- constructor(client, dialect, schema, options = {}) {
330
- super(dialect);
331
- this.client = client;
332
- this.schema = schema;
333
- this.options = options;
334
- this.dialect = dialect;
335
- this.logger = options.logger ?? new NoopLogger;
336
- }
337
- prepareQuery(query, fields, name, isResponseInArrayMode, customResultMapper) {
338
- return new DatabendPreparedQuery(this.client, query.sql, query.params, this.logger, fields, isResponseInArrayMode, customResultMapper);
166
+ return value;
339
167
  }
340
- async transaction(transaction, config) {
341
- let pinnedConnection;
342
- let pool;
343
- let clientForTx = this.client;
344
- if (isPool(this.client)) {
345
- pool = this.client;
346
- pinnedConnection = await pool.acquire();
347
- clientForTx = pinnedConnection;
348
- }
349
- const session = new DatabendSession(clientForTx, this.dialect, this.schema, this.options);
350
- const tx = new DatabendTransaction(this.dialect, session, this.schema);
351
- try {
352
- await tx.execute(sql`BEGIN`);
353
- if (config) {
354
- await tx.setTransaction(config);
355
- }
168
+ })(name);
169
+ var databendTuple = (name, types) => customType({
170
+ dataType() {
171
+ return `TUPLE(${types.join(", ")})`;
172
+ },
173
+ toDriver(value) {
174
+ return value;
175
+ },
176
+ fromDriver(value) {
177
+ if (typeof value === "string") {
356
178
  try {
357
- const result = await transaction(tx);
358
- if (session.isRollbackOnly()) {
359
- await tx.execute(sql`ROLLBACK`);
360
- throw new TransactionRollbackError;
361
- }
362
- await tx.execute(sql`COMMIT`);
363
- return result;
364
- } catch (error) {
365
- await tx.execute(sql`ROLLBACK`);
366
- throw error;
367
- }
368
- } finally {
369
- if (pinnedConnection && pool) {
370
- await pool.release(pinnedConnection);
179
+ return JSON.parse(value);
180
+ } catch {
181
+ return value;
371
182
  }
372
183
  }
184
+ return value;
373
185
  }
374
- markRollbackOnly() {
375
- this.rollbackOnly = true;
376
- }
377
- isRollbackOnly() {
378
- return this.rollbackOnly;
379
- }
380
- }
381
- var VALID_TRANSACTION_ISOLATION_LEVELS = new Set([
382
- "read uncommitted",
383
- "read committed",
384
- "repeatable read",
385
- "serializable"
386
- ]);
387
- var VALID_TRANSACTION_ACCESS_MODES = new Set([
388
- "read only",
389
- "read write"
390
- ]);
391
-
392
- class DatabendTransaction extends PgTransaction {
393
- static [entityKind] = "DatabendTransaction";
394
- rollback() {
395
- throw new TransactionRollbackError;
186
+ })(name);
187
+ var databendMap = (name, keyType, valueType) => customType({
188
+ dataType() {
189
+ return `MAP(${keyType}, ${valueType})`;
190
+ },
191
+ toDriver(value) {
192
+ return value;
193
+ },
194
+ fromDriver(value) {
195
+ if (typeof value === "string") {
196
+ try {
197
+ return JSON.parse(value);
198
+ } catch {
199
+ return value;
200
+ }
201
+ }
202
+ return value;
396
203
  }
397
- getTransactionConfigSQL(config) {
398
- if (config.isolationLevel && !VALID_TRANSACTION_ISOLATION_LEVELS.has(config.isolationLevel)) {
399
- throw new Error(`Invalid transaction isolation level "${config.isolationLevel}". Expected one of: ${Array.from(VALID_TRANSACTION_ISOLATION_LEVELS).join(", ")}.`);
204
+ })(name);
205
+ var databendTimestamp = (name) => customType({
206
+ dataType() {
207
+ return "TIMESTAMP";
208
+ },
209
+ toDriver(value) {
210
+ if (value instanceof Date) {
211
+ return value.toISOString();
400
212
  }
401
- if (config.accessMode && !VALID_TRANSACTION_ACCESS_MODES.has(config.accessMode)) {
402
- throw new Error(`Invalid transaction access mode "${config.accessMode}". Expected one of: ${Array.from(VALID_TRANSACTION_ACCESS_MODES).join(", ")}.`);
213
+ return value;
214
+ },
215
+ fromDriver(value) {
216
+ if (value instanceof Date) {
217
+ return value;
403
218
  }
404
- const chunks = [];
405
- if (config.isolationLevel) {
406
- chunks.push(`isolation level ${config.isolationLevel}`);
219
+ const str = String(value);
220
+ const hasOffset = str.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(str);
221
+ const normalized = hasOffset ? str.replace(" ", "T") : `${str.replace(" ", "T")}Z`;
222
+ return new Date(normalized);
223
+ }
224
+ })(name);
225
+ var databendDate = (name) => customType({
226
+ dataType() {
227
+ return "DATE";
228
+ },
229
+ toDriver(value) {
230
+ if (value instanceof Date) {
231
+ return value.toISOString().slice(0, 10);
407
232
  }
408
- if (config.accessMode) {
409
- chunks.push(config.accessMode);
233
+ return value;
234
+ },
235
+ fromDriver(value) {
236
+ if (value instanceof Date) {
237
+ return value.toISOString().slice(0, 10);
410
238
  }
411
- return sql.raw(chunks.join(" "));
412
- }
413
- setTransaction(config) {
414
- return this.session.execute(sql`SET TRANSACTION ${this.getTransactionConfigSQL(config)}`);
415
- }
416
- async transaction(transaction) {
417
- const internals = this;
418
- const nestedTx = new DatabendTransaction(internals.dialect, internals.session, this.schema, this.nestedIndex + 1);
419
- return transaction(nestedTx).catch((error) => {
420
- internals.session.markRollbackOnly();
421
- throw error;
422
- });
239
+ return value.slice(0, 10);
423
240
  }
424
- }
241
+ })(name);
242
+
243
+ // src/driver.ts
244
+ import { Client } from "databend-driver";
245
+ import { entityKind as entityKind3 } from "drizzle-orm/entity";
246
+ import { DefaultLogger } from "drizzle-orm/logger";
247
+ import { PgDatabase } from "drizzle-orm/pg-core/db";
248
+ import {
249
+ createTableRelationsHelpers,
250
+ extractTablesRelationalConfig
251
+ } from "drizzle-orm/relations";
425
252
 
426
253
  // src/dialect.ts
427
- import { entityKind as entityKind2, is as is2 } from "drizzle-orm/entity";
428
254
  import {
429
- PgDate as PgDate2,
430
- PgDateString as PgDateString2,
255
+ sql
256
+ } from "drizzle-orm";
257
+ import { entityKind, is } from "drizzle-orm/entity";
258
+ import {
259
+ PgBigInt53,
260
+ PgBigInt64,
261
+ PgDate,
262
+ PgDateString,
431
263
  PgDialect,
264
+ PgDoublePrecision,
265
+ PgInteger,
432
266
  PgNumeric,
433
- PgTime as PgTime2,
434
- PgTimestamp as PgTimestamp2,
435
- PgTimestampString as PgTimestampString2,
267
+ PgReal,
268
+ PgSmallInt,
269
+ PgTime,
270
+ PgTimestamp,
271
+ PgTimestampString,
436
272
  PgUUID
437
273
  } from "drizzle-orm/pg-core";
438
- import {
439
- sql as sql2
440
- } from "drizzle-orm";
441
-
442
- class DatabendDialect extends PgDialect {
443
- static [entityKind2] = "DatabendPgDialect";
274
+ var DatabendDialect = class extends PgDialect {
275
+ static [entityKind] = "DatabendPgDialect";
276
+ // Databend does not support savepoints
444
277
  areSavepointsUnsupported() {
445
278
  return true;
446
279
  }
@@ -448,67 +281,79 @@ class DatabendDialect extends PgDialect {
448
281
  const migrationConfig = typeof config === "string" ? { migrationsFolder: config } : config;
449
282
  const migrationsSchema = migrationConfig.migrationsSchema ?? "default";
450
283
  const migrationsTable = migrationConfig.migrationsTable ?? "__drizzle_migrations";
451
- const migrationTableCreate = sql2`
452
- CREATE TABLE IF NOT EXISTS ${sql2.identifier(migrationsSchema)}.${sql2.identifier(migrationsTable)} (
284
+ const migrationTableCreate = sql`
285
+ CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsSchema)}.${sql.identifier(
286
+ migrationsTable
287
+ )} (
453
288
  id INT NOT NULL,
454
289
  hash VARCHAR NOT NULL,
455
290
  created_at BIGINT
456
291
  )
457
292
  `;
458
293
  await session.execute(migrationTableCreate);
459
- const dbMigrations = await session.all(sql2`SELECT id, hash, created_at FROM ${sql2.identifier(migrationsSchema)}.${sql2.identifier(migrationsTable)} ORDER BY created_at DESC LIMIT 1`);
294
+ const dbMigrations = await session.all(
295
+ sql`SELECT id, hash, created_at FROM ${sql.identifier(
296
+ migrationsSchema
297
+ )}.${sql.identifier(migrationsTable)} ORDER BY created_at DESC LIMIT 1`
298
+ );
460
299
  const lastDbMigration = dbMigrations[0];
461
300
  await session.transaction(async (tx) => {
462
301
  for await (const migration of migrations) {
463
302
  if (!lastDbMigration || Number(lastDbMigration.created_at) < migration.folderMillis) {
464
303
  for (const stmt of migration.sql) {
465
- await tx.execute(sql2.raw(stmt));
304
+ await tx.execute(sql.raw(stmt));
466
305
  }
467
- await tx.execute(sql2`INSERT INTO ${sql2.identifier(migrationsSchema)}.${sql2.identifier(migrationsTable)} (id, hash, created_at)
306
+ await tx.execute(
307
+ sql`INSERT INTO ${sql.identifier(
308
+ migrationsSchema
309
+ )}.${sql.identifier(migrationsTable)} (id, hash, created_at)
468
310
  VALUES (
469
- (SELECT COALESCE(MAX(id), 0) + 1 FROM ${sql2.identifier(migrationsSchema)}.${sql2.identifier(migrationsTable)}),
311
+ (SELECT COALESCE(MAX(id), 0) + 1 FROM ${sql.identifier(
312
+ migrationsSchema
313
+ )}.${sql.identifier(migrationsTable)}),
470
314
  ${migration.hash},
471
315
  ${migration.folderMillis}
472
- )`);
316
+ )`
317
+ );
473
318
  }
474
319
  }
475
320
  });
476
321
  }
477
322
  prepareTyping(encoder) {
478
- if (is2(encoder, PgNumeric)) {
323
+ if (is(encoder, PgNumeric) || is(encoder, PgInteger) || is(encoder, PgSmallInt) || is(encoder, PgReal) || is(encoder, PgDoublePrecision) || is(encoder, PgBigInt53) || is(encoder, PgBigInt64)) {
479
324
  return "decimal";
480
- } else if (is2(encoder, PgTime2)) {
325
+ } else if (is(encoder, PgTime)) {
481
326
  return "time";
482
- } else if (is2(encoder, PgTimestamp2) || is2(encoder, PgTimestampString2)) {
327
+ } else if (is(encoder, PgTimestamp) || is(encoder, PgTimestampString)) {
483
328
  return "timestamp";
484
- } else if (is2(encoder, PgDate2) || is2(encoder, PgDateString2)) {
329
+ } else if (is(encoder, PgDate) || is(encoder, PgDateString)) {
485
330
  return "date";
486
- } else if (is2(encoder, PgUUID)) {
331
+ } else if (is(encoder, PgUUID)) {
487
332
  return "uuid";
488
333
  } else {
489
334
  return "none";
490
335
  }
491
336
  }
492
- }
337
+ };
493
338
 
494
339
  // src/pool.ts
495
340
  function createDatabendConnectionPool(client, options = {}) {
496
341
  const size = options.size && options.size > 0 ? options.size : 4;
497
- const acquireTimeout = options.acquireTimeout ?? 30000;
342
+ const acquireTimeout = options.acquireTimeout ?? 3e4;
498
343
  const maxWaitingRequests = options.maxWaitingRequests ?? 100;
499
344
  const maxLifetimeMs = options.maxLifetimeMs;
500
345
  const idleTimeoutMs = options.idleTimeoutMs;
501
- const metadata = new WeakMap;
346
+ const metadata = /* @__PURE__ */ new WeakMap();
502
347
  const idle = [];
503
348
  const waiting = [];
504
349
  let total = 0;
505
350
  let closed = false;
506
351
  let pendingAcquires = 0;
507
352
  const shouldRecycle = (conn, now) => {
508
- if (maxLifetimeMs !== undefined && now - conn.createdAt >= maxLifetimeMs) {
353
+ if (maxLifetimeMs !== void 0 && now - conn.createdAt >= maxLifetimeMs) {
509
354
  return true;
510
355
  }
511
- if (idleTimeoutMs !== undefined && now - conn.lastUsedAt >= idleTimeoutMs) {
356
+ if (idleTimeoutMs !== void 0 && now - conn.lastUsedAt >= idleTimeoutMs) {
512
357
  return true;
513
358
  }
514
359
  return false;
@@ -554,7 +399,9 @@ function createDatabendConnectionPool(client, options = {}) {
554
399
  }
555
400
  }
556
401
  if (waiting.length >= maxWaitingRequests) {
557
- throw new Error(`Databend connection pool queue is full (max ${maxWaitingRequests} waiting requests)`);
402
+ throw new Error(
403
+ `Databend connection pool queue is full (max ${maxWaitingRequests} waiting requests)`
404
+ );
558
405
  }
559
406
  return await new Promise((resolve, reject) => {
560
407
  const timeoutId = setTimeout(() => {
@@ -562,7 +409,11 @@ function createDatabendConnectionPool(client, options = {}) {
562
409
  if (idx !== -1) {
563
410
  waiting.splice(idx, 1);
564
411
  }
565
- reject(new Error(`Databend connection pool acquire timeout after ${acquireTimeout}ms`));
412
+ reject(
413
+ new Error(
414
+ `Databend connection pool acquire timeout after ${acquireTimeout}ms`
415
+ )
416
+ );
566
417
  }, acquireTimeout);
567
418
  waiting.push({ resolve, reject, timeoutId });
568
419
  });
@@ -573,7 +424,7 @@ function createDatabendConnectionPool(client, options = {}) {
573
424
  clearTimeout(waiter.timeoutId);
574
425
  const now2 = Date.now();
575
426
  const meta = metadata.get(connection) ?? { createdAt: now2, lastUsedAt: now2 };
576
- const expired = maxLifetimeMs !== undefined && now2 - meta.createdAt >= maxLifetimeMs;
427
+ const expired = maxLifetimeMs !== void 0 && now2 - meta.createdAt >= maxLifetimeMs;
577
428
  if (closed) {
578
429
  await closeClientConnection(connection);
579
430
  total = Math.max(0, total - 1);
@@ -591,90 +442,451 @@ function createDatabendConnectionPool(client, options = {}) {
591
442
  } catch (error) {
592
443
  waiter.reject(error);
593
444
  }
594
- return;
445
+ return;
446
+ }
447
+ meta.lastUsedAt = now2;
448
+ metadata.set(connection, meta);
449
+ waiter.resolve(connection);
450
+ return;
451
+ }
452
+ if (closed) {
453
+ await closeClientConnection(connection);
454
+ metadata.delete(connection);
455
+ total = Math.max(0, total - 1);
456
+ return;
457
+ }
458
+ const now = Date.now();
459
+ const existingMeta = metadata.get(connection) ?? { createdAt: now, lastUsedAt: now };
460
+ existingMeta.lastUsedAt = now;
461
+ metadata.set(connection, existingMeta);
462
+ if (maxLifetimeMs !== void 0 && now - existingMeta.createdAt >= maxLifetimeMs) {
463
+ await closeClientConnection(connection);
464
+ total -= 1;
465
+ metadata.delete(connection);
466
+ return;
467
+ }
468
+ idle.push({
469
+ connection,
470
+ createdAt: existingMeta.createdAt,
471
+ lastUsedAt: existingMeta.lastUsedAt
472
+ });
473
+ };
474
+ const close = async () => {
475
+ closed = true;
476
+ const waiters = waiting.splice(0, waiting.length);
477
+ for (const waiter of waiters) {
478
+ clearTimeout(waiter.timeoutId);
479
+ waiter.reject(new Error("Databend connection pool is closed"));
480
+ }
481
+ const toClose = idle.splice(0, idle.length);
482
+ await Promise.allSettled(
483
+ toClose.map((item) => closeClientConnection(item.connection))
484
+ );
485
+ total = Math.max(0, total - toClose.length);
486
+ for (const item of toClose) {
487
+ metadata.delete(item.connection);
488
+ }
489
+ const maxWait = 5e3;
490
+ const start = Date.now();
491
+ while (pendingAcquires > 0 && Date.now() - start < maxWait) {
492
+ await new Promise((r) => setTimeout(r, 10));
493
+ }
494
+ };
495
+ return {
496
+ acquire,
497
+ release,
498
+ close,
499
+ size
500
+ };
501
+ }
502
+
503
+ // src/session.ts
504
+ import { entityKind as entityKind2 } from "drizzle-orm/entity";
505
+ import { TransactionRollbackError } from "drizzle-orm/errors";
506
+ import { NoopLogger } from "drizzle-orm/logger";
507
+ import { PgTransaction } from "drizzle-orm/pg-core";
508
+ import { PgPreparedQuery, PgSession } from "drizzle-orm/pg-core/session";
509
+ import { fillPlaceholders, sql as sql2 } from "drizzle-orm/sql/sql";
510
+
511
+ // src/sql/result-mapper.ts
512
+ import {
513
+ Column,
514
+ getTableName,
515
+ is as is2,
516
+ SQL
517
+ } from "drizzle-orm";
518
+ import {
519
+ PgCustomColumn,
520
+ PgDate as PgDate2,
521
+ PgDateString as PgDateString2,
522
+ PgTime as PgTime2,
523
+ PgTimestamp as PgTimestamp2,
524
+ PgTimestampString as PgTimestampString2
525
+ } from "drizzle-orm/pg-core";
526
+ function toDecoderInput(decoder, value) {
527
+ void decoder;
528
+ return value;
529
+ }
530
+ function normalizeTimestampString(value, withTimezone) {
531
+ if (value instanceof Date) {
532
+ const iso = value.toISOString().replace("T", " ");
533
+ return withTimezone ? iso.replace("Z", "+00") : iso.replace("Z", "");
534
+ }
535
+ if (typeof value === "string") {
536
+ const normalized = value.replace("T", " ");
537
+ if (withTimezone) {
538
+ return normalized.includes("+") ? normalized : `${normalized}+00`;
539
+ }
540
+ return normalized.replace(/\+00$/, "");
541
+ }
542
+ return value;
543
+ }
544
+ function normalizeTimestamp(value, withTimezone) {
545
+ if (value instanceof Date) {
546
+ return value;
547
+ }
548
+ if (typeof value === "string") {
549
+ const hasOffset = value.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(value.trim());
550
+ const spaced = value.replace(" ", "T");
551
+ const normalized = withTimezone || hasOffset ? spaced : `${spaced}+00`;
552
+ return new Date(normalized);
553
+ }
554
+ return value;
555
+ }
556
+ function normalizeDateString(value) {
557
+ if (value instanceof Date) {
558
+ return value.toISOString().slice(0, 10);
559
+ }
560
+ if (typeof value === "string") {
561
+ return value.slice(0, 10);
562
+ }
563
+ return value;
564
+ }
565
+ function normalizeDateValue(value) {
566
+ if (value instanceof Date) {
567
+ return value;
568
+ }
569
+ if (typeof value === "string") {
570
+ return /* @__PURE__ */ new Date(`${value.slice(0, 10)}T00:00:00Z`);
571
+ }
572
+ return value;
573
+ }
574
+ function normalizeTime(value) {
575
+ if (typeof value === "bigint") {
576
+ const totalMillis = Number(value) / 1e3;
577
+ const date = new Date(totalMillis);
578
+ return date.toISOString().split("T")[1].replace("Z", "");
579
+ }
580
+ if (value instanceof Date) {
581
+ return value.toISOString().split("T")[1].replace("Z", "");
582
+ }
583
+ return value;
584
+ }
585
+ function mapDriverValue(decoder, rawValue) {
586
+ if (is2(decoder, PgTimestampString2)) {
587
+ return decoder.mapFromDriverValue(
588
+ toDecoderInput(
589
+ decoder,
590
+ normalizeTimestampString(rawValue, decoder.withTimezone)
591
+ )
592
+ );
593
+ }
594
+ if (is2(decoder, PgTimestamp2)) {
595
+ const normalized = normalizeTimestamp(rawValue, decoder.withTimezone);
596
+ if (normalized instanceof Date) {
597
+ return normalized;
598
+ }
599
+ return decoder.mapFromDriverValue(toDecoderInput(decoder, normalized));
600
+ }
601
+ if (is2(decoder, PgDateString2)) {
602
+ return decoder.mapFromDriverValue(
603
+ toDecoderInput(decoder, normalizeDateString(rawValue))
604
+ );
605
+ }
606
+ if (is2(decoder, PgDate2)) {
607
+ return decoder.mapFromDriverValue(
608
+ toDecoderInput(decoder, normalizeDateValue(rawValue))
609
+ );
610
+ }
611
+ if (is2(decoder, PgTime2)) {
612
+ return decoder.mapFromDriverValue(
613
+ toDecoderInput(decoder, normalizeTime(rawValue))
614
+ );
615
+ }
616
+ return decoder.mapFromDriverValue(toDecoderInput(decoder, rawValue));
617
+ }
618
+ function mapResultRow(columns, row, joinsNotNullableMap) {
619
+ const nullifyMap = {};
620
+ const result = columns.reduce(
621
+ (acc, { path, field }, columnIndex) => {
622
+ let decoder;
623
+ if (is2(field, Column)) {
624
+ decoder = field;
625
+ } else if (is2(field, SQL)) {
626
+ decoder = field.decoder;
627
+ } else {
628
+ const col = field.sql.queryChunks.find((chunk) => is2(chunk, Column));
629
+ if (is2(col, PgCustomColumn)) {
630
+ decoder = col;
631
+ } else {
632
+ decoder = field.sql.decoder;
633
+ }
634
+ }
635
+ let node = acc;
636
+ for (const [pathChunkIndex, pathChunk] of path.entries()) {
637
+ if (pathChunkIndex < path.length - 1) {
638
+ if (!(pathChunk in node)) {
639
+ node[pathChunk] = {};
640
+ }
641
+ node = node[pathChunk];
642
+ continue;
643
+ }
644
+ const rawValue = row[columnIndex];
645
+ const value = node[pathChunk] = rawValue === null ? null : mapDriverValue(decoder, rawValue);
646
+ if (joinsNotNullableMap && is2(field, Column) && path.length === 2) {
647
+ const objectName = path[0];
648
+ if (!(objectName in nullifyMap)) {
649
+ nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
650
+ } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
651
+ nullifyMap[objectName] = false;
652
+ }
653
+ continue;
654
+ }
655
+ if (joinsNotNullableMap && is2(field, SQL.Aliased) && path.length === 2) {
656
+ const col = field.sql.queryChunks.find((chunk) => is2(chunk, Column));
657
+ const tableName = col?.table && getTableName(col?.table);
658
+ if (!tableName) {
659
+ continue;
660
+ }
661
+ const objectName = path[0];
662
+ if (!(objectName in nullifyMap)) {
663
+ nullifyMap[objectName] = value === null ? tableName : false;
664
+ continue;
665
+ }
666
+ if (nullifyMap[objectName] && nullifyMap[objectName] !== tableName) {
667
+ nullifyMap[objectName] = false;
668
+ }
669
+ }
670
+ }
671
+ return acc;
672
+ },
673
+ {}
674
+ );
675
+ if (joinsNotNullableMap && Object.keys(nullifyMap).length > 0) {
676
+ for (const [objectName, tableName] of Object.entries(nullifyMap)) {
677
+ if (typeof tableName === "string" && !joinsNotNullableMap[tableName]) {
678
+ result[objectName] = null;
679
+ }
680
+ }
681
+ }
682
+ return result;
683
+ }
684
+
685
+ // src/session.ts
686
+ var DatabendPreparedQuery = class extends PgPreparedQuery {
687
+ constructor(client, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper, typings) {
688
+ super({ sql: queryString, params });
689
+ this.client = client;
690
+ this.queryString = queryString;
691
+ this.params = params;
692
+ this.logger = logger;
693
+ this.fields = fields;
694
+ this._isResponseInArrayMode = _isResponseInArrayMode;
695
+ this.customResultMapper = customResultMapper;
696
+ this.typings = typings;
697
+ }
698
+ static [entityKind2] = "DatabendPreparedQuery";
699
+ async execute(placeholderValues = {}) {
700
+ const params = fillPlaceholders(this.params, placeholderValues);
701
+ this.logger.logQuery(this.queryString, params);
702
+ const { fields, joinsNotNullableMap, customResultMapper, typings } = this;
703
+ if (fields) {
704
+ const { rows: rows2 } = await executeArraysOnClient(
705
+ this.client,
706
+ this.queryString,
707
+ params,
708
+ typings
709
+ );
710
+ if (rows2.length === 0) {
711
+ return [];
712
+ }
713
+ return customResultMapper ? customResultMapper(rows2) : rows2.map(
714
+ (row) => mapResultRow(fields, row, joinsNotNullableMap)
715
+ );
716
+ }
717
+ const rows = await executeOnClient(this.client, this.queryString, params, typings);
718
+ return rows;
719
+ }
720
+ all(placeholderValues = {}) {
721
+ return this.execute(placeholderValues);
722
+ }
723
+ isResponseInArrayMode() {
724
+ return this._isResponseInArrayMode;
725
+ }
726
+ };
727
+ var DatabendSession = class _DatabendSession extends PgSession {
728
+ constructor(client, dialect, schema, options = {}) {
729
+ super(dialect);
730
+ this.client = client;
731
+ this.schema = schema;
732
+ this.options = options;
733
+ this.dialect = dialect;
734
+ this.logger = options.logger ?? new NoopLogger();
735
+ }
736
+ static [entityKind2] = "DatabendSession";
737
+ dialect;
738
+ logger;
739
+ rollbackOnly = false;
740
+ prepareQuery(query, fields, name, isResponseInArrayMode, customResultMapper) {
741
+ void name;
742
+ return new DatabendPreparedQuery(
743
+ this.client,
744
+ query.sql,
745
+ query.params,
746
+ this.logger,
747
+ fields,
748
+ isResponseInArrayMode,
749
+ customResultMapper,
750
+ query.typings
751
+ );
752
+ }
753
+ async transaction(transaction, config) {
754
+ let pinnedConnection;
755
+ let pool;
756
+ let clientForTx = this.client;
757
+ if (isPool(this.client)) {
758
+ pool = this.client;
759
+ pinnedConnection = await pool.acquire();
760
+ clientForTx = pinnedConnection;
761
+ }
762
+ const session = new _DatabendSession(
763
+ clientForTx,
764
+ this.dialect,
765
+ this.schema,
766
+ this.options
767
+ );
768
+ const tx = new DatabendTransaction(
769
+ this.dialect,
770
+ session,
771
+ this.schema
772
+ );
773
+ try {
774
+ await tx.execute(sql2`BEGIN`);
775
+ if (config) {
776
+ await tx.setTransaction(config);
777
+ }
778
+ try {
779
+ const result = await transaction(tx);
780
+ if (session.isRollbackOnly()) {
781
+ await tx.execute(sql2`ROLLBACK`);
782
+ throw new TransactionRollbackError();
783
+ }
784
+ await tx.execute(sql2`COMMIT`);
785
+ return result;
786
+ } catch (error) {
787
+ await tx.execute(sql2`ROLLBACK`);
788
+ throw error;
789
+ }
790
+ } finally {
791
+ if (pinnedConnection && pool) {
792
+ await pool.release(pinnedConnection);
595
793
  }
596
- meta.lastUsedAt = now2;
597
- metadata.set(connection, meta);
598
- waiter.resolve(connection);
599
- return;
600
794
  }
601
- if (closed) {
602
- await closeClientConnection(connection);
603
- metadata.delete(connection);
604
- total = Math.max(0, total - 1);
605
- return;
795
+ }
796
+ markRollbackOnly() {
797
+ this.rollbackOnly = true;
798
+ }
799
+ isRollbackOnly() {
800
+ return this.rollbackOnly;
801
+ }
802
+ };
803
+ var VALID_TRANSACTION_ISOLATION_LEVELS = /* @__PURE__ */ new Set([
804
+ "read uncommitted",
805
+ "read committed",
806
+ "repeatable read",
807
+ "serializable"
808
+ ]);
809
+ var VALID_TRANSACTION_ACCESS_MODES = /* @__PURE__ */ new Set([
810
+ "read only",
811
+ "read write"
812
+ ]);
813
+ var DatabendTransaction = class _DatabendTransaction extends PgTransaction {
814
+ static [entityKind2] = "DatabendTransaction";
815
+ rollback() {
816
+ throw new TransactionRollbackError();
817
+ }
818
+ getTransactionConfigSQL(config) {
819
+ if (config.isolationLevel && !VALID_TRANSACTION_ISOLATION_LEVELS.has(config.isolationLevel)) {
820
+ throw new Error(
821
+ `Invalid transaction isolation level "${config.isolationLevel}". Expected one of: ${Array.from(
822
+ VALID_TRANSACTION_ISOLATION_LEVELS
823
+ ).join(", ")}.`
824
+ );
606
825
  }
607
- const now = Date.now();
608
- const existingMeta = metadata.get(connection) ?? { createdAt: now, lastUsedAt: now };
609
- existingMeta.lastUsedAt = now;
610
- metadata.set(connection, existingMeta);
611
- if (maxLifetimeMs !== undefined && now - existingMeta.createdAt >= maxLifetimeMs) {
612
- await closeClientConnection(connection);
613
- total -= 1;
614
- metadata.delete(connection);
615
- return;
826
+ if (config.accessMode && !VALID_TRANSACTION_ACCESS_MODES.has(config.accessMode)) {
827
+ throw new Error(
828
+ `Invalid transaction access mode "${config.accessMode}". Expected one of: ${Array.from(
829
+ VALID_TRANSACTION_ACCESS_MODES
830
+ ).join(", ")}.`
831
+ );
616
832
  }
617
- idle.push({
618
- connection,
619
- createdAt: existingMeta.createdAt,
620
- lastUsedAt: existingMeta.lastUsedAt
621
- });
622
- };
623
- const close = async () => {
624
- closed = true;
625
- const waiters = waiting.splice(0, waiting.length);
626
- for (const waiter of waiters) {
627
- clearTimeout(waiter.timeoutId);
628
- waiter.reject(new Error("Databend connection pool is closed"));
833
+ const chunks = [];
834
+ if (config.isolationLevel) {
835
+ chunks.push(`isolation level ${config.isolationLevel}`);
629
836
  }
630
- const toClose = idle.splice(0, idle.length);
631
- await Promise.allSettled(toClose.map((item) => closeClientConnection(item.connection)));
632
- total = Math.max(0, total - toClose.length);
633
- toClose.forEach((item) => metadata.delete(item.connection));
634
- const maxWait = 5000;
635
- const start = Date.now();
636
- while (pendingAcquires > 0 && Date.now() - start < maxWait) {
637
- await new Promise((r) => setTimeout(r, 10));
837
+ if (config.accessMode) {
838
+ chunks.push(config.accessMode);
638
839
  }
639
- };
640
- return {
641
- acquire,
642
- release,
643
- close,
644
- size
645
- };
646
- }
840
+ return sql2.raw(chunks.join(" "));
841
+ }
842
+ setTransaction(config) {
843
+ return this.session.execute(
844
+ sql2`SET TRANSACTION ${this.getTransactionConfigSQL(config)}`
845
+ );
846
+ }
847
+ async transaction(transaction) {
848
+ const internals = this;
849
+ const nestedTx = new _DatabendTransaction(
850
+ internals.dialect,
851
+ internals.session,
852
+ this.schema,
853
+ this.nestedIndex + 1
854
+ );
855
+ return transaction(nestedTx).catch((error) => {
856
+ internals.session.markRollbackOnly();
857
+ throw error;
858
+ });
859
+ }
860
+ };
647
861
 
648
862
  // src/driver.ts
649
- class DatabendDriver {
650
- client;
651
- dialect;
652
- options;
653
- static [entityKind3] = "DatabendDriver";
863
+ var DatabendDriver = class {
654
864
  constructor(client, dialect, options = {}) {
655
865
  this.client = client;
656
866
  this.dialect = dialect;
657
867
  this.options = options;
658
868
  }
869
+ static [entityKind3] = "DatabendDriver";
659
870
  createSession(schema) {
660
871
  return new DatabendSession(this.client, this.dialect, schema, {
661
872
  logger: this.options.logger
662
873
  });
663
874
  }
664
- }
875
+ };
665
876
  function isConfigObject(data) {
666
- if (typeof data !== "object" || data === null)
667
- return false;
668
- if (data.constructor?.name !== "Object")
669
- return false;
877
+ if (typeof data !== "object" || data === null) return false;
878
+ if (data.constructor?.name !== "Object") return false;
670
879
  return "connection" in data || "client" in data || "pool" in data || "schema" in data || "logger" in data;
671
880
  }
672
881
  function createFromClient(client, config = {}, databendClient) {
673
- const dialect = new DatabendDialect;
674
- const logger = config.logger === true ? new DefaultLogger : config.logger || undefined;
882
+ const dialect = new DatabendDialect();
883
+ const logger = config.logger === true ? new DefaultLogger() : config.logger || void 0;
675
884
  let schema;
676
885
  if (config.schema) {
677
- const tablesConfig = extractTablesRelationalConfig(config.schema, createTableRelationsHelpers);
886
+ const tablesConfig = extractTablesRelationalConfig(
887
+ config.schema,
888
+ createTableRelationsHelpers
889
+ );
678
890
  schema = {
679
891
  fullSchema: config.schema,
680
892
  schema: tablesConfig.tables,
@@ -683,7 +895,13 @@ function createFromClient(client, config = {}, databendClient) {
683
895
  }
684
896
  const driver = new DatabendDriver(client, dialect, { logger });
685
897
  const session = driver.createSession(schema);
686
- const db = new DatabendDatabase(dialect, session, schema, client, databendClient);
898
+ const db = new DatabendDatabase(
899
+ dialect,
900
+ session,
901
+ schema,
902
+ client,
903
+ databendClient
904
+ );
687
905
  return db;
688
906
  }
689
907
  async function createFromDsn(dsn, config = {}) {
@@ -705,24 +923,26 @@ function drizzle(clientOrConfigOrDsn, config) {
705
923
  if ("connection" in configObj) {
706
924
  const connConfig = configObj;
707
925
  const { connection, ...restConfig } = connConfig;
708
- return createFromDsn(connection, restConfig);
926
+ return createFromDsn(
927
+ connection,
928
+ restConfig
929
+ );
709
930
  }
710
931
  if ("client" in configObj) {
711
932
  const clientConfig = configObj;
712
933
  const { client: clientValue, ...restConfig } = clientConfig;
713
- return createFromClient(clientValue, restConfig);
934
+ return createFromClient(
935
+ clientValue,
936
+ restConfig
937
+ );
714
938
  }
715
- throw new Error("Invalid drizzle config: either connection or client must be provided");
939
+ throw new Error(
940
+ "Invalid drizzle config: either connection or client must be provided"
941
+ );
716
942
  }
717
943
  return createFromClient(clientOrConfigOrDsn, config);
718
944
  }
719
-
720
- class DatabendDatabase extends PgDatabase {
721
- dialect;
722
- session;
723
- static [entityKind3] = "DatabendDatabase";
724
- $client;
725
- $databendClient;
945
+ var DatabendDatabase = class extends PgDatabase {
726
946
  constructor(dialect, session, schema, client, databendClient) {
727
947
  super(dialect, session, schema);
728
948
  this.dialect = dialect;
@@ -730,6 +950,11 @@ class DatabendDatabase extends PgDatabase {
730
950
  this.$client = client;
731
951
  this.$databendClient = databendClient;
732
952
  }
953
+ static [entityKind3] = "DatabendDatabase";
954
+ /** The underlying connection or pool */
955
+ $client;
956
+ /** The Databend Client instance (when created from DSN) */
957
+ $databendClient;
733
958
  async close() {
734
959
  if (isPool(this.$client) && this.$client.close) {
735
960
  await this.$client.close();
@@ -741,147 +966,38 @@ class DatabendDatabase extends PgDatabase {
741
966
  async transaction(transaction) {
742
967
  return await this.session.transaction(transaction);
743
968
  }
744
- }
745
- // src/columns.ts
746
- import { customType } from "drizzle-orm/pg-core";
747
- var databendVariant = (name) => customType({
748
- dataType() {
749
- return "VARIANT";
750
- },
751
- toDriver(value) {
752
- if (typeof value === "string") {
753
- return value;
754
- }
755
- return JSON.stringify(value);
756
- },
757
- fromDriver(value) {
758
- if (typeof value === "string") {
759
- try {
760
- return JSON.parse(value);
761
- } catch {
762
- return value;
763
- }
764
- }
765
- return value;
766
- }
767
- })(name);
768
- var databendArray = (name, elementType) => customType({
769
- dataType() {
770
- return `ARRAY(${elementType})`;
771
- },
772
- toDriver(value) {
773
- return value;
774
- },
775
- fromDriver(value) {
776
- if (typeof value === "string") {
777
- try {
778
- return JSON.parse(value);
779
- } catch {
780
- return [];
781
- }
782
- }
783
- return value;
784
- }
785
- })(name);
786
- var databendTuple = (name, types) => customType({
787
- dataType() {
788
- return `TUPLE(${types.join(", ")})`;
789
- },
790
- toDriver(value) {
791
- return value;
792
- },
793
- fromDriver(value) {
794
- if (typeof value === "string") {
795
- try {
796
- return JSON.parse(value);
797
- } catch {
798
- return value;
799
- }
800
- }
801
- return value;
802
- }
803
- })(name);
804
- var databendMap = (name, keyType, valueType) => customType({
805
- dataType() {
806
- return `MAP(${keyType}, ${valueType})`;
807
- },
808
- toDriver(value) {
809
- return value;
810
- },
811
- fromDriver(value) {
812
- if (typeof value === "string") {
813
- try {
814
- return JSON.parse(value);
815
- } catch {
816
- return value;
817
- }
818
- }
819
- return value;
820
- }
821
- })(name);
822
- var databendTimestamp = (name) => customType({
823
- dataType() {
824
- return "TIMESTAMP";
825
- },
826
- toDriver(value) {
827
- if (value instanceof Date) {
828
- return value.toISOString();
829
- }
830
- return value;
831
- },
832
- fromDriver(value) {
833
- if (value instanceof Date) {
834
- return value;
835
- }
836
- const str = String(value);
837
- const hasOffset = str.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(str);
838
- const normalized = hasOffset ? str.replace(" ", "T") : `${str.replace(" ", "T")}Z`;
839
- return new Date(normalized);
840
- }
841
- })(name);
842
- var databendDate = (name) => customType({
843
- dataType() {
844
- return "DATE";
845
- },
846
- toDriver(value) {
847
- if (value instanceof Date) {
848
- return value.toISOString().slice(0, 10);
849
- }
850
- return value;
851
- },
852
- fromDriver(value) {
853
- if (value instanceof Date) {
854
- return value.toISOString().slice(0, 10);
855
- }
856
- return value.slice(0, 10);
857
- }
858
- })(name);
969
+ };
970
+
859
971
  // src/migrator.ts
860
972
  import { readMigrationFiles } from "drizzle-orm/migrator";
861
973
  async function migrate(db, config) {
862
974
  const migrationConfig = typeof config === "string" ? { migrationsFolder: config } : config;
863
975
  const migrations = readMigrationFiles(migrationConfig);
864
- await db.dialect.migrate(migrations, db.session, migrationConfig);
976
+ await db.dialect.migrate(
977
+ migrations,
978
+ db.session,
979
+ migrationConfig
980
+ );
865
981
  }
866
982
  export {
867
- prepareParams,
868
- migrate,
869
- isPool,
870
- executeOnClient,
871
- executeArraysOnClient,
872
- execOnClient,
873
- drizzle,
874
- databendVariant,
875
- databendTuple,
876
- databendTimestamp,
877
- databendMap,
878
- databendDate,
879
- databendArray,
880
- createDatabendConnectionPool,
881
- closeClientConnection,
882
- DatabendTransaction,
883
- DatabendSession,
884
- DatabendPreparedQuery,
983
+ DatabendDatabase,
885
984
  DatabendDriver,
886
- DatabendDatabase
985
+ DatabendPreparedQuery,
986
+ DatabendSession,
987
+ DatabendTransaction,
988
+ closeClientConnection,
989
+ createDatabendConnectionPool,
990
+ databendArray,
991
+ databendDate,
992
+ databendMap,
993
+ databendTimestamp,
994
+ databendTuple,
995
+ databendVariant,
996
+ drizzle,
997
+ execOnClient,
998
+ executeArraysOnClient,
999
+ executeOnClient,
1000
+ isPool,
1001
+ migrate,
1002
+ prepareParams
887
1003
  };