@holo-js/db 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +256 -206
- package/dist/index.mjs +535 -585
- package/package.json +20 -4
package/dist/index.mjs
CHANGED
|
@@ -119,6 +119,151 @@ function redactSql(sql, policy) {
|
|
|
119
119
|
return "[SQL REDACTED]";
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// src/cache.ts
|
|
123
|
+
import { createHash } from "crypto";
|
|
124
|
+
function getQueryCacheBridgeState() {
|
|
125
|
+
const runtime = globalThis;
|
|
126
|
+
runtime.__holoDbQueryCacheBridge__ ??= {};
|
|
127
|
+
return runtime.__holoDbQueryCacheBridge__;
|
|
128
|
+
}
|
|
129
|
+
function configureDatabaseQueryCacheBridge(bridge) {
|
|
130
|
+
getQueryCacheBridgeState().bridge = bridge;
|
|
131
|
+
}
|
|
132
|
+
function getDatabaseQueryCacheBridge() {
|
|
133
|
+
return getQueryCacheBridgeState().bridge;
|
|
134
|
+
}
|
|
135
|
+
function resetDatabaseQueryCacheBridge() {
|
|
136
|
+
getQueryCacheBridgeState().bridge = void 0;
|
|
137
|
+
}
|
|
138
|
+
function normalizeQueryCacheConfig(input) {
|
|
139
|
+
if (typeof input === "number" || input instanceof Date) {
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
ttl: input
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const ttl = input.ttl;
|
|
145
|
+
const flexible = input.flexible;
|
|
146
|
+
if (typeof ttl === "undefined" && typeof flexible === "undefined") {
|
|
147
|
+
throw new ConfigurationError('[@holo-js/db] Query cache config requires "ttl" or "flexible".');
|
|
148
|
+
}
|
|
149
|
+
if (typeof ttl !== "undefined" && typeof flexible !== "undefined") {
|
|
150
|
+
throw new ConfigurationError('[@holo-js/db] Query cache config cannot define both "ttl" and "flexible".');
|
|
151
|
+
}
|
|
152
|
+
const key = input.key?.trim();
|
|
153
|
+
if (typeof input.key !== "undefined" && !key) {
|
|
154
|
+
throw new ConfigurationError("[@holo-js/db] Query cache keys must be non-empty strings.");
|
|
155
|
+
}
|
|
156
|
+
const driver = input.driver?.trim();
|
|
157
|
+
if (typeof input.driver !== "undefined" && !driver) {
|
|
158
|
+
throw new ConfigurationError("[@holo-js/db] Query cache driver names must be non-empty strings.");
|
|
159
|
+
}
|
|
160
|
+
const invalidate = input.invalidate ? Object.freeze(input.invalidate.map((dependency) => {
|
|
161
|
+
const normalized = dependency.trim();
|
|
162
|
+
if (!normalized) {
|
|
163
|
+
throw new ConfigurationError("[@holo-js/db] Query cache invalidation dependencies must be non-empty strings.");
|
|
164
|
+
}
|
|
165
|
+
return normalized;
|
|
166
|
+
})) : void 0;
|
|
167
|
+
return Object.freeze({
|
|
168
|
+
ttl,
|
|
169
|
+
key,
|
|
170
|
+
driver,
|
|
171
|
+
flexible,
|
|
172
|
+
invalidate
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function createDeterministicQueryCacheKey(statement, connectionName) {
|
|
176
|
+
const digest = createHash("sha256").update(JSON.stringify({
|
|
177
|
+
connectionName,
|
|
178
|
+
sql: statement.sql,
|
|
179
|
+
bindings: statement.bindings ?? []
|
|
180
|
+
})).digest("hex");
|
|
181
|
+
return `db:query:${digest}`;
|
|
182
|
+
}
|
|
183
|
+
function resolveQueryCacheKey(statement, connectionName, config) {
|
|
184
|
+
return config.key ?? createDeterministicQueryCacheKey(statement, connectionName);
|
|
185
|
+
}
|
|
186
|
+
function createTableCacheDependency(connectionName, tableName) {
|
|
187
|
+
return `db:${connectionName}:${tableName}`;
|
|
188
|
+
}
|
|
189
|
+
function normalizeQueryCacheDependencies(connectionName, dependencies) {
|
|
190
|
+
return Object.freeze(dependencies.map((dependency) => {
|
|
191
|
+
return dependency.startsWith("db:") ? dependency : createTableCacheDependency(connectionName, dependency);
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
function supportsAutomaticPredicateInvalidation(predicate) {
|
|
195
|
+
switch (predicate.kind) {
|
|
196
|
+
case "comparison":
|
|
197
|
+
case "column":
|
|
198
|
+
case "null":
|
|
199
|
+
case "date":
|
|
200
|
+
case "json":
|
|
201
|
+
case "fulltext":
|
|
202
|
+
case "vector":
|
|
203
|
+
return true;
|
|
204
|
+
case "group":
|
|
205
|
+
return predicate.predicates.every((child) => supportsAutomaticPredicateInvalidation(child));
|
|
206
|
+
case "exists":
|
|
207
|
+
case "subquery":
|
|
208
|
+
case "raw":
|
|
209
|
+
return false;
|
|
210
|
+
default:
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function supportsAutomaticQueryCacheInvalidation(plan) {
|
|
215
|
+
if (plan.joins.length > 0 || plan.unions.length > 0 || plan.having.length > 0) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (plan.selections.some((selection) => selection.kind === "raw" || selection.kind === "subquery")) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
if (plan.orderBy.some((order) => order.kind === "raw")) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
return plan.predicates.every((predicate) => supportsAutomaticPredicateInvalidation(predicate));
|
|
225
|
+
}
|
|
226
|
+
function inferAutomaticQueryCacheDependencies(plan, connectionName) {
|
|
227
|
+
if (!supportsAutomaticQueryCacheInvalidation(plan)) {
|
|
228
|
+
return void 0;
|
|
229
|
+
}
|
|
230
|
+
return Object.freeze([
|
|
231
|
+
createTableCacheDependency(connectionName, plan.source.tableName)
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
234
|
+
function resolveQueryCacheDependencies(plan, connectionName, explicit) {
|
|
235
|
+
if (explicit && explicit.length > 0) {
|
|
236
|
+
return normalizeQueryCacheDependencies(connectionName, explicit);
|
|
237
|
+
}
|
|
238
|
+
return inferAutomaticQueryCacheDependencies(plan, connectionName);
|
|
239
|
+
}
|
|
240
|
+
async function invalidateQueryCacheDependencies(connection, dependencies) {
|
|
241
|
+
const bridge = getDatabaseQueryCacheBridge();
|
|
242
|
+
if (!bridge || dependencies.length === 0) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (connection.getScope().kind === "root") {
|
|
246
|
+
await bridge.invalidateDependencies(dependencies);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
connection.afterCommit(async () => {
|
|
250
|
+
await bridge.invalidateDependencies(dependencies);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
var queryCacheInternals = {
|
|
254
|
+
configureDatabaseQueryCacheBridge,
|
|
255
|
+
createDeterministicQueryCacheKey,
|
|
256
|
+
createTableCacheDependency,
|
|
257
|
+
getQueryCacheBridgeState,
|
|
258
|
+
inferAutomaticQueryCacheDependencies,
|
|
259
|
+
normalizeQueryCacheConfig,
|
|
260
|
+
normalizeQueryCacheDependencies,
|
|
261
|
+
resolveQueryCacheDependencies,
|
|
262
|
+
resolveQueryCacheKey,
|
|
263
|
+
supportsAutomaticPredicateInvalidation,
|
|
264
|
+
supportsAutomaticQueryCacheInvalidation
|
|
265
|
+
};
|
|
266
|
+
|
|
122
267
|
// src/query/chunkOrdering.ts
|
|
123
268
|
function compareChunkValuesAscending(a, b) {
|
|
124
269
|
if (a === b) return 0;
|
|
@@ -228,6 +373,43 @@ function attachMethods(target, methods) {
|
|
|
228
373
|
);
|
|
229
374
|
}
|
|
230
375
|
|
|
376
|
+
// src/query/pagination.ts
|
|
377
|
+
function assertPositiveInteger(value, kind, createError) {
|
|
378
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
379
|
+
throw createError(`${kind} must be a positive integer.`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function normalizePaginationParameterName(value, fallback, createError) {
|
|
383
|
+
if (typeof value === "undefined") {
|
|
384
|
+
return fallback;
|
|
385
|
+
}
|
|
386
|
+
const trimmed = value.trim();
|
|
387
|
+
if (typeof value !== "string" || trimmed.length === 0) {
|
|
388
|
+
throw createError(
|
|
389
|
+
`${fallback === "cursor" ? "Cursor" : "Page"} parameter name must be a non-empty string.`
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return trimmed;
|
|
393
|
+
}
|
|
394
|
+
function encodeOffsetCursor(offset) {
|
|
395
|
+
return Buffer.from(JSON.stringify({ offset }), "utf8").toString("base64url");
|
|
396
|
+
}
|
|
397
|
+
function decodeOffsetCursor(cursor, createError) {
|
|
398
|
+
if (cursor === null) {
|
|
399
|
+
return 0;
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
403
|
+
const offset = decoded.offset;
|
|
404
|
+
if (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0) {
|
|
405
|
+
throw new Error("invalid offset");
|
|
406
|
+
}
|
|
407
|
+
return offset;
|
|
408
|
+
} catch {
|
|
409
|
+
throw createError("Cursor is malformed.");
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
231
413
|
// src/query/ast.ts
|
|
232
414
|
function createTableSource(table) {
|
|
233
415
|
if (typeof table === "string") {
|
|
@@ -1047,7 +1229,8 @@ var SQLQueryCompiler = class {
|
|
|
1047
1229
|
const groupByClause = plan.groupBy.length === 0 ? "" : ` GROUP BY ${plan.groupBy.map((column2) => this.compileColumnReference(column2)).join(", ")}`;
|
|
1048
1230
|
const havingClause = this.compileHaving(plan.having, bindings);
|
|
1049
1231
|
const orderClause = plan.orderBy.length === 0 ? "" : ` ORDER BY ${plan.orderBy.map((orderBy) => this.compileOrderBy(orderBy, bindings)).join(", ")}`;
|
|
1050
|
-
const
|
|
1232
|
+
const compiledLockClause = plan.lockMode ? this.compileLockClause(plan.lockMode) : "";
|
|
1233
|
+
const lockClause = compiledLockClause ? ` ${compiledLockClause}` : "";
|
|
1051
1234
|
const limitClause = typeof plan.limit === "number" ? ` LIMIT ${plan.limit}` : "";
|
|
1052
1235
|
const offsetClause = typeof plan.offset === "number" ? ` OFFSET ${plan.offset}` : "";
|
|
1053
1236
|
return `${selectKeyword} ${selectList} FROM ${this.compileSource(plan.source)}${joinClause}${whereClause}${groupByClause}${havingClause}${unionClause}${orderClause}${lockClause}${limitClause}${offsetClause}`;
|
|
@@ -1516,6 +1699,9 @@ var SQLITE_JSON_HELPERS = Object.freeze({
|
|
|
1516
1699
|
});
|
|
1517
1700
|
var SQLITE_EMPTY_JSON_OBJECT = "json('{}')";
|
|
1518
1701
|
var SQLiteQueryCompiler = class extends SQLQueryCompiler {
|
|
1702
|
+
compileLockClause(_lockMode) {
|
|
1703
|
+
return "";
|
|
1704
|
+
}
|
|
1519
1705
|
compileJsonPredicate(predicate, bindings) {
|
|
1520
1706
|
const column2 = this.compileColumnReference(predicate.column);
|
|
1521
1707
|
const pathLiteral = this.createJsonPathLiteral(predicate.path);
|
|
@@ -1844,9 +2030,21 @@ function normalizeDialectWriteValue(dialect, column2, value) {
|
|
|
1844
2030
|
}
|
|
1845
2031
|
|
|
1846
2032
|
// src/query/TableQueryBuilder.ts
|
|
2033
|
+
function normalizeAtomicQueryCacheTtl(ttl) {
|
|
2034
|
+
if (ttl instanceof Date) {
|
|
2035
|
+
const expiresAt = ttl.getTime();
|
|
2036
|
+
if (Number.isNaN(expiresAt)) {
|
|
2037
|
+
throw new ConfigurationError("[@holo-js/db] Query cache Date TTL must be valid.");
|
|
2038
|
+
}
|
|
2039
|
+
const seconds = Math.max(1, Math.ceil((expiresAt - Date.now()) / 1e3));
|
|
2040
|
+
return [seconds, seconds];
|
|
2041
|
+
}
|
|
2042
|
+
return [ttl, ttl];
|
|
2043
|
+
}
|
|
1847
2044
|
var TableQueryBuilder = class _TableQueryBuilder {
|
|
1848
|
-
constructor(table, connection, plan) {
|
|
2045
|
+
constructor(table, connection, plan, queryCacheConfig) {
|
|
1849
2046
|
this.connection = connection;
|
|
2047
|
+
this.queryCacheConfig = queryCacheConfig;
|
|
1850
2048
|
this.source = createTableSource(table);
|
|
1851
2049
|
this.plan = plan ?? createSelectQueryPlan(this.source);
|
|
1852
2050
|
}
|
|
@@ -1868,7 +2066,8 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
1868
2066
|
return new _TableQueryBuilder(
|
|
1869
2067
|
table,
|
|
1870
2068
|
this.connection,
|
|
1871
|
-
withSource(this.plan, createTableSource(table))
|
|
2069
|
+
withSource(this.plan, createTableSource(table)),
|
|
2070
|
+
this.queryCacheConfig
|
|
1872
2071
|
);
|
|
1873
2072
|
}
|
|
1874
2073
|
select(...columns) {
|
|
@@ -2485,8 +2684,8 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2485
2684
|
return this.limit(value);
|
|
2486
2685
|
}
|
|
2487
2686
|
forPage(page, perPage = 15) {
|
|
2488
|
-
|
|
2489
|
-
|
|
2687
|
+
assertPositiveInteger(page, "Page", (message) => new SecurityError(message));
|
|
2688
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
2490
2689
|
return this.limit(perPage).offset((page - 1) * perPage);
|
|
2491
2690
|
}
|
|
2492
2691
|
toSQL() {
|
|
@@ -2517,9 +2716,60 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2517
2716
|
console.log(this.debug());
|
|
2518
2717
|
return this;
|
|
2519
2718
|
}
|
|
2719
|
+
cache(config) {
|
|
2720
|
+
return new _TableQueryBuilder(
|
|
2721
|
+
this.source.table ?? this.source.tableName,
|
|
2722
|
+
this.connection,
|
|
2723
|
+
this.plan,
|
|
2724
|
+
normalizeQueryCacheConfig(config)
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2520
2727
|
async get() {
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2728
|
+
const statement = this.toSQL();
|
|
2729
|
+
const cacheConfig = this.queryCacheConfig;
|
|
2730
|
+
if (!cacheConfig || this.plan.lockMode) {
|
|
2731
|
+
const result = await this.connection.queryCompiled(statement);
|
|
2732
|
+
return result.rows;
|
|
2733
|
+
}
|
|
2734
|
+
const bridge = getDatabaseQueryCacheBridge();
|
|
2735
|
+
if (!bridge) {
|
|
2736
|
+
throw new ConfigurationError("[@holo-js/db] Query caching requires @holo-js/cache to be installed and configured.");
|
|
2737
|
+
}
|
|
2738
|
+
const cacheKey = resolveQueryCacheKey(statement, this.connection.getConnectionName(), cacheConfig);
|
|
2739
|
+
const dependencies = resolveQueryCacheDependencies(
|
|
2740
|
+
this.plan,
|
|
2741
|
+
this.connection.getConnectionName(),
|
|
2742
|
+
cacheConfig.invalidate
|
|
2743
|
+
);
|
|
2744
|
+
if (cacheConfig.flexible) {
|
|
2745
|
+
return bridge.flexible(
|
|
2746
|
+
cacheKey,
|
|
2747
|
+
cacheConfig.flexible,
|
|
2748
|
+
async () => {
|
|
2749
|
+
const result = await this.connection.queryCompiled(statement);
|
|
2750
|
+
return result.rows;
|
|
2751
|
+
},
|
|
2752
|
+
{
|
|
2753
|
+
driver: cacheConfig.driver,
|
|
2754
|
+
dependencies
|
|
2755
|
+
}
|
|
2756
|
+
);
|
|
2757
|
+
}
|
|
2758
|
+
if (typeof cacheConfig.ttl === "undefined") {
|
|
2759
|
+
throw new ConfigurationError('[@holo-js/db] Query cache config requires "ttl" or "flexible".');
|
|
2760
|
+
}
|
|
2761
|
+
return bridge.flexible(
|
|
2762
|
+
cacheKey,
|
|
2763
|
+
normalizeAtomicQueryCacheTtl(cacheConfig.ttl),
|
|
2764
|
+
async () => {
|
|
2765
|
+
const result = await this.connection.queryCompiled(statement);
|
|
2766
|
+
return result.rows;
|
|
2767
|
+
},
|
|
2768
|
+
{
|
|
2769
|
+
driver: cacheConfig.driver,
|
|
2770
|
+
dependencies
|
|
2771
|
+
}
|
|
2772
|
+
);
|
|
2523
2773
|
}
|
|
2524
2774
|
async first() {
|
|
2525
2775
|
const rows = await this.limit(1).get();
|
|
@@ -2533,9 +2783,9 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2533
2783
|
return rows[0];
|
|
2534
2784
|
}
|
|
2535
2785
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
const pageName =
|
|
2786
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
2787
|
+
assertPositiveInteger(page, "Page", (message) => new SecurityError(message));
|
|
2788
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new SecurityError(message));
|
|
2539
2789
|
const rows = await this.getUnpaginatedRows();
|
|
2540
2790
|
const total = rows.length;
|
|
2541
2791
|
const offset = (page - 1) * perPage;
|
|
@@ -2554,9 +2804,9 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2554
2804
|
});
|
|
2555
2805
|
}
|
|
2556
2806
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
const pageName =
|
|
2807
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
2808
|
+
assertPositiveInteger(page, "Page", (message) => new SecurityError(message));
|
|
2809
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new SecurityError(message));
|
|
2560
2810
|
const rows = await this.getUnpaginatedRows();
|
|
2561
2811
|
const offset = (page - 1) * perPage;
|
|
2562
2812
|
const pageRows = rows.slice(offset, offset + perPage + 1);
|
|
@@ -2574,9 +2824,9 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2574
2824
|
});
|
|
2575
2825
|
}
|
|
2576
2826
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
2577
|
-
|
|
2578
|
-
const cursorName =
|
|
2579
|
-
const offset =
|
|
2827
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
2828
|
+
const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new SecurityError(message));
|
|
2829
|
+
const offset = decodeOffsetCursor(cursor, (message) => new SecurityError(message));
|
|
2580
2830
|
const orderedQuery = this.prepareCursorPaginationQuery();
|
|
2581
2831
|
const rows = await orderedQuery.getUnpaginatedRows();
|
|
2582
2832
|
const pageRows = rows.slice(offset, offset + perPage + 1);
|
|
@@ -2585,12 +2835,12 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2585
2835
|
return createCursorPaginator(data, {
|
|
2586
2836
|
perPage,
|
|
2587
2837
|
cursorName,
|
|
2588
|
-
nextCursor: hasMorePages ?
|
|
2838
|
+
nextCursor: hasMorePages ? encodeOffsetCursor(offset + perPage) : null,
|
|
2589
2839
|
prevCursor: cursor
|
|
2590
2840
|
});
|
|
2591
2841
|
}
|
|
2592
2842
|
async chunk(size, callback) {
|
|
2593
|
-
|
|
2843
|
+
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
2594
2844
|
const rows = await this.getUnpaginatedRows();
|
|
2595
2845
|
let page = 1;
|
|
2596
2846
|
for (let index = 0; index < rows.length; index += size) {
|
|
@@ -2602,7 +2852,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2602
2852
|
}
|
|
2603
2853
|
}
|
|
2604
2854
|
async chunkById(size, callback, column2 = "id") {
|
|
2605
|
-
|
|
2855
|
+
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
2606
2856
|
const rows = await this.getUnpaginatedRows();
|
|
2607
2857
|
const sortedRows = [...rows].sort((left, right) => {
|
|
2608
2858
|
const a = left[column2];
|
|
@@ -2619,7 +2869,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2619
2869
|
}
|
|
2620
2870
|
}
|
|
2621
2871
|
async chunkByIdDesc(size, callback, column2 = "id") {
|
|
2622
|
-
|
|
2872
|
+
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
2623
2873
|
const rows = await this.getUnpaginatedRows();
|
|
2624
2874
|
const sortedRows = [...rows].sort((left, right) => {
|
|
2625
2875
|
const a = left[column2];
|
|
@@ -2636,7 +2886,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2636
2886
|
}
|
|
2637
2887
|
}
|
|
2638
2888
|
async *lazy(size = 1e3) {
|
|
2639
|
-
|
|
2889
|
+
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
2640
2890
|
const rows = await this.getUnpaginatedRows();
|
|
2641
2891
|
for (let index = 0; index < rows.length; index += size) {
|
|
2642
2892
|
for (const row of rows.slice(index, index + size)) {
|
|
@@ -2713,15 +2963,19 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2713
2963
|
}
|
|
2714
2964
|
async insert(values) {
|
|
2715
2965
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
2716
|
-
|
|
2966
|
+
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
2717
2967
|
createInsertQueryPlan(this.source, rows)
|
|
2718
2968
|
));
|
|
2969
|
+
await this.invalidateSourceTableQueries();
|
|
2970
|
+
return result;
|
|
2719
2971
|
}
|
|
2720
2972
|
async insertOrIgnore(values) {
|
|
2721
2973
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
2722
|
-
|
|
2974
|
+
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
2723
2975
|
createInsertQueryPlan(this.source, rows, { ignoreConflicts: true })
|
|
2724
2976
|
));
|
|
2977
|
+
await this.invalidateSourceTableQueries();
|
|
2978
|
+
return result;
|
|
2725
2979
|
}
|
|
2726
2980
|
async insertGetId(values) {
|
|
2727
2981
|
const result = await this.insert(values);
|
|
@@ -2729,9 +2983,11 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2729
2983
|
}
|
|
2730
2984
|
async upsert(values, uniqueBy, updateColumns = []) {
|
|
2731
2985
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
2732
|
-
|
|
2986
|
+
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
2733
2987
|
createUpsertQueryPlan(this.source, rows, uniqueBy, updateColumns)
|
|
2734
2988
|
));
|
|
2989
|
+
await this.invalidateSourceTableQueries();
|
|
2990
|
+
return result;
|
|
2735
2991
|
}
|
|
2736
2992
|
async increment(column2, amount = 1, extraValues = {}) {
|
|
2737
2993
|
return this.adjustNumericColumn(column2, amount, extraValues);
|
|
@@ -2740,17 +2996,25 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2740
2996
|
return this.adjustNumericColumn(column2, -amount, extraValues);
|
|
2741
2997
|
}
|
|
2742
2998
|
async update(values) {
|
|
2743
|
-
|
|
2999
|
+
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
2744
3000
|
createUpdateQueryPlan(this.source, this.plan.predicates, this.normalizeUpdateValues(values))
|
|
2745
3001
|
));
|
|
3002
|
+
if (result.affectedRows !== 0) {
|
|
3003
|
+
await this.invalidateSourceTableQueries();
|
|
3004
|
+
}
|
|
3005
|
+
return result;
|
|
2746
3006
|
}
|
|
2747
3007
|
async updateJson(columnPath, value) {
|
|
2748
3008
|
return this.update({ [columnPath]: value });
|
|
2749
3009
|
}
|
|
2750
3010
|
async delete() {
|
|
2751
|
-
|
|
3011
|
+
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
2752
3012
|
createDeleteQueryPlan(this.source, this.plan.predicates)
|
|
2753
3013
|
));
|
|
3014
|
+
if (result.affectedRows !== 0) {
|
|
3015
|
+
await this.invalidateSourceTableQueries();
|
|
3016
|
+
}
|
|
3017
|
+
return result;
|
|
2754
3018
|
}
|
|
2755
3019
|
async unsafeQuery(statement) {
|
|
2756
3020
|
return this.connection.unsafeQuery({
|
|
@@ -2768,7 +3032,12 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2768
3032
|
}
|
|
2769
3033
|
clone(plan) {
|
|
2770
3034
|
const table = this.source.table ?? this.source.tableName;
|
|
2771
|
-
return new _TableQueryBuilder(table, this.connection, plan);
|
|
3035
|
+
return new _TableQueryBuilder(table, this.connection, plan, this.queryCacheConfig);
|
|
3036
|
+
}
|
|
3037
|
+
async invalidateSourceTableQueries() {
|
|
3038
|
+
await invalidateQueryCacheDependencies(this.connection, [
|
|
3039
|
+
`db:${this.connection.getConnectionName()}:${this.source.tableName}`
|
|
3040
|
+
]);
|
|
2772
3041
|
}
|
|
2773
3042
|
getCompiler() {
|
|
2774
3043
|
const dialect = this.connection.getDialect();
|
|
@@ -2816,7 +3085,12 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2816
3085
|
throw new SecurityError("Increment/decrement amount must be a valid number.");
|
|
2817
3086
|
}
|
|
2818
3087
|
const primaryKey = this.resolvePrimaryKeyColumn();
|
|
2819
|
-
const
|
|
3088
|
+
const uncachedSelection = new _TableQueryBuilder(
|
|
3089
|
+
this.source.table ?? this.source.tableName,
|
|
3090
|
+
this.connection,
|
|
3091
|
+
withSelections(this.plan, [primaryKey, column2])
|
|
3092
|
+
);
|
|
3093
|
+
const rows = await uncachedSelection.get();
|
|
2820
3094
|
let affectedRows = 0;
|
|
2821
3095
|
let lastInsertId;
|
|
2822
3096
|
for (const row of rows) {
|
|
@@ -2874,22 +3148,6 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2874
3148
|
minSimilarity
|
|
2875
3149
|
})).orderByVectorSimilarity(column2, vector);
|
|
2876
3150
|
}
|
|
2877
|
-
assertPositiveInteger(value, kind) {
|
|
2878
|
-
if (!Number.isInteger(value) || value <= 0) {
|
|
2879
|
-
throw new SecurityError(`${kind} must be a positive integer.`);
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
normalizePaginationParameterName(value, fallback) {
|
|
2883
|
-
if (typeof value === "undefined") {
|
|
2884
|
-
return fallback;
|
|
2885
|
-
}
|
|
2886
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2887
|
-
throw new SecurityError(
|
|
2888
|
-
`${fallback === "cursor" ? "Cursor" : "Page"} parameter name must be a non-empty string.`
|
|
2889
|
-
);
|
|
2890
|
-
}
|
|
2891
|
-
return value;
|
|
2892
|
-
}
|
|
2893
3151
|
prepareCursorPaginationQuery() {
|
|
2894
3152
|
if (this.plan.orderBy.some((orderBy) => orderBy.kind === "random")) {
|
|
2895
3153
|
throw new SecurityError("Cursor pagination cannot use random ordering.");
|
|
@@ -2902,24 +3160,6 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2902
3160
|
}
|
|
2903
3161
|
return this;
|
|
2904
3162
|
}
|
|
2905
|
-
encodeCursor(offset) {
|
|
2906
|
-
return Buffer.from(JSON.stringify({ offset }), "utf8").toString("base64url");
|
|
2907
|
-
}
|
|
2908
|
-
decodeCursor(cursor) {
|
|
2909
|
-
if (cursor === null) {
|
|
2910
|
-
return 0;
|
|
2911
|
-
}
|
|
2912
|
-
try {
|
|
2913
|
-
const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
2914
|
-
const offset = decoded.offset;
|
|
2915
|
-
if (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0) {
|
|
2916
|
-
throw new Error("invalid offset");
|
|
2917
|
-
}
|
|
2918
|
-
return offset;
|
|
2919
|
-
} catch {
|
|
2920
|
-
throw new SecurityError("Cursor is malformed.");
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
3163
|
async aggregateNumeric(column2, kind) {
|
|
2924
3164
|
const rows = await this.get();
|
|
2925
3165
|
if (rows.length === 0) {
|
|
@@ -6147,13 +6387,17 @@ function createModelEventService() {
|
|
|
6147
6387
|
|
|
6148
6388
|
// src/concurrency/AsyncConnectionContext.ts
|
|
6149
6389
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
6390
|
+
function getAsyncConnectionStorage() {
|
|
6391
|
+
const runtime = globalThis;
|
|
6392
|
+
runtime.__holoAsyncConnectionStorage__ ??= new AsyncLocalStorage2();
|
|
6393
|
+
return runtime.__holoAsyncConnectionStorage__;
|
|
6394
|
+
}
|
|
6150
6395
|
var AsyncConnectionContext = class {
|
|
6151
|
-
storage = new AsyncLocalStorage2();
|
|
6152
6396
|
run(scope, callback) {
|
|
6153
|
-
return
|
|
6397
|
+
return getAsyncConnectionStorage().run(scope, callback);
|
|
6154
6398
|
}
|
|
6155
6399
|
getActive() {
|
|
6156
|
-
return
|
|
6400
|
+
return getAsyncConnectionStorage().getStore();
|
|
6157
6401
|
}
|
|
6158
6402
|
};
|
|
6159
6403
|
var connectionAsyncContext = new AsyncConnectionContext();
|
|
@@ -6203,19 +6447,24 @@ function resetMorphRegistry() {
|
|
|
6203
6447
|
}
|
|
6204
6448
|
|
|
6205
6449
|
// src/facade/DB.ts
|
|
6450
|
+
function getDatabaseFacadeState() {
|
|
6451
|
+
const runtime = globalThis;
|
|
6452
|
+
runtime.__holoDatabaseFacade__ ??= {};
|
|
6453
|
+
return runtime.__holoDatabaseFacade__;
|
|
6454
|
+
}
|
|
6206
6455
|
var DatabaseFacade = class {
|
|
6207
|
-
manager;
|
|
6208
6456
|
configure(manager) {
|
|
6209
|
-
|
|
6457
|
+
getDatabaseFacadeState().manager = manager;
|
|
6210
6458
|
}
|
|
6211
6459
|
reset() {
|
|
6212
|
-
|
|
6460
|
+
getDatabaseFacadeState().manager = void 0;
|
|
6213
6461
|
}
|
|
6214
6462
|
getManager() {
|
|
6215
|
-
|
|
6463
|
+
const manager = getDatabaseFacadeState().manager;
|
|
6464
|
+
if (!manager) {
|
|
6216
6465
|
throw new ConfigurationError("DB facade is not configured with a ConnectionManager.");
|
|
6217
6466
|
}
|
|
6218
|
-
return
|
|
6467
|
+
return manager;
|
|
6219
6468
|
}
|
|
6220
6469
|
connection(name) {
|
|
6221
6470
|
if (!name) {
|
|
@@ -7528,40 +7777,16 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7528
7777
|
return this.orWhereHas(relation, (query) => query.where(column2, operator, value));
|
|
7529
7778
|
}
|
|
7530
7779
|
whereMorphRelation(relation, types, column2, operator, value) {
|
|
7531
|
-
this.
|
|
7532
|
-
return this.withRelationFilter({
|
|
7533
|
-
relation,
|
|
7534
|
-
negate: false,
|
|
7535
|
-
boolean: "and",
|
|
7536
|
-
morphTypes: this.normalizeMorphTypes(types),
|
|
7537
|
-
constraint: (query) => query.where(column2, operator, value)
|
|
7538
|
-
});
|
|
7780
|
+
return this.applyMorphRelationFilter(relation, types, column2, operator, value, "and");
|
|
7539
7781
|
}
|
|
7540
7782
|
orWhereMorphRelation(relation, types, column2, operator, value) {
|
|
7541
|
-
this.
|
|
7542
|
-
return this.withRelationFilter({
|
|
7543
|
-
relation,
|
|
7544
|
-
negate: false,
|
|
7545
|
-
boolean: "or",
|
|
7546
|
-
morphTypes: this.normalizeMorphTypes(types),
|
|
7547
|
-
constraint: (query) => query.where(column2, operator, value)
|
|
7548
|
-
});
|
|
7783
|
+
return this.applyMorphRelationFilter(relation, types, column2, operator, value, "or");
|
|
7549
7784
|
}
|
|
7550
7785
|
whereBelongsTo(relatedEntity, relationName) {
|
|
7551
|
-
|
|
7552
|
-
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
7553
|
-
return ownerValue === null || typeof ownerValue === "undefined" ? this.whereDoesntHave(this.resolveBelongsToRelationName(relatedEntity, relationName)) : this.whereHas(
|
|
7554
|
-
this.resolveBelongsToRelationName(relatedEntity, relationName),
|
|
7555
|
-
(query) => query.where(relation.ownerKey, ownerValue)
|
|
7556
|
-
);
|
|
7786
|
+
return this.applyBelongsToFilter(relatedEntity, relationName, "and");
|
|
7557
7787
|
}
|
|
7558
7788
|
orWhereBelongsTo(relatedEntity, relationName) {
|
|
7559
|
-
|
|
7560
|
-
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
7561
|
-
return ownerValue === null || typeof ownerValue === "undefined" ? this.orWhereDoesntHave(this.resolveBelongsToRelationName(relatedEntity, relationName)) : this.orWhereHas(
|
|
7562
|
-
this.resolveBelongsToRelationName(relatedEntity, relationName),
|
|
7563
|
-
(query) => query.where(relation.ownerKey, ownerValue)
|
|
7564
|
-
);
|
|
7789
|
+
return this.applyBelongsToFilter(relatedEntity, relationName, "or");
|
|
7565
7790
|
}
|
|
7566
7791
|
whereMorphedTo(relation, target) {
|
|
7567
7792
|
return this.applyMorphedToFilter(relation, target, false, "and");
|
|
@@ -7606,6 +7831,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7606
7831
|
this.tableQuery.dump();
|
|
7607
7832
|
return this;
|
|
7608
7833
|
}
|
|
7834
|
+
cache(config) {
|
|
7835
|
+
return this.clone(this.tableQuery.cache(config));
|
|
7836
|
+
}
|
|
7609
7837
|
async get() {
|
|
7610
7838
|
const rows = await this.tableQuery.get();
|
|
7611
7839
|
const hasQueryCasts = Object.keys(this.queryCasts).length > 0;
|
|
@@ -7633,9 +7861,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7633
7861
|
return entities[0];
|
|
7634
7862
|
}
|
|
7635
7863
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
const pageName =
|
|
7864
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7865
|
+
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
7866
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
7639
7867
|
const entities = await this.getUnpaginatedEntities();
|
|
7640
7868
|
const total = entities.length;
|
|
7641
7869
|
const offset = (page - 1) * perPage;
|
|
@@ -7654,9 +7882,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7654
7882
|
});
|
|
7655
7883
|
}
|
|
7656
7884
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
const pageName =
|
|
7885
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7886
|
+
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
7887
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
7660
7888
|
const entities = await this.getUnpaginatedEntities();
|
|
7661
7889
|
const offset = (page - 1) * perPage;
|
|
7662
7890
|
const pageEntities = entities.slice(offset, offset + perPage + 1);
|
|
@@ -7674,9 +7902,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7674
7902
|
});
|
|
7675
7903
|
}
|
|
7676
7904
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
7677
|
-
|
|
7678
|
-
const cursorName =
|
|
7679
|
-
const offset =
|
|
7905
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7906
|
+
const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new HydrationError(message));
|
|
7907
|
+
const offset = decodeOffsetCursor(cursor, (message) => new HydrationError(message));
|
|
7680
7908
|
const orderedQuery = this.prepareCursorPaginationQuery();
|
|
7681
7909
|
const entities = await orderedQuery.getUnpaginatedEntities();
|
|
7682
7910
|
const pageEntities = entities.slice(offset, offset + perPage + 1);
|
|
@@ -7685,12 +7913,12 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7685
7913
|
return createCursorPaginator(this.repository.createCollection(data), {
|
|
7686
7914
|
perPage,
|
|
7687
7915
|
cursorName,
|
|
7688
|
-
nextCursor: hasMorePages ?
|
|
7916
|
+
nextCursor: hasMorePages ? encodeOffsetCursor(offset + perPage) : null,
|
|
7689
7917
|
prevCursor: cursor
|
|
7690
7918
|
});
|
|
7691
7919
|
}
|
|
7692
7920
|
async chunk(size, callback) {
|
|
7693
|
-
|
|
7921
|
+
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
7694
7922
|
const entities = await this.getUnpaginatedEntities();
|
|
7695
7923
|
let page = 1;
|
|
7696
7924
|
for (let index = 0; index < entities.length; index += size) {
|
|
@@ -7702,7 +7930,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7702
7930
|
}
|
|
7703
7931
|
}
|
|
7704
7932
|
async chunkById(size, callback, column2 = this.repository.definition.primaryKey) {
|
|
7705
|
-
|
|
7933
|
+
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
7706
7934
|
const entities = await this.getUnpaginatedEntities();
|
|
7707
7935
|
const sorted = [...entities].sort((left, right) => {
|
|
7708
7936
|
const a = left.get(column2);
|
|
@@ -7719,7 +7947,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7719
7947
|
}
|
|
7720
7948
|
}
|
|
7721
7949
|
async chunkByIdDesc(size, callback, column2 = this.repository.definition.primaryKey) {
|
|
7722
|
-
|
|
7950
|
+
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
7723
7951
|
const entities = await this.getUnpaginatedEntities();
|
|
7724
7952
|
const sorted = [...entities].sort((left, right) => {
|
|
7725
7953
|
const a = left.get(column2);
|
|
@@ -7736,7 +7964,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7736
7964
|
}
|
|
7737
7965
|
}
|
|
7738
7966
|
async *lazy(size = 1e3) {
|
|
7739
|
-
|
|
7967
|
+
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
7740
7968
|
const entities = await this.getUnpaginatedEntities();
|
|
7741
7969
|
for (let index = 0; index < entities.length; index += size) {
|
|
7742
7970
|
for (const entity of entities.slice(index, index + size)) {
|
|
@@ -8019,6 +8247,16 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8019
8247
|
constraint
|
|
8020
8248
|
});
|
|
8021
8249
|
}
|
|
8250
|
+
applyMorphRelationFilter(relation, types, column2, operator, value, boolean) {
|
|
8251
|
+
this.assertMorphToRelation(relation);
|
|
8252
|
+
return this.withRelationFilter({
|
|
8253
|
+
relation,
|
|
8254
|
+
negate: false,
|
|
8255
|
+
boolean,
|
|
8256
|
+
morphTypes: this.normalizeMorphTypes(types),
|
|
8257
|
+
constraint: (query) => query.where(column2, operator, value)
|
|
8258
|
+
});
|
|
8259
|
+
}
|
|
8022
8260
|
normalizeMorphedToTarget(target) {
|
|
8023
8261
|
if (typeof target === "object" && target !== null && "definition" in target && target.definition) {
|
|
8024
8262
|
return {
|
|
@@ -8090,6 +8328,15 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8090
8328
|
}
|
|
8091
8329
|
return relation;
|
|
8092
8330
|
}
|
|
8331
|
+
applyBelongsToFilter(relatedEntity, relationName, boolean) {
|
|
8332
|
+
const resolvedRelationName = this.resolveBelongsToRelationName(relatedEntity, relationName);
|
|
8333
|
+
const relation = this.resolveBelongsToRelation(relatedEntity, resolvedRelationName);
|
|
8334
|
+
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
8335
|
+
if (ownerValue === null || typeof ownerValue === "undefined") {
|
|
8336
|
+
return boolean === "and" ? this.whereDoesntHave(resolvedRelationName) : this.orWhereDoesntHave(resolvedRelationName);
|
|
8337
|
+
}
|
|
8338
|
+
return boolean === "and" ? this.whereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue)) : this.orWhereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue));
|
|
8339
|
+
}
|
|
8093
8340
|
resolveBelongsToRelationName(relatedEntity, relationName) {
|
|
8094
8341
|
if (relationName) {
|
|
8095
8342
|
return relationName;
|
|
@@ -8124,40 +8371,6 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8124
8371
|
async getUnpaginatedEntities() {
|
|
8125
8372
|
return this.clone(this.tableQuery.limit(void 0).offset(void 0)).get();
|
|
8126
8373
|
}
|
|
8127
|
-
encodeCursor(offset) {
|
|
8128
|
-
return Buffer.from(JSON.stringify({ offset }), "utf8").toString("base64url");
|
|
8129
|
-
}
|
|
8130
|
-
decodeCursor(cursor) {
|
|
8131
|
-
if (cursor === null) {
|
|
8132
|
-
return 0;
|
|
8133
|
-
}
|
|
8134
|
-
try {
|
|
8135
|
-
const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
8136
|
-
const offset = decoded.offset;
|
|
8137
|
-
if (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0) {
|
|
8138
|
-
throw new Error("invalid offset");
|
|
8139
|
-
}
|
|
8140
|
-
return offset;
|
|
8141
|
-
} catch {
|
|
8142
|
-
throw new HydrationError("Cursor is malformed.");
|
|
8143
|
-
}
|
|
8144
|
-
}
|
|
8145
|
-
assertPositiveInteger(value, kind) {
|
|
8146
|
-
if (!Number.isInteger(value) || value <= 0) {
|
|
8147
|
-
throw new HydrationError(`${kind} must be a positive integer.`);
|
|
8148
|
-
}
|
|
8149
|
-
}
|
|
8150
|
-
normalizePaginationParameterName(value, fallback) {
|
|
8151
|
-
if (typeof value === "undefined") {
|
|
8152
|
-
return fallback;
|
|
8153
|
-
}
|
|
8154
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
8155
|
-
throw new HydrationError(
|
|
8156
|
-
`${fallback === "cursor" ? "Cursor" : "Page"} parameter name must be a non-empty string.`
|
|
8157
|
-
);
|
|
8158
|
-
}
|
|
8159
|
-
return value;
|
|
8160
|
-
}
|
|
8161
8374
|
prepareCursorPaginationQuery() {
|
|
8162
8375
|
const plan = this.tableQuery.getPlan();
|
|
8163
8376
|
if (plan.orderBy.some((orderBy) => orderBy.kind === "random")) {
|
|
@@ -11615,512 +11828,243 @@ function createConnectionManager(options) {
|
|
|
11615
11828
|
return new ConnectionManager(options);
|
|
11616
11829
|
}
|
|
11617
11830
|
|
|
11618
|
-
// src/drivers/
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11831
|
+
// src/drivers/index.ts
|
|
11832
|
+
function isModuleNotFoundError(error) {
|
|
11833
|
+
return !!error && typeof error === "object" && "code" in error && error.code === "ERR_MODULE_NOT_FOUND";
|
|
11834
|
+
}
|
|
11835
|
+
function dynamicImport(specifier) {
|
|
11836
|
+
return import(
|
|
11837
|
+
/* webpackIgnore: true */
|
|
11838
|
+
specifier
|
|
11839
|
+
);
|
|
11840
|
+
}
|
|
11841
|
+
async function importDriverModule(specifier, errorMessage) {
|
|
11842
|
+
try {
|
|
11843
|
+
return await dynamicImport(specifier);
|
|
11844
|
+
} catch (error) {
|
|
11845
|
+
if (isModuleNotFoundError(error)) {
|
|
11846
|
+
throw new Error(errorMessage, { cause: error });
|
|
11847
|
+
}
|
|
11848
|
+
throw error;
|
|
11849
|
+
}
|
|
11850
|
+
}
|
|
11851
|
+
var driverModuleInternals = {
|
|
11852
|
+
importDriverModule
|
|
11853
|
+
};
|
|
11854
|
+
function unsupportedDriverMethod(name, method) {
|
|
11855
|
+
return new Error(`[@holo-js/db] ${name} does not support ${method}().`);
|
|
11856
|
+
}
|
|
11857
|
+
var LazyDriverAdapter = class {
|
|
11858
|
+
adapter;
|
|
11859
|
+
pending;
|
|
11860
|
+
connected = false;
|
|
11861
|
+
async resolveAdapter() {
|
|
11862
|
+
if (this.adapter) {
|
|
11863
|
+
return this.adapter;
|
|
11864
|
+
}
|
|
11865
|
+
this.pending ??= this.createConcreteAdapter().then((adapter) => {
|
|
11866
|
+
this.adapter = adapter;
|
|
11867
|
+
return adapter;
|
|
11868
|
+
}).finally(() => {
|
|
11869
|
+
this.pending = void 0;
|
|
11870
|
+
});
|
|
11871
|
+
return this.pending;
|
|
11630
11872
|
}
|
|
11631
11873
|
async initialize() {
|
|
11632
|
-
|
|
11633
|
-
return;
|
|
11634
|
-
}
|
|
11635
|
-
this.database = this.createDatabaseInstance(this.filename);
|
|
11874
|
+
await (await this.resolveAdapter()).initialize();
|
|
11636
11875
|
this.connected = true;
|
|
11637
11876
|
}
|
|
11638
11877
|
async disconnect() {
|
|
11639
|
-
if (!this.
|
|
11878
|
+
if (!this.adapter && !this.pending) {
|
|
11879
|
+
this.connected = false;
|
|
11640
11880
|
return;
|
|
11641
11881
|
}
|
|
11642
|
-
this.
|
|
11643
|
-
this.database = void 0;
|
|
11882
|
+
await (await this.resolveAdapter()).disconnect();
|
|
11644
11883
|
this.connected = false;
|
|
11645
11884
|
}
|
|
11646
11885
|
isConnected() {
|
|
11647
|
-
return this.connected;
|
|
11886
|
+
return this.adapter?.isConnected() ?? this.connected;
|
|
11648
11887
|
}
|
|
11649
|
-
async
|
|
11650
|
-
const
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
11655
|
-
};
|
|
11888
|
+
async runWithTransactionScope(callback) {
|
|
11889
|
+
const adapter = await this.resolveAdapter();
|
|
11890
|
+
if (typeof adapter.runWithTransactionScope !== "function") {
|
|
11891
|
+
return callback();
|
|
11892
|
+
}
|
|
11893
|
+
return adapter.runWithTransactionScope(callback);
|
|
11656
11894
|
}
|
|
11657
|
-
async introspect(sql, bindings
|
|
11658
|
-
|
|
11895
|
+
async introspect(sql, bindings, options) {
|
|
11896
|
+
const adapter = await this.resolveAdapter();
|
|
11897
|
+
if (typeof adapter.introspect !== "function") {
|
|
11898
|
+
return adapter.query(sql, bindings, options);
|
|
11899
|
+
}
|
|
11900
|
+
return adapter.introspect(sql, bindings, options);
|
|
11659
11901
|
}
|
|
11660
|
-
async
|
|
11661
|
-
|
|
11662
|
-
const result = this.invokeStatement(statement, "run", bindings);
|
|
11663
|
-
return {
|
|
11664
|
-
affectedRows: result.changes,
|
|
11665
|
-
lastInsertId: typeof result.lastInsertRowid === "bigint" ? Number(result.lastInsertRowid) : result.lastInsertRowid
|
|
11666
|
-
};
|
|
11902
|
+
async query(sql, bindings, options) {
|
|
11903
|
+
return (await this.resolveAdapter()).query(sql, bindings, options);
|
|
11667
11904
|
}
|
|
11668
|
-
async
|
|
11669
|
-
this.
|
|
11905
|
+
async execute(sql, bindings, options) {
|
|
11906
|
+
return (await this.resolveAdapter()).execute(sql, bindings, options);
|
|
11670
11907
|
}
|
|
11671
|
-
async
|
|
11672
|
-
this.
|
|
11908
|
+
async beginTransaction(options) {
|
|
11909
|
+
await (await this.resolveAdapter()).beginTransaction(options);
|
|
11673
11910
|
}
|
|
11674
|
-
async
|
|
11675
|
-
this.
|
|
11911
|
+
async commit(options) {
|
|
11912
|
+
await (await this.resolveAdapter()).commit(options);
|
|
11676
11913
|
}
|
|
11677
|
-
async
|
|
11678
|
-
this.
|
|
11914
|
+
async rollback(options) {
|
|
11915
|
+
await (await this.resolveAdapter()).rollback(options);
|
|
11679
11916
|
}
|
|
11680
|
-
async
|
|
11681
|
-
|
|
11917
|
+
async createSavepoint(name, options) {
|
|
11918
|
+
const adapter = await this.resolveAdapter();
|
|
11919
|
+
if (typeof adapter.createSavepoint !== "function") {
|
|
11920
|
+
throw unsupportedDriverMethod(this.driverLabel, "createSavepoint");
|
|
11921
|
+
}
|
|
11922
|
+
await adapter.createSavepoint(name, options);
|
|
11682
11923
|
}
|
|
11683
|
-
async
|
|
11684
|
-
|
|
11924
|
+
async rollbackToSavepoint(name, options) {
|
|
11925
|
+
const adapter = await this.resolveAdapter();
|
|
11926
|
+
if (typeof adapter.rollbackToSavepoint !== "function") {
|
|
11927
|
+
throw unsupportedDriverMethod(this.driverLabel, "rollbackToSavepoint");
|
|
11928
|
+
}
|
|
11929
|
+
await adapter.rollbackToSavepoint(name, options);
|
|
11685
11930
|
}
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
this.
|
|
11931
|
+
async releaseSavepoint(name, options) {
|
|
11932
|
+
const adapter = await this.resolveAdapter();
|
|
11933
|
+
if (typeof adapter.releaseSavepoint !== "function") {
|
|
11934
|
+
throw unsupportedDriverMethod(this.driverLabel, "releaseSavepoint");
|
|
11690
11935
|
}
|
|
11691
|
-
|
|
11936
|
+
await adapter.releaseSavepoint(name, options);
|
|
11692
11937
|
}
|
|
11693
|
-
|
|
11938
|
+
};
|
|
11939
|
+
var SQLiteAdapter = class extends LazyDriverAdapter {
|
|
11940
|
+
constructor(options = {}) {
|
|
11941
|
+
super();
|
|
11942
|
+
this.options = options;
|
|
11943
|
+
this.filename = options.filename ?? ":memory:";
|
|
11944
|
+
this.connected = !!options.database;
|
|
11945
|
+
}
|
|
11946
|
+
driverLabel = "SQLiteAdapter";
|
|
11947
|
+
filename;
|
|
11948
|
+
async createConcreteAdapter() {
|
|
11949
|
+
const module = await driverModuleInternals.importDriverModule(
|
|
11950
|
+
"@holo-js/db-sqlite",
|
|
11951
|
+
"[@holo-js/db] SQLite support requires @holo-js/db-sqlite to be installed."
|
|
11952
|
+
);
|
|
11953
|
+
return module.createSQLiteAdapter(this.options);
|
|
11954
|
+
}
|
|
11955
|
+
async createSavepoint(name, options) {
|
|
11694
11956
|
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
11695
11957
|
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11696
11958
|
}
|
|
11697
|
-
|
|
11959
|
+
await super.createSavepoint(name, options);
|
|
11698
11960
|
}
|
|
11699
|
-
|
|
11700
|
-
|
|
11701
|
-
|
|
11702
|
-
} catch (error) {
|
|
11703
|
-
if (bindings.length > 0 && this.isBindingArityError(error)) {
|
|
11704
|
-
return statement[method](bindings);
|
|
11705
|
-
}
|
|
11706
|
-
throw error;
|
|
11961
|
+
async rollbackToSavepoint(name, options) {
|
|
11962
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
11963
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11707
11964
|
}
|
|
11965
|
+
await super.rollbackToSavepoint(name, options);
|
|
11708
11966
|
}
|
|
11709
|
-
|
|
11710
|
-
|
|
11967
|
+
async releaseSavepoint(name, options) {
|
|
11968
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
11969
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11970
|
+
}
|
|
11971
|
+
await super.releaseSavepoint(name, options);
|
|
11711
11972
|
}
|
|
11712
11973
|
};
|
|
11713
11974
|
function createSQLiteAdapter(options = {}) {
|
|
11714
11975
|
return new SQLiteAdapter(options);
|
|
11715
11976
|
}
|
|
11716
|
-
|
|
11717
|
-
// src/drivers/PostgresAdapter.ts
|
|
11718
|
-
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
11719
|
-
import { Pool } from "pg";
|
|
11720
|
-
var PostgresAdapter = class {
|
|
11721
|
-
pool;
|
|
11722
|
-
directClient;
|
|
11723
|
-
createPoolInstance;
|
|
11724
|
-
config;
|
|
11725
|
-
connected;
|
|
11726
|
-
transactionClient;
|
|
11727
|
-
leasedTransactionClient = false;
|
|
11728
|
-
transactionScope = new AsyncLocalStorage3();
|
|
11977
|
+
var PostgresAdapter = class extends LazyDriverAdapter {
|
|
11729
11978
|
constructor(options = {}) {
|
|
11730
|
-
|
|
11731
|
-
this.
|
|
11732
|
-
this.createPoolInstance = options.createPool ?? (options.client || options.pool ? void 0 : (config) => new Pool(config));
|
|
11979
|
+
super();
|
|
11980
|
+
this.options = options;
|
|
11733
11981
|
this.config = options.config ?? (options.connectionString ? { connectionString: options.connectionString } : void 0);
|
|
11734
11982
|
this.connected = !!(options.client || options.pool);
|
|
11735
11983
|
}
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
|
|
11743
|
-
|
|
11984
|
+
driverLabel = "PostgresAdapter";
|
|
11985
|
+
config;
|
|
11986
|
+
async createConcreteAdapter() {
|
|
11987
|
+
const module = await driverModuleInternals.importDriverModule(
|
|
11988
|
+
"@holo-js/db-postgres",
|
|
11989
|
+
"[@holo-js/db] Postgres support requires @holo-js/db-postgres to be installed."
|
|
11990
|
+
);
|
|
11991
|
+
const createPostgresAdapter2 = module.createPostgresAdapter;
|
|
11992
|
+
return createPostgresAdapter2(this.options);
|
|
11744
11993
|
}
|
|
11745
|
-
|
|
11746
|
-
if (
|
|
11994
|
+
releaseScopedTransaction(state) {
|
|
11995
|
+
if (state.released) {
|
|
11747
11996
|
return;
|
|
11748
11997
|
}
|
|
11749
|
-
if (
|
|
11750
|
-
|
|
11751
|
-
this.transactionClient = void 0;
|
|
11752
|
-
this.leasedTransactionClient = false;
|
|
11753
|
-
}
|
|
11754
|
-
if (this.pool) {
|
|
11755
|
-
await this.pool.end();
|
|
11756
|
-
this.pool = void 0;
|
|
11757
|
-
} else if (this.directClient?.end) {
|
|
11758
|
-
await this.directClient.end();
|
|
11759
|
-
}
|
|
11760
|
-
this.connected = false;
|
|
11761
|
-
}
|
|
11762
|
-
isConnected() {
|
|
11763
|
-
return this.connected;
|
|
11764
|
-
}
|
|
11765
|
-
async runWithTransactionScope(callback) {
|
|
11766
|
-
const active = this.transactionScope.getStore();
|
|
11767
|
-
if (active) {
|
|
11768
|
-
return callback();
|
|
11769
|
-
}
|
|
11770
|
-
await this.initialize();
|
|
11771
|
-
if (this.directClient) {
|
|
11772
|
-
return this.transactionScope.run({
|
|
11773
|
-
client: this.directClient,
|
|
11774
|
-
leased: false,
|
|
11775
|
-
released: false
|
|
11776
|
-
}, callback);
|
|
11777
|
-
}
|
|
11778
|
-
if (!this.pool) {
|
|
11779
|
-
throw new TransactionError("Postgres adapter is not initialized with a pool or client.");
|
|
11780
|
-
}
|
|
11781
|
-
const state = {
|
|
11782
|
-
client: await this.pool.connect(),
|
|
11783
|
-
leased: true,
|
|
11784
|
-
released: false
|
|
11785
|
-
};
|
|
11786
|
-
return this.transactionScope.run(state, async () => {
|
|
11787
|
-
try {
|
|
11788
|
-
return await callback();
|
|
11789
|
-
} finally {
|
|
11790
|
-
this.releaseScopedTransaction(state);
|
|
11791
|
-
}
|
|
11792
|
-
});
|
|
11793
|
-
}
|
|
11794
|
-
async query(sql, bindings = []) {
|
|
11795
|
-
const client = await this.getQueryable();
|
|
11796
|
-
const result = await client.query(sql, bindings);
|
|
11797
|
-
return {
|
|
11798
|
-
rows: result.rows,
|
|
11799
|
-
rowCount: result.rowCount ?? result.rows.length
|
|
11800
|
-
};
|
|
11801
|
-
}
|
|
11802
|
-
async introspect(sql, bindings = []) {
|
|
11803
|
-
return this.query(sql, bindings);
|
|
11804
|
-
}
|
|
11805
|
-
async execute(sql, bindings = []) {
|
|
11806
|
-
const client = await this.getQueryable();
|
|
11807
|
-
const result = await client.query(sql, bindings);
|
|
11808
|
-
const firstRow = result.rows[0];
|
|
11809
|
-
const firstValue = firstRow ? Object.values(firstRow)[0] : void 0;
|
|
11810
|
-
return {
|
|
11811
|
-
affectedRows: result.rowCount ?? 0,
|
|
11812
|
-
...typeof firstValue !== "undefined" ? { lastInsertId: firstValue } : {}
|
|
11813
|
-
};
|
|
11814
|
-
}
|
|
11815
|
-
async beginTransaction() {
|
|
11816
|
-
const client = await this.leaseTransactionClient();
|
|
11817
|
-
await client.query("BEGIN");
|
|
11818
|
-
}
|
|
11819
|
-
async commit() {
|
|
11820
|
-
const client = this.requireTransactionClient();
|
|
11821
|
-
await client.query("COMMIT");
|
|
11822
|
-
this.releaseTransactionClient();
|
|
11823
|
-
}
|
|
11824
|
-
async rollback() {
|
|
11825
|
-
const client = this.requireTransactionClient();
|
|
11826
|
-
await client.query("ROLLBACK");
|
|
11827
|
-
this.releaseTransactionClient();
|
|
11828
|
-
}
|
|
11829
|
-
async createSavepoint(name) {
|
|
11830
|
-
await this.requireTransactionClient().query(`SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
11831
|
-
}
|
|
11832
|
-
async rollbackToSavepoint(name) {
|
|
11833
|
-
await this.requireTransactionClient().query(`ROLLBACK TO SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
11834
|
-
}
|
|
11835
|
-
async releaseSavepoint(name) {
|
|
11836
|
-
await this.requireTransactionClient().query(`RELEASE SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
11837
|
-
}
|
|
11838
|
-
async getQueryable() {
|
|
11839
|
-
const scoped = this.transactionScope.getStore();
|
|
11840
|
-
if (scoped) {
|
|
11841
|
-
return scoped.client;
|
|
11842
|
-
}
|
|
11843
|
-
if (this.transactionClient) {
|
|
11844
|
-
return this.transactionClient;
|
|
11845
|
-
}
|
|
11846
|
-
await this.initialize();
|
|
11847
|
-
if (this.directClient) {
|
|
11848
|
-
return this.directClient;
|
|
11849
|
-
}
|
|
11850
|
-
if (!this.pool) {
|
|
11851
|
-
throw new TransactionError("Postgres adapter is not initialized with a pool or client.");
|
|
11998
|
+
if (state.leased) {
|
|
11999
|
+
state.client.release?.();
|
|
11852
12000
|
}
|
|
11853
|
-
|
|
11854
|
-
}
|
|
11855
|
-
async leaseTransactionClient() {
|
|
11856
|
-
const scoped = this.transactionScope.getStore();
|
|
11857
|
-
if (scoped) {
|
|
11858
|
-
return scoped.client;
|
|
11859
|
-
}
|
|
11860
|
-
if (this.transactionClient) {
|
|
11861
|
-
return this.transactionClient;
|
|
11862
|
-
}
|
|
11863
|
-
await this.initialize();
|
|
11864
|
-
if (this.directClient) {
|
|
11865
|
-
this.transactionClient = this.directClient;
|
|
11866
|
-
this.leasedTransactionClient = false;
|
|
11867
|
-
return this.transactionClient;
|
|
11868
|
-
}
|
|
11869
|
-
if (!this.pool) {
|
|
11870
|
-
throw new TransactionError("Postgres adapter is not initialized with a pool or client.");
|
|
11871
|
-
}
|
|
11872
|
-
this.transactionClient = await this.pool.connect();
|
|
11873
|
-
this.leasedTransactionClient = true;
|
|
11874
|
-
return this.transactionClient;
|
|
11875
|
-
}
|
|
11876
|
-
requireTransactionClient() {
|
|
11877
|
-
const scoped = this.transactionScope.getStore();
|
|
11878
|
-
if (scoped) {
|
|
11879
|
-
return scoped.client;
|
|
11880
|
-
}
|
|
11881
|
-
if (!this.transactionClient) {
|
|
11882
|
-
throw new TransactionError("No active Postgres transaction client is available.");
|
|
11883
|
-
}
|
|
11884
|
-
return this.transactionClient;
|
|
12001
|
+
state.released = true;
|
|
11885
12002
|
}
|
|
11886
|
-
|
|
11887
|
-
if (
|
|
11888
|
-
|
|
12003
|
+
async createSavepoint(name, options) {
|
|
12004
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
12005
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11889
12006
|
}
|
|
11890
|
-
|
|
11891
|
-
this.leasedTransactionClient = false;
|
|
12007
|
+
await super.createSavepoint(name, options);
|
|
11892
12008
|
}
|
|
11893
|
-
|
|
11894
|
-
if (
|
|
11895
|
-
|
|
12009
|
+
async rollbackToSavepoint(name, options) {
|
|
12010
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
12011
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11896
12012
|
}
|
|
11897
|
-
|
|
11898
|
-
state.released = true;
|
|
12013
|
+
await super.rollbackToSavepoint(name, options);
|
|
11899
12014
|
}
|
|
11900
|
-
|
|
12015
|
+
async releaseSavepoint(name, options) {
|
|
11901
12016
|
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
11902
12017
|
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11903
12018
|
}
|
|
11904
|
-
|
|
12019
|
+
await super.releaseSavepoint(name, options);
|
|
11905
12020
|
}
|
|
11906
12021
|
};
|
|
11907
12022
|
function createPostgresAdapter(options = {}) {
|
|
11908
12023
|
return new PostgresAdapter(options);
|
|
11909
12024
|
}
|
|
11910
|
-
|
|
11911
|
-
// src/drivers/MySQLAdapter.ts
|
|
11912
|
-
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
11913
|
-
import mysql from "mysql2/promise";
|
|
11914
|
-
function toMutableBindings(bindings = []) {
|
|
11915
|
-
return [...bindings];
|
|
11916
|
-
}
|
|
11917
|
-
function wrapMySQLClient(client) {
|
|
11918
|
-
const rawClient = client;
|
|
11919
|
-
return {
|
|
11920
|
-
async query(sql, bindings = []) {
|
|
11921
|
-
return rawClient.query(sql, toMutableBindings(bindings));
|
|
11922
|
-
},
|
|
11923
|
-
release: rawClient.release?.bind(rawClient),
|
|
11924
|
-
end: rawClient.end?.bind(rawClient)
|
|
11925
|
-
};
|
|
11926
|
-
}
|
|
11927
|
-
function wrapMySQLPool(pool) {
|
|
11928
|
-
const rawPool = pool;
|
|
11929
|
-
return {
|
|
11930
|
-
async query(sql, bindings = []) {
|
|
11931
|
-
return rawPool.query(sql, toMutableBindings(bindings));
|
|
11932
|
-
},
|
|
11933
|
-
async getConnection() {
|
|
11934
|
-
return wrapMySQLClient(await rawPool.getConnection());
|
|
11935
|
-
},
|
|
11936
|
-
end: rawPool.end.bind(rawPool)
|
|
11937
|
-
};
|
|
11938
|
-
}
|
|
11939
|
-
var MySQLAdapter = class {
|
|
11940
|
-
pool;
|
|
11941
|
-
directClient;
|
|
11942
|
-
createPoolInstance;
|
|
11943
|
-
config;
|
|
11944
|
-
connected;
|
|
11945
|
-
transactionClient;
|
|
11946
|
-
leasedTransactionClient = false;
|
|
11947
|
-
transactionScope = new AsyncLocalStorage4();
|
|
12025
|
+
var MySQLAdapter = class extends LazyDriverAdapter {
|
|
11948
12026
|
constructor(options = {}) {
|
|
11949
|
-
|
|
11950
|
-
this.
|
|
11951
|
-
this.createPoolInstance = options.createPool ?? (options.client || options.pool ? void 0 : (config) => wrapMySQLPool(mysql.createPool(config)));
|
|
12027
|
+
super();
|
|
12028
|
+
this.options = options;
|
|
11952
12029
|
this.config = options.config ?? (options.uri ? { uri: options.uri } : {});
|
|
11953
12030
|
this.connected = !!(options.client || options.pool);
|
|
11954
12031
|
}
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
12032
|
+
driverLabel = "MySQLAdapter";
|
|
12033
|
+
config;
|
|
12034
|
+
async createConcreteAdapter() {
|
|
12035
|
+
const module = await driverModuleInternals.importDriverModule(
|
|
12036
|
+
"@holo-js/db-mysql",
|
|
12037
|
+
"[@holo-js/db] MySQL support requires @holo-js/db-mysql to be installed."
|
|
12038
|
+
);
|
|
12039
|
+
const createMySQLAdapter2 = module.createMySQLAdapter;
|
|
12040
|
+
return createMySQLAdapter2(this.options);
|
|
11963
12041
|
}
|
|
11964
|
-
|
|
11965
|
-
if (
|
|
12042
|
+
releaseScopedTransaction(state) {
|
|
12043
|
+
if (state.released) {
|
|
11966
12044
|
return;
|
|
11967
12045
|
}
|
|
11968
|
-
if (
|
|
11969
|
-
|
|
11970
|
-
this.transactionClient = void 0;
|
|
11971
|
-
this.leasedTransactionClient = false;
|
|
11972
|
-
}
|
|
11973
|
-
if (this.pool) {
|
|
11974
|
-
await this.pool.end();
|
|
11975
|
-
this.pool = void 0;
|
|
11976
|
-
} else if (this.directClient?.end) {
|
|
11977
|
-
await this.directClient.end();
|
|
11978
|
-
}
|
|
11979
|
-
this.connected = false;
|
|
11980
|
-
}
|
|
11981
|
-
isConnected() {
|
|
11982
|
-
return this.connected;
|
|
11983
|
-
}
|
|
11984
|
-
async runWithTransactionScope(callback) {
|
|
11985
|
-
const active = this.transactionScope.getStore();
|
|
11986
|
-
if (active) {
|
|
11987
|
-
return callback();
|
|
11988
|
-
}
|
|
11989
|
-
await this.initialize();
|
|
11990
|
-
if (this.directClient) {
|
|
11991
|
-
return this.transactionScope.run({
|
|
11992
|
-
client: this.directClient,
|
|
11993
|
-
leased: false,
|
|
11994
|
-
released: false
|
|
11995
|
-
}, callback);
|
|
11996
|
-
}
|
|
11997
|
-
if (!this.pool) {
|
|
11998
|
-
throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
|
|
11999
|
-
}
|
|
12000
|
-
const state = {
|
|
12001
|
-
client: await this.pool.getConnection(),
|
|
12002
|
-
leased: true,
|
|
12003
|
-
released: false
|
|
12004
|
-
};
|
|
12005
|
-
return this.transactionScope.run(state, async () => {
|
|
12006
|
-
try {
|
|
12007
|
-
return await callback();
|
|
12008
|
-
} finally {
|
|
12009
|
-
this.releaseScopedTransaction(state);
|
|
12010
|
-
}
|
|
12011
|
-
});
|
|
12012
|
-
}
|
|
12013
|
-
async query(sql, bindings = []) {
|
|
12014
|
-
const queryable = await this.getQueryable();
|
|
12015
|
-
const [rows] = await queryable.query(sql, bindings);
|
|
12016
|
-
const normalized = rows;
|
|
12017
|
-
return {
|
|
12018
|
-
rows: Array.isArray(normalized) ? [...normalized] : [],
|
|
12019
|
-
rowCount: Array.isArray(normalized) ? normalized.length : 0
|
|
12020
|
-
};
|
|
12021
|
-
}
|
|
12022
|
-
async introspect(sql, bindings = []) {
|
|
12023
|
-
return this.query(sql, bindings);
|
|
12024
|
-
}
|
|
12025
|
-
async execute(sql, bindings = []) {
|
|
12026
|
-
const queryable = await this.getQueryable();
|
|
12027
|
-
const [result] = await queryable.query(sql, bindings);
|
|
12028
|
-
const execution = result;
|
|
12029
|
-
return {
|
|
12030
|
-
affectedRows: typeof execution.affectedRows === "number" ? execution.affectedRows : 0,
|
|
12031
|
-
lastInsertId: execution.insertId
|
|
12032
|
-
};
|
|
12033
|
-
}
|
|
12034
|
-
async beginTransaction() {
|
|
12035
|
-
const client = await this.leaseTransactionClient();
|
|
12036
|
-
await client.query("START TRANSACTION");
|
|
12037
|
-
}
|
|
12038
|
-
async commit() {
|
|
12039
|
-
const client = this.requireTransactionClient();
|
|
12040
|
-
await client.query("COMMIT");
|
|
12041
|
-
this.releaseTransactionClient();
|
|
12042
|
-
}
|
|
12043
|
-
async rollback() {
|
|
12044
|
-
const client = this.requireTransactionClient();
|
|
12045
|
-
await client.query("ROLLBACK");
|
|
12046
|
-
this.releaseTransactionClient();
|
|
12047
|
-
}
|
|
12048
|
-
async createSavepoint(name) {
|
|
12049
|
-
await this.requireTransactionClient().query(`SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
12050
|
-
}
|
|
12051
|
-
async rollbackToSavepoint(name) {
|
|
12052
|
-
await this.requireTransactionClient().query(`ROLLBACK TO SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
12053
|
-
}
|
|
12054
|
-
async releaseSavepoint(name) {
|
|
12055
|
-
await this.requireTransactionClient().query(`RELEASE SAVEPOINT ${this.normalizeSavepointName(name)}`);
|
|
12056
|
-
}
|
|
12057
|
-
async getQueryable() {
|
|
12058
|
-
const scoped = this.transactionScope.getStore();
|
|
12059
|
-
if (scoped) {
|
|
12060
|
-
return scoped.client;
|
|
12046
|
+
if (state.leased) {
|
|
12047
|
+
state.client.release?.();
|
|
12061
12048
|
}
|
|
12062
|
-
|
|
12063
|
-
return this.transactionClient;
|
|
12064
|
-
}
|
|
12065
|
-
await this.initialize();
|
|
12066
|
-
if (this.directClient) {
|
|
12067
|
-
return this.directClient;
|
|
12068
|
-
}
|
|
12069
|
-
if (!this.pool) {
|
|
12070
|
-
throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
|
|
12071
|
-
}
|
|
12072
|
-
return this.pool;
|
|
12073
|
-
}
|
|
12074
|
-
async leaseTransactionClient() {
|
|
12075
|
-
const scoped = this.transactionScope.getStore();
|
|
12076
|
-
if (scoped) {
|
|
12077
|
-
return scoped.client;
|
|
12078
|
-
}
|
|
12079
|
-
if (this.transactionClient) {
|
|
12080
|
-
return this.transactionClient;
|
|
12081
|
-
}
|
|
12082
|
-
await this.initialize();
|
|
12083
|
-
if (this.directClient) {
|
|
12084
|
-
this.transactionClient = this.directClient;
|
|
12085
|
-
this.leasedTransactionClient = false;
|
|
12086
|
-
return this.transactionClient;
|
|
12087
|
-
}
|
|
12088
|
-
if (!this.pool) {
|
|
12089
|
-
throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
|
|
12090
|
-
}
|
|
12091
|
-
this.transactionClient = await this.pool.getConnection();
|
|
12092
|
-
this.leasedTransactionClient = true;
|
|
12093
|
-
return this.transactionClient;
|
|
12094
|
-
}
|
|
12095
|
-
requireTransactionClient() {
|
|
12096
|
-
const scoped = this.transactionScope.getStore();
|
|
12097
|
-
if (scoped) {
|
|
12098
|
-
return scoped.client;
|
|
12099
|
-
}
|
|
12100
|
-
if (!this.transactionClient) {
|
|
12101
|
-
throw new TransactionError("No active MySQL transaction client is available.");
|
|
12102
|
-
}
|
|
12103
|
-
return this.transactionClient;
|
|
12049
|
+
state.released = true;
|
|
12104
12050
|
}
|
|
12105
|
-
|
|
12106
|
-
if (
|
|
12107
|
-
|
|
12051
|
+
async createSavepoint(name, options) {
|
|
12052
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
12053
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12108
12054
|
}
|
|
12109
|
-
|
|
12110
|
-
this.leasedTransactionClient = false;
|
|
12055
|
+
await super.createSavepoint(name, options);
|
|
12111
12056
|
}
|
|
12112
|
-
|
|
12113
|
-
if (
|
|
12114
|
-
|
|
12057
|
+
async rollbackToSavepoint(name, options) {
|
|
12058
|
+
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
12059
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12115
12060
|
}
|
|
12116
|
-
|
|
12117
|
-
state.released = true;
|
|
12061
|
+
await super.rollbackToSavepoint(name, options);
|
|
12118
12062
|
}
|
|
12119
|
-
|
|
12063
|
+
async releaseSavepoint(name, options) {
|
|
12120
12064
|
if (!/^[A-Z_]\w*$/i.test(name)) {
|
|
12121
12065
|
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12122
12066
|
}
|
|
12123
|
-
|
|
12067
|
+
await super.releaseSavepoint(name, options);
|
|
12124
12068
|
}
|
|
12125
12069
|
};
|
|
12126
12070
|
function createMySQLAdapter(options = {}) {
|
|
@@ -13051,7 +12995,7 @@ function defineFactory(model, definition) {
|
|
|
13051
12995
|
}
|
|
13052
12996
|
|
|
13053
12997
|
// src/model/casts.ts
|
|
13054
|
-
import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto";
|
|
12998
|
+
import { createCipheriv, createDecipheriv, createHash as createHash2, randomBytes } from "crypto";
|
|
13055
12999
|
function enumCast(enumObject) {
|
|
13056
13000
|
const values = Object.entries(enumObject).filter(([key]) => !/^\d+$/.test(key)).map(([, value]) => value).filter((value, index, items) => items.indexOf(value) === index);
|
|
13057
13001
|
return Object.freeze({
|
|
@@ -13089,7 +13033,7 @@ function binaryCast() {
|
|
|
13089
13033
|
});
|
|
13090
13034
|
}
|
|
13091
13035
|
function encryptedCast(secret) {
|
|
13092
|
-
const key =
|
|
13036
|
+
const key = createHash2("sha256").update(secret).digest();
|
|
13093
13037
|
return Object.freeze({
|
|
13094
13038
|
get(value) {
|
|
13095
13039
|
if (value == null) {
|
|
@@ -14136,7 +14080,9 @@ var DEFAULT_HOLO_PROJECT_PATHS = Object.freeze({
|
|
|
14136
14080
|
commands: "server/commands",
|
|
14137
14081
|
jobs: "server/jobs",
|
|
14138
14082
|
events: "server/events",
|
|
14139
|
-
listeners: "server/listeners"
|
|
14083
|
+
listeners: "server/listeners",
|
|
14084
|
+
authorizationPolicies: "server/policies",
|
|
14085
|
+
authorizationAbilities: "server/abilities"
|
|
14140
14086
|
});
|
|
14141
14087
|
function normalizeHoloProjectConfig(config = {}) {
|
|
14142
14088
|
return Object.freeze({
|
|
@@ -14215,6 +14161,7 @@ export {
|
|
|
14215
14161
|
column,
|
|
14216
14162
|
compileDialectDefaultLiteral,
|
|
14217
14163
|
configureDB,
|
|
14164
|
+
configureDatabaseQueryCacheBridge,
|
|
14218
14165
|
connectionAsyncContext,
|
|
14219
14166
|
createAdapter,
|
|
14220
14167
|
createCapabilities,
|
|
@@ -14267,6 +14214,7 @@ export {
|
|
|
14267
14214
|
generateSnowflake,
|
|
14268
14215
|
generateUlid,
|
|
14269
14216
|
generateUuidV7,
|
|
14217
|
+
getDatabaseQueryCacheBridge,
|
|
14270
14218
|
getGeneratedTableDefinition,
|
|
14271
14219
|
getModelDefinition,
|
|
14272
14220
|
hasMany,
|
|
@@ -14293,6 +14241,7 @@ export {
|
|
|
14293
14241
|
oldestMorphOne,
|
|
14294
14242
|
oldestOfMany,
|
|
14295
14243
|
parseDatabaseDriver,
|
|
14244
|
+
queryCacheInternals,
|
|
14296
14245
|
redactBindings,
|
|
14297
14246
|
redactSql,
|
|
14298
14247
|
registerGeneratedTables,
|
|
@@ -14302,6 +14251,7 @@ export {
|
|
|
14302
14251
|
renderGeneratedSchemaModule,
|
|
14303
14252
|
renderGeneratedSchemaPlaceholder,
|
|
14304
14253
|
resetDB,
|
|
14254
|
+
resetDatabaseQueryCacheBridge,
|
|
14305
14255
|
resetMorphRegistry,
|
|
14306
14256
|
resolveDialectColumnType,
|
|
14307
14257
|
resolveDialectIdStrategyType,
|