@event-driven-io/dumbo 0.13.0-beta.42 → 0.13.0-beta.44
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/cloudflare.cjs +2256 -86
- package/dist/cloudflare.cjs.map +1 -1
- package/dist/cloudflare.d.cts +1102 -3
- package/dist/cloudflare.d.ts +1102 -3
- package/dist/cloudflare.js +2147 -4
- package/dist/cloudflare.js.map +1 -1
- package/dist/index.cjs +2623 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1694 -2
- package/dist/index.d.ts +1694 -2
- package/dist/index.js +2437 -4
- package/dist/index.js.map +1 -1
- package/dist/pg.cjs +2197 -101
- package/dist/pg.cjs.map +1 -1
- package/dist/pg.d.cts +1059 -5
- package/dist/pg.d.ts +1059 -5
- package/dist/pg.js +2115 -47
- package/dist/pg.js.map +1 -1
- package/dist/postgresql.cjs +1845 -25
- package/dist/postgresql.cjs.map +1 -0
- package/dist/postgresql.d.cts +1037 -3
- package/dist/postgresql.d.ts +1037 -3
- package/dist/postgresql.js +1795 -3
- package/dist/postgresql.js.map +1 -0
- package/dist/sqlite.cjs +2187 -30
- package/dist/sqlite.cjs.map +1 -0
- package/dist/sqlite.d.cts +1103 -3
- package/dist/sqlite.d.ts +1103 -3
- package/dist/sqlite.js +2133 -3
- package/dist/sqlite.js.map +1 -0
- package/dist/sqlite3.cjs +2520 -68
- package/dist/sqlite3.cjs.map +1 -1
- package/dist/sqlite3.d.cts +1102 -4
- package/dist/sqlite3.d.ts +1102 -4
- package/dist/sqlite3.js +2437 -12
- package/dist/sqlite3.js.map +1 -1
- package/package.json +1 -1
- package/dist/core-BPSzA-lq.cjs +0 -3259
- package/dist/core-BPSzA-lq.cjs.map +0 -1
- package/dist/core-BuSVyamf.cjs +0 -480
- package/dist/core-BuSVyamf.cjs.map +0 -1
- package/dist/core-C3xoqqDs.js +0 -403
- package/dist/core-C3xoqqDs.js.map +0 -1
- package/dist/core-CHw8vO17.js +0 -456
- package/dist/core-CHw8vO17.js.map +0 -1
- package/dist/core-CUGYxOEQ.cjs +0 -599
- package/dist/core-CUGYxOEQ.cjs.map +0 -1
- package/dist/core-IV7or0Mj.js +0 -2278
- package/dist/core-IV7or0Mj.js.map +0 -1
- package/dist/index-BJC_v03L.d.ts +0 -192
- package/dist/index-CfH0u2y_.d.cts +0 -1682
- package/dist/index-DP9b7v4e.d.cts +0 -192
- package/dist/index-QWEAqtHF.d.ts +0 -1682
- package/dist/index-qxECrBHo.d.ts +0 -75
- package/dist/index-tS9lpLPz.d.cts +0 -75
- package/dist/postgreSQLMetadata-CCsCJ-eH.cjs +0 -118
- package/dist/postgreSQLMetadata-CCsCJ-eH.cjs.map +0 -1
- package/dist/postgreSQLMetadata-bCBDGz1f.js +0 -65
- package/dist/postgreSQLMetadata-bCBDGz1f.js.map +0 -1
- package/dist/sqliteMetadata-Cc7Z03lm.cjs +0 -46
- package/dist/sqliteMetadata-Cc7Z03lm.cjs.map +0 -1
- package/dist/sqliteMetadata-CvvEc1-v.js +0 -29
- package/dist/sqliteMetadata-CvvEc1-v.js.map +0 -1
package/dist/sqlite3.cjs
CHANGED
|
@@ -1,17 +1,2458 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let uuid = require("uuid");
|
|
30
|
+
let ansis = require("ansis");
|
|
31
|
+
ansis = __toESM(ansis, 1);
|
|
5
32
|
let sqlite3 = require("sqlite3");
|
|
6
|
-
sqlite3 =
|
|
33
|
+
sqlite3 = __toESM(sqlite3, 1);
|
|
7
34
|
let os = require("os");
|
|
8
35
|
let node_async_hooks = require("node:async_hooks");
|
|
9
36
|
|
|
37
|
+
//#region src/core/errors/index.ts
|
|
38
|
+
const isNumber = (val) => typeof val === "number" && val === val;
|
|
39
|
+
const isString = (val) => typeof val === "string";
|
|
40
|
+
var DumboError = class DumboError extends Error {
|
|
41
|
+
static ErrorCode = 500;
|
|
42
|
+
static ErrorType = "DumboError";
|
|
43
|
+
errorCode;
|
|
44
|
+
errorType;
|
|
45
|
+
innerError;
|
|
46
|
+
constructor(options) {
|
|
47
|
+
const errorCode = options && typeof options === "object" && "errorCode" in options ? options.errorCode : isNumber(options) ? options : DumboError.ErrorCode;
|
|
48
|
+
const errorType = options && typeof options === "object" && "errorType" in options ? options.errorType ?? DumboError.ErrorType : DumboError.ErrorType;
|
|
49
|
+
const message = options && typeof options === "object" && "message" in options ? options.message : isString(options) ? options : `Error with status code '${errorCode}' ocurred during DumboError processing`;
|
|
50
|
+
const innerError = options && typeof options === "object" && "innerError" in options ? options.innerError : void 0;
|
|
51
|
+
super(message, { cause: innerError });
|
|
52
|
+
this.errorCode = errorCode;
|
|
53
|
+
this.errorType = errorType;
|
|
54
|
+
this.innerError = innerError;
|
|
55
|
+
Object.setPrototypeOf(this, DumboError.prototype);
|
|
56
|
+
}
|
|
57
|
+
static isInstanceOf(error, options) {
|
|
58
|
+
if (typeof error !== "object" || error === null || !("errorCode" in error) || !isNumber(error.errorCode) || !("errorType" in error) || !isString(error.errorType)) return false;
|
|
59
|
+
if (!options) return true;
|
|
60
|
+
if (options.errorCode !== void 0 && error.errorCode !== options.errorCode) return false;
|
|
61
|
+
if (options.errorType !== void 0 && error.errorType !== options.errorType) return false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var TransientDatabaseError = class TransientDatabaseError extends DumboError {
|
|
66
|
+
static ErrorCode = 503;
|
|
67
|
+
static ErrorType = "TransientDatabaseError";
|
|
68
|
+
constructor(message, innerError) {
|
|
69
|
+
super({
|
|
70
|
+
errorCode: TransientDatabaseError.ErrorCode,
|
|
71
|
+
errorType: TransientDatabaseError.ErrorType,
|
|
72
|
+
message: message ?? `A transient error occurred during database operation. Retrying the operation might succeed.`,
|
|
73
|
+
innerError
|
|
74
|
+
});
|
|
75
|
+
Object.setPrototypeOf(this, TransientDatabaseError.prototype);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var ConnectionError = class ConnectionError extends TransientDatabaseError {
|
|
79
|
+
static ErrorCode = 503;
|
|
80
|
+
static ErrorType = "ConnectionError";
|
|
81
|
+
constructor(message, innerError) {
|
|
82
|
+
super(message ?? `A connection error occurred during database operation.`, innerError);
|
|
83
|
+
this.errorType = ConnectionError.ErrorType;
|
|
84
|
+
Object.setPrototypeOf(this, ConnectionError.prototype);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var SerializationError = class SerializationError extends TransientDatabaseError {
|
|
88
|
+
static ErrorCode = 503;
|
|
89
|
+
static ErrorType = "SerializationError";
|
|
90
|
+
constructor(message, innerError) {
|
|
91
|
+
super(message ?? `A serialization failure occurred. The transaction can be retried.`, innerError);
|
|
92
|
+
this.errorType = SerializationError.ErrorType;
|
|
93
|
+
Object.setPrototypeOf(this, SerializationError.prototype);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var DeadlockError = class DeadlockError extends TransientDatabaseError {
|
|
97
|
+
static ErrorCode = 503;
|
|
98
|
+
static ErrorType = "DeadlockError";
|
|
99
|
+
constructor(message, innerError) {
|
|
100
|
+
super(message ?? `A deadlock was detected. The transaction can be retried.`, innerError);
|
|
101
|
+
this.errorType = DeadlockError.ErrorType;
|
|
102
|
+
Object.setPrototypeOf(this, DeadlockError.prototype);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var LockNotAvailableError = class LockNotAvailableError extends TransientDatabaseError {
|
|
106
|
+
static ErrorCode = 503;
|
|
107
|
+
static ErrorType = "LockNotAvailableError";
|
|
108
|
+
constructor(message, innerError) {
|
|
109
|
+
super(message ?? `The requested lock is not available.`, innerError);
|
|
110
|
+
this.errorType = LockNotAvailableError.ErrorType;
|
|
111
|
+
Object.setPrototypeOf(this, LockNotAvailableError.prototype);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var InsufficientResourcesError = class InsufficientResourcesError extends TransientDatabaseError {
|
|
115
|
+
static ErrorCode = 503;
|
|
116
|
+
static ErrorType = "InsufficientResourcesError";
|
|
117
|
+
constructor(message, innerError) {
|
|
118
|
+
super(message ?? `Insufficient resources to complete the database operation (e.g. disk full, out of memory, too many connections).`, innerError);
|
|
119
|
+
this.errorType = InsufficientResourcesError.ErrorType;
|
|
120
|
+
Object.setPrototypeOf(this, InsufficientResourcesError.prototype);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var SystemError = class SystemError extends TransientDatabaseError {
|
|
124
|
+
static ErrorCode = 503;
|
|
125
|
+
static ErrorType = "SystemError";
|
|
126
|
+
constructor(message, innerError) {
|
|
127
|
+
super(message ?? `A system-level error occurred (e.g. I/O error).`, innerError);
|
|
128
|
+
this.errorType = SystemError.ErrorType;
|
|
129
|
+
Object.setPrototypeOf(this, SystemError.prototype);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var IntegrityConstraintViolationError = class IntegrityConstraintViolationError extends DumboError {
|
|
133
|
+
static ErrorCode = 409;
|
|
134
|
+
static ErrorType = "IntegrityConstraintViolationError";
|
|
135
|
+
constructor(message, innerError) {
|
|
136
|
+
super({
|
|
137
|
+
errorCode: IntegrityConstraintViolationError.ErrorCode,
|
|
138
|
+
errorType: IntegrityConstraintViolationError.ErrorType,
|
|
139
|
+
message: message ?? `An integrity constraint violation occurred!`,
|
|
140
|
+
innerError
|
|
141
|
+
});
|
|
142
|
+
Object.setPrototypeOf(this, IntegrityConstraintViolationError.prototype);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var UniqueConstraintError = class UniqueConstraintError extends IntegrityConstraintViolationError {
|
|
146
|
+
static ErrorCode = 409;
|
|
147
|
+
static ErrorType = "UniqueConstraintError";
|
|
148
|
+
constructor(message, innerError) {
|
|
149
|
+
super(message ?? `Unique constraint violation occurred!`, innerError);
|
|
150
|
+
this.errorType = UniqueConstraintError.ErrorType;
|
|
151
|
+
Object.setPrototypeOf(this, UniqueConstraintError.prototype);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var ForeignKeyViolationError = class ForeignKeyViolationError extends IntegrityConstraintViolationError {
|
|
155
|
+
static ErrorCode = 409;
|
|
156
|
+
static ErrorType = "ForeignKeyViolationError";
|
|
157
|
+
constructor(message, innerError) {
|
|
158
|
+
super(message ?? `Foreign key constraint violation occurred!`, innerError);
|
|
159
|
+
this.errorType = ForeignKeyViolationError.ErrorType;
|
|
160
|
+
Object.setPrototypeOf(this, ForeignKeyViolationError.prototype);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var NotNullViolationError = class NotNullViolationError extends IntegrityConstraintViolationError {
|
|
164
|
+
static ErrorCode = 409;
|
|
165
|
+
static ErrorType = "NotNullViolationError";
|
|
166
|
+
constructor(message, innerError) {
|
|
167
|
+
super(message ?? `NOT NULL constraint violation occurred!`, innerError);
|
|
168
|
+
this.errorType = NotNullViolationError.ErrorType;
|
|
169
|
+
Object.setPrototypeOf(this, NotNullViolationError.prototype);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
var CheckViolationError = class CheckViolationError extends IntegrityConstraintViolationError {
|
|
173
|
+
static ErrorCode = 409;
|
|
174
|
+
static ErrorType = "CheckViolationError";
|
|
175
|
+
constructor(message, innerError) {
|
|
176
|
+
super(message ?? `CHECK constraint violation occurred!`, innerError);
|
|
177
|
+
this.errorType = CheckViolationError.ErrorType;
|
|
178
|
+
Object.setPrototypeOf(this, CheckViolationError.prototype);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
var DataError = class DataError extends DumboError {
|
|
182
|
+
static ErrorCode = 400;
|
|
183
|
+
static ErrorType = "DataError";
|
|
184
|
+
constructor(message, innerError) {
|
|
185
|
+
super({
|
|
186
|
+
errorCode: DataError.ErrorCode,
|
|
187
|
+
errorType: DataError.ErrorType,
|
|
188
|
+
message: message ?? `A data error occurred (e.g. invalid value, type mismatch).`,
|
|
189
|
+
innerError
|
|
190
|
+
});
|
|
191
|
+
Object.setPrototypeOf(this, DataError.prototype);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var InvalidOperationError = class InvalidOperationError extends DumboError {
|
|
195
|
+
static ErrorCode = 400;
|
|
196
|
+
static ErrorType = "InvalidOperationError";
|
|
197
|
+
constructor(message, innerError) {
|
|
198
|
+
super({
|
|
199
|
+
errorCode: InvalidOperationError.ErrorCode,
|
|
200
|
+
errorType: InvalidOperationError.ErrorType,
|
|
201
|
+
message: message ?? `Invalid operation (e.g. syntax error, insufficient privileges, undefined table).`,
|
|
202
|
+
innerError
|
|
203
|
+
});
|
|
204
|
+
Object.setPrototypeOf(this, InvalidOperationError.prototype);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/core/execute/execute.ts
|
|
210
|
+
const mapSQLQueryResult = (result, mapping) => {
|
|
211
|
+
if (typeof result !== "object" || result === null) return result;
|
|
212
|
+
const mappedResult = { ...result };
|
|
213
|
+
for (const column of Object.keys(mapping)) if (column in mappedResult) mappedResult[column] = mapping[column](mappedResult[column]);
|
|
214
|
+
return mappedResult;
|
|
215
|
+
};
|
|
216
|
+
var BatchCommandNoChangesError = class BatchCommandNoChangesError extends DumboError {
|
|
217
|
+
static ErrorCode = 409;
|
|
218
|
+
static ErrorType = "BatchCommandNoChangesError";
|
|
219
|
+
statementIndex;
|
|
220
|
+
constructor(statementIndex) {
|
|
221
|
+
super({
|
|
222
|
+
errorCode: BatchCommandNoChangesError.ErrorCode,
|
|
223
|
+
errorType: BatchCommandNoChangesError.ErrorType,
|
|
224
|
+
message: `Batch command at index ${statementIndex} affected no rows`
|
|
225
|
+
});
|
|
226
|
+
this.name = "BatchCommandNoChangesError";
|
|
227
|
+
this.statementIndex = statementIndex;
|
|
228
|
+
Object.setPrototypeOf(this, BatchCommandNoChangesError.prototype);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const sqlExecutor = (sqlExecutor, options) => ({
|
|
232
|
+
query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), options),
|
|
233
|
+
batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), options),
|
|
234
|
+
command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), options),
|
|
235
|
+
batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), options)
|
|
236
|
+
});
|
|
237
|
+
const sqlExecutorInNewConnection = (options) => ({
|
|
238
|
+
query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), options),
|
|
239
|
+
batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
|
|
240
|
+
command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), options),
|
|
241
|
+
batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
|
|
242
|
+
});
|
|
243
|
+
const sqlExecutorInAmbientConnection = (options) => ({
|
|
244
|
+
query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), options),
|
|
245
|
+
batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
|
|
246
|
+
command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), options),
|
|
247
|
+
batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
|
|
248
|
+
});
|
|
249
|
+
const executeInNewDbClient = async (handle, options) => {
|
|
250
|
+
const { connect, close } = options;
|
|
251
|
+
const client = await connect();
|
|
252
|
+
try {
|
|
253
|
+
return await handle(client);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (close) await close(client, error);
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const executeInNewConnection = async (handle, options) => {
|
|
260
|
+
const connection = await options.connection();
|
|
261
|
+
try {
|
|
262
|
+
return await handle(connection);
|
|
263
|
+
} finally {
|
|
264
|
+
await connection.close();
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const executeInAmbientConnection = async (handle, options) => {
|
|
268
|
+
const connection = await options.connection();
|
|
269
|
+
try {
|
|
270
|
+
return await handle(connection);
|
|
271
|
+
} finally {}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/core/connections/transaction.ts
|
|
276
|
+
const transactionNestingCounter = () => {
|
|
277
|
+
let transactionLevel = 0;
|
|
278
|
+
return {
|
|
279
|
+
reset: () => {
|
|
280
|
+
transactionLevel = 0;
|
|
281
|
+
},
|
|
282
|
+
increment: () => {
|
|
283
|
+
transactionLevel++;
|
|
284
|
+
},
|
|
285
|
+
decrement: () => {
|
|
286
|
+
transactionLevel--;
|
|
287
|
+
if (transactionLevel < 0) throw new Error("Transaction level is out of bounds");
|
|
288
|
+
},
|
|
289
|
+
get level() {
|
|
290
|
+
return transactionLevel;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
const databaseTransaction = (backend, options) => {
|
|
295
|
+
const allowNestedTransactions = options?.allowNestedTransactions ?? false;
|
|
296
|
+
const useSavepoints = options?.useSavepoints ?? false;
|
|
297
|
+
const counter = transactionNestingCounter();
|
|
298
|
+
let hasBegun = false;
|
|
299
|
+
return {
|
|
300
|
+
begin: async () => {
|
|
301
|
+
if (!allowNestedTransactions && hasBegun) throw new InvalidOperationError("Cannot start a nested transaction: allowNestedTransactions is false. Set transactionOptions: { allowNestedTransactions: true } on your pool or connection.");
|
|
302
|
+
if (allowNestedTransactions) {
|
|
303
|
+
if (counter.level >= 1) {
|
|
304
|
+
counter.increment();
|
|
305
|
+
if (useSavepoints && backend.savepoint) await backend.savepoint(counter.level);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
counter.increment();
|
|
309
|
+
}
|
|
310
|
+
hasBegun = true;
|
|
311
|
+
await backend.begin();
|
|
312
|
+
},
|
|
313
|
+
commit: async () => {
|
|
314
|
+
if (allowNestedTransactions && counter.level > 1) {
|
|
315
|
+
if (useSavepoints && backend.releaseSavepoint) await backend.releaseSavepoint(counter.level);
|
|
316
|
+
counter.decrement();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (allowNestedTransactions) counter.reset();
|
|
320
|
+
hasBegun = false;
|
|
321
|
+
await backend.commit();
|
|
322
|
+
},
|
|
323
|
+
rollback: async (error) => {
|
|
324
|
+
if (allowNestedTransactions && counter.level > 1) {
|
|
325
|
+
if (useSavepoints && backend.rollbackToSavepoint) await backend.rollbackToSavepoint(counter.level);
|
|
326
|
+
counter.decrement();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (allowNestedTransactions) counter.reset();
|
|
330
|
+
hasBegun = false;
|
|
331
|
+
await backend.rollback(error);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
const toTransactionResult = (transactionResult) => transactionResult !== void 0 && transactionResult !== null && typeof transactionResult === "object" && "success" in transactionResult ? transactionResult : {
|
|
336
|
+
success: true,
|
|
337
|
+
result: transactionResult
|
|
338
|
+
};
|
|
339
|
+
const executeInTransaction = async (transaction, handle) => {
|
|
340
|
+
await transaction.begin();
|
|
341
|
+
try {
|
|
342
|
+
const { success, result } = toTransactionResult(await handle(transaction));
|
|
343
|
+
if (success) await transaction.commit();
|
|
344
|
+
else await transaction.rollback();
|
|
345
|
+
return result;
|
|
346
|
+
} catch (e) {
|
|
347
|
+
await transaction.rollback();
|
|
348
|
+
throw e;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
const transactionFactoryWithDbClient = (connect, initTransaction) => {
|
|
352
|
+
let currentTransaction = void 0;
|
|
353
|
+
const getOrInitCurrentTransaction = (options) => currentTransaction ?? (currentTransaction = initTransaction(connect(), {
|
|
354
|
+
close: () => {
|
|
355
|
+
currentTransaction = void 0;
|
|
356
|
+
return Promise.resolve();
|
|
357
|
+
},
|
|
358
|
+
...options ?? {}
|
|
359
|
+
}));
|
|
360
|
+
return {
|
|
361
|
+
transaction: getOrInitCurrentTransaction,
|
|
362
|
+
withTransaction: (handle, options) => executeInTransaction(getOrInitCurrentTransaction(options), handle)
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
const wrapInConnectionClosure = async (connection, handle) => {
|
|
366
|
+
try {
|
|
367
|
+
return await handle();
|
|
368
|
+
} finally {
|
|
369
|
+
await connection.close();
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
const transactionFactoryWithNewConnection = (connect) => ({
|
|
373
|
+
transaction: (options) => {
|
|
374
|
+
const connection = connect();
|
|
375
|
+
const transaction = connection.transaction(options);
|
|
376
|
+
return {
|
|
377
|
+
...transaction,
|
|
378
|
+
commit: () => wrapInConnectionClosure(connection, () => transaction.commit()),
|
|
379
|
+
rollback: () => wrapInConnectionClosure(connection, () => transaction.rollback())
|
|
380
|
+
};
|
|
381
|
+
},
|
|
382
|
+
withTransaction: (handle, options) => {
|
|
383
|
+
const connection = connect();
|
|
384
|
+
const withTx = connection.withTransaction;
|
|
385
|
+
return wrapInConnectionClosure(connection, () => withTx(handle, options));
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close) => {
|
|
389
|
+
close ??= () => Promise.resolve();
|
|
390
|
+
return {
|
|
391
|
+
transaction: (options) => {
|
|
392
|
+
let conn = null;
|
|
393
|
+
let innerTx = null;
|
|
394
|
+
let connectingPromise = null;
|
|
395
|
+
const ensureConnection = async () => {
|
|
396
|
+
if (conn) return innerTx;
|
|
397
|
+
if (!connectingPromise) connectingPromise = (async () => {
|
|
398
|
+
conn = await connect();
|
|
399
|
+
innerTx = conn.transaction(options);
|
|
400
|
+
})();
|
|
401
|
+
await connectingPromise;
|
|
402
|
+
return innerTx;
|
|
403
|
+
};
|
|
404
|
+
return {
|
|
405
|
+
driverType,
|
|
406
|
+
get connection() {
|
|
407
|
+
if (!conn) throw new Error("Transaction not started - call begin() first");
|
|
408
|
+
return conn;
|
|
409
|
+
},
|
|
410
|
+
execute: {
|
|
411
|
+
query: async (sql, queryOptions) => {
|
|
412
|
+
return (await ensureConnection()).execute.query(sql, queryOptions);
|
|
413
|
+
},
|
|
414
|
+
batchQuery: async (sqls, queryOptions) => {
|
|
415
|
+
return (await ensureConnection()).execute.batchQuery(sqls, queryOptions);
|
|
416
|
+
},
|
|
417
|
+
command: async (sql, commandOptions) => {
|
|
418
|
+
return (await ensureConnection()).execute.command(sql, commandOptions);
|
|
419
|
+
},
|
|
420
|
+
batchCommand: async (sqls, commandOptions) => {
|
|
421
|
+
return (await ensureConnection()).execute.batchCommand(sqls, commandOptions);
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
begin: async () => {
|
|
425
|
+
return (await ensureConnection()).begin();
|
|
426
|
+
},
|
|
427
|
+
commit: async () => {
|
|
428
|
+
if (!innerTx) throw new Error("Transaction not started");
|
|
429
|
+
try {
|
|
430
|
+
return await innerTx.commit();
|
|
431
|
+
} finally {
|
|
432
|
+
if (conn) await close(conn);
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
rollback: async (error) => {
|
|
436
|
+
if (!innerTx) {
|
|
437
|
+
if (conn) await close(conn);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
return await innerTx.rollback(error);
|
|
442
|
+
} finally {
|
|
443
|
+
if (conn) await close(conn);
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
_transactionOptions: void 0
|
|
447
|
+
};
|
|
448
|
+
},
|
|
449
|
+
withTransaction: async (handle, options) => {
|
|
450
|
+
const conn = await connect();
|
|
451
|
+
try {
|
|
452
|
+
const withTx = conn.withTransaction;
|
|
453
|
+
return await withTx(handle, options);
|
|
454
|
+
} finally {
|
|
455
|
+
await close(conn);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/core/connections/connection.ts
|
|
463
|
+
const createAmbientConnection = (options) => {
|
|
464
|
+
const { driverType, client, executor, initTransaction, serializer } = options;
|
|
465
|
+
const clientPromise = Promise.resolve(client);
|
|
466
|
+
const closePromise = Promise.resolve();
|
|
467
|
+
const open = () => clientPromise;
|
|
468
|
+
const close = () => closePromise;
|
|
469
|
+
const typedConnection = {
|
|
470
|
+
driverType,
|
|
471
|
+
open,
|
|
472
|
+
close,
|
|
473
|
+
...transactionFactoryWithDbClient(open, initTransaction(() => typedConnection)),
|
|
474
|
+
execute: sqlExecutor(executor({ serializer }), { connect: open }),
|
|
475
|
+
_transactionType: void 0
|
|
476
|
+
};
|
|
477
|
+
return typedConnection;
|
|
478
|
+
};
|
|
479
|
+
const createConnection = (options) => {
|
|
480
|
+
const { driverType, connect, close, initTransaction, executor, serializer } = options;
|
|
481
|
+
let client = null;
|
|
482
|
+
let connectPromise = null;
|
|
483
|
+
const getClient = async () => {
|
|
484
|
+
if (client) return client;
|
|
485
|
+
if (!connectPromise) connectPromise = connect().then((c) => {
|
|
486
|
+
client = c;
|
|
487
|
+
return c;
|
|
488
|
+
});
|
|
489
|
+
return connectPromise;
|
|
490
|
+
};
|
|
491
|
+
const typedConnection = {
|
|
492
|
+
driverType,
|
|
493
|
+
open: getClient,
|
|
494
|
+
close: () => client ? close(client) : Promise.resolve(),
|
|
495
|
+
...transactionFactoryWithDbClient(getClient, initTransaction(() => typedConnection)),
|
|
496
|
+
execute: sqlExecutor(executor({ serializer }), { connect: getClient }),
|
|
497
|
+
_transactionType: void 0
|
|
498
|
+
};
|
|
499
|
+
return typedConnection;
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/core/taskProcessing/taskProcessor.ts
|
|
504
|
+
var TaskProcessor = class {
|
|
505
|
+
queue = [];
|
|
506
|
+
isProcessing = false;
|
|
507
|
+
activeTasks = 0;
|
|
508
|
+
activeGroups = /* @__PURE__ */ new Set();
|
|
509
|
+
options;
|
|
510
|
+
stopped = false;
|
|
511
|
+
constructor(options) {
|
|
512
|
+
this.options = options;
|
|
513
|
+
}
|
|
514
|
+
enqueue(task, options) {
|
|
515
|
+
if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
|
|
516
|
+
if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
|
|
517
|
+
return this.schedule(task, options);
|
|
518
|
+
}
|
|
519
|
+
waitForEndOfProcessing() {
|
|
520
|
+
return this.schedule(({ ack }) => Promise.resolve(ack()));
|
|
521
|
+
}
|
|
522
|
+
async stop(options) {
|
|
523
|
+
if (this.stopped) return;
|
|
524
|
+
this.stopped = true;
|
|
525
|
+
this.queue.length = 0;
|
|
526
|
+
this.activeGroups.clear();
|
|
527
|
+
if (!options?.force) await this.waitForEndOfProcessing();
|
|
528
|
+
}
|
|
529
|
+
schedule(task, options) {
|
|
530
|
+
return promiseWithDeadline((resolve, reject) => {
|
|
531
|
+
const taskWithContext = () => {
|
|
532
|
+
return new Promise((resolveTask, failTask) => {
|
|
533
|
+
task({ ack: resolveTask }).then(resolve).catch((err) => {
|
|
534
|
+
failTask(err);
|
|
535
|
+
reject(err);
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
};
|
|
539
|
+
this.queue.push({
|
|
540
|
+
task: taskWithContext,
|
|
541
|
+
options
|
|
542
|
+
});
|
|
543
|
+
if (!this.isProcessing) this.ensureProcessing();
|
|
544
|
+
}, { deadline: this.options.maxTaskIdleTime });
|
|
545
|
+
}
|
|
546
|
+
ensureProcessing() {
|
|
547
|
+
if (this.isProcessing) return;
|
|
548
|
+
this.isProcessing = true;
|
|
549
|
+
this.processQueue();
|
|
550
|
+
}
|
|
551
|
+
processQueue() {
|
|
552
|
+
try {
|
|
553
|
+
while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
|
|
554
|
+
const item = this.takeFirstAvailableItem();
|
|
555
|
+
if (item === null) return;
|
|
556
|
+
const groupId = item.options?.taskGroupId;
|
|
557
|
+
if (groupId) this.activeGroups.add(groupId);
|
|
558
|
+
this.activeTasks++;
|
|
559
|
+
this.executeItem(item);
|
|
560
|
+
}
|
|
561
|
+
} catch (error) {
|
|
562
|
+
console.error(error);
|
|
563
|
+
throw error;
|
|
564
|
+
} finally {
|
|
565
|
+
this.isProcessing = false;
|
|
566
|
+
if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
async executeItem({ task, options }) {
|
|
570
|
+
try {
|
|
571
|
+
await task();
|
|
572
|
+
} finally {
|
|
573
|
+
this.activeTasks--;
|
|
574
|
+
if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
|
|
575
|
+
this.ensureProcessing();
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
takeFirstAvailableItem = () => {
|
|
579
|
+
const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
|
|
580
|
+
if (taskIndex === -1) return null;
|
|
581
|
+
const [item] = this.queue.splice(taskIndex, 1);
|
|
582
|
+
return item ?? null;
|
|
583
|
+
};
|
|
584
|
+
hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
|
|
585
|
+
};
|
|
586
|
+
const DEFAULT_PROMISE_DEADLINE = 2147483647;
|
|
587
|
+
const promiseWithDeadline = (executor, options) => {
|
|
588
|
+
return new Promise((resolve, reject) => {
|
|
589
|
+
let taskStarted = false;
|
|
590
|
+
let timeoutId = null;
|
|
591
|
+
const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;
|
|
592
|
+
timeoutId = setTimeout(() => {
|
|
593
|
+
if (!taskStarted) reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
|
|
594
|
+
}, deadline);
|
|
595
|
+
timeoutId.unref();
|
|
596
|
+
executor((value) => {
|
|
597
|
+
taskStarted = true;
|
|
598
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
599
|
+
timeoutId = null;
|
|
600
|
+
resolve(value);
|
|
601
|
+
}, (reason) => {
|
|
602
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
603
|
+
timeoutId = null;
|
|
604
|
+
reject(reason);
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region src/core/taskProcessing/executionGuards.ts
|
|
611
|
+
const guardBoundedAccess = (getResource, options) => {
|
|
612
|
+
let isStopped = false;
|
|
613
|
+
const taskProcessor = new TaskProcessor({
|
|
614
|
+
maxActiveTasks: options.maxResources,
|
|
615
|
+
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
616
|
+
});
|
|
617
|
+
const resourcePool = [];
|
|
618
|
+
const allResources = /* @__PURE__ */ new Set();
|
|
619
|
+
const ackCallbacks = /* @__PURE__ */ new Map();
|
|
620
|
+
const acquire = async () => taskProcessor.enqueue(async ({ ack }) => {
|
|
621
|
+
try {
|
|
622
|
+
let resource;
|
|
623
|
+
if (options.reuseResources) resource = resourcePool.pop();
|
|
624
|
+
if (!resource) {
|
|
625
|
+
resource = await getResource();
|
|
626
|
+
allResources.add(resource);
|
|
627
|
+
}
|
|
628
|
+
ackCallbacks.set(resource, ack);
|
|
629
|
+
return resource;
|
|
630
|
+
} catch (e) {
|
|
631
|
+
ack();
|
|
632
|
+
throw e;
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
const release = (resource) => {
|
|
636
|
+
const ack = ackCallbacks.get(resource);
|
|
637
|
+
if (ack) {
|
|
638
|
+
ackCallbacks.delete(resource);
|
|
639
|
+
if (options.reuseResources) resourcePool.push(resource);
|
|
640
|
+
ack();
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const execute = async (operation) => {
|
|
644
|
+
const resource = await acquire();
|
|
645
|
+
try {
|
|
646
|
+
return await operation(resource);
|
|
647
|
+
} finally {
|
|
648
|
+
release(resource);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
return {
|
|
652
|
+
acquire,
|
|
653
|
+
release,
|
|
654
|
+
execute,
|
|
655
|
+
waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
|
|
656
|
+
stop: async (stopOptions) => {
|
|
657
|
+
if (isStopped) return;
|
|
658
|
+
isStopped = true;
|
|
659
|
+
if (options?.closeResource) {
|
|
660
|
+
const resources = [...allResources];
|
|
661
|
+
allResources.clear();
|
|
662
|
+
resourcePool.length = 0;
|
|
663
|
+
await Promise.all(resources.map(async (resource) => await options.closeResource(resource)));
|
|
664
|
+
}
|
|
665
|
+
await taskProcessor.stop(stopOptions);
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
};
|
|
669
|
+
const guardInitializedOnce = (initialize, options) => {
|
|
670
|
+
let initPromise = null;
|
|
671
|
+
const taskProcessor = new TaskProcessor({
|
|
672
|
+
maxActiveTasks: 1,
|
|
673
|
+
maxQueueSize: options?.maxQueueSize ?? 1e3
|
|
674
|
+
});
|
|
675
|
+
const ensureInitialized = async (retryCount = 0) => {
|
|
676
|
+
if (initPromise !== null) return initPromise;
|
|
677
|
+
return taskProcessor.enqueue(async ({ ack }) => {
|
|
678
|
+
if (initPromise !== null) {
|
|
679
|
+
ack();
|
|
680
|
+
return initPromise;
|
|
681
|
+
}
|
|
682
|
+
try {
|
|
683
|
+
const promise = initialize();
|
|
684
|
+
initPromise = promise;
|
|
685
|
+
const result = await promise;
|
|
686
|
+
ack();
|
|
687
|
+
return result;
|
|
688
|
+
} catch (error) {
|
|
689
|
+
initPromise = null;
|
|
690
|
+
ack();
|
|
691
|
+
if (retryCount < (options?.maxRetries ?? 3)) return ensureInitialized(retryCount + 1);
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
}, { taskGroupId: (0, uuid.v7)() });
|
|
695
|
+
};
|
|
696
|
+
return {
|
|
697
|
+
ensureInitialized,
|
|
698
|
+
reset: () => {
|
|
699
|
+
initPromise = null;
|
|
700
|
+
},
|
|
701
|
+
stop: (options) => taskProcessor.stop(options)
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
//#endregion
|
|
706
|
+
//#region src/core/connections/pool.ts
|
|
707
|
+
const wrapPooledConnection = (conn, onClose) => ({
|
|
708
|
+
...conn,
|
|
709
|
+
close: onClose
|
|
710
|
+
});
|
|
711
|
+
const createAmbientConnectionPool = (options) => {
|
|
712
|
+
const { driverType, connection } = options;
|
|
713
|
+
return createConnectionPool({
|
|
714
|
+
driverType,
|
|
715
|
+
getConnection: () => connection,
|
|
716
|
+
execute: connection.execute,
|
|
717
|
+
transaction: (options) => connection.transaction(options),
|
|
718
|
+
withConnection: (handle, _options) => handle(connection),
|
|
719
|
+
withTransaction: (handle, options) => {
|
|
720
|
+
const withTx = connection.withTransaction;
|
|
721
|
+
return withTx(handle, options);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
};
|
|
725
|
+
const createSingletonConnectionPool = (options) => {
|
|
726
|
+
const { driverType, getConnection } = options;
|
|
727
|
+
let connectionPromise = null;
|
|
728
|
+
let closed = false;
|
|
729
|
+
const activeOperations = /* @__PURE__ */ new Set();
|
|
730
|
+
const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
|
|
731
|
+
const run = async (operation) => {
|
|
732
|
+
if (closed) throw closedError();
|
|
733
|
+
const activeOperation = operation();
|
|
734
|
+
activeOperations.add(activeOperation);
|
|
735
|
+
try {
|
|
736
|
+
return await activeOperation;
|
|
737
|
+
} finally {
|
|
738
|
+
activeOperations.delete(activeOperation);
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
const getExistingOrNewConnection = () => {
|
|
742
|
+
if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
|
|
743
|
+
return connectionPromise;
|
|
744
|
+
};
|
|
745
|
+
const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
|
|
746
|
+
return {
|
|
747
|
+
driverType,
|
|
748
|
+
connection: () => run(() => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve()))),
|
|
749
|
+
execute: (() => {
|
|
750
|
+
const ambientExecutor = sqlExecutorInAmbientConnection({
|
|
751
|
+
driverType,
|
|
752
|
+
connection: getExistingOrNewConnection
|
|
753
|
+
});
|
|
754
|
+
return {
|
|
755
|
+
query: (sql, opts) => run(() => ambientExecutor.query(sql, opts)),
|
|
756
|
+
batchQuery: (sqls, opts) => run(() => ambientExecutor.batchQuery(sqls, opts)),
|
|
757
|
+
command: (sql, opts) => run(() => ambientExecutor.command(sql, opts)),
|
|
758
|
+
batchCommand: (sqls, opts) => run(() => ambientExecutor.batchCommand(sqls, opts))
|
|
759
|
+
};
|
|
760
|
+
})(),
|
|
761
|
+
withConnection: (handle, _options) => run(() => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection })),
|
|
762
|
+
transaction: (transactionOptions) => {
|
|
763
|
+
if (closed) throw closedError();
|
|
764
|
+
return innerTransactionFactory.transaction(transactionOptions);
|
|
765
|
+
},
|
|
766
|
+
withTransaction: (handle, transactionOptions) => run(() => innerTransactionFactory.withTransaction(handle, transactionOptions)),
|
|
767
|
+
close: async (closeOptions) => {
|
|
768
|
+
if (closed) return;
|
|
769
|
+
closed = true;
|
|
770
|
+
if (!closeOptions?.force) await Promise.allSettled([...activeOperations]);
|
|
771
|
+
if (!connectionPromise) return;
|
|
772
|
+
const connection = await connectionPromise;
|
|
773
|
+
connectionPromise = null;
|
|
774
|
+
await connection.close();
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
};
|
|
778
|
+
const createBoundedConnectionPool = (options) => {
|
|
779
|
+
const { driverType, maxConnections } = options;
|
|
780
|
+
const allConnections = /* @__PURE__ */ new Set();
|
|
781
|
+
const getTrackedConnection = async () => {
|
|
782
|
+
const connection = await options.getConnection();
|
|
783
|
+
allConnections.add(connection);
|
|
784
|
+
return connection;
|
|
785
|
+
};
|
|
786
|
+
const guardMaxConnections = guardBoundedAccess(getTrackedConnection, {
|
|
787
|
+
maxResources: maxConnections,
|
|
788
|
+
reuseResources: true
|
|
789
|
+
});
|
|
790
|
+
let closed = false;
|
|
791
|
+
const closedError = () => /* @__PURE__ */ new Error("Bounded connection pool has been closed");
|
|
792
|
+
const ensureOpen = () => {
|
|
793
|
+
if (closed) throw closedError();
|
|
794
|
+
};
|
|
795
|
+
const closeAllConnections = async () => {
|
|
796
|
+
const connections = [...allConnections];
|
|
797
|
+
allConnections.clear();
|
|
798
|
+
await Promise.all(connections.map((conn) => conn.close()));
|
|
799
|
+
};
|
|
800
|
+
const executeWithPooling = async (operation) => {
|
|
801
|
+
ensureOpen();
|
|
802
|
+
const conn = await guardMaxConnections.acquire();
|
|
803
|
+
try {
|
|
804
|
+
return await operation(conn);
|
|
805
|
+
} finally {
|
|
806
|
+
guardMaxConnections.release(conn);
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
return {
|
|
810
|
+
driverType,
|
|
811
|
+
connection: async () => {
|
|
812
|
+
ensureOpen();
|
|
813
|
+
const conn = await guardMaxConnections.acquire();
|
|
814
|
+
return wrapPooledConnection(conn, () => Promise.resolve(guardMaxConnections.release(conn)));
|
|
815
|
+
},
|
|
816
|
+
execute: {
|
|
817
|
+
query: (sql, opts) => executeWithPooling((c) => c.execute.query(sql, opts)),
|
|
818
|
+
batchQuery: (sqls, opts) => executeWithPooling((c) => c.execute.batchQuery(sqls, opts)),
|
|
819
|
+
command: (sql, opts) => executeWithPooling((c) => c.execute.command(sql, opts)),
|
|
820
|
+
batchCommand: (sqls, opts) => executeWithPooling((c) => c.execute.batchCommand(sqls, opts))
|
|
821
|
+
},
|
|
822
|
+
withConnection: executeWithPooling,
|
|
823
|
+
transaction: (transactionOptions) => {
|
|
824
|
+
ensureOpen();
|
|
825
|
+
return transactionFactoryWithAsyncAmbientConnection(driverType, guardMaxConnections.acquire, guardMaxConnections.release).transaction(transactionOptions);
|
|
826
|
+
},
|
|
827
|
+
withTransaction: (handle, transactionOptions) => executeWithPooling((conn) => {
|
|
828
|
+
const withTx = conn.withTransaction;
|
|
829
|
+
return withTx(handle, transactionOptions);
|
|
830
|
+
}),
|
|
831
|
+
close: async (closeOptions) => {
|
|
832
|
+
if (closed) return;
|
|
833
|
+
closed = true;
|
|
834
|
+
if (!closeOptions?.force) await guardMaxConnections.waitForIdle();
|
|
835
|
+
await guardMaxConnections.stop({ force: true });
|
|
836
|
+
await closeAllConnections();
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
};
|
|
840
|
+
const createAlwaysNewConnectionPool = (options) => {
|
|
841
|
+
const { driverType, getConnection, connectionOptions } = options;
|
|
842
|
+
return createConnectionPool({
|
|
843
|
+
driverType,
|
|
844
|
+
getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
|
|
845
|
+
});
|
|
846
|
+
};
|
|
847
|
+
const createConnectionPool = (pool) => {
|
|
848
|
+
const { driverType, getConnection } = pool;
|
|
849
|
+
const connection = "connection" in pool ? pool.connection : () => Promise.resolve(getConnection());
|
|
850
|
+
return {
|
|
851
|
+
driverType,
|
|
852
|
+
connection,
|
|
853
|
+
withConnection: "withConnection" in pool ? pool.withConnection : (handle, _options) => executeInNewConnection(handle, { connection }),
|
|
854
|
+
close: "close" in pool ? pool.close : () => Promise.resolve(),
|
|
855
|
+
execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
|
|
856
|
+
driverType,
|
|
857
|
+
connection
|
|
858
|
+
}),
|
|
859
|
+
..."transaction" in pool && "withTransaction" in pool ? {
|
|
860
|
+
transaction: pool.transaction,
|
|
861
|
+
withTransaction: pool.withTransaction
|
|
862
|
+
} : transactionFactoryWithNewConnection(getConnection)
|
|
863
|
+
};
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
//#endregion
|
|
867
|
+
//#region src/core/drivers/databaseDriver.ts
|
|
868
|
+
const canHandleDriverWithConnectionString = (driver, tryParseConnectionString) => (options) => {
|
|
869
|
+
if ("driverType" in options) return options.driverType === driver;
|
|
870
|
+
if ("connectionString" in options && typeof options.connectionString === "string") return tryParseConnectionString(options.connectionString) !== null;
|
|
871
|
+
return false;
|
|
872
|
+
};
|
|
873
|
+
const DumboDatabaseDriverRegistry = () => {
|
|
874
|
+
const drivers = /* @__PURE__ */ new Map();
|
|
875
|
+
const register = (driverType, plugin) => {
|
|
876
|
+
const entry = drivers.get(driverType);
|
|
877
|
+
if (entry && (typeof entry !== "function" || typeof plugin === "function")) return;
|
|
878
|
+
drivers.set(driverType, plugin);
|
|
879
|
+
};
|
|
880
|
+
const getDriver = (options) => options.driverType ? drivers.get(options.driverType) : [...drivers.values()].find((d) => typeof d !== "function" && d.canHandle(options));
|
|
881
|
+
const tryResolve = async (options) => {
|
|
882
|
+
const driver = getDriver(options);
|
|
883
|
+
if (!driver) return null;
|
|
884
|
+
if (typeof driver !== "function") return driver;
|
|
885
|
+
const plugin = await driver();
|
|
886
|
+
register(plugin.driverType, plugin);
|
|
887
|
+
return plugin;
|
|
888
|
+
};
|
|
889
|
+
const tryGet = (options) => {
|
|
890
|
+
const driver = getDriver(options);
|
|
891
|
+
return driver && typeof driver !== "function" ? driver : null;
|
|
892
|
+
};
|
|
893
|
+
const has = (driverType) => drivers.has(driverType);
|
|
894
|
+
return {
|
|
895
|
+
register,
|
|
896
|
+
tryResolve,
|
|
897
|
+
tryGet,
|
|
898
|
+
has,
|
|
899
|
+
get databaseDriverTypes() {
|
|
900
|
+
return Array.from(drivers.keys());
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
};
|
|
904
|
+
const dumboDatabaseDriverRegistry = globalThis.dumboDatabaseDriverRegistry = globalThis.dumboDatabaseDriverRegistry ?? DumboDatabaseDriverRegistry();
|
|
905
|
+
|
|
906
|
+
//#endregion
|
|
907
|
+
//#region src/core/query/selectors.ts
|
|
908
|
+
const single = async (getResult) => {
|
|
909
|
+
const result = await getResult;
|
|
910
|
+
if (result.rows.length === 0) throw new Error("Query didn't return any result");
|
|
911
|
+
if (result.rows.length > 1) throw new Error("Query had more than one result");
|
|
912
|
+
return result.rows[0];
|
|
913
|
+
};
|
|
914
|
+
const exists = async (getResult) => {
|
|
915
|
+
const result = await single(getResult);
|
|
916
|
+
return result.exists === true || result.exists === 1;
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
//#endregion
|
|
920
|
+
//#region src/core/schema/schemaComponent.ts
|
|
921
|
+
const schemaComponent = (key, options) => {
|
|
922
|
+
const componentsMap = new Map(options.components?.map((comp) => [comp.schemaComponentKey, comp]));
|
|
923
|
+
const migrations = [...options.migrations ?? []];
|
|
924
|
+
return {
|
|
925
|
+
schemaComponentKey: key,
|
|
926
|
+
components: componentsMap,
|
|
927
|
+
get migrations() {
|
|
928
|
+
return [...migrations, ...Array.from(componentsMap.values()).flatMap((c) => c.migrations)];
|
|
929
|
+
},
|
|
930
|
+
addComponent: (component) => {
|
|
931
|
+
componentsMap.set(component.schemaComponentKey, component);
|
|
932
|
+
migrations.push(...component.migrations);
|
|
933
|
+
return component;
|
|
934
|
+
},
|
|
935
|
+
addMigration: (migration) => {
|
|
936
|
+
migrations.push(migration);
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
};
|
|
940
|
+
const isSchemaComponentOfType = (component, prefix) => component.schemaComponentKey.startsWith(prefix);
|
|
941
|
+
const mapSchemaComponentsOfType = (components, prefix, keyMapper) => new Map(Array.from(components.entries()).filter(([urn]) => urn.startsWith(prefix)).map(([urn, component]) => [keyMapper ? keyMapper(component) : urn, component]));
|
|
942
|
+
|
|
943
|
+
//#endregion
|
|
944
|
+
//#region src/core/schema/components/columnSchemaComponent.ts
|
|
945
|
+
const ColumnURNType = "sc:dumbo:column";
|
|
946
|
+
const ColumnURN = ({ name }) => `${ColumnURNType}:${name}`;
|
|
947
|
+
const columnSchemaComponent = (params) => {
|
|
948
|
+
const { columnName, type, notNull, unique, primaryKey, default: defaultValue, ...schemaOptions } = params;
|
|
949
|
+
return {
|
|
950
|
+
...schemaComponent(ColumnURN({ name: columnName }), schemaOptions),
|
|
951
|
+
columnName,
|
|
952
|
+
notNull,
|
|
953
|
+
unique,
|
|
954
|
+
primaryKey,
|
|
955
|
+
defaultValue,
|
|
956
|
+
sqlTokenType: "SQL_COLUMN",
|
|
957
|
+
name: columnName,
|
|
958
|
+
type
|
|
959
|
+
};
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
//#endregion
|
|
963
|
+
//#region src/core/schema/components/indexSchemaComponent.ts
|
|
964
|
+
const IndexURNType = "sc:dumbo:index";
|
|
965
|
+
|
|
966
|
+
//#endregion
|
|
967
|
+
//#region src/core/schema/components/tableSchemaComponent.ts
|
|
968
|
+
const TableURNType = "sc:dumbo:table";
|
|
969
|
+
const TableURN = ({ name }) => `${TableURNType}:${name}`;
|
|
970
|
+
const tableSchemaComponent = ({ tableName, columns, primaryKey, relationships, ...migrationsOrComponents }) => {
|
|
971
|
+
columns ??= {};
|
|
972
|
+
relationships ??= {};
|
|
973
|
+
const base = schemaComponent(TableURN({ name: tableName }), {
|
|
974
|
+
migrations: migrationsOrComponents.migrations ?? [],
|
|
975
|
+
components: [...migrationsOrComponents.components ?? [], ...Object.values(columns)]
|
|
976
|
+
});
|
|
977
|
+
return {
|
|
978
|
+
...base,
|
|
979
|
+
tableName,
|
|
980
|
+
primaryKey: primaryKey ?? [],
|
|
981
|
+
relationships,
|
|
982
|
+
get columns() {
|
|
983
|
+
const columnsMap = mapSchemaComponentsOfType(base.components, ColumnURNType, (c) => c.columnName);
|
|
984
|
+
return Object.assign(columnsMap, columns);
|
|
985
|
+
},
|
|
986
|
+
get indexes() {
|
|
987
|
+
return mapSchemaComponentsOfType(base.components, IndexURNType, (c) => c.indexName);
|
|
988
|
+
},
|
|
989
|
+
addColumn: (column) => base.addComponent(column),
|
|
990
|
+
addIndex: (index) => base.addComponent(index)
|
|
991
|
+
};
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
//#endregion
|
|
995
|
+
//#region src/core/schema/components/databaseSchemaSchemaComponent.ts
|
|
996
|
+
const DatabaseSchemaURNType = "sc:dumbo:database_schema";
|
|
997
|
+
const DatabaseSchemaURN = ({ name }) => `${DatabaseSchemaURNType}:${name}`;
|
|
998
|
+
const databaseSchemaSchemaComponent = ({ schemaName, tables, ...migrationsOrComponents }) => {
|
|
999
|
+
const base = schemaComponent(DatabaseSchemaURN({ name: schemaName }), {
|
|
1000
|
+
migrations: migrationsOrComponents.migrations ?? [],
|
|
1001
|
+
components: [...migrationsOrComponents.components ?? [], ...Object.values(tables ?? {})]
|
|
1002
|
+
});
|
|
1003
|
+
return {
|
|
1004
|
+
...base,
|
|
1005
|
+
schemaName,
|
|
1006
|
+
get tables() {
|
|
1007
|
+
const tablesMap = mapSchemaComponentsOfType(base.components, TableURNType, (c) => c.tableName);
|
|
1008
|
+
return Object.assign(tablesMap, tables);
|
|
1009
|
+
},
|
|
1010
|
+
addTable: (table) => base.addComponent(typeof table === "string" ? tableSchemaComponent({ tableName: table }) : table)
|
|
1011
|
+
};
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
//#endregion
|
|
1015
|
+
//#region src/core/schema/components/databaseSchemaComponent.ts
|
|
1016
|
+
const DatabaseURNType = "sc:dumbo:database";
|
|
1017
|
+
const DatabaseURN = ({ name }) => `${DatabaseURNType}:${name}`;
|
|
1018
|
+
const databaseSchemaComponent = ({ databaseName, schemas, ...migrationsOrComponents }) => {
|
|
1019
|
+
schemas ??= {};
|
|
1020
|
+
const base = schemaComponent(DatabaseURN({ name: databaseName }), {
|
|
1021
|
+
migrations: migrationsOrComponents.migrations ?? [],
|
|
1022
|
+
components: [...migrationsOrComponents.components ?? [], ...Object.values(schemas)]
|
|
1023
|
+
});
|
|
1024
|
+
return {
|
|
1025
|
+
...base,
|
|
1026
|
+
databaseName,
|
|
1027
|
+
get schemas() {
|
|
1028
|
+
const schemasMap = mapSchemaComponentsOfType(base.components, DatabaseSchemaURNType, (c) => c.schemaName);
|
|
1029
|
+
return Object.assign(schemasMap, schemas);
|
|
1030
|
+
},
|
|
1031
|
+
addSchema: (schema) => base.addComponent(typeof schema === "string" ? databaseSchemaSchemaComponent({ schemaName: schema }) : schema)
|
|
1032
|
+
};
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
//#endregion
|
|
1036
|
+
//#region src/core/schema/databaseMetadata/databaseMetadata.ts
|
|
1037
|
+
const DumboDatabaseMetadataRegistry = () => {
|
|
1038
|
+
const infos = /* @__PURE__ */ new Map();
|
|
1039
|
+
const register = (databaseType, info) => {
|
|
1040
|
+
const entry = infos.get(databaseType);
|
|
1041
|
+
if (entry && (typeof entry !== "function" || typeof info === "function")) return;
|
|
1042
|
+
infos.set(databaseType, info);
|
|
1043
|
+
};
|
|
1044
|
+
const tryResolve = async (databaseType) => {
|
|
1045
|
+
const entry = infos.get(databaseType);
|
|
1046
|
+
if (!entry) return null;
|
|
1047
|
+
if (typeof entry !== "function") return entry;
|
|
1048
|
+
const resolved = await entry();
|
|
1049
|
+
register(databaseType, resolved);
|
|
1050
|
+
return resolved;
|
|
1051
|
+
};
|
|
1052
|
+
const tryGet = (databaseType) => {
|
|
1053
|
+
const entry = infos.get(databaseType);
|
|
1054
|
+
return entry && typeof entry !== "function" ? entry : null;
|
|
1055
|
+
};
|
|
1056
|
+
const has = (databaseType) => infos.has(databaseType);
|
|
1057
|
+
return {
|
|
1058
|
+
register,
|
|
1059
|
+
tryResolve,
|
|
1060
|
+
tryGet,
|
|
1061
|
+
has,
|
|
1062
|
+
get databaseTypes() {
|
|
1063
|
+
return Array.from(infos.keys());
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
};
|
|
1067
|
+
const dumboDatabaseMetadataRegistry$1 = globalThis.dumboDatabaseMetadataRegistry = globalThis.dumboDatabaseMetadataRegistry ?? DumboDatabaseMetadataRegistry();
|
|
1068
|
+
|
|
1069
|
+
//#endregion
|
|
1070
|
+
//#region src/core/schema/dumboSchema/dumboSchema.ts
|
|
1071
|
+
const DEFAULT_DATABASE_NAME = "__default_database__";
|
|
1072
|
+
const DEFAULT_DATABASE_SCHEMA_NAME = "__default_database_schema__";
|
|
1073
|
+
const dumboTable = (name, definition) => {
|
|
1074
|
+
const { columns, indexes, primaryKey, relationships, ...options } = definition;
|
|
1075
|
+
const components = [...indexes ? Object.values(indexes) : []];
|
|
1076
|
+
return tableSchemaComponent({
|
|
1077
|
+
tableName: name,
|
|
1078
|
+
columns: columns ?? {},
|
|
1079
|
+
primaryKey: primaryKey ?? [],
|
|
1080
|
+
...relationships !== void 0 ? { relationships } : {},
|
|
1081
|
+
components,
|
|
1082
|
+
...options
|
|
1083
|
+
});
|
|
1084
|
+
};
|
|
1085
|
+
function dumboDatabaseSchema(nameOrTables, tables, options) {
|
|
1086
|
+
return databaseSchemaSchemaComponent({
|
|
1087
|
+
schemaName: typeof nameOrTables === "string" ? nameOrTables : DEFAULT_DATABASE_SCHEMA_NAME,
|
|
1088
|
+
tables: (typeof nameOrTables === "string" ? tables : nameOrTables) ?? {},
|
|
1089
|
+
...options
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
dumboDatabaseSchema.from = (schemaName, tableNames) => {
|
|
1093
|
+
const tables = tableNames.reduce((acc, tableName) => {
|
|
1094
|
+
acc[tableName] = dumboTable(tableName, {});
|
|
1095
|
+
return acc;
|
|
1096
|
+
}, {});
|
|
1097
|
+
return schemaName ? dumboDatabaseSchema(schemaName, tables) : dumboDatabaseSchema(tables);
|
|
1098
|
+
};
|
|
1099
|
+
function dumboDatabase(nameOrSchemas, schemasOrOptions, options) {
|
|
1100
|
+
const databaseName = typeof nameOrSchemas === "string" ? nameOrSchemas : DEFAULT_DATABASE_NAME;
|
|
1101
|
+
const schemasOrSchema = typeof nameOrSchemas === "string" ? schemasOrOptions ?? {} : nameOrSchemas;
|
|
1102
|
+
return databaseSchemaComponent({
|
|
1103
|
+
databaseName,
|
|
1104
|
+
schemas: "schemaComponentKey" in schemasOrSchema && isSchemaComponentOfType(schemasOrSchema, "sc:dumbo:database_schema") ? { [DEFAULT_DATABASE_SCHEMA_NAME]: schemasOrSchema } : schemasOrSchema,
|
|
1105
|
+
...typeof nameOrSchemas === "string" ? options : schemasOrOptions
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
dumboDatabase.from = (databaseName, schemaNames) => {
|
|
1109
|
+
const schemas = schemaNames.reduce((acc, schemaName) => {
|
|
1110
|
+
acc[schemaName] = dumboDatabaseSchema(schemaName, {});
|
|
1111
|
+
return acc;
|
|
1112
|
+
}, {});
|
|
1113
|
+
return databaseName ? dumboDatabase(databaseName, schemas) : dumboDatabase(schemas);
|
|
1114
|
+
};
|
|
1115
|
+
dumboDatabase.defaultName = DEFAULT_DATABASE_NAME;
|
|
1116
|
+
dumboDatabaseSchema.defaultName = DEFAULT_DATABASE_SCHEMA_NAME;
|
|
1117
|
+
|
|
1118
|
+
//#endregion
|
|
1119
|
+
//#region src/core/serializer/json/index.ts
|
|
1120
|
+
const bigIntReplacer = (_key, value) => {
|
|
1121
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
1122
|
+
};
|
|
1123
|
+
const dateReplacer = (_key, value) => {
|
|
1124
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
1125
|
+
};
|
|
1126
|
+
const isFirstLetterNumeric = (str) => {
|
|
1127
|
+
const c = str.charCodeAt(0);
|
|
1128
|
+
return c >= 48 && c <= 57;
|
|
1129
|
+
};
|
|
1130
|
+
const isFirstLetterNumericOrMinus = (str) => {
|
|
1131
|
+
const c = str.charCodeAt(0);
|
|
1132
|
+
return c >= 48 && c <= 57 || c === 45;
|
|
1133
|
+
};
|
|
1134
|
+
const bigIntReviver = (_key, value, context) => {
|
|
1135
|
+
if (typeof value === "number" && Number.isInteger(value) && !Number.isSafeInteger(value)) try {
|
|
1136
|
+
return BigInt(context?.source ?? value.toString());
|
|
1137
|
+
} catch {
|
|
1138
|
+
return value;
|
|
1139
|
+
}
|
|
1140
|
+
if (typeof value === "string" && value.length > 15) {
|
|
1141
|
+
if (isFirstLetterNumericOrMinus(value)) {
|
|
1142
|
+
const num = Number(value);
|
|
1143
|
+
if (Number.isFinite(num) && !Number.isSafeInteger(num)) try {
|
|
1144
|
+
return BigInt(value);
|
|
1145
|
+
} catch {}
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return value;
|
|
1149
|
+
};
|
|
1150
|
+
const dateReviver = (_key, value) => {
|
|
1151
|
+
if (typeof value === "string" && value.length === 24 && isFirstLetterNumeric(value) && value[10] === "T" && value[23] === "Z") {
|
|
1152
|
+
const date = new Date(value);
|
|
1153
|
+
if (!isNaN(date.getTime())) return date;
|
|
1154
|
+
}
|
|
1155
|
+
return value;
|
|
1156
|
+
};
|
|
1157
|
+
const composeJSONReplacers = (...replacers) => {
|
|
1158
|
+
const filteredReplacers = replacers.filter((r) => r !== void 0);
|
|
1159
|
+
if (filteredReplacers.length === 0) return void 0;
|
|
1160
|
+
return (key, value) => filteredReplacers.reduce((accValue, replacer) => replacer(key, accValue), value);
|
|
1161
|
+
};
|
|
1162
|
+
const composeJSONRevivers = (...revivers) => {
|
|
1163
|
+
const filteredRevivers = revivers.filter((r) => r !== void 0);
|
|
1164
|
+
if (filteredRevivers.length === 0) return void 0;
|
|
1165
|
+
return (key, value, context) => filteredRevivers.reduce((accValue, reviver) => reviver(key, accValue, context), value);
|
|
1166
|
+
};
|
|
1167
|
+
const JSONReplacer = (opts) => composeJSONReplacers(opts?.replacer, opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : void 0, opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : void 0);
|
|
1168
|
+
const JSONReviver = (opts) => composeJSONRevivers(opts?.reviver, opts?.parseBigInts === true ? JSONRevivers.bigInt : void 0, opts?.parseDates === true ? JSONRevivers.date : void 0);
|
|
1169
|
+
const JSONReplacers = {
|
|
1170
|
+
bigInt: bigIntReplacer,
|
|
1171
|
+
date: dateReplacer
|
|
1172
|
+
};
|
|
1173
|
+
const JSONRevivers = {
|
|
1174
|
+
bigInt: bigIntReviver,
|
|
1175
|
+
date: dateReviver
|
|
1176
|
+
};
|
|
1177
|
+
const jsonSerializer = (options) => {
|
|
1178
|
+
const defaultReplacer = JSONReplacer(options);
|
|
1179
|
+
const defaultReviver = JSONReviver(options);
|
|
1180
|
+
return {
|
|
1181
|
+
serialize: (object, serializerOptions) => JSON.stringify(object, serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer),
|
|
1182
|
+
deserialize: (payload, deserializerOptions) => JSON.parse(payload, deserializerOptions ? JSONReviver(deserializerOptions) : defaultReviver)
|
|
1183
|
+
};
|
|
1184
|
+
};
|
|
1185
|
+
const JSONSerializer = Object.assign(jsonSerializer(), { from: (options) => options?.serialization?.serializer ?? (options?.serialization?.options ? jsonSerializer(options?.serialization?.options) : JSONSerializer) });
|
|
1186
|
+
|
|
1187
|
+
//#endregion
|
|
1188
|
+
//#region src/core/sql/parametrizedSQL/parametrizedSQL.ts
|
|
1189
|
+
const ParametrizedSQLBuilder = ({ mapParamPlaceholder }) => {
|
|
1190
|
+
const sql = [];
|
|
1191
|
+
const params = [];
|
|
1192
|
+
return {
|
|
1193
|
+
addSQL(str) {
|
|
1194
|
+
sql.push(str);
|
|
1195
|
+
return this;
|
|
1196
|
+
},
|
|
1197
|
+
addParam(value) {
|
|
1198
|
+
sql.push(mapParamPlaceholder(params.length, value));
|
|
1199
|
+
params.push(value);
|
|
1200
|
+
return this;
|
|
1201
|
+
},
|
|
1202
|
+
addParams(values) {
|
|
1203
|
+
const placeholders = values.map((value, i) => mapParamPlaceholder(params.length + i, value));
|
|
1204
|
+
this.addSQL(`${placeholders.join(", ")}`);
|
|
1205
|
+
params.push(...values);
|
|
1206
|
+
return this;
|
|
1207
|
+
},
|
|
1208
|
+
build() {
|
|
1209
|
+
return {
|
|
1210
|
+
query: sql.join(""),
|
|
1211
|
+
params
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1217
|
+
//#endregion
|
|
1218
|
+
//#region src/core/sql/tokens/sqlToken.ts
|
|
1219
|
+
const SQLToken = (sqlTokenType, map) => {
|
|
1220
|
+
const factory = (input) => {
|
|
1221
|
+
let props;
|
|
1222
|
+
if (map !== void 0) props = map(input);
|
|
1223
|
+
else if (input === void 0 || input === null) props = {};
|
|
1224
|
+
else if (typeof input === "object" && !Array.isArray(input)) props = input;
|
|
1225
|
+
else throw new Error(`Cannot create SQLToken of type ${sqlTokenType} with input: ${input}`);
|
|
1226
|
+
return {
|
|
1227
|
+
sqlTokenType,
|
|
1228
|
+
[sqlTokenType]: true,
|
|
1229
|
+
...props
|
|
1230
|
+
};
|
|
1231
|
+
};
|
|
1232
|
+
const check = (token) => SQLToken.check(token) && token.sqlTokenType === sqlTokenType;
|
|
1233
|
+
return {
|
|
1234
|
+
from: factory,
|
|
1235
|
+
check,
|
|
1236
|
+
type: sqlTokenType
|
|
1237
|
+
};
|
|
1238
|
+
};
|
|
1239
|
+
SQLToken.check = (token) => token !== null && typeof token === "object" && "sqlTokenType" in token;
|
|
1240
|
+
const SQLIdentifier = SQLToken("SQL_IDENTIFIER", (value) => ({ value }));
|
|
1241
|
+
const SQLPlain = SQLToken("SQL_RAW", (value) => ({ value }));
|
|
1242
|
+
const SQLLiteral = SQLToken("SQL_LITERAL", (value) => ({ value }));
|
|
1243
|
+
const SQLArray = SQLToken("SQL_ARRAY", (input) => {
|
|
1244
|
+
if (Array.isArray(input)) return { value: input };
|
|
1245
|
+
return input.mode !== void 0 ? {
|
|
1246
|
+
value: input.value,
|
|
1247
|
+
mode: input.mode
|
|
1248
|
+
} : { value: input.value };
|
|
1249
|
+
});
|
|
1250
|
+
const SQLIn = SQLToken("SQL_IN", ({ column, values, mode }) => mode !== void 0 ? {
|
|
1251
|
+
column: SQLIdentifier.from(column),
|
|
1252
|
+
values: SQLArray.from(values),
|
|
1253
|
+
mode
|
|
1254
|
+
} : {
|
|
1255
|
+
column: SQLIdentifier.from(column),
|
|
1256
|
+
values: SQLArray.from(values)
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
//#endregion
|
|
1260
|
+
//#region src/core/sql/tokens/columnTokens.ts
|
|
1261
|
+
const ColumnTypeToken = (sqlTokenType, jsTypeName, map) => {
|
|
1262
|
+
const factory = (input) => {
|
|
1263
|
+
let props;
|
|
1264
|
+
if (map !== void 0) props = map(input);
|
|
1265
|
+
else if (input === void 0 || input === null) props = {};
|
|
1266
|
+
else if (typeof input === "object" && !Array.isArray(input)) props = input;
|
|
1267
|
+
else throw new Error(`Cannot create SQLToken of type ${sqlTokenType} with input: ${input}`);
|
|
1268
|
+
return {
|
|
1269
|
+
sqlTokenType,
|
|
1270
|
+
[sqlTokenType]: true,
|
|
1271
|
+
jsTypeName,
|
|
1272
|
+
...props
|
|
1273
|
+
};
|
|
1274
|
+
};
|
|
1275
|
+
const check = (token) => SQLToken.check(token) && token.sqlTokenType === sqlTokenType;
|
|
1276
|
+
return {
|
|
1277
|
+
from: factory,
|
|
1278
|
+
check,
|
|
1279
|
+
type: sqlTokenType
|
|
1280
|
+
};
|
|
1281
|
+
};
|
|
1282
|
+
const SerialToken = ColumnTypeToken("SQL_COLUMN_SERIAL", "value_type:js:number");
|
|
1283
|
+
const BigSerialToken = ColumnTypeToken("SQL_COLUMN_BIGSERIAL", "value_type:js:bigint");
|
|
1284
|
+
const IntegerToken = ColumnTypeToken("SQL_COLUMN_INTEGER", "value_type:js:number");
|
|
1285
|
+
const BigIntegerToken = ColumnTypeToken("SQL_COLUMN_BIGINT", "value_type:js:bigint");
|
|
1286
|
+
const JSONBToken = {
|
|
1287
|
+
type: "SQL_COLUMN_JSONB",
|
|
1288
|
+
from: () => {
|
|
1289
|
+
return {
|
|
1290
|
+
sqlTokenType: "SQL_COLUMN_JSONB",
|
|
1291
|
+
["SQL_COLUMN_JSONB"]: true
|
|
1292
|
+
};
|
|
1293
|
+
},
|
|
1294
|
+
check: (token) => SQLToken.check(token) && token.sqlTokenType === "SQL_COLUMN_JSONB"
|
|
1295
|
+
};
|
|
1296
|
+
const TimestampToken = ColumnTypeToken("SQL_COLUMN_TIMESTAMP", "value_type:js:date");
|
|
1297
|
+
const TimestamptzToken = ColumnTypeToken("SQL_COLUMN_TIMESTAMPTZ", "value_type:js:date");
|
|
1298
|
+
const VarcharToken = ColumnTypeToken("SQL_COLUMN_VARCHAR", "value_type:js:string", (length) => ({
|
|
1299
|
+
length: length ?? "max",
|
|
1300
|
+
jsTypeName: "value_type:js:string"
|
|
1301
|
+
}));
|
|
1302
|
+
const AutoIncrementSQLColumnToken = ColumnTypeToken("SQL_COLUMN_AUTO_INCREMENT", "value_type:js:bigint");
|
|
1303
|
+
const SQLColumnTypeTokensFactory = {
|
|
1304
|
+
AutoIncrement: AutoIncrementSQLColumnToken.from,
|
|
1305
|
+
BigInteger: BigIntegerToken.from(),
|
|
1306
|
+
BigSerial: BigSerialToken.from(),
|
|
1307
|
+
Integer: IntegerToken.from(),
|
|
1308
|
+
JSONB: JSONBToken.from,
|
|
1309
|
+
Serial: SerialToken.from(),
|
|
1310
|
+
Timestamp: TimestampToken.from(),
|
|
1311
|
+
Timestamptz: TimestamptzToken.from(),
|
|
1312
|
+
Varchar: VarcharToken.from
|
|
1313
|
+
};
|
|
1314
|
+
const SQLColumnToken = SQLToken("SQL_COLUMN");
|
|
1315
|
+
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/core/sql/processors/sqlProcessor.ts
|
|
1318
|
+
const SQLProcessor = (options) => options;
|
|
1319
|
+
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region src/core/sql/processors/defaultProcessors.ts
|
|
1322
|
+
const ExpandArrayProcessor = SQLProcessor({
|
|
1323
|
+
canHandle: "SQL_ARRAY",
|
|
1324
|
+
handle: (token, { builder, serializer, mapper }) => {
|
|
1325
|
+
if (token.value.length === 0) throw new Error("Empty arrays are not supported. If you're using it with SELECT IN statement Use SQL.in(column, array) helper instead.");
|
|
1326
|
+
builder.addParams(mapper.mapValue(token.value, serializer));
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
const ExpandSQLInProcessor = SQLProcessor({
|
|
1330
|
+
canHandle: "SQL_IN",
|
|
1331
|
+
handle: (token, context) => {
|
|
1332
|
+
const { builder, mapper, processorsRegistry, serializer } = context;
|
|
1333
|
+
const { values: inValues, column } = token;
|
|
1334
|
+
if (inValues.value.length === 0) {
|
|
1335
|
+
builder.addParam(mapper.mapValue(false, serializer));
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
builder.addSQL(mapper.mapValue(column.value, serializer));
|
|
1339
|
+
builder.addSQL(` IN (`);
|
|
1340
|
+
const arrayProcessor = processorsRegistry.get(SQLArray.type);
|
|
1341
|
+
if (!arrayProcessor) throw new Error("No sql processor registered for an array. Cannot expand IN statement");
|
|
1342
|
+
arrayProcessor.handle(inValues, {
|
|
1343
|
+
builder,
|
|
1344
|
+
mapper,
|
|
1345
|
+
processorsRegistry,
|
|
1346
|
+
serializer
|
|
1347
|
+
});
|
|
1348
|
+
builder.addSQL(`)`);
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
const FormatIdentifierProcessor = SQLProcessor({
|
|
1352
|
+
canHandle: "SQL_IDENTIFIER",
|
|
1353
|
+
handle: (token, { builder, mapper, serializer }) => {
|
|
1354
|
+
builder.addSQL(mapper.mapValue(token, serializer));
|
|
1355
|
+
}
|
|
1356
|
+
});
|
|
1357
|
+
const MapLiteralProcessor = SQLProcessor({
|
|
1358
|
+
canHandle: "SQL_LITERAL",
|
|
1359
|
+
handle: (token, { builder, mapper, serializer }) => builder.addParam(mapper.mapValue(token.value, serializer))
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
//#endregion
|
|
1363
|
+
//#region src/core/sql/processors/sqlProcessorRegistry.ts
|
|
1364
|
+
const SQLProcessorsRegistry = (options) => {
|
|
1365
|
+
const processors = options ? new Map(options.from.all()) : /* @__PURE__ */ new Map();
|
|
1366
|
+
function register(...args) {
|
|
1367
|
+
if (args.length === 1 && typeof args[0] === "object" && !Array.isArray(args[0])) Object.entries(args[0]).forEach(([_, processor]) => {
|
|
1368
|
+
processors.set(processor.canHandle, processor);
|
|
1369
|
+
});
|
|
1370
|
+
else args.forEach((p) => processors.set(p.canHandle, p));
|
|
1371
|
+
return registry;
|
|
1372
|
+
}
|
|
1373
|
+
const registry = {
|
|
1374
|
+
register,
|
|
1375
|
+
get: (tokenType) => {
|
|
1376
|
+
return processors.get(tokenType) ?? null;
|
|
1377
|
+
},
|
|
1378
|
+
all: () => processors
|
|
1379
|
+
};
|
|
1380
|
+
return registry;
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
//#endregion
|
|
1384
|
+
//#region src/core/sql/processors/columnProcessors.ts
|
|
1385
|
+
const mapDefaultSQLColumnProcessors = (mapColumnType) => ({
|
|
1386
|
+
AutoIncrement: SQLProcessor({
|
|
1387
|
+
canHandle: "SQL_COLUMN_AUTO_INCREMENT",
|
|
1388
|
+
handle: (token, context) => {
|
|
1389
|
+
mapColumnType(token, context);
|
|
1390
|
+
}
|
|
1391
|
+
}),
|
|
1392
|
+
BigInteger: SQLProcessor({
|
|
1393
|
+
canHandle: "SQL_COLUMN_BIGINT",
|
|
1394
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1395
|
+
}),
|
|
1396
|
+
BigSerial: SQLProcessor({
|
|
1397
|
+
canHandle: "SQL_COLUMN_BIGSERIAL",
|
|
1398
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1399
|
+
}),
|
|
1400
|
+
Serial: SQLProcessor({
|
|
1401
|
+
canHandle: "SQL_COLUMN_SERIAL",
|
|
1402
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1403
|
+
}),
|
|
1404
|
+
Integer: SQLProcessor({
|
|
1405
|
+
canHandle: "SQL_COLUMN_INTEGER",
|
|
1406
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1407
|
+
}),
|
|
1408
|
+
JSONB: SQLProcessor({
|
|
1409
|
+
canHandle: "SQL_COLUMN_JSONB",
|
|
1410
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1411
|
+
}),
|
|
1412
|
+
Timestamp: SQLProcessor({
|
|
1413
|
+
canHandle: "SQL_COLUMN_TIMESTAMP",
|
|
1414
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1415
|
+
}),
|
|
1416
|
+
Timestamptz: SQLProcessor({
|
|
1417
|
+
canHandle: "SQL_COLUMN_TIMESTAMPTZ",
|
|
1418
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1419
|
+
}),
|
|
1420
|
+
Varchar: SQLProcessor({
|
|
1421
|
+
canHandle: "SQL_COLUMN_VARCHAR",
|
|
1422
|
+
handle: (token, context) => mapColumnType(token, context)
|
|
1423
|
+
})
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/core/sql/processors/index.ts
|
|
1428
|
+
const defaultProcessorsRegistry = globalThis.defaultProcessorsRegistry = globalThis.defaultProcessorsRegistry ?? SQLProcessorsRegistry().register(FormatIdentifierProcessor, MapLiteralProcessor, ExpandArrayProcessor, ExpandSQLInProcessor);
|
|
1429
|
+
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/core/sql/tokenizedSQL/tokenizedSQL.ts
|
|
1432
|
+
const TokenizedSQLBuilder = () => {
|
|
1433
|
+
const sqlChunks = [];
|
|
1434
|
+
const sqlTokens = [];
|
|
1435
|
+
return {
|
|
1436
|
+
addSQL(str) {
|
|
1437
|
+
sqlChunks.push(str);
|
|
1438
|
+
},
|
|
1439
|
+
addSQLs(str) {
|
|
1440
|
+
sqlChunks.push(...str);
|
|
1441
|
+
},
|
|
1442
|
+
addToken(value) {
|
|
1443
|
+
sqlTokens.push(value);
|
|
1444
|
+
},
|
|
1445
|
+
addTokens(vals) {
|
|
1446
|
+
sqlTokens.push(...vals);
|
|
1447
|
+
},
|
|
1448
|
+
build() {
|
|
1449
|
+
return sqlChunks.length > 0 ? {
|
|
1450
|
+
__brand: "tokenized-sql",
|
|
1451
|
+
sqlChunks,
|
|
1452
|
+
sqlTokens
|
|
1453
|
+
} : TokenizedSQL.empty;
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
};
|
|
1457
|
+
const TokenizedSQL = (strings, values) => {
|
|
1458
|
+
const builder = TokenizedSQLBuilder();
|
|
1459
|
+
for (let i = 0; i < strings.length; i++) {
|
|
1460
|
+
if (strings[i] !== "") builder.addSQL(strings[i]);
|
|
1461
|
+
if (i >= values.length) break;
|
|
1462
|
+
const value = values[i];
|
|
1463
|
+
if (isTokenizedSQL(value)) {
|
|
1464
|
+
builder.addSQLs(value.sqlChunks);
|
|
1465
|
+
builder.addTokens(value.sqlTokens);
|
|
1466
|
+
} else if (SQLPlain.check(value)) builder.addSQL(value.value);
|
|
1467
|
+
else {
|
|
1468
|
+
builder.addSQL(TokenizedSQL.paramPlaceholder);
|
|
1469
|
+
builder.addToken(SQLToken.check(value) ? value : Array.isArray(value) ? SQLArray.from(value) : SQLLiteral.from(value));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return builder.build();
|
|
1473
|
+
};
|
|
1474
|
+
const isTokenizedSQL = (value) => {
|
|
1475
|
+
return value !== null && typeof value === "object" && "__brand" in value && value.__brand === "tokenized-sql";
|
|
1476
|
+
};
|
|
1477
|
+
TokenizedSQL.paramPlaceholder = `__P__`;
|
|
1478
|
+
TokenizedSQL.empty = {
|
|
1479
|
+
__brand: "tokenized-sql",
|
|
1480
|
+
sqlChunks: [""],
|
|
1481
|
+
sqlTokens: []
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
//#endregion
|
|
1485
|
+
//#region src/core/sql/sql.ts
|
|
1486
|
+
const createSQL = (strings, ...values) => {
|
|
1487
|
+
return TokenizedSQL(strings, values);
|
|
1488
|
+
};
|
|
1489
|
+
/** Returns true when the value is a tokenized SQL statement. */
|
|
1490
|
+
const isSQL = (value) => {
|
|
1491
|
+
if (value === void 0 || value === null) return false;
|
|
1492
|
+
return isTokenizedSQL(value);
|
|
1493
|
+
};
|
|
1494
|
+
const emptySQL = {
|
|
1495
|
+
__brand: "tokenized-sql",
|
|
1496
|
+
sqlChunks: [""],
|
|
1497
|
+
sqlTokens: []
|
|
1498
|
+
};
|
|
1499
|
+
const mergeSQL = (sqls, separator = " ") => {
|
|
1500
|
+
const parametrized = sqls.filter((sql) => !isEmpty(sql)).map((sql) => sql);
|
|
1501
|
+
const params = parametrized.flatMap((p) => p.sqlTokens);
|
|
1502
|
+
const sqlChunks = parametrized.flatMap((p, i) => i == parametrized.length - 1 || separator === "" ? p.sqlChunks : [...p.sqlChunks, separator]);
|
|
1503
|
+
return sqlChunks.length > 0 ? {
|
|
1504
|
+
__brand: "tokenized-sql",
|
|
1505
|
+
sqlChunks,
|
|
1506
|
+
sqlTokens: params
|
|
1507
|
+
} : TokenizedSQL.empty;
|
|
1508
|
+
};
|
|
1509
|
+
const concatSQL = (...sqls) => mergeSQL(sqls, "");
|
|
1510
|
+
const literal = (value) => SQLPlain.from(`'${value.replace(/'/g, "''")}'`);
|
|
1511
|
+
const isEmpty = (sql) => {
|
|
1512
|
+
if (isTokenizedSQL(sql)) {
|
|
1513
|
+
const parametrized = sql;
|
|
1514
|
+
return parametrized.sqlChunks.every((chunk) => chunk.trim() === "") && parametrized.sqlTokens.length === 0;
|
|
1515
|
+
}
|
|
1516
|
+
return false;
|
|
1517
|
+
};
|
|
1518
|
+
const columnFactory = SQLColumnToken.from;
|
|
1519
|
+
columnFactory.type = SQLColumnTypeTokensFactory;
|
|
1520
|
+
const schemaColumnFactory = ((name, type, options) => columnSchemaComponent({
|
|
1521
|
+
columnName: name,
|
|
1522
|
+
type,
|
|
1523
|
+
...options
|
|
1524
|
+
}));
|
|
1525
|
+
const SQL = Object.assign(createSQL, {
|
|
1526
|
+
EMPTY: emptySQL,
|
|
1527
|
+
concat: concatSQL,
|
|
1528
|
+
merge: mergeSQL,
|
|
1529
|
+
format: (sql, formatter, options) => formatSQL(sql, formatter, options?.serializer ?? JSONSerializer, options),
|
|
1530
|
+
describe: (sql, formatter, options) => describeSQL(sql, formatter, options?.serializer ?? JSONSerializer, options),
|
|
1531
|
+
in: (column, values, options) => options?.mode ? SQLIn.from({
|
|
1532
|
+
column,
|
|
1533
|
+
values,
|
|
1534
|
+
mode: options.mode
|
|
1535
|
+
}) : SQLIn.from({
|
|
1536
|
+
column,
|
|
1537
|
+
values
|
|
1538
|
+
}),
|
|
1539
|
+
array: (values, options) => SQLArray.from(options?.mode ? {
|
|
1540
|
+
value: values,
|
|
1541
|
+
mode: options.mode
|
|
1542
|
+
} : values),
|
|
1543
|
+
identifier: SQLIdentifier.from,
|
|
1544
|
+
plain: SQLPlain.from,
|
|
1545
|
+
literal,
|
|
1546
|
+
check: {
|
|
1547
|
+
isSQL,
|
|
1548
|
+
isTokenizedSQL: (value) => isTokenizedSQL(value),
|
|
1549
|
+
isEmpty,
|
|
1550
|
+
isIdentifier: SQLIdentifier.check,
|
|
1551
|
+
isPlain: SQLPlain.check,
|
|
1552
|
+
isSQLIn: SQLIn.check
|
|
1553
|
+
},
|
|
1554
|
+
column: columnFactory,
|
|
1555
|
+
columnN: Object.assign(schemaColumnFactory, { type: SQLColumnTypeTokensFactory })
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
//#endregion
|
|
1559
|
+
//#region src/core/sql/valueMappers/reservedSqlWords.ts
|
|
1560
|
+
const ansiSqlReservedMap = {
|
|
1561
|
+
ALL: true,
|
|
1562
|
+
AND: true,
|
|
1563
|
+
ANY: true,
|
|
1564
|
+
ARRAY: true,
|
|
1565
|
+
AS: true,
|
|
1566
|
+
ASC: true,
|
|
1567
|
+
AUTHORIZATION: true,
|
|
1568
|
+
BETWEEN: true,
|
|
1569
|
+
BINARY: true,
|
|
1570
|
+
BOTH: true,
|
|
1571
|
+
CASE: true,
|
|
1572
|
+
CAST: true,
|
|
1573
|
+
CHECK: true,
|
|
1574
|
+
COLLATE: true,
|
|
1575
|
+
COLUMN: true,
|
|
1576
|
+
CONSTRAINT: true,
|
|
1577
|
+
CREATE: true,
|
|
1578
|
+
CROSS: true,
|
|
1579
|
+
CURRENT_DATE: true,
|
|
1580
|
+
CURRENT_TIME: true,
|
|
1581
|
+
CURRENT_TIMESTAMP: true,
|
|
1582
|
+
CURRENT_USER: true,
|
|
1583
|
+
DEFAULT: true,
|
|
1584
|
+
DEFERRABLE: true,
|
|
1585
|
+
DESC: true,
|
|
1586
|
+
DISTINCT: true,
|
|
1587
|
+
DO: true,
|
|
1588
|
+
ELSE: true,
|
|
1589
|
+
END: true,
|
|
1590
|
+
EXCEPT: true,
|
|
1591
|
+
FALSE: true,
|
|
1592
|
+
FOR: true,
|
|
1593
|
+
FOREIGN: true,
|
|
1594
|
+
FROM: true,
|
|
1595
|
+
FULL: true,
|
|
1596
|
+
GRANT: true,
|
|
1597
|
+
GROUP: true,
|
|
1598
|
+
HAVING: true,
|
|
1599
|
+
IN: true,
|
|
1600
|
+
INITIALLY: true,
|
|
1601
|
+
INNER: true,
|
|
1602
|
+
INTERSECT: true,
|
|
1603
|
+
INTO: true,
|
|
1604
|
+
IS: true,
|
|
1605
|
+
JOIN: true,
|
|
1606
|
+
LEADING: true,
|
|
1607
|
+
LEFT: true,
|
|
1608
|
+
LIKE: true,
|
|
1609
|
+
LOCALTIME: true,
|
|
1610
|
+
LOCALTIMESTAMP: true,
|
|
1611
|
+
NATURAL: true,
|
|
1612
|
+
NEW: true,
|
|
1613
|
+
NOT: true,
|
|
1614
|
+
NULL: true,
|
|
1615
|
+
NULLS: true,
|
|
1616
|
+
OLD: true,
|
|
1617
|
+
ON: true,
|
|
1618
|
+
ONLY: true,
|
|
1619
|
+
OPEN: true,
|
|
1620
|
+
OR: true,
|
|
1621
|
+
ORDER: true,
|
|
1622
|
+
OUTER: true,
|
|
1623
|
+
OVERLAPS: true,
|
|
1624
|
+
PARTITION: true,
|
|
1625
|
+
PLACING: true,
|
|
1626
|
+
PRIMARY: true,
|
|
1627
|
+
REFERENCES: true,
|
|
1628
|
+
RIGHT: true,
|
|
1629
|
+
SELECT: true,
|
|
1630
|
+
SESSION_USER: true,
|
|
1631
|
+
SIMILAR: true,
|
|
1632
|
+
SOME: true,
|
|
1633
|
+
TABLE: true,
|
|
1634
|
+
THEN: true,
|
|
1635
|
+
TO: true,
|
|
1636
|
+
TRAILING: true,
|
|
1637
|
+
TRUE: true,
|
|
1638
|
+
UNION: true,
|
|
1639
|
+
UNIQUE: true,
|
|
1640
|
+
USER: true,
|
|
1641
|
+
USING: true,
|
|
1642
|
+
WHEN: true,
|
|
1643
|
+
WHERE: true,
|
|
1644
|
+
WITH: true,
|
|
1645
|
+
WITHOUT: true,
|
|
1646
|
+
ADD: true,
|
|
1647
|
+
ALTER: true,
|
|
1648
|
+
ARE: true,
|
|
1649
|
+
AT: true,
|
|
1650
|
+
BEGIN: true,
|
|
1651
|
+
BY: true,
|
|
1652
|
+
CASCADE: true,
|
|
1653
|
+
CLOSE: true,
|
|
1654
|
+
COMMIT: true,
|
|
1655
|
+
CONNECT: true,
|
|
1656
|
+
CONTINUE: true,
|
|
1657
|
+
CORRESPONDING: true,
|
|
1658
|
+
CURSOR: true,
|
|
1659
|
+
DEALLOCATE: true,
|
|
1660
|
+
DECLARE: true,
|
|
1661
|
+
DELETE: true,
|
|
1662
|
+
DESCRIBE: true,
|
|
1663
|
+
DISCONNECT: true,
|
|
1664
|
+
DROP: true,
|
|
1665
|
+
ESCAPE: true,
|
|
1666
|
+
EXECUTE: true,
|
|
1667
|
+
EXISTS: true,
|
|
1668
|
+
FETCH: true,
|
|
1669
|
+
FIRST: true,
|
|
1670
|
+
FLOAT: true,
|
|
1671
|
+
GET: true,
|
|
1672
|
+
GLOBAL: true,
|
|
1673
|
+
GO: true,
|
|
1674
|
+
GOTO: true,
|
|
1675
|
+
HOUR: true,
|
|
1676
|
+
IMMEDIATE: true,
|
|
1677
|
+
INDICATOR: true,
|
|
1678
|
+
INPUT: true,
|
|
1679
|
+
INSERT: true,
|
|
1680
|
+
INT: true,
|
|
1681
|
+
INTEGER: true,
|
|
1682
|
+
INTERVAL: true,
|
|
1683
|
+
LANGUAGE: true,
|
|
1684
|
+
LAST: true,
|
|
1685
|
+
LOCAL: true,
|
|
1686
|
+
MATCH: true,
|
|
1687
|
+
MINUTE: true,
|
|
1688
|
+
MODULE: true,
|
|
1689
|
+
MONTH: true,
|
|
1690
|
+
NATIONAL: true,
|
|
1691
|
+
NEXT: true,
|
|
1692
|
+
NO: true,
|
|
1693
|
+
OF: true,
|
|
1694
|
+
OUTPUT: true,
|
|
1695
|
+
PARTIAL: true,
|
|
1696
|
+
PREPARE: true,
|
|
1697
|
+
PRESERVE: true,
|
|
1698
|
+
PRIOR: true,
|
|
1699
|
+
PRIVILEGES: true,
|
|
1700
|
+
PROCEDURE: true,
|
|
1701
|
+
PUBLIC: true,
|
|
1702
|
+
READ: true,
|
|
1703
|
+
REAL: true,
|
|
1704
|
+
RESTRICT: true,
|
|
1705
|
+
REVOKE: true,
|
|
1706
|
+
ROLLBACK: true,
|
|
1707
|
+
ROWS: true,
|
|
1708
|
+
SCHEMA: true,
|
|
1709
|
+
SCROLL: true,
|
|
1710
|
+
SECOND: true,
|
|
1711
|
+
SECTION: true,
|
|
1712
|
+
SET: true,
|
|
1713
|
+
SIZE: true,
|
|
1714
|
+
SMALLINT: true,
|
|
1715
|
+
SQL: true,
|
|
1716
|
+
SQLCODE: true,
|
|
1717
|
+
SQLERROR: true,
|
|
1718
|
+
SQLSTATE: true,
|
|
1719
|
+
TEMPORARY: true,
|
|
1720
|
+
TIMEZONE_HOUR: true,
|
|
1721
|
+
TIMEZONE_MINUTE: true,
|
|
1722
|
+
TRANSACTION: true,
|
|
1723
|
+
TRANSLATE: true,
|
|
1724
|
+
TRANSLATION: true,
|
|
1725
|
+
UNKNOWN: true,
|
|
1726
|
+
UPDATE: true,
|
|
1727
|
+
VALUE: true,
|
|
1728
|
+
VALUES: true,
|
|
1729
|
+
VARCHAR: true,
|
|
1730
|
+
VARYING: true,
|
|
1731
|
+
VIEW: true,
|
|
1732
|
+
WHENEVER: true,
|
|
1733
|
+
WORK: true,
|
|
1734
|
+
WRITE: true,
|
|
1735
|
+
YEAR: true,
|
|
1736
|
+
ZONE: true
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
//#endregion
|
|
1740
|
+
//#region src/core/sql/valueMappers/sqlValueMapper.ts
|
|
1741
|
+
const ANSISQLParamPlaceholder = "?";
|
|
1742
|
+
const ANSISQLIdentifierQuote = "\"";
|
|
1743
|
+
const mapANSISQLParamPlaceholder = () => "?";
|
|
1744
|
+
const isReserved = (value, reserved) => !!reserved[value.toUpperCase()];
|
|
1745
|
+
const mapSQLIdentifier = (value, options) => {
|
|
1746
|
+
if (value === void 0 || value === null) throw new Error("SQL identifier cannot be null or undefined");
|
|
1747
|
+
const ident = value.toString().slice(0);
|
|
1748
|
+
const quoteSign = options?.quote ?? "\"";
|
|
1749
|
+
if (/^[a-z_][a-z0-9_$]*$/.test(ident) && !isReserved(ident, options?.reservedWords ?? ansiSqlReservedMap)) return ident;
|
|
1750
|
+
let quoted = quoteSign;
|
|
1751
|
+
for (let i = 0; i < ident.length; i++) {
|
|
1752
|
+
const c = ident[i];
|
|
1753
|
+
quoted += c === quoteSign ? c + c : c;
|
|
1754
|
+
}
|
|
1755
|
+
quoted += quoteSign;
|
|
1756
|
+
return quoted;
|
|
1757
|
+
};
|
|
1758
|
+
const DefaultMapSQLParamValueOptions = {
|
|
1759
|
+
mapPlaceholder: mapANSISQLParamPlaceholder,
|
|
1760
|
+
mapIdentifier: mapSQLIdentifier
|
|
1761
|
+
};
|
|
1762
|
+
const SQLValueMapper = (options) => {
|
|
1763
|
+
const mapSQLParamValueOptions = {
|
|
1764
|
+
...DefaultMapSQLParamValueOptions,
|
|
1765
|
+
...options ?? {}
|
|
1766
|
+
};
|
|
1767
|
+
return {
|
|
1768
|
+
mapValue: (value, serializer, mapOptions) => mapSQLParamValue(value, serializer, {
|
|
1769
|
+
...mapSQLParamValueOptions,
|
|
1770
|
+
...mapOptions
|
|
1771
|
+
}),
|
|
1772
|
+
mapPlaceholder: mapSQLParamValueOptions.mapPlaceholder,
|
|
1773
|
+
mapIdentifier: mapSQLParamValueOptions.mapIdentifier
|
|
1774
|
+
};
|
|
1775
|
+
};
|
|
1776
|
+
function mapSQLParamValue(value, serializer, options) {
|
|
1777
|
+
if (value === null || value === void 0) return null;
|
|
1778
|
+
else if (typeof value === "number") return value;
|
|
1779
|
+
else if (typeof value === "string") return value;
|
|
1780
|
+
else if (Array.isArray(value)) {
|
|
1781
|
+
const mapValue = options?.mapValue ?? mapSQLParamValue;
|
|
1782
|
+
return options?.mapArray ? options.mapArray(value, mapValue) : value.map((item) => mapValue(item, serializer, options));
|
|
1783
|
+
} else if (typeof value === "boolean") return options?.mapBoolean ? options.mapBoolean(value) : value;
|
|
1784
|
+
else if (typeof value === "bigint") return options?.mapBigInt ? options.mapBigInt(value) : value.toString();
|
|
1785
|
+
else if (value instanceof Date) return options?.mapDate ? options.mapDate(value) : value.toISOString();
|
|
1786
|
+
else if (SQL.check.isIdentifier(value)) return (options?.mapIdentifier ?? mapSQLIdentifier)(value.value);
|
|
1787
|
+
else if (typeof value === "object") return options?.mapObject ? options.mapObject(value) : serializer.serialize(value);
|
|
1788
|
+
else return serializer.serialize(value);
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
//#endregion
|
|
1792
|
+
//#region src/core/sql/formatters/sqlFormatter.ts
|
|
1793
|
+
const SQLFormatter = ({ format, describe, valueMapper: valueMapperOptions, processorsRegistry }) => {
|
|
1794
|
+
const valueMapper = SQLValueMapper(valueMapperOptions);
|
|
1795
|
+
const options = {
|
|
1796
|
+
builder: ParametrizedSQLBuilder({ mapParamPlaceholder: valueMapper.mapPlaceholder }),
|
|
1797
|
+
mapper: valueMapper,
|
|
1798
|
+
processorsRegistry: processorsRegistry ?? defaultProcessorsRegistry
|
|
1799
|
+
};
|
|
1800
|
+
const resultFormatter = {
|
|
1801
|
+
format: format ?? ((sql, methodOptions) => formatSQL(sql, resultFormatter, methodOptions?.serializer ?? JSONSerializer, {
|
|
1802
|
+
...options,
|
|
1803
|
+
...methodOptions ?? {}
|
|
1804
|
+
})),
|
|
1805
|
+
describe: describe ?? ((sql, methodOptions) => describeSQL(sql, resultFormatter, methodOptions?.serializer ?? JSONSerializer, {
|
|
1806
|
+
...options,
|
|
1807
|
+
...methodOptions ?? {}
|
|
1808
|
+
})),
|
|
1809
|
+
valueMapper
|
|
1810
|
+
};
|
|
1811
|
+
return resultFormatter;
|
|
1812
|
+
};
|
|
1813
|
+
const dumboSQLFormatters = globalThis.dumboSQLFormatters = globalThis.dumboSQLFormatters ?? {};
|
|
1814
|
+
const registerFormatter = (dialect, formatter) => {
|
|
1815
|
+
dumboSQLFormatters[dialect] = formatter;
|
|
1816
|
+
};
|
|
1817
|
+
function formatSQL(sql, formatter, serializer, context) {
|
|
1818
|
+
const mapper = context?.mapper == void 0 ? formatter.valueMapper : {
|
|
1819
|
+
...formatter.valueMapper,
|
|
1820
|
+
...context.mapper
|
|
1821
|
+
};
|
|
1822
|
+
const processorsRegistry = context?.processorsRegistry ?? defaultProcessorsRegistry;
|
|
1823
|
+
const merged = Array.isArray(sql) ? SQL.merge(sql, "\n") : sql;
|
|
1824
|
+
if (!isTokenizedSQL(merged)) throw new Error("Expected TokenizedSQL, got string-based SQL");
|
|
1825
|
+
const builder = ParametrizedSQLBuilder({ mapParamPlaceholder: mapper.mapPlaceholder });
|
|
1826
|
+
let paramIndex = 0;
|
|
1827
|
+
for (let i = 0; i < merged.sqlChunks.length; i++) {
|
|
1828
|
+
const sqlChunk = merged.sqlChunks[i];
|
|
1829
|
+
if (sqlChunk !== TokenizedSQL.paramPlaceholder) {
|
|
1830
|
+
builder.addSQL(sqlChunk);
|
|
1831
|
+
continue;
|
|
1832
|
+
}
|
|
1833
|
+
const token = merged.sqlTokens[paramIndex++];
|
|
1834
|
+
const processor = processorsRegistry.get(token.sqlTokenType);
|
|
1835
|
+
if (!processor) throw new Error(`No SQL processor registered for token type: ${token.sqlTokenType}`);
|
|
1836
|
+
processor.handle(token, {
|
|
1837
|
+
builder,
|
|
1838
|
+
processorsRegistry,
|
|
1839
|
+
serializer,
|
|
1840
|
+
mapper
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
return builder.build();
|
|
1844
|
+
}
|
|
1845
|
+
const describeSQL = (sql, formatter, serializer, options) => formatSQL(sql, formatter, serializer, {
|
|
1846
|
+
...options ?? {},
|
|
1847
|
+
mapper: { mapPlaceholder: (_, value) => serializer.serialize(value) }
|
|
1848
|
+
}).query;
|
|
1849
|
+
|
|
1850
|
+
//#endregion
|
|
1851
|
+
//#region src/core/tracing/printing/color.ts
|
|
1852
|
+
let enableColors = true;
|
|
1853
|
+
const color = {
|
|
1854
|
+
set level(value) {
|
|
1855
|
+
enableColors = value === 1;
|
|
1856
|
+
},
|
|
1857
|
+
hex: (value) => (text) => enableColors ? ansis.default.hex(value)(text) : text,
|
|
1858
|
+
red: (value) => enableColors ? ansis.default.red(value) : value,
|
|
1859
|
+
green: (value) => enableColors ? ansis.default.green(value) : value,
|
|
1860
|
+
blue: (value) => enableColors ? ansis.default.blue(value) : value,
|
|
1861
|
+
cyan: (value) => enableColors ? ansis.default.cyan(value) : value,
|
|
1862
|
+
yellow: (value) => enableColors ? ansis.default.yellow(value) : value
|
|
1863
|
+
};
|
|
1864
|
+
|
|
1865
|
+
//#endregion
|
|
1866
|
+
//#region src/core/tracing/printing/pretty.ts
|
|
1867
|
+
const TWO_SPACES = " ";
|
|
1868
|
+
const COLOR_STRING = color.hex("#98c379");
|
|
1869
|
+
const COLOR_KEY = color.hex("#61afef");
|
|
1870
|
+
const COLOR_NUMBER_OR_DATE = color.hex("#d19a66");
|
|
1871
|
+
const COLOR_BOOLEAN = color.hex("#c678dd");
|
|
1872
|
+
const COLOR_NULL_OR_UNDEFINED = color.hex("#c678dd");
|
|
1873
|
+
const COLOR_BRACKETS = color.hex("#abb2bf");
|
|
1874
|
+
const processString = (str, indent, handleMultiline) => {
|
|
1875
|
+
if (handleMultiline && str.includes("\n")) {
|
|
1876
|
+
const indentedLines = str.split("\n").map((line) => indent + TWO_SPACES + COLOR_STRING(line));
|
|
1877
|
+
return COLOR_STRING("\"") + "\n" + indentedLines.join("\n") + "\n" + indent + COLOR_STRING("\"");
|
|
1878
|
+
}
|
|
1879
|
+
return COLOR_STRING(`"${str}"`);
|
|
1880
|
+
};
|
|
1881
|
+
const shouldPrint = (obj) => typeof obj !== "function" && typeof obj !== "symbol";
|
|
1882
|
+
const formatJson = (obj, indentLevel = 0, handleMultiline = false) => {
|
|
1883
|
+
const indent = TWO_SPACES.repeat(indentLevel);
|
|
1884
|
+
if (obj === null) return COLOR_NULL_OR_UNDEFINED("null");
|
|
1885
|
+
if (obj === void 0) return COLOR_NULL_OR_UNDEFINED("undefined");
|
|
1886
|
+
if (typeof obj === "string") return processString(obj, indent, handleMultiline);
|
|
1887
|
+
if (typeof obj === "number" || typeof obj === "bigint" || obj instanceof Date) return COLOR_NUMBER_OR_DATE(String(obj));
|
|
1888
|
+
if (typeof obj === "boolean") return COLOR_BOOLEAN(String(obj));
|
|
1889
|
+
if (obj instanceof Error) {
|
|
1890
|
+
const errorObj = {};
|
|
1891
|
+
Object.getOwnPropertyNames(obj).forEach((key) => {
|
|
1892
|
+
errorObj[key] = obj[key];
|
|
1893
|
+
});
|
|
1894
|
+
return formatJson(errorObj, indentLevel, handleMultiline);
|
|
1895
|
+
}
|
|
1896
|
+
if (obj instanceof Promise) return COLOR_STRING("Promise {pending}");
|
|
1897
|
+
if (Array.isArray(obj)) {
|
|
1898
|
+
const arrayItems = obj.map((item) => formatJson(item, indentLevel + 1, handleMultiline));
|
|
1899
|
+
return `${COLOR_BRACKETS("[")}\n${indent} ${arrayItems.join(`,\n${indent} `)}\n${indent}${COLOR_BRACKETS("]")}`;
|
|
1900
|
+
}
|
|
1901
|
+
const entries = Object.entries(obj).filter(([_, value]) => shouldPrint(value)).map(([key, value]) => `${COLOR_KEY(`"${key}"`)}: ${formatJson(value, indentLevel + 1, handleMultiline)}`);
|
|
1902
|
+
return `${COLOR_BRACKETS("{")}\n${indent} ${entries.join(`,\n${indent} `)}\n${indent}${COLOR_BRACKETS("}")}`;
|
|
1903
|
+
};
|
|
1904
|
+
const prettyJson = (obj, options) => formatJson(obj, 0, options?.handleMultiline);
|
|
1905
|
+
|
|
1906
|
+
//#endregion
|
|
1907
|
+
//#region src/core/tracing/index.ts
|
|
1908
|
+
const tracer = () => {};
|
|
1909
|
+
const LogLevel = {
|
|
1910
|
+
DISABLED: "DISABLED",
|
|
1911
|
+
INFO: "INFO",
|
|
1912
|
+
LOG: "LOG",
|
|
1913
|
+
WARN: "WARN",
|
|
1914
|
+
ERROR: "ERROR"
|
|
1915
|
+
};
|
|
1916
|
+
const getEnvVariable = (name) => {
|
|
1917
|
+
try {
|
|
1918
|
+
if (typeof process !== "undefined" && process.env) return process.env[name];
|
|
1919
|
+
return;
|
|
1920
|
+
} catch {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
const shouldLog = (logLevel) => {
|
|
1925
|
+
const definedLogLevel = getEnvVariable("DUMBO_LOG_LEVEL") ?? LogLevel.ERROR;
|
|
1926
|
+
if (definedLogLevel === LogLevel.ERROR && logLevel === LogLevel.ERROR) return true;
|
|
1927
|
+
if (definedLogLevel === LogLevel.WARN && [LogLevel.ERROR, LogLevel.WARN].includes(logLevel)) return true;
|
|
1928
|
+
if (definedLogLevel === LogLevel.LOG && [
|
|
1929
|
+
LogLevel.ERROR,
|
|
1930
|
+
LogLevel.WARN,
|
|
1931
|
+
LogLevel.LOG
|
|
1932
|
+
].includes(logLevel)) return true;
|
|
1933
|
+
if (definedLogLevel === LogLevel.INFO && [
|
|
1934
|
+
LogLevel.ERROR,
|
|
1935
|
+
LogLevel.WARN,
|
|
1936
|
+
LogLevel.LOG,
|
|
1937
|
+
LogLevel.INFO
|
|
1938
|
+
].includes(logLevel)) return true;
|
|
1939
|
+
return false;
|
|
1940
|
+
};
|
|
1941
|
+
const nulloTraceEventRecorder = () => {};
|
|
1942
|
+
const getTraceEventFormatter = (logStyle, serializer = JSONSerializer) => (event) => {
|
|
1943
|
+
switch (logStyle) {
|
|
1944
|
+
case "RAW": return serializer.serialize(event);
|
|
1945
|
+
case "PRETTY": return prettyJson(event, { handleMultiline: true });
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
const getTraceEventRecorder = (logLevel, logStyle) => {
|
|
1949
|
+
const format = getTraceEventFormatter(logStyle);
|
|
1950
|
+
switch (logLevel) {
|
|
1951
|
+
case "DISABLED": return nulloTraceEventRecorder;
|
|
1952
|
+
case "INFO": return (event) => console.info(format(event));
|
|
1953
|
+
case "LOG": return (event) => console.log(format(event));
|
|
1954
|
+
case "WARN": return (event) => console.warn(format(event));
|
|
1955
|
+
case "ERROR": return (event) => console.error(format(event));
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
const recordTraceEvent = (logLevel, eventName, attributes) => {
|
|
1959
|
+
if (!shouldLog(LogLevel.LOG)) return;
|
|
1960
|
+
const event = {
|
|
1961
|
+
name: eventName,
|
|
1962
|
+
timestamp: (/* @__PURE__ */ new Date()).getTime(),
|
|
1963
|
+
...attributes
|
|
1964
|
+
};
|
|
1965
|
+
getTraceEventRecorder(logLevel, getEnvVariable("DUMBO_LOG_STYLE") ?? "RAW")(event);
|
|
1966
|
+
};
|
|
1967
|
+
tracer.info = (eventName, attributes) => recordTraceEvent(LogLevel.INFO, eventName, attributes);
|
|
1968
|
+
tracer.warn = (eventName, attributes) => recordTraceEvent(LogLevel.WARN, eventName, attributes);
|
|
1969
|
+
tracer.log = (eventName, attributes) => recordTraceEvent(LogLevel.LOG, eventName, attributes);
|
|
1970
|
+
tracer.error = (eventName, attributes) => recordTraceEvent(LogLevel.ERROR, eventName, attributes);
|
|
1971
|
+
|
|
1972
|
+
//#endregion
|
|
1973
|
+
//#region src/core/schema/sqlMigration.ts
|
|
1974
|
+
const sqlMigration = (name, sqls) => ({
|
|
1975
|
+
name,
|
|
1976
|
+
sqls
|
|
1977
|
+
});
|
|
1978
|
+
|
|
1979
|
+
//#endregion
|
|
1980
|
+
//#region src/core/schema/migrators/schemaComponentMigrator.ts
|
|
1981
|
+
const { AutoIncrement, Varchar, Timestamp } = SQL.column.type;
|
|
1982
|
+
const migrationTableSQL = SQL`
|
|
1983
|
+
CREATE TABLE IF NOT EXISTS dmb_migrations (
|
|
1984
|
+
id ${AutoIncrement({ primaryKey: true })},
|
|
1985
|
+
name ${Varchar(255)} NOT NULL UNIQUE,
|
|
1986
|
+
application ${Varchar(255)} NOT NULL DEFAULT 'default',
|
|
1987
|
+
sql_hash ${Varchar(64)} NOT NULL,
|
|
1988
|
+
timestamp ${Timestamp} NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
1989
|
+
);
|
|
1990
|
+
`;
|
|
1991
|
+
const migrationTableSchemaComponent = schemaComponent("dumbo:schema-component:migrations-table", { migrations: [sqlMigration("dumbo:migrationTable:001", [migrationTableSQL])] });
|
|
1992
|
+
|
|
1993
|
+
//#endregion
|
|
1994
|
+
//#region src/core/schema/migrators/migrator.ts
|
|
1995
|
+
const defaultMigratorOptions = globalThis.defaultMigratorOptions = globalThis.defaultMigratorOptions ?? {};
|
|
1996
|
+
const registerDefaultMigratorOptions = (databaseType, options) => {
|
|
1997
|
+
defaultMigratorOptions[databaseType] = options;
|
|
1998
|
+
};
|
|
1999
|
+
|
|
2000
|
+
//#endregion
|
|
2001
|
+
//#region src/storage/sqlite/core/errors/errorMapper.ts
|
|
2002
|
+
/**
|
|
2003
|
+
* Extracts the SQLite error code string from a `sqlite3` driver error.
|
|
2004
|
+
*
|
|
2005
|
+
* The `sqlite3` (node-sqlite3) driver sets `error.code` to a string like
|
|
2006
|
+
* `'SQLITE_CONSTRAINT'` and `error.errno` to the numeric result code.
|
|
2007
|
+
* See: https://github.com/TryGhost/node-sqlite3
|
|
2008
|
+
*/
|
|
2009
|
+
const getSqliteErrorCode = (error) => {
|
|
2010
|
+
if (error instanceof Error && "code" in error && typeof error.code === "string") return error.code;
|
|
2011
|
+
};
|
|
2012
|
+
const getErrorMessage = (error) => error instanceof Error ? error.message : void 0;
|
|
2013
|
+
const asError = (error) => error instanceof Error ? error : void 0;
|
|
2014
|
+
/**
|
|
2015
|
+
* Maps a constraint error to a specific DumboError subtype by inspecting the
|
|
2016
|
+
* error message. The `sqlite3` driver only exposes the primary result code
|
|
2017
|
+
* `SQLITE_CONSTRAINT` — the constraint subtype (UNIQUE, FOREIGN KEY, etc.)
|
|
2018
|
+
* is embedded in the message string by SQLite, e.g.:
|
|
2019
|
+
* "SQLITE_CONSTRAINT: UNIQUE constraint failed: users.email"
|
|
2020
|
+
*
|
|
2021
|
+
* Reference: https://www.sqlite.org/rescode.html (extended result codes 275–3091)
|
|
2022
|
+
*/
|
|
2023
|
+
const mapConstraintError = (message, innerError) => {
|
|
2024
|
+
const upperMessage = message?.toUpperCase() ?? "";
|
|
2025
|
+
if (upperMessage.includes("UNIQUE") || upperMessage.includes("PRIMARY KEY")) return new UniqueConstraintError(message, innerError);
|
|
2026
|
+
if (upperMessage.includes("FOREIGN KEY")) return new ForeignKeyViolationError(message, innerError);
|
|
2027
|
+
if (upperMessage.includes("NOT NULL")) return new NotNullViolationError(message, innerError);
|
|
2028
|
+
if (upperMessage.includes("CHECK")) return new CheckViolationError(message, innerError);
|
|
2029
|
+
return new IntegrityConstraintViolationError(message, innerError);
|
|
2030
|
+
};
|
|
2031
|
+
/**
|
|
2032
|
+
* Maps a SQLite error (from the `sqlite3` / node-sqlite3 driver) to a typed
|
|
2033
|
+
* DumboError based on the SQLite result code.
|
|
2034
|
+
*
|
|
2035
|
+
* Result code reference: https://www.sqlite.org/rescode.html
|
|
2036
|
+
*
|
|
2037
|
+
* Falls back to a generic DumboError (500) if the error is not a recognized SQLite error.
|
|
2038
|
+
*/
|
|
2039
|
+
const mapSqliteError = (error) => {
|
|
2040
|
+
if (DumboError.isInstanceOf(error)) return error;
|
|
2041
|
+
const code = getSqliteErrorCode(error);
|
|
2042
|
+
if (!code) return new DumboError({
|
|
2043
|
+
errorCode: 500,
|
|
2044
|
+
message: getErrorMessage(error),
|
|
2045
|
+
innerError: asError(error)
|
|
2046
|
+
});
|
|
2047
|
+
const message = getErrorMessage(error);
|
|
2048
|
+
const innerError = asError(error);
|
|
2049
|
+
switch (code) {
|
|
2050
|
+
case "SQLITE_CONSTRAINT": return mapConstraintError(message, innerError);
|
|
2051
|
+
case "SQLITE_BUSY": return new LockNotAvailableError(message, innerError);
|
|
2052
|
+
case "SQLITE_LOCKED": return new DeadlockError(message, innerError);
|
|
2053
|
+
case "SQLITE_PROTOCOL": return new LockNotAvailableError(message, innerError);
|
|
2054
|
+
case "SQLITE_CANTOPEN": return new ConnectionError(message, innerError);
|
|
2055
|
+
case "SQLITE_NOTADB": return new ConnectionError(message, innerError);
|
|
2056
|
+
case "SQLITE_NOMEM": return new InsufficientResourcesError(message, innerError);
|
|
2057
|
+
case "SQLITE_FULL": return new InsufficientResourcesError(message, innerError);
|
|
2058
|
+
case "SQLITE_IOERR": return new SystemError(message, innerError);
|
|
2059
|
+
case "SQLITE_CORRUPT": return new SystemError(message, innerError);
|
|
2060
|
+
case "SQLITE_INTERNAL": return new SystemError(message, innerError);
|
|
2061
|
+
case "SQLITE_NOLFS": return new SystemError(message, innerError);
|
|
2062
|
+
case "SQLITE_TOOBIG": return new DataError(message, innerError);
|
|
2063
|
+
case "SQLITE_MISMATCH": return new DataError(message, innerError);
|
|
2064
|
+
case "SQLITE_RANGE": return new DataError(message, innerError);
|
|
2065
|
+
case "SQLITE_ERROR": return new InvalidOperationError(message, innerError);
|
|
2066
|
+
case "SQLITE_READONLY": return new InvalidOperationError(message, innerError);
|
|
2067
|
+
case "SQLITE_MISUSE": return new InvalidOperationError(message, innerError);
|
|
2068
|
+
case "SQLITE_AUTH": return new InvalidOperationError(message, innerError);
|
|
2069
|
+
case "SQLITE_PERM": return new InvalidOperationError(message, innerError);
|
|
2070
|
+
case "SQLITE_SCHEMA": return new InvalidOperationError(message, innerError);
|
|
2071
|
+
case "SQLITE_ABORT": return new SerializationError(message, innerError);
|
|
2072
|
+
case "SQLITE_INTERRUPT": return new SerializationError(message, innerError);
|
|
2073
|
+
}
|
|
2074
|
+
return new DumboError({
|
|
2075
|
+
errorCode: 500,
|
|
2076
|
+
message,
|
|
2077
|
+
innerError
|
|
2078
|
+
});
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
//#endregion
|
|
2082
|
+
//#region src/storage/sqlite/core/sql/processors/columProcessors.ts
|
|
2083
|
+
const mapColumnType = (token, { builder }) => {
|
|
2084
|
+
let columnSQL;
|
|
2085
|
+
const { sqlTokenType } = token;
|
|
2086
|
+
switch (sqlTokenType) {
|
|
2087
|
+
case "SQL_COLUMN_AUTO_INCREMENT":
|
|
2088
|
+
columnSQL = `INTEGER ${token.primaryKey ? "PRIMARY KEY" : ""} AUTOINCREMENT`;
|
|
2089
|
+
break;
|
|
2090
|
+
case "SQL_COLUMN_BIGINT":
|
|
2091
|
+
columnSQL = "INTEGER";
|
|
2092
|
+
break;
|
|
2093
|
+
case "SQL_COLUMN_SERIAL":
|
|
2094
|
+
columnSQL = "INTEGER";
|
|
2095
|
+
break;
|
|
2096
|
+
case "SQL_COLUMN_INTEGER":
|
|
2097
|
+
columnSQL = "INTEGER";
|
|
2098
|
+
break;
|
|
2099
|
+
case "SQL_COLUMN_JSONB":
|
|
2100
|
+
columnSQL = "BLOB";
|
|
2101
|
+
break;
|
|
2102
|
+
case "SQL_COLUMN_BIGSERIAL":
|
|
2103
|
+
columnSQL = "INTEGER";
|
|
2104
|
+
break;
|
|
2105
|
+
case "SQL_COLUMN_TIMESTAMP":
|
|
2106
|
+
columnSQL = "DATETIME";
|
|
2107
|
+
break;
|
|
2108
|
+
case "SQL_COLUMN_TIMESTAMPTZ":
|
|
2109
|
+
columnSQL = "DATETIME";
|
|
2110
|
+
break;
|
|
2111
|
+
case "SQL_COLUMN_VARCHAR":
|
|
2112
|
+
columnSQL = `VARCHAR ${Number.isNaN(token.length) ? "" : `(${token.length})`}`;
|
|
2113
|
+
break;
|
|
2114
|
+
default: throw new Error(`Unknown column type: ${sqlTokenType}`);
|
|
2115
|
+
}
|
|
2116
|
+
builder.addSQL(columnSQL);
|
|
2117
|
+
};
|
|
2118
|
+
const sqliteColumnProcessors = mapDefaultSQLColumnProcessors(mapColumnType);
|
|
2119
|
+
|
|
2120
|
+
//#endregion
|
|
2121
|
+
//#region src/storage/sqlite/core/sql/formatter/index.ts
|
|
2122
|
+
const sqliteFormatter = SQLFormatter({ processorsRegistry: SQLProcessorsRegistry({ from: defaultProcessorsRegistry }).register(sqliteColumnProcessors) });
|
|
2123
|
+
registerFormatter("SQLite", sqliteFormatter);
|
|
2124
|
+
|
|
2125
|
+
//#endregion
|
|
2126
|
+
//#region src/storage/sqlite/core/execute/execute.ts
|
|
2127
|
+
const sqliteExecute = async (database, handle) => {
|
|
2128
|
+
try {
|
|
2129
|
+
return await handle(database);
|
|
2130
|
+
} finally {
|
|
2131
|
+
await database.close();
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
const sqliteSQLExecutor = (driverType, serializer, formatter, errorMapper) => ({
|
|
2135
|
+
driverType,
|
|
2136
|
+
query: async (client, sql, options) => {
|
|
2137
|
+
tracer.info("db:sql:query", {
|
|
2138
|
+
query: (formatter ?? sqliteFormatter).format(sql, { serializer }).query,
|
|
2139
|
+
params: (formatter ?? sqliteFormatter).format(sql, { serializer }).params,
|
|
2140
|
+
debugSQL: (formatter ?? sqliteFormatter).describe(sql, { serializer })
|
|
2141
|
+
});
|
|
2142
|
+
try {
|
|
2143
|
+
let result = await client.query(sql, options);
|
|
2144
|
+
if (options?.mapping) result = {
|
|
2145
|
+
...result,
|
|
2146
|
+
rows: result.rows.map((row) => mapSQLQueryResult(row, options.mapping))
|
|
2147
|
+
};
|
|
2148
|
+
return result;
|
|
2149
|
+
} catch (error) {
|
|
2150
|
+
tracer.error("db:sql:query:execute:error", { error });
|
|
2151
|
+
throw (errorMapper ?? mapSqliteError)(error);
|
|
2152
|
+
}
|
|
2153
|
+
},
|
|
2154
|
+
batchQuery: async (client, sqls, options) => {
|
|
2155
|
+
try {
|
|
2156
|
+
const results = await client.batchQuery(sqls, options);
|
|
2157
|
+
if (options?.mapping) return results.map((result) => ({
|
|
2158
|
+
...result,
|
|
2159
|
+
rows: result.rows.map((row) => mapSQLQueryResult(row, options.mapping))
|
|
2160
|
+
}));
|
|
2161
|
+
return results;
|
|
2162
|
+
} catch (error) {
|
|
2163
|
+
tracer.error("db:sql:batch_query:execute:error", { error });
|
|
2164
|
+
throw (errorMapper ?? mapSqliteError)(error);
|
|
2165
|
+
}
|
|
2166
|
+
},
|
|
2167
|
+
command: async (client, sql, options) => {
|
|
2168
|
+
tracer.info("db:sql:command", {
|
|
2169
|
+
query: (formatter ?? sqliteFormatter).format(sql, { serializer }).query,
|
|
2170
|
+
params: (formatter ?? sqliteFormatter).format(sql, { serializer }).params,
|
|
2171
|
+
debugSQL: (formatter ?? sqliteFormatter).describe(sql, { serializer })
|
|
2172
|
+
});
|
|
2173
|
+
try {
|
|
2174
|
+
return await client.command(sql, options);
|
|
2175
|
+
} catch (error) {
|
|
2176
|
+
tracer.error("db:sql:command:execute:error", { error });
|
|
2177
|
+
throw (errorMapper ?? mapSqliteError)(error);
|
|
2178
|
+
}
|
|
2179
|
+
},
|
|
2180
|
+
batchCommand: async (client, sqls, options) => {
|
|
2181
|
+
try {
|
|
2182
|
+
return await client.batchCommand(sqls, options);
|
|
2183
|
+
} catch (error) {
|
|
2184
|
+
tracer.error("db:sql:batch_command:execute:error", { error });
|
|
2185
|
+
throw (errorMapper ?? mapSqliteError)(error);
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
formatter: formatter ?? sqliteFormatter
|
|
2189
|
+
});
|
|
2190
|
+
|
|
2191
|
+
//#endregion
|
|
2192
|
+
//#region src/storage/sqlite/core/transactions/index.ts
|
|
2193
|
+
const sqliteTransaction = (driverType, connection, allowNestedTransactions, serializer, defaultTransactionMode) => (getClient, options) => {
|
|
2194
|
+
allowNestedTransactions = options?.allowNestedTransactions ?? allowNestedTransactions;
|
|
2195
|
+
const useSavepoints = options?.useSavepoints ?? false;
|
|
2196
|
+
const tx = databaseTransaction({
|
|
2197
|
+
begin: async () => {
|
|
2198
|
+
const client = await getClient;
|
|
2199
|
+
const mode = options?.mode ?? defaultTransactionMode ?? "IMMEDIATE";
|
|
2200
|
+
await client.command(SQL`BEGIN ${SQL.plain(mode)} TRANSACTION`);
|
|
2201
|
+
},
|
|
2202
|
+
commit: async () => {
|
|
2203
|
+
const client = await getClient;
|
|
2204
|
+
try {
|
|
2205
|
+
await client.command(SQL`COMMIT`);
|
|
2206
|
+
} finally {
|
|
2207
|
+
if (options?.close) await options.close(client);
|
|
2208
|
+
}
|
|
2209
|
+
},
|
|
2210
|
+
rollback: async (error) => {
|
|
2211
|
+
const client = await getClient;
|
|
2212
|
+
try {
|
|
2213
|
+
await client.command(SQL`ROLLBACK`);
|
|
2214
|
+
} finally {
|
|
2215
|
+
if (options?.close) await options.close(client, error);
|
|
2216
|
+
}
|
|
2217
|
+
},
|
|
2218
|
+
savepoint: async (level) => {
|
|
2219
|
+
await (await getClient).command(SQL`SAVEPOINT transaction${SQL.plain(level.toString())}`);
|
|
2220
|
+
},
|
|
2221
|
+
releaseSavepoint: async (level) => {
|
|
2222
|
+
await (await getClient).command(SQL`RELEASE transaction${SQL.plain(level.toString())}`);
|
|
2223
|
+
}
|
|
2224
|
+
}, {
|
|
2225
|
+
allowNestedTransactions,
|
|
2226
|
+
useSavepoints
|
|
2227
|
+
});
|
|
2228
|
+
return {
|
|
2229
|
+
connection: connection(),
|
|
2230
|
+
driverType,
|
|
2231
|
+
begin: tx.begin,
|
|
2232
|
+
commit: tx.commit,
|
|
2233
|
+
rollback: tx.rollback,
|
|
2234
|
+
execute: sqlExecutor(sqliteSQLExecutor(driverType, serializer), { connect: () => getClient }),
|
|
2235
|
+
_transactionOptions: {
|
|
2236
|
+
...options,
|
|
2237
|
+
allowNestedTransactions
|
|
2238
|
+
}
|
|
2239
|
+
};
|
|
2240
|
+
};
|
|
2241
|
+
|
|
2242
|
+
//#endregion
|
|
2243
|
+
//#region src/storage/sqlite/core/connections/connectionString.ts
|
|
2244
|
+
const SQLiteConnectionString = (connectionString) => {
|
|
2245
|
+
if (!connectionString.startsWith("file:") && connectionString !== ":memory:" && !connectionString.startsWith("/") && !connectionString.startsWith("./")) throw new Error(`Invalid SQLite connection string: ${connectionString}. It should start with "file:", ":memory:", "/", or "./".`);
|
|
2246
|
+
return connectionString;
|
|
2247
|
+
};
|
|
2248
|
+
const parsePragmasFromConnectionString = (connectionString) => {
|
|
2249
|
+
const str = String(connectionString);
|
|
2250
|
+
if (!str.startsWith("file:")) return {};
|
|
2251
|
+
const params = new URL(str).searchParams;
|
|
2252
|
+
const pragmas = {};
|
|
2253
|
+
const journalMode = params.get("journal_mode");
|
|
2254
|
+
if (journalMode !== null) pragmas.journal_mode = journalMode;
|
|
2255
|
+
const synchronous = params.get("synchronous");
|
|
2256
|
+
if (synchronous !== null) pragmas.synchronous = synchronous;
|
|
2257
|
+
const cacheSize = params.get("cache_size");
|
|
2258
|
+
if (cacheSize !== null) pragmas.cache_size = parseInt(cacheSize, 10);
|
|
2259
|
+
const foreignKeys = params.get("foreign_keys");
|
|
2260
|
+
if (foreignKeys !== null) {
|
|
2261
|
+
const val = foreignKeys.toLowerCase();
|
|
2262
|
+
pragmas.foreign_keys = val === "true" || val === "on" || val === "1";
|
|
2263
|
+
}
|
|
2264
|
+
const tempStore = params.get("temp_store");
|
|
2265
|
+
if (tempStore !== null) pragmas.temp_store = tempStore.toUpperCase();
|
|
2266
|
+
const busyTimeout = params.get("busy_timeout");
|
|
2267
|
+
if (busyTimeout !== null) pragmas.busy_timeout = parseInt(busyTimeout, 10);
|
|
2268
|
+
const mmapSize = params.get("mmap_size");
|
|
2269
|
+
if (mmapSize !== null) pragmas.mmap_size = parseInt(mmapSize, 10);
|
|
2270
|
+
return pragmas;
|
|
2271
|
+
};
|
|
2272
|
+
|
|
2273
|
+
//#endregion
|
|
2274
|
+
//#region src/storage/sqlite/core/connections/index.ts
|
|
2275
|
+
const isSQLiteError = (error) => {
|
|
2276
|
+
if (error instanceof Error && "code" in error) return true;
|
|
2277
|
+
return false;
|
|
2278
|
+
};
|
|
2279
|
+
const sqliteAmbientClientConnection = (options) => {
|
|
2280
|
+
const { client, driverType, initTransaction, allowNestedTransactions, defaultTransactionMode, serializer, errorMapper } = options;
|
|
2281
|
+
return createAmbientConnection({
|
|
2282
|
+
driverType,
|
|
2283
|
+
client,
|
|
2284
|
+
initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, allowNestedTransactions ?? false, serializer, defaultTransactionMode)),
|
|
2285
|
+
executor: ({ serializer }) => sqliteSQLExecutor(driverType, serializer, void 0, errorMapper),
|
|
2286
|
+
serializer
|
|
2287
|
+
});
|
|
2288
|
+
};
|
|
2289
|
+
const sqliteClientConnection = (options) => {
|
|
2290
|
+
const { connectionOptions, sqliteClientFactory, serializer } = options;
|
|
2291
|
+
let client = null;
|
|
2292
|
+
const connect = async () => {
|
|
2293
|
+
if (client) return Promise.resolve(client);
|
|
2294
|
+
client = sqliteClientFactory(connectionOptions);
|
|
2295
|
+
if (client && "connect" in client && typeof client.connect === "function") try {
|
|
2296
|
+
await client.connect();
|
|
2297
|
+
} catch (error) {
|
|
2298
|
+
throw mapSqliteError(error);
|
|
2299
|
+
}
|
|
2300
|
+
return client;
|
|
2301
|
+
};
|
|
2302
|
+
return createConnection({
|
|
2303
|
+
driverType: options.driverType,
|
|
2304
|
+
connect,
|
|
2305
|
+
close: async () => {
|
|
2306
|
+
if (client && "close" in client && typeof client.close === "function") await client.close();
|
|
2307
|
+
else if (client && "release" in client && typeof client.release === "function") client.release();
|
|
2308
|
+
},
|
|
2309
|
+
initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
|
|
2310
|
+
executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
|
|
2311
|
+
serializer
|
|
2312
|
+
});
|
|
2313
|
+
};
|
|
2314
|
+
const sqlitePoolClientConnection = (options) => {
|
|
2315
|
+
const { connectionOptions, sqliteClientFactory, serializer } = options;
|
|
2316
|
+
let client = null;
|
|
2317
|
+
const connect = async () => {
|
|
2318
|
+
if (client) return Promise.resolve(client);
|
|
2319
|
+
client = sqliteClientFactory(connectionOptions);
|
|
2320
|
+
try {
|
|
2321
|
+
await client.connect();
|
|
2322
|
+
} catch (error) {
|
|
2323
|
+
throw mapSqliteError(error);
|
|
2324
|
+
}
|
|
2325
|
+
return client;
|
|
2326
|
+
};
|
|
2327
|
+
return createConnection({
|
|
2328
|
+
driverType: options.driverType,
|
|
2329
|
+
connect,
|
|
2330
|
+
close: () => client !== null ? Promise.resolve(client.release()) : Promise.resolve(),
|
|
2331
|
+
initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
|
|
2332
|
+
executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
|
|
2333
|
+
serializer
|
|
2334
|
+
});
|
|
2335
|
+
};
|
|
2336
|
+
function sqliteConnection(options) {
|
|
2337
|
+
return options.type === "Client" ? sqliteClientConnection(options) : sqlitePoolClientConnection(options);
|
|
2338
|
+
}
|
|
2339
|
+
const InMemorySQLiteDatabase = SQLiteConnectionString(":memory:");
|
|
2340
|
+
const DEFAULT_SQLITE_PRAGMA_OPTIONS = {
|
|
2341
|
+
journal_mode: "WAL",
|
|
2342
|
+
synchronous: "NORMAL",
|
|
2343
|
+
cache_size: -1e6,
|
|
2344
|
+
foreign_keys: true,
|
|
2345
|
+
temp_store: "MEMORY",
|
|
2346
|
+
busy_timeout: 5e3,
|
|
2347
|
+
mmap_size: 268435456
|
|
2348
|
+
};
|
|
2349
|
+
|
|
2350
|
+
//#endregion
|
|
2351
|
+
//#region src/storage/sqlite/core/pool/pool.ts
|
|
2352
|
+
const isInMemoryDatabase = (options) => {
|
|
2353
|
+
if ("fileName" in options) return options.fileName === InMemorySQLiteDatabase;
|
|
2354
|
+
if ("connectionString" in options) return options.connectionString === InMemorySQLiteDatabase;
|
|
2355
|
+
return false;
|
|
2356
|
+
};
|
|
2357
|
+
const sqliteAmbientConnectionPool = (options) => {
|
|
2358
|
+
const { connection, driverType } = options;
|
|
2359
|
+
return createAmbientConnectionPool({
|
|
2360
|
+
driverType,
|
|
2361
|
+
connection
|
|
2362
|
+
});
|
|
2363
|
+
};
|
|
2364
|
+
const sqliteSingletonConnectionPool = (options) => {
|
|
2365
|
+
const { driverType, sqliteConnectionFactory, connectionOptions } = options;
|
|
2366
|
+
return createSingletonConnectionPool({
|
|
2367
|
+
driverType,
|
|
2368
|
+
getConnection: () => sqliteConnectionFactory(connectionOptions)
|
|
2369
|
+
});
|
|
2370
|
+
};
|
|
2371
|
+
const sqliteAlwaysNewConnectionPool = (options) => {
|
|
2372
|
+
const { driverType, sqliteConnectionFactory, connectionOptions } = options;
|
|
2373
|
+
return createAlwaysNewConnectionPool({
|
|
2374
|
+
driverType,
|
|
2375
|
+
getConnection: () => sqliteConnectionFactory(connectionOptions)
|
|
2376
|
+
});
|
|
2377
|
+
};
|
|
2378
|
+
const toSqlitePoolOptions = (options) => {
|
|
2379
|
+
const { singleton, ...rest } = options;
|
|
2380
|
+
const isInMemory = isInMemoryDatabase(options);
|
|
2381
|
+
if ("client" in options && options.client) return {
|
|
2382
|
+
...rest,
|
|
2383
|
+
singleton: true
|
|
2384
|
+
};
|
|
2385
|
+
if (isInMemory) return {
|
|
2386
|
+
...rest,
|
|
2387
|
+
singleton: true
|
|
2388
|
+
};
|
|
2389
|
+
if (singleton === true) return {
|
|
2390
|
+
...rest,
|
|
2391
|
+
singleton: true
|
|
2392
|
+
};
|
|
2393
|
+
return rest;
|
|
2394
|
+
};
|
|
2395
|
+
function sqlitePool(options) {
|
|
2396
|
+
const { driverType } = options;
|
|
2397
|
+
if (options.connection) return createAmbientConnectionPool({
|
|
2398
|
+
driverType,
|
|
2399
|
+
connection: options.connection
|
|
2400
|
+
});
|
|
2401
|
+
if (options.singleton === true && options.sqliteConnectionFactory) return createSingletonConnectionPool({
|
|
2402
|
+
driverType,
|
|
2403
|
+
getConnection: () => options.sqliteConnectionFactory(options.connectionOptions)
|
|
2404
|
+
});
|
|
2405
|
+
return createAlwaysNewConnectionPool({
|
|
2406
|
+
driverType,
|
|
2407
|
+
getConnection: () => options.sqliteConnectionFactory(options.connectionOptions)
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
//#endregion
|
|
2412
|
+
//#region src/storage/sqlite/core/schema/migrations.ts
|
|
2413
|
+
const DefaultSQLiteMigratorOptions = {};
|
|
2414
|
+
registerDefaultMigratorOptions("SQLite", DefaultSQLiteMigratorOptions);
|
|
2415
|
+
|
|
2416
|
+
//#endregion
|
|
2417
|
+
//#region src/storage/sqlite/core/schema/schema.ts
|
|
2418
|
+
const defaultSQLiteDatabase = ":memory:";
|
|
2419
|
+
const tableExistsSQL = (tableName) => SQL`
|
|
2420
|
+
SELECT EXISTS (
|
|
2421
|
+
SELECT 1
|
|
2422
|
+
FROM sqlite_master
|
|
2423
|
+
WHERE type = 'table' AND name = ${tableName}
|
|
2424
|
+
) AS "exists"
|
|
2425
|
+
`;
|
|
2426
|
+
const tableExists = async (execute, tableName) => exists(execute.query(tableExistsSQL(tableName)));
|
|
2427
|
+
|
|
2428
|
+
//#endregion
|
|
2429
|
+
//#region src/storage/sqlite/core/schema/sqliteMetadata.ts
|
|
2430
|
+
const sqliteMetadata = {
|
|
2431
|
+
databaseType: "SQLite",
|
|
2432
|
+
capabilities: {
|
|
2433
|
+
supportsSchemas: false,
|
|
2434
|
+
supportsFunctions: false,
|
|
2435
|
+
supportsMultipleDatabases: false
|
|
2436
|
+
},
|
|
2437
|
+
tableExists
|
|
2438
|
+
};
|
|
2439
|
+
dumboDatabaseMetadataRegistry.register("SQLite", sqliteMetadata);
|
|
2440
|
+
|
|
2441
|
+
//#endregion
|
|
2442
|
+
//#region src/storage/sqlite/core/sql/json.ts
|
|
2443
|
+
const path = (path) => SQL.literal(`$.${path}`);
|
|
2444
|
+
const SQLiteJSON = { path };
|
|
2445
|
+
|
|
2446
|
+
//#endregion
|
|
2447
|
+
//#region src/storage/sqlite/core/index.ts
|
|
2448
|
+
const SQLiteDatabaseName = "SQLite";
|
|
2449
|
+
|
|
2450
|
+
//#endregion
|
|
10
2451
|
//#region src/storage/sqlite/core/connections/pragmas.ts
|
|
11
2452
|
const mergePragmaOptions = (connectionString, userOptions) => {
|
|
12
|
-
const connectionStringPragmas =
|
|
2453
|
+
const connectionStringPragmas = parsePragmasFromConnectionString(connectionString);
|
|
13
2454
|
return {
|
|
14
|
-
...
|
|
2455
|
+
...DEFAULT_SQLITE_PRAGMA_OPTIONS,
|
|
15
2456
|
...connectionStringPragmas,
|
|
16
2457
|
...userOptions
|
|
17
2458
|
};
|
|
@@ -70,7 +2511,7 @@ const sqlite3Client = (options) => {
|
|
|
70
2511
|
let db;
|
|
71
2512
|
let isClosed = false;
|
|
72
2513
|
const { serializer } = options;
|
|
73
|
-
const connectionString = options.fileName ?? options.connectionString ??
|
|
2514
|
+
const connectionString = options.fileName ?? options.connectionString ?? InMemorySQLiteDatabase;
|
|
74
2515
|
const finalPragmas = mergePragmaOptions(String(connectionString), options.pragmaOptions);
|
|
75
2516
|
const connectionPragmas = buildConnectionPragmaStatements(finalPragmas);
|
|
76
2517
|
const connect = () => db ? Promise.resolve() : new Promise((resolve, reject) => {
|
|
@@ -80,7 +2521,7 @@ const sqlite3Client = (options) => {
|
|
|
80
2521
|
reject(err);
|
|
81
2522
|
return;
|
|
82
2523
|
}
|
|
83
|
-
const busyTimeout = finalPragmas.busy_timeout ??
|
|
2524
|
+
const busyTimeout = finalPragmas.busy_timeout ?? DEFAULT_SQLITE_PRAGMA_OPTIONS.busy_timeout;
|
|
84
2525
|
db.configure("busyTimeout", busyTimeout);
|
|
85
2526
|
applyPragmas(db, connectionPragmas.filter((p) => p.pragma !== "busy_timeout")).then(async () => {
|
|
86
2527
|
if (options.skipDatabasePragmas) return;
|
|
@@ -169,26 +2610,26 @@ const sqlite3Client = (options) => {
|
|
|
169
2610
|
});
|
|
170
2611
|
});
|
|
171
2612
|
} catch (error) {
|
|
172
|
-
throw
|
|
2613
|
+
throw mapSqliteError(error);
|
|
173
2614
|
}
|
|
174
2615
|
},
|
|
175
2616
|
query: async (sql, _options) => {
|
|
176
2617
|
try {
|
|
177
|
-
const { query, params } =
|
|
2618
|
+
const { query, params } = sqliteFormatter.format(sql, { serializer });
|
|
178
2619
|
const result = await executeQuery(query, params);
|
|
179
2620
|
return {
|
|
180
2621
|
rowCount: result.length,
|
|
181
2622
|
rows: result
|
|
182
2623
|
};
|
|
183
2624
|
} catch (error) {
|
|
184
|
-
throw
|
|
2625
|
+
throw mapSqliteError(error);
|
|
185
2626
|
}
|
|
186
2627
|
},
|
|
187
2628
|
batchQuery: async (sqls, _options) => {
|
|
188
2629
|
try {
|
|
189
2630
|
const results = [];
|
|
190
2631
|
for (const sql of sqls) {
|
|
191
|
-
const { query, params } =
|
|
2632
|
+
const { query, params } = sqliteFormatter.format(sql, { serializer });
|
|
192
2633
|
const result = await executeQuery(query, params);
|
|
193
2634
|
results.push({
|
|
194
2635
|
rowCount: result.length,
|
|
@@ -197,29 +2638,29 @@ const sqlite3Client = (options) => {
|
|
|
197
2638
|
}
|
|
198
2639
|
return results;
|
|
199
2640
|
} catch (error) {
|
|
200
|
-
throw
|
|
2641
|
+
throw mapSqliteError(error);
|
|
201
2642
|
}
|
|
202
2643
|
},
|
|
203
2644
|
command: async (sql, options) => {
|
|
204
2645
|
try {
|
|
205
|
-
const { query, params } =
|
|
2646
|
+
const { query, params } = sqliteFormatter.format(sql, { serializer });
|
|
206
2647
|
return await executeCommand(query, params, options);
|
|
207
2648
|
} catch (error) {
|
|
208
|
-
throw
|
|
2649
|
+
throw mapSqliteError(error);
|
|
209
2650
|
}
|
|
210
2651
|
},
|
|
211
2652
|
batchCommand: async (sqls, options) => {
|
|
212
2653
|
try {
|
|
213
2654
|
const results = [];
|
|
214
2655
|
for (let i = 0; i < sqls.length; i++) {
|
|
215
|
-
const { query, params } =
|
|
2656
|
+
const { query, params } = sqliteFormatter.format(sqls[i], { serializer });
|
|
216
2657
|
const result = await executeCommand(query, params, options);
|
|
217
2658
|
results.push(result);
|
|
218
|
-
if (options?.assertChanges && (result.rowCount ?? 0) === 0) throw new
|
|
2659
|
+
if (options?.assertChanges && (result.rowCount ?? 0) === 0) throw new BatchCommandNoChangesError(i);
|
|
219
2660
|
}
|
|
220
2661
|
return results;
|
|
221
2662
|
} catch (error) {
|
|
222
|
-
throw
|
|
2663
|
+
throw mapSqliteError(error);
|
|
223
2664
|
}
|
|
224
2665
|
}
|
|
225
2666
|
};
|
|
@@ -230,7 +2671,7 @@ const checkConnection = async (fileName, serializer) => {
|
|
|
230
2671
|
serializer
|
|
231
2672
|
});
|
|
232
2673
|
try {
|
|
233
|
-
await client.query(
|
|
2674
|
+
await client.query(SQL`SELECT 1`);
|
|
234
2675
|
return { successful: true };
|
|
235
2676
|
} catch (error) {
|
|
236
2677
|
const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
@@ -244,7 +2685,7 @@ const checkConnection = async (fileName, serializer) => {
|
|
|
244
2685
|
await client.close();
|
|
245
2686
|
}
|
|
246
2687
|
};
|
|
247
|
-
const sqlite3Connection = (options) =>
|
|
2688
|
+
const sqlite3Connection = (options) => sqliteConnection({
|
|
248
2689
|
type: "Client",
|
|
249
2690
|
driverType: SQLite3DriverType,
|
|
250
2691
|
sqliteClientFactory: (connectionOptions) => {
|
|
@@ -260,15 +2701,18 @@ const sqlite3Connection = (options) => require_core$1.sqliteConnection({
|
|
|
260
2701
|
|
|
261
2702
|
//#endregion
|
|
262
2703
|
//#region src/storage/sqlite/sqlite3/pool/singletonPool.ts
|
|
2704
|
+
const DEFAULT_SQLITE_MAX_TASK_IDLE_TIME_MS = 3e4;
|
|
263
2705
|
const sqlite3SingletonPool = (options) => {
|
|
264
|
-
const
|
|
2706
|
+
const maxTaskIdleTime = options.maxTaskIdleTime ?? 3e4;
|
|
2707
|
+
const inner = createSingletonConnectionPool({
|
|
265
2708
|
driverType: options.driverType,
|
|
266
2709
|
getConnection: options.getConnection,
|
|
267
2710
|
...options.closeConnection ? { closeConnection: options.closeConnection } : {}
|
|
268
2711
|
});
|
|
269
|
-
const taskProcessor = new
|
|
2712
|
+
const taskProcessor = new TaskProcessor({
|
|
270
2713
|
maxActiveTasks: 1,
|
|
271
|
-
maxQueueSize: options.maxQueueSize ?? 1e3
|
|
2714
|
+
maxQueueSize: options.maxQueueSize ?? 1e3,
|
|
2715
|
+
maxTaskIdleTime
|
|
272
2716
|
});
|
|
273
2717
|
const insideWriterTask = new node_async_hooks.AsyncLocalStorage();
|
|
274
2718
|
const enqueue = (op) => {
|
|
@@ -293,9 +2737,9 @@ const sqlite3SingletonPool = (options) => {
|
|
|
293
2737
|
command: (sql, commandOptions) => enqueue(() => inner.execute.command(sql, commandOptions)),
|
|
294
2738
|
batchCommand: (sqls, commandOptions) => enqueue(() => inner.execute.batchCommand(sqls, commandOptions))
|
|
295
2739
|
},
|
|
296
|
-
close: async () => {
|
|
297
|
-
await taskProcessor.stop();
|
|
298
|
-
await inner.close();
|
|
2740
|
+
close: async (closeOptions) => {
|
|
2741
|
+
await taskProcessor.stop({ ...closeOptions?.force ? { force: true } : {} });
|
|
2742
|
+
await inner.close(closeOptions);
|
|
299
2743
|
}
|
|
300
2744
|
};
|
|
301
2745
|
};
|
|
@@ -306,7 +2750,7 @@ const sqliteDualConnectionPool = (options) => {
|
|
|
306
2750
|
const { sqliteConnectionFactory, connectionOptions } = options;
|
|
307
2751
|
const readerPoolSize = options.readerPoolSize ?? Math.max(4, (0, os.cpus)().length);
|
|
308
2752
|
let databaseInitPromise = null;
|
|
309
|
-
const guardSingleConnection =
|
|
2753
|
+
const guardSingleConnection = guardInitializedOnce(async () => {
|
|
310
2754
|
if (databaseInitPromise !== null) return databaseInitPromise;
|
|
311
2755
|
const initConnection = sqliteConnectionFactory({
|
|
312
2756
|
...connectionOptions,
|
|
@@ -321,7 +2765,7 @@ const sqliteDualConnectionPool = (options) => {
|
|
|
321
2765
|
} catch (error) {
|
|
322
2766
|
databaseInitPromise = null;
|
|
323
2767
|
await initConnection.close();
|
|
324
|
-
throw
|
|
2768
|
+
throw mapSqliteError(error);
|
|
325
2769
|
}
|
|
326
2770
|
});
|
|
327
2771
|
const ensureDatabaseInitialized = async () => {
|
|
@@ -340,9 +2784,10 @@ const sqliteDualConnectionPool = (options) => {
|
|
|
340
2784
|
};
|
|
341
2785
|
const writerPool = sqlite3SingletonPool({
|
|
342
2786
|
driverType: options.driverType,
|
|
343
|
-
getConnection: () => wrappedConnectionFactory(false, connectionOptions)
|
|
2787
|
+
getConnection: () => wrappedConnectionFactory(false, connectionOptions),
|
|
2788
|
+
...options.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: options.maxTaskIdleTime } : {}
|
|
344
2789
|
});
|
|
345
|
-
const readerPool =
|
|
2790
|
+
const readerPool = createBoundedConnectionPool({
|
|
346
2791
|
driverType: options.driverType,
|
|
347
2792
|
getConnection: () => wrappedConnectionFactory(true, connectionOptions),
|
|
348
2793
|
maxConnections: readerPoolSize
|
|
@@ -369,29 +2814,37 @@ const sqliteDualConnectionPool = (options) => {
|
|
|
369
2814
|
//#endregion
|
|
370
2815
|
//#region src/storage/sqlite/sqlite3/index.ts
|
|
371
2816
|
const sqlite3Pool = (options) => {
|
|
372
|
-
if ("connection" in options && options.connection) return
|
|
2817
|
+
if ("connection" in options && options.connection) return sqlitePool(toSqlitePoolOptions({
|
|
373
2818
|
...options,
|
|
374
2819
|
driverType: SQLite3DriverType
|
|
375
2820
|
}));
|
|
376
2821
|
const sqliteConnectionFactory = (opts) => sqlite3Connection({
|
|
377
2822
|
...opts,
|
|
378
|
-
serializer: options.serializer ??
|
|
2823
|
+
serializer: options.serializer ?? JSONSerializer
|
|
379
2824
|
});
|
|
380
|
-
|
|
2825
|
+
const isSingleton = isInMemoryDatabase(options) || "client" in options && Boolean(options.client) || options.singleton === true;
|
|
2826
|
+
const lifecycleOptions = extractLifecycleOptions(options);
|
|
2827
|
+
if (isSingleton) return sqlite3SingletonPool({
|
|
381
2828
|
driverType: SQLite3DriverType,
|
|
382
|
-
getConnection: () => sqliteConnectionFactory(options)
|
|
2829
|
+
getConnection: () => sqliteConnectionFactory(options),
|
|
2830
|
+
...lifecycleOptions
|
|
383
2831
|
});
|
|
384
2832
|
const readerPoolSize = options.readerPoolSize;
|
|
385
2833
|
return sqliteDualConnectionPool({
|
|
386
2834
|
driverType: SQLite3DriverType,
|
|
387
2835
|
sqliteConnectionFactory,
|
|
388
2836
|
connectionOptions: options,
|
|
389
|
-
...readerPoolSize !== void 0 ? { readerPoolSize } : {}
|
|
2837
|
+
...readerPoolSize !== void 0 ? { readerPoolSize } : {},
|
|
2838
|
+
...lifecycleOptions
|
|
390
2839
|
});
|
|
391
2840
|
};
|
|
2841
|
+
const extractLifecycleOptions = (options) => {
|
|
2842
|
+
const lifecycle = options;
|
|
2843
|
+
return { ...lifecycle.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: lifecycle.maxTaskIdleTime } : {} };
|
|
2844
|
+
};
|
|
392
2845
|
const tryParseConnectionString = (connectionString) => {
|
|
393
2846
|
try {
|
|
394
|
-
return
|
|
2847
|
+
return SQLiteConnectionString(connectionString);
|
|
395
2848
|
} catch {
|
|
396
2849
|
return null;
|
|
397
2850
|
}
|
|
@@ -399,49 +2852,48 @@ const tryParseConnectionString = (connectionString) => {
|
|
|
399
2852
|
const sqlite3DumboDriver = {
|
|
400
2853
|
driverType: SQLite3DriverType,
|
|
401
2854
|
createPool: (options) => sqlite3Pool(options),
|
|
402
|
-
sqlFormatter:
|
|
403
|
-
defaultMigratorOptions:
|
|
404
|
-
canHandle:
|
|
405
|
-
databaseMetadata:
|
|
2855
|
+
sqlFormatter: sqliteFormatter,
|
|
2856
|
+
defaultMigratorOptions: DefaultSQLiteMigratorOptions,
|
|
2857
|
+
canHandle: canHandleDriverWithConnectionString(SQLite3DriverType, tryParseConnectionString),
|
|
2858
|
+
databaseMetadata: sqliteMetadata
|
|
406
2859
|
};
|
|
407
2860
|
const useSqlite3DumboDriver = () => {
|
|
408
|
-
|
|
2861
|
+
dumboDatabaseDriverRegistry.register(SQLite3DriverType, sqlite3DumboDriver);
|
|
409
2862
|
};
|
|
410
2863
|
useSqlite3DumboDriver();
|
|
411
2864
|
|
|
412
2865
|
//#endregion
|
|
413
|
-
exports.DEFAULT_SQLITE_PRAGMA_OPTIONS =
|
|
414
|
-
exports.DefaultSQLiteMigratorOptions =
|
|
415
|
-
exports.InMemorySQLiteDatabase =
|
|
2866
|
+
exports.DEFAULT_SQLITE_PRAGMA_OPTIONS = DEFAULT_SQLITE_PRAGMA_OPTIONS;
|
|
2867
|
+
exports.DefaultSQLiteMigratorOptions = DefaultSQLiteMigratorOptions;
|
|
2868
|
+
exports.InMemorySQLiteDatabase = InMemorySQLiteDatabase;
|
|
416
2869
|
exports.SQLite3DriverType = SQLite3DriverType;
|
|
417
|
-
exports.SQLiteConnectionString =
|
|
418
|
-
exports.SQLiteDatabaseName =
|
|
419
|
-
exports.SQLiteJSON =
|
|
2870
|
+
exports.SQLiteConnectionString = SQLiteConnectionString;
|
|
2871
|
+
exports.SQLiteDatabaseName = SQLiteDatabaseName;
|
|
2872
|
+
exports.SQLiteJSON = SQLiteJSON;
|
|
420
2873
|
exports.checkConnection = checkConnection;
|
|
421
|
-
exports.defaultSQLiteDatabase =
|
|
422
|
-
exports.isInMemoryDatabase =
|
|
423
|
-
exports.isSQLiteError =
|
|
424
|
-
exports.mapSqliteError =
|
|
425
|
-
exports.parsePragmasFromConnectionString =
|
|
2874
|
+
exports.defaultSQLiteDatabase = defaultSQLiteDatabase;
|
|
2875
|
+
exports.isInMemoryDatabase = isInMemoryDatabase;
|
|
2876
|
+
exports.isSQLiteError = isSQLiteError;
|
|
2877
|
+
exports.mapSqliteError = mapSqliteError;
|
|
2878
|
+
exports.parsePragmasFromConnectionString = parsePragmasFromConnectionString;
|
|
426
2879
|
exports.sqlite3Client = sqlite3Client;
|
|
427
2880
|
exports.sqlite3Connection = sqlite3Connection;
|
|
428
2881
|
exports.sqlite3DumboDriver = sqlite3DumboDriver;
|
|
429
2882
|
exports.sqlite3Pool = sqlite3Pool;
|
|
430
|
-
exports.sqliteAlwaysNewConnectionPool =
|
|
431
|
-
exports.sqliteAmbientClientConnection =
|
|
432
|
-
exports.sqliteAmbientConnectionPool =
|
|
433
|
-
exports.sqliteClientConnection =
|
|
434
|
-
exports.sqliteConnection =
|
|
435
|
-
exports.sqliteExecute =
|
|
436
|
-
exports.sqliteFormatter =
|
|
437
|
-
exports.sqliteMetadata =
|
|
438
|
-
exports.sqlitePool =
|
|
439
|
-
exports.sqlitePoolClientConnection =
|
|
440
|
-
exports.sqliteSQLExecutor =
|
|
441
|
-
exports.sqliteSingletonConnectionPool =
|
|
442
|
-
exports.sqliteTransaction =
|
|
443
|
-
exports.tableExists =
|
|
444
|
-
exports.toSqlitePoolOptions =
|
|
445
|
-
exports.transactionNestingCounter = require_core$1.transactionNestingCounter;
|
|
2883
|
+
exports.sqliteAlwaysNewConnectionPool = sqliteAlwaysNewConnectionPool;
|
|
2884
|
+
exports.sqliteAmbientClientConnection = sqliteAmbientClientConnection;
|
|
2885
|
+
exports.sqliteAmbientConnectionPool = sqliteAmbientConnectionPool;
|
|
2886
|
+
exports.sqliteClientConnection = sqliteClientConnection;
|
|
2887
|
+
exports.sqliteConnection = sqliteConnection;
|
|
2888
|
+
exports.sqliteExecute = sqliteExecute;
|
|
2889
|
+
exports.sqliteFormatter = sqliteFormatter;
|
|
2890
|
+
exports.sqliteMetadata = sqliteMetadata;
|
|
2891
|
+
exports.sqlitePool = sqlitePool;
|
|
2892
|
+
exports.sqlitePoolClientConnection = sqlitePoolClientConnection;
|
|
2893
|
+
exports.sqliteSQLExecutor = sqliteSQLExecutor;
|
|
2894
|
+
exports.sqliteSingletonConnectionPool = sqliteSingletonConnectionPool;
|
|
2895
|
+
exports.sqliteTransaction = sqliteTransaction;
|
|
2896
|
+
exports.tableExists = tableExists;
|
|
2897
|
+
exports.toSqlitePoolOptions = toSqlitePoolOptions;
|
|
446
2898
|
exports.useSqlite3DumboDriver = useSqlite3DumboDriver;
|
|
447
2899
|
//# sourceMappingURL=sqlite3.cjs.map
|