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/client.d.ts +8 -4
- package/dist/dialect.d.ts +2 -2
- package/dist/driver.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +705 -589
- package/dist/session.d.ts +5 -4
- package/package.json +11 -5
- package/src/client.ts +71 -27
- package/src/columns.ts +1 -1
- package/src/dialect.ts +17 -7
- package/src/driver.ts +9 -9
- package/src/index.ts +3 -3
- package/src/migrator.ts +1 -1
- package/src/pool.ts +3 -1
- package/src/session.ts +15 -15
- package/src/sql/result-mapper.ts +3 -4
- package/src/sql/selection.ts +1 -1
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 ===
|
|
188
|
-
|
|
189
|
-
if (param
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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 :
|
|
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
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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 :
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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 :
|
|
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/
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
402
|
-
|
|
213
|
+
return value;
|
|
214
|
+
},
|
|
215
|
+
fromDriver(value) {
|
|
216
|
+
if (value instanceof Date) {
|
|
217
|
+
return value;
|
|
403
218
|
}
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
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
|
-
|
|
409
|
-
|
|
233
|
+
return value;
|
|
234
|
+
},
|
|
235
|
+
fromDriver(value) {
|
|
236
|
+
if (value instanceof Date) {
|
|
237
|
+
return value.toISOString().slice(0, 10);
|
|
410
238
|
}
|
|
411
|
-
return
|
|
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
|
-
|
|
430
|
-
|
|
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
|
-
|
|
434
|
-
|
|
435
|
-
|
|
267
|
+
PgReal,
|
|
268
|
+
PgSmallInt,
|
|
269
|
+
PgTime,
|
|
270
|
+
PgTimestamp,
|
|
271
|
+
PgTimestampString,
|
|
436
272
|
PgUUID
|
|
437
273
|
} from "drizzle-orm/pg-core";
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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 =
|
|
452
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
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(
|
|
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(
|
|
304
|
+
await tx.execute(sql.raw(stmt));
|
|
466
305
|
}
|
|
467
|
-
await tx.execute(
|
|
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 ${
|
|
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 (
|
|
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 (
|
|
325
|
+
} else if (is(encoder, PgTime)) {
|
|
481
326
|
return "time";
|
|
482
|
-
} else if (
|
|
327
|
+
} else if (is(encoder, PgTimestamp) || is(encoder, PgTimestampString)) {
|
|
483
328
|
return "timestamp";
|
|
484
|
-
} else if (
|
|
329
|
+
} else if (is(encoder, PgDate) || is(encoder, PgDateString)) {
|
|
485
330
|
return "date";
|
|
486
|
-
} else if (
|
|
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 ??
|
|
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 !==
|
|
353
|
+
if (maxLifetimeMs !== void 0 && now - conn.createdAt >= maxLifetimeMs) {
|
|
509
354
|
return true;
|
|
510
355
|
}
|
|
511
|
-
if (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(
|
|
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(
|
|
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 !==
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
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
|
-
|
|
631
|
-
|
|
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
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ||
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
934
|
+
return createFromClient(
|
|
935
|
+
clientValue,
|
|
936
|
+
restConfig
|
|
937
|
+
);
|
|
714
938
|
}
|
|
715
|
-
throw new Error(
|
|
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
|
-
|
|
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(
|
|
976
|
+
await db.dialect.migrate(
|
|
977
|
+
migrations,
|
|
978
|
+
db.session,
|
|
979
|
+
migrationConfig
|
|
980
|
+
);
|
|
865
981
|
}
|
|
866
982
|
export {
|
|
867
|
-
|
|
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
|
-
|
|
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
|
};
|