@holo-js/db 0.1.3 → 0.1.5
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 +356 -337
- package/dist/index.mjs +1216 -925
- package/package.json +8 -9
package/dist/index.mjs
CHANGED
|
@@ -110,7 +110,7 @@ function redactBindings(bindings, policy) {
|
|
|
110
110
|
if (policy.redactBindingsInLogs) {
|
|
111
111
|
return limited.map(() => "[REDACTED]");
|
|
112
112
|
}
|
|
113
|
-
return
|
|
113
|
+
return limited;
|
|
114
114
|
}
|
|
115
115
|
function redactSql(sql, policy) {
|
|
116
116
|
if (policy.debugSqlInLogs) {
|
|
@@ -278,13 +278,50 @@ function compareChunkValuesDescending(a, b) {
|
|
|
278
278
|
return a < b ? 1 : -1;
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
// src/query/pagination.ts
|
|
282
|
+
function assertPositiveInteger(value, kind, createError) {
|
|
283
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
284
|
+
throw createError(`${kind} must be a positive integer.`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function normalizePaginationParameterName(value, fallback, createError) {
|
|
288
|
+
if (typeof value === "undefined") {
|
|
289
|
+
return fallback;
|
|
290
|
+
}
|
|
291
|
+
const trimmed = value.trim();
|
|
292
|
+
if (typeof value !== "string" || trimmed.length === 0) {
|
|
293
|
+
throw createError(
|
|
294
|
+
`${fallback === "cursor" ? "Cursor" : "Page"} parameter name must be a non-empty string.`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return trimmed;
|
|
298
|
+
}
|
|
299
|
+
function encodeOffsetCursor(offset) {
|
|
300
|
+
return Buffer.from(JSON.stringify({ offset }), "utf8").toString("base64url");
|
|
301
|
+
}
|
|
302
|
+
function decodeOffsetCursor(cursor, createError) {
|
|
303
|
+
if (cursor === null) {
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
308
|
+
const offset = decoded.offset;
|
|
309
|
+
if (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0) {
|
|
310
|
+
throw new Error("invalid offset");
|
|
311
|
+
}
|
|
312
|
+
return offset;
|
|
313
|
+
} catch {
|
|
314
|
+
throw createError("Cursor is malformed.");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
281
318
|
// src/query/paginator.ts
|
|
282
319
|
function createPaginator(data, meta) {
|
|
283
320
|
const result = {
|
|
284
321
|
data,
|
|
285
322
|
meta: {
|
|
286
323
|
...meta,
|
|
287
|
-
pageName:
|
|
324
|
+
pageName: normalizePaginationParameterName(meta.pageName, "page", (message) => new SecurityError(message))
|
|
288
325
|
}
|
|
289
326
|
};
|
|
290
327
|
attachMethods(result, {
|
|
@@ -306,7 +343,7 @@ function createSimplePaginator(data, meta) {
|
|
|
306
343
|
data,
|
|
307
344
|
meta: {
|
|
308
345
|
...meta,
|
|
309
|
-
pageName:
|
|
346
|
+
pageName: normalizePaginationParameterName(meta.pageName, "page", (message) => new SecurityError(message))
|
|
310
347
|
}
|
|
311
348
|
};
|
|
312
349
|
attachMethods(result, {
|
|
@@ -327,7 +364,7 @@ function createCursorPaginator(data, meta) {
|
|
|
327
364
|
const result = {
|
|
328
365
|
data,
|
|
329
366
|
perPage: meta.perPage,
|
|
330
|
-
cursorName:
|
|
367
|
+
cursorName: normalizePaginationParameterName(meta.cursorName, "cursor", (message) => new SecurityError(message)),
|
|
331
368
|
nextCursor: meta.nextCursor,
|
|
332
369
|
prevCursor: meta.prevCursor
|
|
333
370
|
};
|
|
@@ -347,15 +384,6 @@ function createCursorPaginator(data, meta) {
|
|
|
347
384
|
});
|
|
348
385
|
return result;
|
|
349
386
|
}
|
|
350
|
-
function normalizeParameterName(value, fallback) {
|
|
351
|
-
if (typeof value === "undefined") {
|
|
352
|
-
return fallback;
|
|
353
|
-
}
|
|
354
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
355
|
-
throw new SecurityError(`${fallback === "cursor" ? "Cursor" : "Page"} parameter name must be a non-empty string.`);
|
|
356
|
-
}
|
|
357
|
-
return value;
|
|
358
|
-
}
|
|
359
387
|
function attachMethods(target, methods) {
|
|
360
388
|
Object.defineProperties(
|
|
361
389
|
target,
|
|
@@ -373,43 +401,6 @@ function attachMethods(target, methods) {
|
|
|
373
401
|
);
|
|
374
402
|
}
|
|
375
403
|
|
|
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
|
-
|
|
413
404
|
// src/query/ast.ts
|
|
414
405
|
function createTableSource(table) {
|
|
415
406
|
if (typeof table === "string") {
|
|
@@ -1687,16 +1678,6 @@ var SQLQueryCompiler = class {
|
|
|
1687
1678
|
function createSqliteJsonExtractExpression(column2, pathLiteral) {
|
|
1688
1679
|
return `json_extract(${column2}, ${pathLiteral})`;
|
|
1689
1680
|
}
|
|
1690
|
-
function compileSqliteJsonValuePredicate(extracted, predicate, bindings, createPlaceholder) {
|
|
1691
|
-
bindings.push(predicate.value);
|
|
1692
|
-
const operator = predicate.operator.toUpperCase();
|
|
1693
|
-
const placeholder = createPlaceholder(bindings.length);
|
|
1694
|
-
return `${extracted} ${operator} ${placeholder}`;
|
|
1695
|
-
}
|
|
1696
|
-
var SQLITE_JSON_HELPERS = Object.freeze({
|
|
1697
|
-
compileValuePredicate: compileSqliteJsonValuePredicate,
|
|
1698
|
-
createExtractExpression: createSqliteJsonExtractExpression
|
|
1699
|
-
});
|
|
1700
1681
|
var SQLITE_EMPTY_JSON_OBJECT = "json('{}')";
|
|
1701
1682
|
var SQLiteQueryCompiler = class extends SQLQueryCompiler {
|
|
1702
1683
|
compileLockClause(_lockMode) {
|
|
@@ -1705,16 +1686,12 @@ var SQLiteQueryCompiler = class extends SQLQueryCompiler {
|
|
|
1705
1686
|
compileJsonPredicate(predicate, bindings) {
|
|
1706
1687
|
const column2 = this.compileColumnReference(predicate.column);
|
|
1707
1688
|
const pathLiteral = this.createJsonPathLiteral(predicate.path);
|
|
1689
|
+
const extracted = createSqliteJsonExtractExpression(column2, pathLiteral);
|
|
1708
1690
|
if (predicate.jsonMode === "value") {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
predicate,
|
|
1712
|
-
bindings,
|
|
1713
|
-
(index) => this.createPlaceholder(index)
|
|
1714
|
-
);
|
|
1691
|
+
bindings.push(predicate.value);
|
|
1692
|
+
return `${extracted} ${predicate.operator.toUpperCase()} ${this.createPlaceholder(bindings.length)}`;
|
|
1715
1693
|
}
|
|
1716
1694
|
if (predicate.jsonMode === "contains") {
|
|
1717
|
-
const extracted = SQLITE_JSON_HELPERS.createExtractExpression(column2, pathLiteral);
|
|
1718
1695
|
if (predicate.value === null || ["string", "number", "boolean"].includes(typeof predicate.value)) {
|
|
1719
1696
|
bindings.push(predicate.value);
|
|
1720
1697
|
return `EXISTS (SELECT 1 FROM json_each(${extracted}) WHERE value = ${this.createPlaceholder(bindings.length)})`;
|
|
@@ -1723,7 +1700,7 @@ var SQLiteQueryCompiler = class extends SQLQueryCompiler {
|
|
|
1723
1700
|
return `${extracted} = json(${this.createPlaceholder(bindings.length)})`;
|
|
1724
1701
|
}
|
|
1725
1702
|
bindings.push(predicate.value);
|
|
1726
|
-
return `json_array_length(${
|
|
1703
|
+
return `json_array_length(${extracted}) ${predicate.operator.toUpperCase()} ${this.createPlaceholder(bindings.length)}`;
|
|
1727
1704
|
}
|
|
1728
1705
|
compileJsonUpdateOperations(column2, operations, bindings) {
|
|
1729
1706
|
let expression = `COALESCE(${this.compileColumnReference(column2)}, ${SQLITE_EMPTY_JSON_OBJECT})`;
|
|
@@ -1878,23 +1855,6 @@ var MySQLQueryCompiler = class extends SQLQueryCompiler {
|
|
|
1878
1855
|
const modifier = predicate.mode === "boolean" ? " IN BOOLEAN MODE" : " IN NATURAL LANGUAGE MODE";
|
|
1879
1856
|
return `MATCH (${columns}) AGAINST (${this.createPlaceholder(bindings.length)}${modifier})`;
|
|
1880
1857
|
}
|
|
1881
|
-
compileDatePredicate(predicate, placeholder) {
|
|
1882
|
-
const column2 = this.compileColumnReference(predicate.column);
|
|
1883
|
-
switch (predicate.part) {
|
|
1884
|
-
case "date":
|
|
1885
|
-
return `DATE(${column2}) ${predicate.operator.toUpperCase()} ${placeholder}`;
|
|
1886
|
-
case "time":
|
|
1887
|
-
return `TIME(${column2}) ${predicate.operator.toUpperCase()} ${placeholder}`;
|
|
1888
|
-
case "year":
|
|
1889
|
-
return `EXTRACT(YEAR FROM ${column2}) ${predicate.operator.toUpperCase()} ${placeholder}`;
|
|
1890
|
-
case "month":
|
|
1891
|
-
return `EXTRACT(MONTH FROM ${column2}) ${predicate.operator.toUpperCase()} ${placeholder}`;
|
|
1892
|
-
case "day":
|
|
1893
|
-
return `EXTRACT(DAY FROM ${column2}) ${predicate.operator.toUpperCase()} ${placeholder}`;
|
|
1894
|
-
default:
|
|
1895
|
-
return super.compileDatePredicate(predicate, placeholder);
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
1858
|
};
|
|
1899
1859
|
|
|
1900
1860
|
// src/schema/normalization.ts
|
|
@@ -3246,14 +3206,9 @@ function sanitizeIdentifierForGeneratedName(identifier) {
|
|
|
3246
3206
|
}
|
|
3247
3207
|
|
|
3248
3208
|
// src/schema/pluralize.ts
|
|
3209
|
+
import { pluralize } from "inflection";
|
|
3249
3210
|
function pluralizeTableName(word) {
|
|
3250
|
-
|
|
3251
|
-
return `${word.slice(0, -1)}ies`;
|
|
3252
|
-
}
|
|
3253
|
-
if (/(?:[sxz]|ch|sh)$/i.test(word)) {
|
|
3254
|
-
return `${word}es`;
|
|
3255
|
-
}
|
|
3256
|
-
return `${word}s`;
|
|
3211
|
+
return pluralize(word);
|
|
3257
3212
|
}
|
|
3258
3213
|
function inferConstrainedTableName(columnName) {
|
|
3259
3214
|
if (columnName.endsWith("_id")) {
|
|
@@ -3559,7 +3514,11 @@ function defineTable(name, columns, options = {}) {
|
|
|
3559
3514
|
}
|
|
3560
3515
|
|
|
3561
3516
|
// src/schema/generated.ts
|
|
3562
|
-
var generatedTables =
|
|
3517
|
+
var generatedTables = (() => {
|
|
3518
|
+
const runtime = globalThis;
|
|
3519
|
+
runtime.__holoGeneratedTables__ ??= /* @__PURE__ */ new Map();
|
|
3520
|
+
return runtime.__holoGeneratedTables__;
|
|
3521
|
+
})();
|
|
3563
3522
|
function registerGeneratedTables(tables) {
|
|
3564
3523
|
for (const table of Object.values(tables)) {
|
|
3565
3524
|
generatedTables.set(table.tableName, table);
|
|
@@ -3707,22 +3666,7 @@ function renderColumnBuilder(table, columnDefinition) {
|
|
|
3707
3666
|
function renderIndex(index) {
|
|
3708
3667
|
return `{ columns: ${JSON.stringify([...index.columns])}, unique: ${index.unique}${index.name ? `, name: ${JSON.stringify(index.name)}` : ""} }`;
|
|
3709
3668
|
}
|
|
3710
|
-
function
|
|
3711
|
-
return [
|
|
3712
|
-
"/* eslint-disable @typescript-eslint/no-empty-object-type */",
|
|
3713
|
-
"import { registerGeneratedTables } from '@holo-js/db'",
|
|
3714
|
-
"",
|
|
3715
|
-
"declare module '@holo-js/db' {",
|
|
3716
|
-
" interface GeneratedSchemaTables {}",
|
|
3717
|
-
"}",
|
|
3718
|
-
"",
|
|
3719
|
-
"export const tables = {} as const",
|
|
3720
|
-
"",
|
|
3721
|
-
"registerGeneratedTables(tables)",
|
|
3722
|
-
""
|
|
3723
|
-
].join("\n");
|
|
3724
|
-
}
|
|
3725
|
-
function renderGeneratedSchemaModule(tables) {
|
|
3669
|
+
function buildGeneratedSchemaModuleLines(tables, options) {
|
|
3726
3670
|
const renderedTables = [...tables].sort((left, right) => left.tableName.localeCompare(right.tableName));
|
|
3727
3671
|
const declarations = [
|
|
3728
3672
|
"import { column, defineGeneratedTable, registerGeneratedTables } from '@holo-js/db'",
|
|
@@ -3741,24 +3685,146 @@ function renderGeneratedSchemaModule(tables) {
|
|
|
3741
3685
|
declarations.push(`}${table.indexes.length > 0 ? `, { indexes: [${table.indexes.map(renderIndex).join(", ")}] }` : ""})`);
|
|
3742
3686
|
declarations.push("");
|
|
3743
3687
|
}
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3688
|
+
if (options.withTypeAugmentation) {
|
|
3689
|
+
declarations.push("declare module '@holo-js/db' {");
|
|
3690
|
+
declarations.push(" interface GeneratedSchemaTables {");
|
|
3691
|
+
declarations.push(...interfaceLines);
|
|
3692
|
+
declarations.push(" }");
|
|
3693
|
+
declarations.push("}");
|
|
3694
|
+
declarations.push("");
|
|
3695
|
+
}
|
|
3696
|
+
declarations.push(
|
|
3697
|
+
options.withTypeAugmentation ? `export const tables = { ${exportedTableEntries.join(", ")} } as const` : `export const tables = Object.freeze({ ${exportedTableEntries.join(", ")} })`
|
|
3698
|
+
);
|
|
3751
3699
|
declarations.push("");
|
|
3752
3700
|
declarations.push("registerGeneratedTables(tables)");
|
|
3753
3701
|
declarations.push("");
|
|
3754
|
-
return declarations
|
|
3702
|
+
return declarations;
|
|
3703
|
+
}
|
|
3704
|
+
function renderGeneratedSchemaPlaceholder() {
|
|
3705
|
+
return [
|
|
3706
|
+
"/* eslint-disable @typescript-eslint/no-empty-object-type */",
|
|
3707
|
+
"import { registerGeneratedTables } from '@holo-js/db'",
|
|
3708
|
+
"",
|
|
3709
|
+
"declare module '@holo-js/db' {",
|
|
3710
|
+
" interface GeneratedSchemaTables {}",
|
|
3711
|
+
"}",
|
|
3712
|
+
"",
|
|
3713
|
+
"export const tables = {} as const",
|
|
3714
|
+
"",
|
|
3715
|
+
"registerGeneratedTables(tables)",
|
|
3716
|
+
""
|
|
3717
|
+
].join("\n");
|
|
3718
|
+
}
|
|
3719
|
+
function renderGeneratedSchemaModule(tables) {
|
|
3720
|
+
return buildGeneratedSchemaModuleLines(tables, { withTypeAugmentation: true }).join("\n");
|
|
3721
|
+
}
|
|
3722
|
+
function renderGeneratedSchemaRuntimeModule(tables) {
|
|
3723
|
+
return buildGeneratedSchemaModuleLines(tables, { withTypeAugmentation: false }).join("\n");
|
|
3724
|
+
}
|
|
3725
|
+
|
|
3726
|
+
// src/schema/foreignKeyBuilderState.ts
|
|
3727
|
+
var ForeignKeyBuilderState = class {
|
|
3728
|
+
constructor(columnName, referenceColumn = "id") {
|
|
3729
|
+
this.columnName = columnName;
|
|
3730
|
+
this.referenceColumn = referenceColumn;
|
|
3731
|
+
}
|
|
3732
|
+
referenceTable;
|
|
3733
|
+
referenceColumn;
|
|
3734
|
+
onDeleteAction;
|
|
3735
|
+
onUpdateAction;
|
|
3736
|
+
references(columnName) {
|
|
3737
|
+
this.referenceColumn = columnName;
|
|
3738
|
+
}
|
|
3739
|
+
on(table) {
|
|
3740
|
+
this.referenceTable = table;
|
|
3741
|
+
}
|
|
3742
|
+
constrained(table, columnName = "id") {
|
|
3743
|
+
this.referenceTable = table ?? inferConstrainedTableName(this.columnName);
|
|
3744
|
+
this.referenceColumn = columnName;
|
|
3745
|
+
}
|
|
3746
|
+
onDelete(action) {
|
|
3747
|
+
this.onDeleteAction = action;
|
|
3748
|
+
}
|
|
3749
|
+
onUpdate(action) {
|
|
3750
|
+
this.onUpdateAction = action;
|
|
3751
|
+
}
|
|
3752
|
+
toReference(defaultTable = "") {
|
|
3753
|
+
return {
|
|
3754
|
+
table: this.referenceTable ?? defaultTable,
|
|
3755
|
+
column: this.referenceColumn,
|
|
3756
|
+
onDelete: this.onDeleteAction,
|
|
3757
|
+
onUpdate: this.onUpdateAction
|
|
3758
|
+
};
|
|
3759
|
+
}
|
|
3760
|
+
applyToColumnBuilder(builder) {
|
|
3761
|
+
let next = builder.references(this.referenceColumn);
|
|
3762
|
+
if (this.referenceTable) {
|
|
3763
|
+
next = next.on(this.referenceTable);
|
|
3764
|
+
}
|
|
3765
|
+
if (this.onDeleteAction) {
|
|
3766
|
+
next = next.onDelete(this.onDeleteAction);
|
|
3767
|
+
}
|
|
3768
|
+
if (this.onUpdateAction) {
|
|
3769
|
+
next = next.onUpdate(this.onUpdateAction);
|
|
3770
|
+
}
|
|
3771
|
+
return next;
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
|
|
3775
|
+
// src/schema/generatedNames.ts
|
|
3776
|
+
var DEFAULT_INDEX_NAME_LENGTH_POLICY = Object.freeze({
|
|
3777
|
+
maxBytes: 63,
|
|
3778
|
+
label: "portable PostgreSQL-compatible (NAMEDATALEN-1)"
|
|
3779
|
+
});
|
|
3780
|
+
function assertValidIndexName(indexName, policy = DEFAULT_INDEX_NAME_LENGTH_POLICY) {
|
|
3781
|
+
assertValidIdentifierSegment(indexName, "Index name");
|
|
3782
|
+
const byteLength = new TextEncoder().encode(indexName).length;
|
|
3783
|
+
if (byteLength > policy.maxBytes) {
|
|
3784
|
+
throw new SchemaError(
|
|
3785
|
+
`Index name "${indexName}" is ${byteLength} bytes long; ${policy.label} index names must be ${policy.maxBytes} bytes or fewer. Provide a shorter explicit index name.`
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
function assertUniqueResolvedIndexNames(tableName, indexes) {
|
|
3790
|
+
const names = /* @__PURE__ */ new Set();
|
|
3791
|
+
for (const index of indexes) {
|
|
3792
|
+
const indexName = resolveGeneratedIndexName(tableName, index);
|
|
3793
|
+
if (names.has(indexName)) {
|
|
3794
|
+
throw new SchemaError(
|
|
3795
|
+
`Index name "${indexName}" is used by multiple indexes on table "${tableName}". Provide explicit unique index names.`
|
|
3796
|
+
);
|
|
3797
|
+
}
|
|
3798
|
+
names.add(indexName);
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
function resolveGeneratedIndexName(tableName, index) {
|
|
3802
|
+
const suffix = index.unique ? "unique" : "index";
|
|
3803
|
+
const indexName = index.name ?? createConventionalIndexName(tableName, index.columns, suffix);
|
|
3804
|
+
assertValidIndexName(indexName);
|
|
3805
|
+
return indexName;
|
|
3806
|
+
}
|
|
3807
|
+
function createConventionalIndexName(tableName, columns, suffix) {
|
|
3808
|
+
const columnsName = columns.map((column2) => sanitizeIdentifierForGeneratedName(column2)).join("_");
|
|
3809
|
+
return `${sanitizeIdentifierForGeneratedName(tableName)}_${columnsName}_${suffix}`;
|
|
3810
|
+
}
|
|
3811
|
+
function resolveConventionalIndexName(tableName, columns, suffix = "index") {
|
|
3812
|
+
const indexName = createConventionalIndexName(tableName, columns, suffix);
|
|
3813
|
+
assertValidIndexName(indexName);
|
|
3814
|
+
return indexName;
|
|
3815
|
+
}
|
|
3816
|
+
function resolveGeneratedForeignKeyName(tableName, columnName, constraintName) {
|
|
3817
|
+
const resolvedName = constraintName ?? `${sanitizeIdentifierForGeneratedName(tableName)}_${sanitizeIdentifierForGeneratedName(columnName)}_foreign`;
|
|
3818
|
+
assertValidIdentifierSegment(resolvedName, "Foreign key name");
|
|
3819
|
+
return resolvedName;
|
|
3755
3820
|
}
|
|
3756
3821
|
|
|
3757
3822
|
// src/schema/TableDefinitionBuilder.ts
|
|
3758
3823
|
var TableCreateColumnBuilder = class {
|
|
3759
|
-
constructor(root, builderRef) {
|
|
3824
|
+
constructor(root, builderRef, columnName) {
|
|
3760
3825
|
this.root = root;
|
|
3761
3826
|
this.builderRef = builderRef;
|
|
3827
|
+
this.columnName = columnName;
|
|
3762
3828
|
}
|
|
3763
3829
|
build() {
|
|
3764
3830
|
return this.root.build();
|
|
@@ -3794,6 +3860,16 @@ var TableCreateColumnBuilder = class {
|
|
|
3794
3860
|
this.builderRef.builder = this.builderRef.builder.unique();
|
|
3795
3861
|
return this;
|
|
3796
3862
|
}
|
|
3863
|
+
index(nameOrColumns, name) {
|
|
3864
|
+
if (typeof nameOrColumns !== "string" && nameOrColumns !== void 0) {
|
|
3865
|
+
return this.root.index(nameOrColumns, name);
|
|
3866
|
+
}
|
|
3867
|
+
this.root.index(
|
|
3868
|
+
[this.columnName],
|
|
3869
|
+
nameOrColumns ?? resolveConventionalIndexName(this.root.tableName, [this.columnName])
|
|
3870
|
+
);
|
|
3871
|
+
return this;
|
|
3872
|
+
}
|
|
3797
3873
|
foreign(columnName) {
|
|
3798
3874
|
return this.root.foreign(columnName);
|
|
3799
3875
|
}
|
|
@@ -3866,9 +3942,6 @@ var TableCreateColumnBuilder = class {
|
|
|
3866
3942
|
enum(columnName, values) {
|
|
3867
3943
|
return this.root.enum(columnName, values);
|
|
3868
3944
|
}
|
|
3869
|
-
index(columns, name) {
|
|
3870
|
-
return this.root.index(columns, name);
|
|
3871
|
-
}
|
|
3872
3945
|
timestamps() {
|
|
3873
3946
|
return this.root.timestamps();
|
|
3874
3947
|
}
|
|
@@ -3901,33 +3974,29 @@ var TableCreateColumnBuilder = class {
|
|
|
3901
3974
|
}
|
|
3902
3975
|
};
|
|
3903
3976
|
var TableCreateForeignIdBuilder = class extends TableCreateColumnBuilder {
|
|
3977
|
+
foreignKeyState;
|
|
3904
3978
|
constructor(root, builderRef, columnName) {
|
|
3905
|
-
super(root, builderRef);
|
|
3906
|
-
this.
|
|
3979
|
+
super(root, builderRef, columnName);
|
|
3980
|
+
this.foreignKeyState = new ForeignKeyBuilderState(columnName);
|
|
3907
3981
|
}
|
|
3908
|
-
referenceTable;
|
|
3909
|
-
referenceColumn = "id";
|
|
3910
|
-
onDeleteAction;
|
|
3911
|
-
onUpdateAction;
|
|
3912
3982
|
references(columnName) {
|
|
3913
|
-
this.
|
|
3983
|
+
this.foreignKeyState.references(columnName);
|
|
3914
3984
|
return this.applyReference();
|
|
3915
3985
|
}
|
|
3916
3986
|
on(table) {
|
|
3917
|
-
this.
|
|
3987
|
+
this.foreignKeyState.on(table);
|
|
3918
3988
|
return this.applyReference();
|
|
3919
3989
|
}
|
|
3920
3990
|
constrained(table, columnName = "id") {
|
|
3921
|
-
this.
|
|
3922
|
-
this.referenceColumn = columnName;
|
|
3991
|
+
this.foreignKeyState.constrained(table, columnName);
|
|
3923
3992
|
return this.applyReference();
|
|
3924
3993
|
}
|
|
3925
3994
|
onDelete(action) {
|
|
3926
|
-
this.
|
|
3995
|
+
this.foreignKeyState.onDelete(action);
|
|
3927
3996
|
return this.applyReference();
|
|
3928
3997
|
}
|
|
3929
3998
|
onUpdate(action) {
|
|
3930
|
-
this.
|
|
3999
|
+
this.foreignKeyState.onUpdate(action);
|
|
3931
4000
|
return this.applyReference();
|
|
3932
4001
|
}
|
|
3933
4002
|
cascadeOnDelete() {
|
|
@@ -3955,17 +4024,7 @@ var TableCreateForeignIdBuilder = class extends TableCreateColumnBuilder {
|
|
|
3955
4024
|
return this.onUpdate("no action");
|
|
3956
4025
|
}
|
|
3957
4026
|
applyReference() {
|
|
3958
|
-
|
|
3959
|
-
if (this.referenceTable) {
|
|
3960
|
-
builder = builder.on(this.referenceTable);
|
|
3961
|
-
}
|
|
3962
|
-
if (this.onDeleteAction) {
|
|
3963
|
-
builder = builder.onDelete(this.onDeleteAction);
|
|
3964
|
-
}
|
|
3965
|
-
if (this.onUpdateAction) {
|
|
3966
|
-
builder = builder.onUpdate(this.onUpdateAction);
|
|
3967
|
-
}
|
|
3968
|
-
this.builderRef.builder = builder;
|
|
4027
|
+
this.builderRef.builder = this.foreignKeyState.applyToColumnBuilder(this.builderRef.builder);
|
|
3969
4028
|
return this;
|
|
3970
4029
|
}
|
|
3971
4030
|
};
|
|
@@ -3973,31 +4032,27 @@ var TableCreateForeignKeyBuilder = class {
|
|
|
3973
4032
|
constructor(root, builderRef, columnName) {
|
|
3974
4033
|
this.root = root;
|
|
3975
4034
|
this.builderRef = builderRef;
|
|
3976
|
-
this.
|
|
4035
|
+
this.foreignKeyState = new ForeignKeyBuilderState(columnName);
|
|
3977
4036
|
}
|
|
3978
|
-
|
|
3979
|
-
referenceColumn = "id";
|
|
3980
|
-
onDeleteAction;
|
|
3981
|
-
onUpdateAction;
|
|
4037
|
+
foreignKeyState;
|
|
3982
4038
|
references(columnName) {
|
|
3983
|
-
this.
|
|
4039
|
+
this.foreignKeyState.references(columnName);
|
|
3984
4040
|
return this.applyReference();
|
|
3985
4041
|
}
|
|
3986
4042
|
on(table) {
|
|
3987
|
-
this.
|
|
4043
|
+
this.foreignKeyState.on(table);
|
|
3988
4044
|
return this.applyReference();
|
|
3989
4045
|
}
|
|
3990
4046
|
constrained(table, columnName = "id") {
|
|
3991
|
-
this.
|
|
3992
|
-
this.referenceColumn = columnName;
|
|
4047
|
+
this.foreignKeyState.constrained(table, columnName);
|
|
3993
4048
|
return this.applyReference();
|
|
3994
4049
|
}
|
|
3995
4050
|
onDelete(action) {
|
|
3996
|
-
this.
|
|
4051
|
+
this.foreignKeyState.onDelete(action);
|
|
3997
4052
|
return this.applyReference();
|
|
3998
4053
|
}
|
|
3999
4054
|
onUpdate(action) {
|
|
4000
|
-
this.
|
|
4055
|
+
this.foreignKeyState.onUpdate(action);
|
|
4001
4056
|
return this.applyReference();
|
|
4002
4057
|
}
|
|
4003
4058
|
cascadeOnDelete() {
|
|
@@ -4028,17 +4083,7 @@ var TableCreateForeignKeyBuilder = class {
|
|
|
4028
4083
|
return this.root.build();
|
|
4029
4084
|
}
|
|
4030
4085
|
applyReference() {
|
|
4031
|
-
|
|
4032
|
-
if (this.referenceTable) {
|
|
4033
|
-
builder = builder.on(this.referenceTable);
|
|
4034
|
-
}
|
|
4035
|
-
if (this.onDeleteAction) {
|
|
4036
|
-
builder = builder.onDelete(this.onDeleteAction);
|
|
4037
|
-
}
|
|
4038
|
-
if (this.onUpdateAction) {
|
|
4039
|
-
builder = builder.onUpdate(this.onUpdateAction);
|
|
4040
|
-
}
|
|
4041
|
-
this.builderRef.builder = builder;
|
|
4086
|
+
this.builderRef.builder = this.foreignKeyState.applyToColumnBuilder(this.builderRef.builder);
|
|
4042
4087
|
return this;
|
|
4043
4088
|
}
|
|
4044
4089
|
};
|
|
@@ -4180,7 +4225,8 @@ var TableDefinitionBuilder = class {
|
|
|
4180
4225
|
};
|
|
4181
4226
|
return new TableCreateColumnBuilder(
|
|
4182
4227
|
this,
|
|
4183
|
-
builderRef
|
|
4228
|
+
builderRef,
|
|
4229
|
+
columnName
|
|
4184
4230
|
);
|
|
4185
4231
|
}
|
|
4186
4232
|
foreignColumn(columnName, initialBuilder) {
|
|
@@ -4202,7 +4248,10 @@ var TableDefinitionBuilder = class {
|
|
|
4202
4248
|
const idBuilder = nullable ? createIdBuilder().nullable() : createIdBuilder();
|
|
4203
4249
|
this.column(typeColumn, typeBuilder);
|
|
4204
4250
|
this.column(idColumn, idBuilder);
|
|
4205
|
-
this.index(
|
|
4251
|
+
this.index(
|
|
4252
|
+
[typeColumn, idColumn],
|
|
4253
|
+
indexName ?? resolveConventionalIndexName(this.tableName, [typeColumn, idColumn])
|
|
4254
|
+
);
|
|
4206
4255
|
return this;
|
|
4207
4256
|
}
|
|
4208
4257
|
};
|
|
@@ -4211,36 +4260,32 @@ var TableDefinitionBuilder = class {
|
|
|
4211
4260
|
var TableForeignKeyBuilder = class {
|
|
4212
4261
|
constructor(operation) {
|
|
4213
4262
|
this.operation = operation;
|
|
4263
|
+
this.foreignKeyState = new ForeignKeyBuilderState(operation.columnName, operation.reference.column);
|
|
4214
4264
|
}
|
|
4265
|
+
foreignKeyState;
|
|
4215
4266
|
references(columnName) {
|
|
4216
|
-
this.
|
|
4217
|
-
|
|
4218
|
-
column: columnName
|
|
4219
|
-
};
|
|
4267
|
+
this.foreignKeyState.references(columnName);
|
|
4268
|
+
this.applyReference();
|
|
4220
4269
|
return this;
|
|
4221
4270
|
}
|
|
4222
4271
|
on(table) {
|
|
4223
|
-
this.
|
|
4224
|
-
|
|
4225
|
-
table
|
|
4226
|
-
};
|
|
4272
|
+
this.foreignKeyState.on(table);
|
|
4273
|
+
this.applyReference();
|
|
4227
4274
|
return this;
|
|
4228
4275
|
}
|
|
4229
4276
|
constrained(table, columnName = "id") {
|
|
4230
|
-
|
|
4277
|
+
this.foreignKeyState.constrained(table, columnName);
|
|
4278
|
+
this.applyReference();
|
|
4279
|
+
return this;
|
|
4231
4280
|
}
|
|
4232
4281
|
onDelete(action) {
|
|
4233
|
-
this.
|
|
4234
|
-
|
|
4235
|
-
onDelete: action
|
|
4236
|
-
};
|
|
4282
|
+
this.foreignKeyState.onDelete(action);
|
|
4283
|
+
this.applyReference();
|
|
4237
4284
|
return this;
|
|
4238
4285
|
}
|
|
4239
4286
|
onUpdate(action) {
|
|
4240
|
-
this.
|
|
4241
|
-
|
|
4242
|
-
onUpdate: action
|
|
4243
|
-
};
|
|
4287
|
+
this.foreignKeyState.onUpdate(action);
|
|
4288
|
+
this.applyReference();
|
|
4244
4289
|
return this;
|
|
4245
4290
|
}
|
|
4246
4291
|
cascadeOnDelete() {
|
|
@@ -4267,6 +4312,9 @@ var TableForeignKeyBuilder = class {
|
|
|
4267
4312
|
noActionOnUpdate() {
|
|
4268
4313
|
return this.onUpdate("no action");
|
|
4269
4314
|
}
|
|
4315
|
+
applyReference() {
|
|
4316
|
+
this.operation.reference = this.foreignKeyState.toReference();
|
|
4317
|
+
}
|
|
4270
4318
|
};
|
|
4271
4319
|
var TableColumnMutationBuilder = class {
|
|
4272
4320
|
constructor(root, operation) {
|
|
@@ -4301,6 +4349,13 @@ var TableColumnMutationBuilder = class {
|
|
|
4301
4349
|
this.operation.column = this.operation.column.unique();
|
|
4302
4350
|
return this;
|
|
4303
4351
|
}
|
|
4352
|
+
index(name) {
|
|
4353
|
+
this.root.index(
|
|
4354
|
+
[this.operation.columnName],
|
|
4355
|
+
name ?? resolveConventionalIndexName(this.root.table, [this.operation.columnName])
|
|
4356
|
+
);
|
|
4357
|
+
return this;
|
|
4358
|
+
}
|
|
4304
4359
|
foreignId(columnName) {
|
|
4305
4360
|
return this.root.foreignId(columnName);
|
|
4306
4361
|
}
|
|
@@ -4347,31 +4402,28 @@ var TableForeignIdMutationBuilder = class extends TableColumnMutationBuilder {
|
|
|
4347
4402
|
super(root, operation);
|
|
4348
4403
|
this.operations = operations;
|
|
4349
4404
|
this.columnName = columnName;
|
|
4405
|
+
this.foreignKeyState = new ForeignKeyBuilderState(columnName);
|
|
4350
4406
|
}
|
|
4407
|
+
foreignKeyState;
|
|
4351
4408
|
foreignOperation;
|
|
4352
|
-
referenceTable;
|
|
4353
|
-
referenceColumn = "id";
|
|
4354
|
-
onDeleteAction;
|
|
4355
|
-
onUpdateAction;
|
|
4356
4409
|
references(columnName) {
|
|
4357
|
-
this.
|
|
4410
|
+
this.foreignKeyState.references(columnName);
|
|
4358
4411
|
return this.applyForeignKey();
|
|
4359
4412
|
}
|
|
4360
4413
|
on(table) {
|
|
4361
|
-
this.
|
|
4414
|
+
this.foreignKeyState.on(table);
|
|
4362
4415
|
return this.applyForeignKey();
|
|
4363
4416
|
}
|
|
4364
4417
|
constrained(table, columnName = "id") {
|
|
4365
|
-
this.
|
|
4366
|
-
this.referenceColumn = columnName;
|
|
4418
|
+
this.foreignKeyState.constrained(table, columnName);
|
|
4367
4419
|
return this.applyForeignKey();
|
|
4368
4420
|
}
|
|
4369
4421
|
onDelete(action) {
|
|
4370
|
-
this.
|
|
4422
|
+
this.foreignKeyState.onDelete(action);
|
|
4371
4423
|
return this.applyForeignKey();
|
|
4372
4424
|
}
|
|
4373
4425
|
onUpdate(action) {
|
|
4374
|
-
this.
|
|
4426
|
+
this.foreignKeyState.onUpdate(action);
|
|
4375
4427
|
return this.applyForeignKey();
|
|
4376
4428
|
}
|
|
4377
4429
|
cascadeOnDelete() {
|
|
@@ -4400,12 +4452,7 @@ var TableForeignIdMutationBuilder = class extends TableColumnMutationBuilder {
|
|
|
4400
4452
|
}
|
|
4401
4453
|
applyForeignKey() {
|
|
4402
4454
|
const operation = this.ensureForeignOperation();
|
|
4403
|
-
operation.reference =
|
|
4404
|
-
table: this.referenceTable ?? "",
|
|
4405
|
-
column: this.referenceColumn,
|
|
4406
|
-
onDelete: this.onDeleteAction,
|
|
4407
|
-
onUpdate: this.onUpdateAction
|
|
4408
|
-
};
|
|
4455
|
+
operation.reference = this.foreignKeyState.toReference();
|
|
4409
4456
|
return this;
|
|
4410
4457
|
}
|
|
4411
4458
|
ensureForeignOperation() {
|
|
@@ -4413,12 +4460,7 @@ var TableForeignIdMutationBuilder = class extends TableColumnMutationBuilder {
|
|
|
4413
4460
|
this.foreignOperation = {
|
|
4414
4461
|
kind: "createForeignKey",
|
|
4415
4462
|
columnName: this.columnName,
|
|
4416
|
-
reference:
|
|
4417
|
-
table: this.referenceTable ?? "",
|
|
4418
|
-
column: this.referenceColumn,
|
|
4419
|
-
onDelete: this.onDeleteAction,
|
|
4420
|
-
onUpdate: this.onUpdateAction
|
|
4421
|
-
}
|
|
4463
|
+
reference: this.foreignKeyState.toReference()
|
|
4422
4464
|
};
|
|
4423
4465
|
this.operations.push(this.foreignOperation);
|
|
4424
4466
|
}
|
|
@@ -4586,7 +4628,10 @@ var TableMutationBuilder = class {
|
|
|
4586
4628
|
const idColumn = `${name}_id`;
|
|
4587
4629
|
this.columnMutation(typeColumn, () => nullable ? column.string().nullable() : column.string());
|
|
4588
4630
|
this.columnMutation(idColumn, () => nullable ? createIdBuilder().nullable() : createIdBuilder());
|
|
4589
|
-
this.index(
|
|
4631
|
+
this.index(
|
|
4632
|
+
[typeColumn, idColumn],
|
|
4633
|
+
indexName ?? resolveConventionalIndexName(this.table, [typeColumn, idColumn])
|
|
4634
|
+
);
|
|
4590
4635
|
return this;
|
|
4591
4636
|
}
|
|
4592
4637
|
};
|
|
@@ -4766,6 +4811,7 @@ var SQLSchemaCompiler = class {
|
|
|
4766
4811
|
}
|
|
4767
4812
|
compileCreateTable(table) {
|
|
4768
4813
|
assertValidIdentifierPath(table.tableName, "Table name");
|
|
4814
|
+
assertUniqueResolvedIndexNames(table.tableName, table.indexes);
|
|
4769
4815
|
const columnSql = Object.values(table.columns).map((column2) => this.compileColumn(column2));
|
|
4770
4816
|
const sql = `CREATE TABLE IF NOT EXISTS ${this.compileIdentifierPath(table.tableName)} (${columnSql.join(", ")})`;
|
|
4771
4817
|
const statements = [{
|
|
@@ -4857,7 +4903,7 @@ var SQLSchemaCompiler = class {
|
|
|
4857
4903
|
}
|
|
4858
4904
|
compileDropIndex(tableName, indexName) {
|
|
4859
4905
|
assertValidIdentifierPath(tableName, "Table name");
|
|
4860
|
-
|
|
4906
|
+
assertValidIndexName(indexName);
|
|
4861
4907
|
return {
|
|
4862
4908
|
sql: `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`,
|
|
4863
4909
|
source: `schema:dropIndex:${tableName}:${indexName}`
|
|
@@ -4873,8 +4919,8 @@ var SQLSchemaCompiler = class {
|
|
|
4873
4919
|
}
|
|
4874
4920
|
compileRenameIndex(tableName, fromIndexName, toIndexName) {
|
|
4875
4921
|
assertValidIdentifierPath(tableName, "Table name");
|
|
4876
|
-
|
|
4877
|
-
|
|
4922
|
+
assertValidIndexName(fromIndexName);
|
|
4923
|
+
assertValidIndexName(toIndexName);
|
|
4878
4924
|
return {
|
|
4879
4925
|
sql: `ALTER INDEX ${this.quoteIdentifier(fromIndexName)} RENAME TO ${this.quoteIdentifier(toIndexName)}`,
|
|
4880
4926
|
source: `schema:renameIndex:${tableName}:${fromIndexName}:${toIndexName}`
|
|
@@ -4964,14 +5010,10 @@ var SQLSchemaCompiler = class {
|
|
|
4964
5010
|
return false;
|
|
4965
5011
|
}
|
|
4966
5012
|
resolveIndexName(tableName, index) {
|
|
4967
|
-
|
|
4968
|
-
assertValidIdentifierSegment(indexName, "Index name");
|
|
4969
|
-
return indexName;
|
|
5013
|
+
return resolveGeneratedIndexName(tableName, index);
|
|
4970
5014
|
}
|
|
4971
5015
|
resolveForeignKeyName(tableName, columnName, constraintName) {
|
|
4972
|
-
|
|
4973
|
-
assertValidIdentifierSegment(resolvedName, "Foreign key name");
|
|
4974
|
-
return resolvedName;
|
|
5016
|
+
return resolveGeneratedForeignKeyName(tableName, columnName, constraintName);
|
|
4975
5017
|
}
|
|
4976
5018
|
assertSupportedAlterColumnDefinition(column2) {
|
|
4977
5019
|
if (column2.primaryKey || column2.unique || column2.references || column2.kind === "id") {
|
|
@@ -5130,6 +5172,41 @@ function resolveDialectColumnType(dialect, column2) {
|
|
|
5130
5172
|
}
|
|
5131
5173
|
return typeof entry === "function" ? entry(column2) : entry;
|
|
5132
5174
|
}
|
|
5175
|
+
function resolveDialectComparisonColumnType(dialect, column2) {
|
|
5176
|
+
const compiledType = resolveDialectColumnType(dialect, column2);
|
|
5177
|
+
const normalized = compiledType.toLowerCase();
|
|
5178
|
+
if (dialect === "sqlite") {
|
|
5179
|
+
return normalized.split(/\s+/, 1)[0].toUpperCase();
|
|
5180
|
+
}
|
|
5181
|
+
if (dialect === "postgres") {
|
|
5182
|
+
if (normalized.startsWith("varchar")) {
|
|
5183
|
+
return "character varying";
|
|
5184
|
+
}
|
|
5185
|
+
if (normalized.startsWith("bigint")) {
|
|
5186
|
+
return "bigint";
|
|
5187
|
+
}
|
|
5188
|
+
return normalized;
|
|
5189
|
+
}
|
|
5190
|
+
if (normalized.startsWith("varchar")) {
|
|
5191
|
+
return "varchar";
|
|
5192
|
+
}
|
|
5193
|
+
if (normalized.startsWith("char")) {
|
|
5194
|
+
return "char";
|
|
5195
|
+
}
|
|
5196
|
+
if (normalized.startsWith("tinyint")) {
|
|
5197
|
+
return "tinyint";
|
|
5198
|
+
}
|
|
5199
|
+
if (normalized.startsWith("decimal")) {
|
|
5200
|
+
return "decimal";
|
|
5201
|
+
}
|
|
5202
|
+
if (normalized.startsWith("enum")) {
|
|
5203
|
+
return "enum";
|
|
5204
|
+
}
|
|
5205
|
+
if (normalized.startsWith("bigint")) {
|
|
5206
|
+
return "bigint";
|
|
5207
|
+
}
|
|
5208
|
+
return normalized;
|
|
5209
|
+
}
|
|
5133
5210
|
|
|
5134
5211
|
// src/schema/SQLiteSchemaCompiler.ts
|
|
5135
5212
|
var SQLiteSchemaCompiler = class extends SQLSchemaCompiler {
|
|
@@ -5211,6 +5288,8 @@ var MySQLSchemaCompiler = class extends SQLSchemaCompiler {
|
|
|
5211
5288
|
};
|
|
5212
5289
|
}
|
|
5213
5290
|
compileRenameIndex(tableName, fromIndexName, toIndexName) {
|
|
5291
|
+
assertValidIndexName(fromIndexName);
|
|
5292
|
+
assertValidIndexName(toIndexName);
|
|
5214
5293
|
return {
|
|
5215
5294
|
sql: `ALTER TABLE ${this.compileIdentifierPath(tableName)} RENAME INDEX ${this.quoteIdentifier(fromIndexName)} TO ${this.quoteIdentifier(toIndexName)}`,
|
|
5216
5295
|
source: `schema:renameIndex:${tableName}:${fromIndexName}:${toIndexName}`
|
|
@@ -5225,6 +5304,7 @@ var MySQLSchemaCompiler = class extends SQLSchemaCompiler {
|
|
|
5225
5304
|
};
|
|
5226
5305
|
}
|
|
5227
5306
|
compileDropIndex(tableName, indexName) {
|
|
5307
|
+
assertValidIndexName(indexName);
|
|
5228
5308
|
return {
|
|
5229
5309
|
sql: `DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.compileIdentifierPath(tableName)}`,
|
|
5230
5310
|
source: `schema:dropIndex:${tableName}:${indexName}`
|
|
@@ -5268,7 +5348,9 @@ var SchemaService = class {
|
|
|
5268
5348
|
assertValidIdentifierPath(tableName, "Table name");
|
|
5269
5349
|
const builder = new TableMutationBuilder(tableName);
|
|
5270
5350
|
await callback(builder);
|
|
5271
|
-
|
|
5351
|
+
const operations = builder.getOperations();
|
|
5352
|
+
this.assertTableMutationIndexNames(tableName, operations);
|
|
5353
|
+
for (const operation of operations) {
|
|
5272
5354
|
await this.executeTableMutation(tableName, operation);
|
|
5273
5355
|
}
|
|
5274
5356
|
}
|
|
@@ -5556,10 +5638,31 @@ var SchemaService = class {
|
|
|
5556
5638
|
return column2.toDefinition({ name: columnName });
|
|
5557
5639
|
}
|
|
5558
5640
|
async createDefinedTable(table) {
|
|
5641
|
+
const statements = this.createCompiler().compile(createTableOperation(table));
|
|
5559
5642
|
if (!this.connection.getSchemaRegistry().has(table.tableName)) {
|
|
5560
5643
|
this.register(table);
|
|
5561
5644
|
}
|
|
5562
|
-
await this.execute(
|
|
5645
|
+
await this.execute(statements);
|
|
5646
|
+
}
|
|
5647
|
+
assertTableMutationIndexNames(tableName, operations) {
|
|
5648
|
+
const indexes = [];
|
|
5649
|
+
for (const operation of operations) {
|
|
5650
|
+
switch (operation.kind) {
|
|
5651
|
+
case "createIndex":
|
|
5652
|
+
indexes.push(operation.index);
|
|
5653
|
+
this.resolveIndexName(tableName, operation.index);
|
|
5654
|
+
break;
|
|
5655
|
+
case "dropIndex":
|
|
5656
|
+
assertValidIndexName(operation.indexName);
|
|
5657
|
+
break;
|
|
5658
|
+
case "renameIndex":
|
|
5659
|
+
assertValidIndexName(operation.fromIndexName);
|
|
5660
|
+
assertValidIndexName(operation.toIndexName);
|
|
5661
|
+
indexes.push({ columns: [], name: operation.toIndexName, unique: false });
|
|
5662
|
+
break;
|
|
5663
|
+
}
|
|
5664
|
+
}
|
|
5665
|
+
assertUniqueResolvedIndexNames(tableName, indexes);
|
|
5563
5666
|
}
|
|
5564
5667
|
async executeTableMutation(tableName, operation) {
|
|
5565
5668
|
switch (operation.kind) {
|
|
@@ -5757,10 +5860,10 @@ var SchemaService = class {
|
|
|
5757
5860
|
return defineTable(table.tableName, nextColumns, { indexes: table.indexes });
|
|
5758
5861
|
}
|
|
5759
5862
|
resolveIndexName(tableName, index) {
|
|
5760
|
-
return
|
|
5863
|
+
return resolveGeneratedIndexName(tableName, index);
|
|
5761
5864
|
}
|
|
5762
5865
|
resolveForeignKeyName(tableName, columnName) {
|
|
5763
|
-
return
|
|
5866
|
+
return resolveGeneratedForeignKeyName(tableName, columnName);
|
|
5764
5867
|
}
|
|
5765
5868
|
createForeignKeyConstraintStatement(enable) {
|
|
5766
5869
|
if (this.isSqlite()) {
|
|
@@ -5969,117 +6072,15 @@ async function diffTable(schema, table) {
|
|
|
5969
6072
|
}
|
|
5970
6073
|
function lowerLogicalColumnType(column2, dialectName) {
|
|
5971
6074
|
if (dialectName.startsWith("postgres")) {
|
|
5972
|
-
return
|
|
6075
|
+
return resolveDialectComparisonColumnType("postgres", column2);
|
|
5973
6076
|
}
|
|
5974
6077
|
if (dialectName.startsWith("mysql")) {
|
|
5975
|
-
return
|
|
5976
|
-
}
|
|
5977
|
-
switch (column2.kind) {
|
|
5978
|
-
case "id":
|
|
5979
|
-
case "integer":
|
|
5980
|
-
case "bigInteger":
|
|
5981
|
-
case "boolean":
|
|
5982
|
-
return "INTEGER";
|
|
5983
|
-
case "string":
|
|
5984
|
-
case "uuid":
|
|
5985
|
-
case "ulid":
|
|
5986
|
-
case "snowflake":
|
|
5987
|
-
case "date":
|
|
5988
|
-
case "datetime":
|
|
5989
|
-
case "timestamp":
|
|
5990
|
-
case "text":
|
|
5991
|
-
case "json":
|
|
5992
|
-
case "enum":
|
|
5993
|
-
return "TEXT";
|
|
5994
|
-
case "real":
|
|
5995
|
-
return "REAL";
|
|
5996
|
-
case "decimal":
|
|
5997
|
-
return "NUMERIC";
|
|
5998
|
-
case "blob":
|
|
5999
|
-
return "BLOB";
|
|
6000
|
-
case "vector":
|
|
6001
|
-
throw new SchemaError("SQLite schema diffing does not support logical vector columns.");
|
|
6002
|
-
default:
|
|
6003
|
-
throw new SchemaError(`Unsupported logical column kind "${String(column2.kind)}" for SQLite schema diffing.`);
|
|
6004
|
-
}
|
|
6005
|
-
}
|
|
6006
|
-
function lowerPostgresLogicalColumnType(column2) {
|
|
6007
|
-
switch (column2.kind) {
|
|
6008
|
-
case "id":
|
|
6009
|
-
case "bigInteger":
|
|
6010
|
-
return "bigint";
|
|
6011
|
-
case "integer":
|
|
6012
|
-
return "integer";
|
|
6013
|
-
case "boolean":
|
|
6014
|
-
return "boolean";
|
|
6015
|
-
case "string":
|
|
6016
|
-
return "character varying";
|
|
6017
|
-
case "text":
|
|
6018
|
-
case "enum":
|
|
6019
|
-
return "text";
|
|
6020
|
-
case "uuid":
|
|
6021
|
-
return "uuid";
|
|
6022
|
-
case "ulid":
|
|
6023
|
-
case "snowflake":
|
|
6024
|
-
return "character varying";
|
|
6025
|
-
case "date":
|
|
6026
|
-
return "date";
|
|
6027
|
-
case "datetime":
|
|
6028
|
-
case "timestamp":
|
|
6029
|
-
return "timestamp";
|
|
6030
|
-
case "json":
|
|
6031
|
-
return "jsonb";
|
|
6032
|
-
case "real":
|
|
6033
|
-
return "double precision";
|
|
6034
|
-
case "decimal":
|
|
6035
|
-
return "numeric";
|
|
6036
|
-
case "blob":
|
|
6037
|
-
return "bytea";
|
|
6038
|
-
case "vector":
|
|
6039
|
-
return `vector(${column2.vectorDimensions})`;
|
|
6040
|
-
default:
|
|
6041
|
-
throw new SchemaError(`Unsupported logical column kind "${String(column2.kind)}" for Postgres schema diffing.`);
|
|
6078
|
+
return resolveDialectComparisonColumnType("mysql", column2);
|
|
6042
6079
|
}
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
switch (column2.kind) {
|
|
6046
|
-
case "id":
|
|
6047
|
-
case "bigInteger":
|
|
6048
|
-
return "bigint";
|
|
6049
|
-
case "integer":
|
|
6050
|
-
return "int";
|
|
6051
|
-
case "boolean":
|
|
6052
|
-
return "tinyint";
|
|
6053
|
-
case "string":
|
|
6054
|
-
return "varchar";
|
|
6055
|
-
case "text":
|
|
6056
|
-
return "text";
|
|
6057
|
-
case "uuid":
|
|
6058
|
-
case "ulid":
|
|
6059
|
-
return "char";
|
|
6060
|
-
case "snowflake":
|
|
6061
|
-
return "varchar";
|
|
6062
|
-
case "date":
|
|
6063
|
-
return "date";
|
|
6064
|
-
case "datetime":
|
|
6065
|
-
return "datetime";
|
|
6066
|
-
case "timestamp":
|
|
6067
|
-
return "timestamp";
|
|
6068
|
-
case "enum":
|
|
6069
|
-
return "enum";
|
|
6070
|
-
case "json":
|
|
6071
|
-
return "json";
|
|
6072
|
-
case "real":
|
|
6073
|
-
return "double";
|
|
6074
|
-
case "decimal":
|
|
6075
|
-
return "decimal";
|
|
6076
|
-
case "blob":
|
|
6077
|
-
return "blob";
|
|
6078
|
-
case "vector":
|
|
6079
|
-
throw new SchemaError("MySQL schema diffing does not support logical vector columns.");
|
|
6080
|
-
default:
|
|
6081
|
-
throw new SchemaError(`Unsupported logical column kind "${String(column2.kind)}" for MySQL schema diffing.`);
|
|
6080
|
+
if (dialectName.startsWith("sqlite")) {
|
|
6081
|
+
return resolveDialectComparisonColumnType("sqlite", column2);
|
|
6082
6082
|
}
|
|
6083
|
+
return resolveDialectComparisonColumnType(dialectName, column2);
|
|
6083
6084
|
}
|
|
6084
6085
|
function normalizeExpectedIndex(table, index) {
|
|
6085
6086
|
return {
|
|
@@ -6105,10 +6106,8 @@ function normalizeActualForeignKeyName(foreignKey) {
|
|
|
6105
6106
|
// src/migrations/defineMigration.ts
|
|
6106
6107
|
var MIGRATION_NAME_PATTERN = /^\d{4}_\d{2}_\d{2}_\d{6}_[a-z0-9_]+$/;
|
|
6107
6108
|
function defineMigration(definition) {
|
|
6108
|
-
if (definition.name
|
|
6109
|
-
|
|
6110
|
-
`Migration name "${definition.name}" must match YYYY_MM_DD_HHMMSS_description.`
|
|
6111
|
-
);
|
|
6109
|
+
if (definition.name) {
|
|
6110
|
+
assertMigrationName(definition.name);
|
|
6112
6111
|
}
|
|
6113
6112
|
return Object.freeze(definition);
|
|
6114
6113
|
}
|
|
@@ -6206,9 +6205,7 @@ var MigrationService = class {
|
|
|
6206
6205
|
const executed = [];
|
|
6207
6206
|
for (const migration of pending) {
|
|
6208
6207
|
const log = this.createMigrationLog(migration.name, "up", nextBatch);
|
|
6209
|
-
|
|
6210
|
-
await this.connection.getLogger()?.onMigrationStart?.(log);
|
|
6211
|
-
try {
|
|
6208
|
+
await this.runMigrationLifecycle(log, async () => {
|
|
6212
6209
|
await this.connection.transaction(async (tx) => {
|
|
6213
6210
|
const context = this.createContext(tx);
|
|
6214
6211
|
await migration.up(context);
|
|
@@ -6218,18 +6215,7 @@ var MigrationService = class {
|
|
|
6218
6215
|
migrated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
6219
6216
|
});
|
|
6220
6217
|
});
|
|
6221
|
-
|
|
6222
|
-
...log,
|
|
6223
|
-
durationMs: Date.now() - startedAt
|
|
6224
|
-
});
|
|
6225
|
-
} catch (error) {
|
|
6226
|
-
await this.connection.getLogger()?.onMigrationError?.({
|
|
6227
|
-
...log,
|
|
6228
|
-
durationMs: Date.now() - startedAt,
|
|
6229
|
-
error
|
|
6230
|
-
});
|
|
6231
|
-
throw error;
|
|
6232
|
-
}
|
|
6218
|
+
});
|
|
6233
6219
|
executed.push(migration);
|
|
6234
6220
|
}
|
|
6235
6221
|
return executed;
|
|
@@ -6252,9 +6238,7 @@ var MigrationService = class {
|
|
|
6252
6238
|
continue;
|
|
6253
6239
|
}
|
|
6254
6240
|
const log = this.createMigrationLog(record.name, "down", record.batch);
|
|
6255
|
-
|
|
6256
|
-
await this.connection.getLogger()?.onMigrationStart?.(log);
|
|
6257
|
-
try {
|
|
6241
|
+
await this.runMigrationLifecycle(log, async () => {
|
|
6258
6242
|
await this.connection.transaction(async (tx) => {
|
|
6259
6243
|
const context = this.createContext(tx);
|
|
6260
6244
|
if (migration.down) {
|
|
@@ -6262,18 +6246,7 @@ var MigrationService = class {
|
|
|
6262
6246
|
}
|
|
6263
6247
|
await new TableQueryBuilder(migrationsTable, tx).where("name", record.name).delete();
|
|
6264
6248
|
});
|
|
6265
|
-
|
|
6266
|
-
...log,
|
|
6267
|
-
durationMs: Date.now() - startedAt
|
|
6268
|
-
});
|
|
6269
|
-
} catch (error) {
|
|
6270
|
-
await this.connection.getLogger()?.onMigrationError?.({
|
|
6271
|
-
...log,
|
|
6272
|
-
durationMs: Date.now() - startedAt,
|
|
6273
|
-
error
|
|
6274
|
-
});
|
|
6275
|
-
throw error;
|
|
6276
|
-
}
|
|
6249
|
+
});
|
|
6277
6250
|
rolledBack.push(migration);
|
|
6278
6251
|
}
|
|
6279
6252
|
return rolledBack;
|
|
@@ -6312,6 +6285,25 @@ var MigrationService = class {
|
|
|
6312
6285
|
schema: createSchemaService(connection)
|
|
6313
6286
|
};
|
|
6314
6287
|
}
|
|
6288
|
+
async runMigrationLifecycle(log, callback) {
|
|
6289
|
+
const startedAt = Date.now();
|
|
6290
|
+
await this.connection.getLogger()?.onMigrationStart?.(log);
|
|
6291
|
+
try {
|
|
6292
|
+
const result = await callback();
|
|
6293
|
+
await this.connection.getLogger()?.onMigrationSuccess?.({
|
|
6294
|
+
...log,
|
|
6295
|
+
durationMs: Date.now() - startedAt
|
|
6296
|
+
});
|
|
6297
|
+
return result;
|
|
6298
|
+
} catch (error) {
|
|
6299
|
+
await this.connection.getLogger()?.onMigrationError?.({
|
|
6300
|
+
...log,
|
|
6301
|
+
durationMs: Date.now() - startedAt,
|
|
6302
|
+
error
|
|
6303
|
+
});
|
|
6304
|
+
throw error;
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6315
6307
|
normalizeMigratedAt(value) {
|
|
6316
6308
|
const normalized = value instanceof Date ? value : new Date(value);
|
|
6317
6309
|
if (Number.isNaN(normalized.getTime())) {
|
|
@@ -6412,15 +6404,101 @@ function unsafeSql(sql, bindings = [], source) {
|
|
|
6412
6404
|
};
|
|
6413
6405
|
}
|
|
6414
6406
|
|
|
6407
|
+
// src/model/ModelRegistry.ts
|
|
6408
|
+
function resolveDefinition(reference) {
|
|
6409
|
+
return "definition" in reference ? reference.definition : reference;
|
|
6410
|
+
}
|
|
6411
|
+
function isMissingGeneratedSchemaModelError(error) {
|
|
6412
|
+
return error instanceof Error && error.message.includes("is not present in the generated schema registry");
|
|
6413
|
+
}
|
|
6414
|
+
function tryGetDefinitionTableName(definition) {
|
|
6415
|
+
try {
|
|
6416
|
+
return definition.table.tableName;
|
|
6417
|
+
} catch (error) {
|
|
6418
|
+
if (isMissingGeneratedSchemaModelError(error)) {
|
|
6419
|
+
return void 0;
|
|
6420
|
+
}
|
|
6421
|
+
throw error;
|
|
6422
|
+
}
|
|
6423
|
+
}
|
|
6424
|
+
function definitionsReferToSameModel(left, right) {
|
|
6425
|
+
if (left === right) {
|
|
6426
|
+
return true;
|
|
6427
|
+
}
|
|
6428
|
+
const leftTableName = tryGetDefinitionTableName(left);
|
|
6429
|
+
const rightTableName = tryGetDefinitionTableName(right);
|
|
6430
|
+
if (!leftTableName || !rightTableName) {
|
|
6431
|
+
return left.name === right.name && left.primaryKey === right.primaryKey && left.morphClass === right.morphClass;
|
|
6432
|
+
}
|
|
6433
|
+
return leftTableName === rightTableName && left.primaryKey === right.primaryKey && left.morphClass === right.morphClass;
|
|
6434
|
+
}
|
|
6435
|
+
function getGlobalModels() {
|
|
6436
|
+
const runtime = globalThis;
|
|
6437
|
+
runtime.__holoDbGlobalModels__ ??= /* @__PURE__ */ new Map();
|
|
6438
|
+
return runtime.__holoDbGlobalModels__;
|
|
6439
|
+
}
|
|
6440
|
+
var ModelRegistry = class {
|
|
6441
|
+
models = /* @__PURE__ */ new Map();
|
|
6442
|
+
register(reference) {
|
|
6443
|
+
const definition = resolveDefinition(reference);
|
|
6444
|
+
const existing = this.models.get(definition.name);
|
|
6445
|
+
if (existing && !definitionsReferToSameModel(existing, definition)) {
|
|
6446
|
+
throw new DatabaseError(`Model "${definition.name}" is already registered.`, "DUPLICATE_MODEL");
|
|
6447
|
+
}
|
|
6448
|
+
this.models.set(definition.name, definition);
|
|
6449
|
+
return definition;
|
|
6450
|
+
}
|
|
6451
|
+
has(name) {
|
|
6452
|
+
return this.models.has(name);
|
|
6453
|
+
}
|
|
6454
|
+
get(name) {
|
|
6455
|
+
return this.models.get(name);
|
|
6456
|
+
}
|
|
6457
|
+
list() {
|
|
6458
|
+
return [...this.models.values()];
|
|
6459
|
+
}
|
|
6460
|
+
clear() {
|
|
6461
|
+
this.models.clear();
|
|
6462
|
+
}
|
|
6463
|
+
};
|
|
6464
|
+
function createModelRegistry() {
|
|
6465
|
+
return new ModelRegistry();
|
|
6466
|
+
}
|
|
6467
|
+
function registerGlobalModel(reference) {
|
|
6468
|
+
const definition = resolveDefinition(reference);
|
|
6469
|
+
const globalModels = getGlobalModels();
|
|
6470
|
+
const existing = globalModels.get(definition.name);
|
|
6471
|
+
if (existing) {
|
|
6472
|
+
const existingDefinition = resolveDefinition(existing);
|
|
6473
|
+
if (!definitionsReferToSameModel(existingDefinition, definition)) {
|
|
6474
|
+
throw new DatabaseError(`Model "${definition.name}" is already registered globally.`, "DUPLICATE_MODEL");
|
|
6475
|
+
}
|
|
6476
|
+
return existing;
|
|
6477
|
+
}
|
|
6478
|
+
globalModels.set(definition.name, reference);
|
|
6479
|
+
return reference;
|
|
6480
|
+
}
|
|
6481
|
+
function getGlobalModel(name) {
|
|
6482
|
+
return getGlobalModels().get(name);
|
|
6483
|
+
}
|
|
6484
|
+
function resetGlobalModelRegistry() {
|
|
6485
|
+
getGlobalModels().clear();
|
|
6486
|
+
}
|
|
6487
|
+
|
|
6415
6488
|
// src/model/morphRegistry.ts
|
|
6416
|
-
|
|
6489
|
+
function getMorphRegistry() {
|
|
6490
|
+
const runtime = globalThis;
|
|
6491
|
+
runtime.__holoDbMorphRegistry__ ??= /* @__PURE__ */ new Map();
|
|
6492
|
+
return runtime.__holoDbMorphRegistry__;
|
|
6493
|
+
}
|
|
6417
6494
|
function registerMorphModel(type, reference) {
|
|
6418
|
-
|
|
6495
|
+
getMorphRegistry().set(type, reference);
|
|
6419
6496
|
}
|
|
6420
6497
|
function resolveMorphModel(type) {
|
|
6421
|
-
return
|
|
6498
|
+
return getMorphRegistry().get(type);
|
|
6422
6499
|
}
|
|
6423
6500
|
function resolveMorphSelector(label) {
|
|
6501
|
+
const morphRegistry = getMorphRegistry();
|
|
6424
6502
|
const exact = morphRegistry.get(label);
|
|
6425
6503
|
if (exact) {
|
|
6426
6504
|
return exact;
|
|
@@ -6440,10 +6518,10 @@ function resolveMorphSelector(label) {
|
|
|
6440
6518
|
return void 0;
|
|
6441
6519
|
}
|
|
6442
6520
|
function listMorphModels() {
|
|
6443
|
-
return [...
|
|
6521
|
+
return [...getMorphRegistry().values()];
|
|
6444
6522
|
}
|
|
6445
6523
|
function resetMorphRegistry() {
|
|
6446
|
-
|
|
6524
|
+
getMorphRegistry().clear();
|
|
6447
6525
|
}
|
|
6448
6526
|
|
|
6449
6527
|
// src/facade/DB.ts
|
|
@@ -6505,13 +6583,11 @@ function configureDB(manager) {
|
|
|
6505
6583
|
}
|
|
6506
6584
|
function resetDB() {
|
|
6507
6585
|
DB.reset();
|
|
6586
|
+
resetGlobalModelRegistry();
|
|
6508
6587
|
resetMorphRegistry();
|
|
6509
6588
|
}
|
|
6510
6589
|
|
|
6511
|
-
// src/model/
|
|
6512
|
-
function isEntity(value) {
|
|
6513
|
-
return value instanceof EntityBase;
|
|
6514
|
-
}
|
|
6590
|
+
// src/model/entityRuntime.ts
|
|
6515
6591
|
function valuesAreEqual(left, right) {
|
|
6516
6592
|
if (Object.is(left, right)) {
|
|
6517
6593
|
return true;
|
|
@@ -6534,15 +6610,76 @@ function valuesAreEqual(left, right) {
|
|
|
6534
6610
|
return left.length === right.length && left.every((value, index) => valuesAreEqual(value, right[index]));
|
|
6535
6611
|
}
|
|
6536
6612
|
if (left && right && typeof left === "object" && typeof right === "object" && Object.getPrototypeOf(left) === Object.getPrototypeOf(right)) {
|
|
6537
|
-
const
|
|
6538
|
-
const
|
|
6539
|
-
|
|
6613
|
+
const leftRecord = left;
|
|
6614
|
+
const rightRecord = right;
|
|
6615
|
+
const leftKeys = Object.keys(leftRecord);
|
|
6616
|
+
const rightKeys = Object.keys(rightRecord);
|
|
6617
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
6540
6618
|
return false;
|
|
6541
6619
|
}
|
|
6542
|
-
|
|
6620
|
+
if (leftKeys.some((key) => !Object.prototype.hasOwnProperty.call(rightRecord, key)) || rightKeys.some((key) => !Object.prototype.hasOwnProperty.call(leftRecord, key))) {
|
|
6621
|
+
return false;
|
|
6622
|
+
}
|
|
6623
|
+
return leftKeys.every((key) => valuesAreEqual(leftRecord[key], rightRecord[key]));
|
|
6543
6624
|
}
|
|
6544
6625
|
return false;
|
|
6545
6626
|
}
|
|
6627
|
+
function initializeEntityModelProperties(entity, repo) {
|
|
6628
|
+
const columns = repo?.definition?.table?.columns;
|
|
6629
|
+
if (columns && typeof columns === "object") {
|
|
6630
|
+
for (const key of Object.keys(columns)) {
|
|
6631
|
+
if (key in entity) {
|
|
6632
|
+
continue;
|
|
6633
|
+
}
|
|
6634
|
+
Object.defineProperty(entity, key, {
|
|
6635
|
+
configurable: true,
|
|
6636
|
+
enumerable: true,
|
|
6637
|
+
get: () => entity.get(key),
|
|
6638
|
+
set: (value) => {
|
|
6639
|
+
entity.set(key, value);
|
|
6640
|
+
}
|
|
6641
|
+
});
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
const relationNames = typeof repo?.getRelationNames === "function" ? repo.getRelationNames() : Object.keys(repo?.definition?.relations ?? {});
|
|
6645
|
+
for (const key of relationNames) {
|
|
6646
|
+
if (key in entity) {
|
|
6647
|
+
continue;
|
|
6648
|
+
}
|
|
6649
|
+
Object.defineProperty(entity, key, {
|
|
6650
|
+
configurable: true,
|
|
6651
|
+
enumerable: false,
|
|
6652
|
+
get: () => {
|
|
6653
|
+
if (entity.hasRelation(key)) {
|
|
6654
|
+
return entity.getRelation(key);
|
|
6655
|
+
}
|
|
6656
|
+
const relationMethod = (() => entity.relation(key));
|
|
6657
|
+
const loadRelation = () => {
|
|
6658
|
+
if (typeof repo?.resolveRelationProperty !== "function") {
|
|
6659
|
+
return Promise.resolve(void 0);
|
|
6660
|
+
}
|
|
6661
|
+
try {
|
|
6662
|
+
return Promise.resolve(repo.resolveRelationProperty(entity, key));
|
|
6663
|
+
} catch (error) {
|
|
6664
|
+
return Promise.reject(error);
|
|
6665
|
+
}
|
|
6666
|
+
};
|
|
6667
|
+
relationMethod.then = (onFulfilled, onRejected) => loadRelation().then(onFulfilled, onRejected);
|
|
6668
|
+
relationMethod.catch = (onRejected) => loadRelation().catch(onRejected);
|
|
6669
|
+
relationMethod.finally = (onFinally) => loadRelation().finally(onFinally);
|
|
6670
|
+
return relationMethod;
|
|
6671
|
+
},
|
|
6672
|
+
set: (value) => {
|
|
6673
|
+
entity.setRelation(key, value);
|
|
6674
|
+
}
|
|
6675
|
+
});
|
|
6676
|
+
}
|
|
6677
|
+
}
|
|
6678
|
+
|
|
6679
|
+
// src/model/Entity.ts
|
|
6680
|
+
function isEntity(value) {
|
|
6681
|
+
return value instanceof EntityBase;
|
|
6682
|
+
}
|
|
6546
6683
|
var EntityBase = class _EntityBase {
|
|
6547
6684
|
constructor(repository, attributes, exists = true) {
|
|
6548
6685
|
this.repository = repository;
|
|
@@ -6551,7 +6688,7 @@ var EntityBase = class _EntityBase {
|
|
|
6551
6688
|
this.changes = exists ? {} : { ...attributes };
|
|
6552
6689
|
this.persisted = exists;
|
|
6553
6690
|
this.relations = {};
|
|
6554
|
-
this.
|
|
6691
|
+
initializeEntityModelProperties(this, this.getRepositoryRuntime());
|
|
6555
6692
|
}
|
|
6556
6693
|
attributes;
|
|
6557
6694
|
original;
|
|
@@ -6613,6 +6750,10 @@ var EntityBase = class _EntityBase {
|
|
|
6613
6750
|
Object.assign(this.attributes, values);
|
|
6614
6751
|
return this;
|
|
6615
6752
|
}
|
|
6753
|
+
async update(values) {
|
|
6754
|
+
this.fill(values);
|
|
6755
|
+
return await this.save();
|
|
6756
|
+
}
|
|
6616
6757
|
forceFill(values) {
|
|
6617
6758
|
Object.assign(this.attributes, values);
|
|
6618
6759
|
return this;
|
|
@@ -6744,6 +6885,75 @@ var EntityBase = class _EntityBase {
|
|
|
6744
6885
|
Reflect.deleteProperty(this.relations, name);
|
|
6745
6886
|
return this;
|
|
6746
6887
|
}
|
|
6888
|
+
relation(name) {
|
|
6889
|
+
const repo = this.getRepositoryRuntime();
|
|
6890
|
+
const relationDef = typeof repo.getRelationDefinition === "function" ? repo.getRelationDefinition(name) : repo.definition.relations[name];
|
|
6891
|
+
if (!relationDef) {
|
|
6892
|
+
throw new Error(`Relation '${name}' is not defined on this model`);
|
|
6893
|
+
}
|
|
6894
|
+
if (relationDef.kind === "belongsTo") {
|
|
6895
|
+
return {
|
|
6896
|
+
associate: (related) => {
|
|
6897
|
+
this.associate(name, related);
|
|
6898
|
+
},
|
|
6899
|
+
dissociate: () => {
|
|
6900
|
+
this.dissociate(name);
|
|
6901
|
+
}
|
|
6902
|
+
};
|
|
6903
|
+
}
|
|
6904
|
+
if (relationDef.kind === "hasOne" || relationDef.kind === "hasOneOfMany" || relationDef.kind === "hasOneThrough" || relationDef.kind === "morphOne" || relationDef.kind === "morphOneOfMany") {
|
|
6905
|
+
return {
|
|
6906
|
+
create: async (values) => {
|
|
6907
|
+
return this.createRelated(name, values);
|
|
6908
|
+
},
|
|
6909
|
+
save: async (related) => {
|
|
6910
|
+
return this.saveRelated(name, related);
|
|
6911
|
+
}
|
|
6912
|
+
};
|
|
6913
|
+
}
|
|
6914
|
+
if (relationDef.kind === "hasMany" || relationDef.kind === "hasManyThrough" || relationDef.kind === "morphMany") {
|
|
6915
|
+
return {
|
|
6916
|
+
create: async (values) => {
|
|
6917
|
+
return this.createRelated(name, values);
|
|
6918
|
+
},
|
|
6919
|
+
createMany: async (values) => {
|
|
6920
|
+
return this.createManyRelated(name, values);
|
|
6921
|
+
},
|
|
6922
|
+
save: async (related) => {
|
|
6923
|
+
return this.saveRelated(name, related);
|
|
6924
|
+
},
|
|
6925
|
+
saveMany: async (related) => {
|
|
6926
|
+
return this.saveManyRelated(name, related);
|
|
6927
|
+
}
|
|
6928
|
+
};
|
|
6929
|
+
}
|
|
6930
|
+
if (relationDef.kind === "belongsToMany" || relationDef.kind === "morphToMany" || relationDef.kind === "morphedByMany") {
|
|
6931
|
+
return {
|
|
6932
|
+
attach: async (ids, attributes) => {
|
|
6933
|
+
await this.attach(name, ids, attributes ?? {});
|
|
6934
|
+
},
|
|
6935
|
+
detach: async (ids) => {
|
|
6936
|
+
return this.detach(name, ids);
|
|
6937
|
+
},
|
|
6938
|
+
sync: async (ids) => {
|
|
6939
|
+
return this.sync(name, ids);
|
|
6940
|
+
},
|
|
6941
|
+
toggle: async (ids) => {
|
|
6942
|
+
return this.toggle(name, ids);
|
|
6943
|
+
},
|
|
6944
|
+
updateExistingPivot: async (id, attributes) => {
|
|
6945
|
+
return this.updateExistingPivot(name, id, attributes);
|
|
6946
|
+
},
|
|
6947
|
+
create: async (values) => {
|
|
6948
|
+
return this.createRelated(name, values);
|
|
6949
|
+
},
|
|
6950
|
+
save: async (related) => {
|
|
6951
|
+
return this.saveRelated(name, related);
|
|
6952
|
+
}
|
|
6953
|
+
};
|
|
6954
|
+
}
|
|
6955
|
+
return {};
|
|
6956
|
+
}
|
|
6747
6957
|
toJSON() {
|
|
6748
6958
|
const repo = this.getRepositoryRuntime();
|
|
6749
6959
|
if (typeof repo.serializeEntity === "function") {
|
|
@@ -6751,19 +6961,68 @@ var EntityBase = class _EntityBase {
|
|
|
6751
6961
|
}
|
|
6752
6962
|
return this.toAttributes();
|
|
6753
6963
|
}
|
|
6754
|
-
|
|
6755
|
-
const repo = this.getRepositoryRuntime();
|
|
6756
|
-
if (typeof repo.saveEntity !== "function") {
|
|
6757
|
-
throw new HydrationError("The bound repository cannot persist entities.");
|
|
6758
|
-
}
|
|
6759
|
-
const pendingChanges = this.persisted ? this.getDirty() : this.toAttributes();
|
|
6760
|
-
const persisted = await repo.saveEntity(this);
|
|
6964
|
+
applyPersistedEntity(persisted, changes) {
|
|
6761
6965
|
this.attributes = { ...persisted.toAttributes() };
|
|
6762
6966
|
this.original = { ...persisted.toAttributes() };
|
|
6763
|
-
this.changes = { ...
|
|
6967
|
+
this.changes = { ...changes };
|
|
6764
6968
|
this.persisted = true;
|
|
6969
|
+
}
|
|
6970
|
+
async persistEntity(methodName, errorMessage) {
|
|
6971
|
+
const repo = this.getRepositoryRuntime();
|
|
6972
|
+
const method = repo[methodName];
|
|
6973
|
+
if (typeof method !== "function") {
|
|
6974
|
+
throw new HydrationError(errorMessage);
|
|
6975
|
+
}
|
|
6976
|
+
const pendingChanges = this.persisted ? this.getDirty() : this.toAttributes();
|
|
6977
|
+
const persisted = await method.call(repo, this);
|
|
6978
|
+
this.applyPersistedEntity(persisted, pendingChanges);
|
|
6979
|
+
return this;
|
|
6980
|
+
}
|
|
6981
|
+
async deletePersistedEntity(methodName, errorMessage) {
|
|
6982
|
+
if (!this.persisted) {
|
|
6983
|
+
throw new HydrationError("Cannot delete an entity that has not been persisted yet.");
|
|
6984
|
+
}
|
|
6985
|
+
const repo = this.getRepositoryRuntime();
|
|
6986
|
+
const method = repo[methodName];
|
|
6987
|
+
if (typeof method !== "function") {
|
|
6988
|
+
throw new HydrationError(errorMessage);
|
|
6989
|
+
}
|
|
6990
|
+
await method.call(repo, this);
|
|
6991
|
+
this.persisted = typeof repo.shouldKeepEntityPersistedOnDelete === "function" ? repo.shouldKeepEntityPersistedOnDelete(this) : false;
|
|
6992
|
+
}
|
|
6993
|
+
async restoreEntity(methodName, errorMessage) {
|
|
6994
|
+
const repo = this.getRepositoryRuntime();
|
|
6995
|
+
const method = repo[methodName];
|
|
6996
|
+
if (typeof method !== "function") {
|
|
6997
|
+
throw new HydrationError(errorMessage);
|
|
6998
|
+
}
|
|
6999
|
+
const restored = await method.call(repo, this);
|
|
7000
|
+
this.applyPersistedEntity(restored, restored.getChanges());
|
|
7001
|
+
return this;
|
|
7002
|
+
}
|
|
7003
|
+
async forceDeletePersistedEntity(methodName, errorMessage) {
|
|
7004
|
+
if (!this.persisted) {
|
|
7005
|
+
throw new HydrationError("Cannot force-delete an entity that has not been persisted yet.");
|
|
7006
|
+
}
|
|
7007
|
+
const repo = this.getRepositoryRuntime();
|
|
7008
|
+
const method = repo[methodName];
|
|
7009
|
+
if (typeof method !== "function") {
|
|
7010
|
+
throw new HydrationError(errorMessage);
|
|
7011
|
+
}
|
|
7012
|
+
await method.call(repo, this);
|
|
7013
|
+
this.persisted = false;
|
|
7014
|
+
}
|
|
7015
|
+
async loadAggregateDefinitions(aggregates) {
|
|
7016
|
+
const repo = this.getRepositoryRuntime();
|
|
7017
|
+
if (typeof repo.loadRelationAggregates !== "function") {
|
|
7018
|
+
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
7019
|
+
}
|
|
7020
|
+
await repo.loadRelationAggregates([this], aggregates);
|
|
6765
7021
|
return this;
|
|
6766
7022
|
}
|
|
7023
|
+
async save() {
|
|
7024
|
+
return this.persistEntity("saveEntity", "The bound repository cannot persist entities.");
|
|
7025
|
+
}
|
|
6767
7026
|
async push() {
|
|
6768
7027
|
const repo = this.getRepositoryRuntime();
|
|
6769
7028
|
if (typeof repo.getRelationDefinition !== "function") {
|
|
@@ -6801,85 +7060,25 @@ var EntityBase = class _EntityBase {
|
|
|
6801
7060
|
return this;
|
|
6802
7061
|
}
|
|
6803
7062
|
async saveQuietly() {
|
|
6804
|
-
|
|
6805
|
-
if (typeof repo.saveEntityQuietly !== "function") {
|
|
6806
|
-
throw new HydrationError("The bound repository cannot persist entities quietly.");
|
|
6807
|
-
}
|
|
6808
|
-
const pendingChanges = this.persisted ? this.getDirty() : this.toAttributes();
|
|
6809
|
-
const persisted = await repo.saveEntityQuietly(this);
|
|
6810
|
-
this.attributes = { ...persisted.toAttributes() };
|
|
6811
|
-
this.original = { ...persisted.toAttributes() };
|
|
6812
|
-
this.changes = { ...pendingChanges };
|
|
6813
|
-
this.persisted = true;
|
|
6814
|
-
return this;
|
|
7063
|
+
return this.persistEntity("saveEntityQuietly", "The bound repository cannot persist entities quietly.");
|
|
6815
7064
|
}
|
|
6816
7065
|
async delete() {
|
|
6817
|
-
|
|
6818
|
-
throw new HydrationError("Cannot delete an entity that has not been persisted yet.");
|
|
6819
|
-
}
|
|
6820
|
-
const repo = this.getRepositoryRuntime();
|
|
6821
|
-
if (typeof repo.deleteEntity !== "function") {
|
|
6822
|
-
throw new HydrationError("The bound repository cannot delete entities.");
|
|
6823
|
-
}
|
|
6824
|
-
await repo.deleteEntity(this);
|
|
6825
|
-
this.persisted = typeof repo.shouldKeepEntityPersistedOnDelete === "function" ? repo.shouldKeepEntityPersistedOnDelete(this) : false;
|
|
7066
|
+
await this.deletePersistedEntity("deleteEntity", "The bound repository cannot delete entities.");
|
|
6826
7067
|
}
|
|
6827
7068
|
async deleteQuietly() {
|
|
6828
|
-
|
|
6829
|
-
throw new HydrationError("Cannot delete an entity that has not been persisted yet.");
|
|
6830
|
-
}
|
|
6831
|
-
const repo = this.getRepositoryRuntime();
|
|
6832
|
-
if (typeof repo.deleteEntityQuietly !== "function") {
|
|
6833
|
-
throw new HydrationError("The bound repository cannot delete entities quietly.");
|
|
6834
|
-
}
|
|
6835
|
-
await repo.deleteEntityQuietly(this);
|
|
6836
|
-
this.persisted = typeof repo.shouldKeepEntityPersistedOnDelete === "function" ? repo.shouldKeepEntityPersistedOnDelete(this) : false;
|
|
7069
|
+
await this.deletePersistedEntity("deleteEntityQuietly", "The bound repository cannot delete entities quietly.");
|
|
6837
7070
|
}
|
|
6838
7071
|
async restore() {
|
|
6839
|
-
|
|
6840
|
-
if (typeof repo.restoreEntity !== "function") {
|
|
6841
|
-
throw new HydrationError("The bound repository cannot restore entities.");
|
|
6842
|
-
}
|
|
6843
|
-
const restored = await repo.restoreEntity(this);
|
|
6844
|
-
this.attributes = { ...restored.toAttributes() };
|
|
6845
|
-
this.original = { ...restored.toAttributes() };
|
|
6846
|
-
this.changes = { ...restored.getChanges() };
|
|
6847
|
-
this.persisted = true;
|
|
6848
|
-
return this;
|
|
7072
|
+
return this.restoreEntity("restoreEntity", "The bound repository cannot restore entities.");
|
|
6849
7073
|
}
|
|
6850
7074
|
async restoreQuietly() {
|
|
6851
|
-
|
|
6852
|
-
if (typeof repo.restoreEntityQuietly !== "function") {
|
|
6853
|
-
throw new HydrationError("The bound repository cannot restore entities quietly.");
|
|
6854
|
-
}
|
|
6855
|
-
const restored = await repo.restoreEntityQuietly(this);
|
|
6856
|
-
this.attributes = { ...restored.toAttributes() };
|
|
6857
|
-
this.original = { ...restored.toAttributes() };
|
|
6858
|
-
this.changes = { ...restored.getChanges() };
|
|
6859
|
-
this.persisted = true;
|
|
6860
|
-
return this;
|
|
7075
|
+
return this.restoreEntity("restoreEntityQuietly", "The bound repository cannot restore entities quietly.");
|
|
6861
7076
|
}
|
|
6862
7077
|
async forceDelete() {
|
|
6863
|
-
|
|
6864
|
-
throw new HydrationError("Cannot force-delete an entity that has not been persisted yet.");
|
|
6865
|
-
}
|
|
6866
|
-
const repo = this.getRepositoryRuntime();
|
|
6867
|
-
if (typeof repo.forceDeleteEntity !== "function") {
|
|
6868
|
-
throw new HydrationError("The bound repository cannot force-delete entities.");
|
|
6869
|
-
}
|
|
6870
|
-
await repo.forceDeleteEntity(this);
|
|
6871
|
-
this.persisted = false;
|
|
7078
|
+
await this.forceDeletePersistedEntity("forceDeleteEntity", "The bound repository cannot force-delete entities.");
|
|
6872
7079
|
}
|
|
6873
7080
|
async forceDeleteQuietly() {
|
|
6874
|
-
|
|
6875
|
-
throw new HydrationError("Cannot force-delete an entity that has not been persisted yet.");
|
|
6876
|
-
}
|
|
6877
|
-
const repo = this.getRepositoryRuntime();
|
|
6878
|
-
if (typeof repo.forceDeleteEntityQuietly !== "function") {
|
|
6879
|
-
throw new HydrationError("The bound repository cannot force-delete entities quietly.");
|
|
6880
|
-
}
|
|
6881
|
-
await repo.forceDeleteEntityQuietly(this);
|
|
6882
|
-
this.persisted = false;
|
|
7081
|
+
await this.forceDeletePersistedEntity("forceDeleteEntityQuietly", "The bound repository cannot force-delete entities quietly.");
|
|
6883
7082
|
}
|
|
6884
7083
|
async fresh() {
|
|
6885
7084
|
const repo = this.getRepositoryRuntime();
|
|
@@ -6936,52 +7135,22 @@ var EntityBase = class _EntityBase {
|
|
|
6936
7135
|
return this;
|
|
6937
7136
|
}
|
|
6938
7137
|
async loadCount(...relations) {
|
|
6939
|
-
|
|
6940
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6941
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6942
|
-
}
|
|
6943
|
-
await repo.loadRelationAggregates([this], relations.map((relation) => ({ relation, kind: "count" })));
|
|
6944
|
-
return this;
|
|
7138
|
+
return this.loadAggregateDefinitions(relations.map((relation) => ({ relation, kind: "count" })));
|
|
6945
7139
|
}
|
|
6946
7140
|
async loadExists(...relations) {
|
|
6947
|
-
|
|
6948
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6949
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6950
|
-
}
|
|
6951
|
-
await repo.loadRelationAggregates([this], relations.map((relation) => ({ relation, kind: "exists" })));
|
|
6952
|
-
return this;
|
|
7141
|
+
return this.loadAggregateDefinitions(relations.map((relation) => ({ relation, kind: "exists" })));
|
|
6953
7142
|
}
|
|
6954
7143
|
async loadSum(relation, column2) {
|
|
6955
|
-
|
|
6956
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6957
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6958
|
-
}
|
|
6959
|
-
await repo.loadRelationAggregates([this], [{ relation, kind: "sum", column: column2 }]);
|
|
6960
|
-
return this;
|
|
7144
|
+
return this.loadAggregateDefinitions([{ relation, kind: "sum", column: column2 }]);
|
|
6961
7145
|
}
|
|
6962
7146
|
async loadAvg(relation, column2) {
|
|
6963
|
-
|
|
6964
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6965
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6966
|
-
}
|
|
6967
|
-
await repo.loadRelationAggregates([this], [{ relation, kind: "avg", column: column2 }]);
|
|
6968
|
-
return this;
|
|
7147
|
+
return this.loadAggregateDefinitions([{ relation, kind: "avg", column: column2 }]);
|
|
6969
7148
|
}
|
|
6970
7149
|
async loadMin(relation, column2) {
|
|
6971
|
-
|
|
6972
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6973
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6974
|
-
}
|
|
6975
|
-
await repo.loadRelationAggregates([this], [{ relation, kind: "min", column: column2 }]);
|
|
6976
|
-
return this;
|
|
7150
|
+
return this.loadAggregateDefinitions([{ relation, kind: "min", column: column2 }]);
|
|
6977
7151
|
}
|
|
6978
7152
|
async loadMax(relation, column2) {
|
|
6979
|
-
|
|
6980
|
-
if (typeof repo.loadRelationAggregates !== "function") {
|
|
6981
|
-
throw new HydrationError("The bound repository cannot load relation aggregates.");
|
|
6982
|
-
}
|
|
6983
|
-
await repo.loadRelationAggregates([this], [{ relation, kind: "max", column: column2 }]);
|
|
6984
|
-
return this;
|
|
7153
|
+
return this.loadAggregateDefinitions([{ relation, kind: "max", column: column2 }]);
|
|
6985
7154
|
}
|
|
6986
7155
|
associate(relation, related) {
|
|
6987
7156
|
const repo = this.getRepositoryRuntime();
|
|
@@ -7108,47 +7277,6 @@ var EntityBase = class _EntityBase {
|
|
|
7108
7277
|
this.forgetRelation(relation);
|
|
7109
7278
|
return result;
|
|
7110
7279
|
}
|
|
7111
|
-
initializeModelProperties() {
|
|
7112
|
-
const repo = this.getRepositoryRuntime();
|
|
7113
|
-
const columns = repo?.definition?.table?.columns;
|
|
7114
|
-
if (columns && typeof columns === "object") {
|
|
7115
|
-
for (const key of Object.keys(columns)) {
|
|
7116
|
-
if (key in this) {
|
|
7117
|
-
continue;
|
|
7118
|
-
}
|
|
7119
|
-
Object.defineProperty(this, key, {
|
|
7120
|
-
configurable: true,
|
|
7121
|
-
enumerable: true,
|
|
7122
|
-
get: () => this.get(key),
|
|
7123
|
-
set: (value) => {
|
|
7124
|
-
this.set(key, value);
|
|
7125
|
-
}
|
|
7126
|
-
});
|
|
7127
|
-
}
|
|
7128
|
-
}
|
|
7129
|
-
const relationNames = typeof repo?.getRelationNames === "function" ? repo.getRelationNames() : Object.keys(repo?.definition?.relations ?? {});
|
|
7130
|
-
for (const key of relationNames) {
|
|
7131
|
-
if (key in this) {
|
|
7132
|
-
continue;
|
|
7133
|
-
}
|
|
7134
|
-
Object.defineProperty(this, key, {
|
|
7135
|
-
configurable: true,
|
|
7136
|
-
enumerable: false,
|
|
7137
|
-
get: () => {
|
|
7138
|
-
if (this.hasRelation(key)) {
|
|
7139
|
-
return this.getRelation(key);
|
|
7140
|
-
}
|
|
7141
|
-
if (typeof repo?.resolveRelationProperty === "function") {
|
|
7142
|
-
return repo.resolveRelationProperty(this, key);
|
|
7143
|
-
}
|
|
7144
|
-
return void 0;
|
|
7145
|
-
},
|
|
7146
|
-
set: (value) => {
|
|
7147
|
-
this.setRelation(key, value);
|
|
7148
|
-
}
|
|
7149
|
-
});
|
|
7150
|
-
}
|
|
7151
|
-
}
|
|
7152
7280
|
};
|
|
7153
7281
|
var Entity = EntityBase;
|
|
7154
7282
|
|
|
@@ -7156,6 +7284,14 @@ var Entity = EntityBase;
|
|
|
7156
7284
|
function createModelCollection(items) {
|
|
7157
7285
|
const collection = [...items];
|
|
7158
7286
|
const getRepository = (entity) => entity.getRepository();
|
|
7287
|
+
const loadRelationAggregates = async (aggregates) => {
|
|
7288
|
+
const first = collection[0];
|
|
7289
|
+
if (!first || aggregates.length === 0) {
|
|
7290
|
+
return collection;
|
|
7291
|
+
}
|
|
7292
|
+
await getRepository(first).loadRelationAggregates(collection, aggregates);
|
|
7293
|
+
return collection;
|
|
7294
|
+
};
|
|
7159
7295
|
const methods = {
|
|
7160
7296
|
modelKeys() {
|
|
7161
7297
|
return collection.map((entity) => {
|
|
@@ -7171,6 +7307,9 @@ function createModelCollection(items) {
|
|
|
7171
7307
|
const repo = getRepository(first);
|
|
7172
7308
|
return repo.query().where(repo.definition.primaryKey, "in", this.modelKeys());
|
|
7173
7309
|
},
|
|
7310
|
+
toJSON() {
|
|
7311
|
+
return collection.map((item) => item.toJSON());
|
|
7312
|
+
},
|
|
7174
7313
|
async load(...relations) {
|
|
7175
7314
|
const first = collection[0];
|
|
7176
7315
|
if (!first || relations.length === 0) {
|
|
@@ -7202,58 +7341,22 @@ function createModelCollection(items) {
|
|
|
7202
7341
|
return collection;
|
|
7203
7342
|
},
|
|
7204
7343
|
async loadCount(...relations) {
|
|
7205
|
-
|
|
7206
|
-
if (!first || relations.length === 0) {
|
|
7207
|
-
return collection;
|
|
7208
|
-
}
|
|
7209
|
-
const repo = getRepository(first);
|
|
7210
|
-
await repo.loadRelationAggregates(collection, relations.map((relation) => ({ relation, kind: "count" })));
|
|
7211
|
-
return collection;
|
|
7344
|
+
return loadRelationAggregates(relations.map((relation) => ({ relation, kind: "count" })));
|
|
7212
7345
|
},
|
|
7213
7346
|
async loadExists(...relations) {
|
|
7214
|
-
|
|
7215
|
-
if (!first || relations.length === 0) {
|
|
7216
|
-
return collection;
|
|
7217
|
-
}
|
|
7218
|
-
const repo = getRepository(first);
|
|
7219
|
-
await repo.loadRelationAggregates(collection, relations.map((relation) => ({ relation, kind: "exists" })));
|
|
7220
|
-
return collection;
|
|
7347
|
+
return loadRelationAggregates(relations.map((relation) => ({ relation, kind: "exists" })));
|
|
7221
7348
|
},
|
|
7222
7349
|
async loadSum(relation, column2) {
|
|
7223
|
-
|
|
7224
|
-
if (!first || !relation) {
|
|
7225
|
-
return collection;
|
|
7226
|
-
}
|
|
7227
|
-
const repo = getRepository(first);
|
|
7228
|
-
await repo.loadRelationAggregates(collection, [{ relation, kind: "sum", column: column2 }]);
|
|
7229
|
-
return collection;
|
|
7350
|
+
return loadRelationAggregates(relation ? [{ relation, kind: "sum", column: column2 }] : []);
|
|
7230
7351
|
},
|
|
7231
7352
|
async loadAvg(relation, column2) {
|
|
7232
|
-
|
|
7233
|
-
if (!first || !relation) {
|
|
7234
|
-
return collection;
|
|
7235
|
-
}
|
|
7236
|
-
const repo = getRepository(first);
|
|
7237
|
-
await repo.loadRelationAggregates(collection, [{ relation, kind: "avg", column: column2 }]);
|
|
7238
|
-
return collection;
|
|
7353
|
+
return loadRelationAggregates(relation ? [{ relation, kind: "avg", column: column2 }] : []);
|
|
7239
7354
|
},
|
|
7240
7355
|
async loadMin(relation, column2) {
|
|
7241
|
-
|
|
7242
|
-
if (!first || !relation) {
|
|
7243
|
-
return collection;
|
|
7244
|
-
}
|
|
7245
|
-
const repo = getRepository(first);
|
|
7246
|
-
await repo.loadRelationAggregates(collection, [{ relation, kind: "min", column: column2 }]);
|
|
7247
|
-
return collection;
|
|
7356
|
+
return loadRelationAggregates(relation ? [{ relation, kind: "min", column: column2 }] : []);
|
|
7248
7357
|
},
|
|
7249
7358
|
async loadMax(relation, column2) {
|
|
7250
|
-
|
|
7251
|
-
if (!first || !relation) {
|
|
7252
|
-
return collection;
|
|
7253
|
-
}
|
|
7254
|
-
const repo = getRepository(first);
|
|
7255
|
-
await repo.loadRelationAggregates(collection, [{ relation, kind: "max", column: column2 }]);
|
|
7256
|
-
return collection;
|
|
7359
|
+
return loadRelationAggregates(relation ? [{ relation, kind: "max", column: column2 }] : []);
|
|
7257
7360
|
},
|
|
7258
7361
|
async fresh() {
|
|
7259
7362
|
const refreshed = await Promise.all(
|
|
@@ -7361,118 +7464,65 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7361
7464
|
getTableQueryBuilder() {
|
|
7362
7465
|
return this.tableQuery;
|
|
7363
7466
|
}
|
|
7467
|
+
collectNestedPredicates(callback) {
|
|
7468
|
+
const nested = new _ModelQueryBuilder(
|
|
7469
|
+
this.repository,
|
|
7470
|
+
new TableQueryBuilder(this.repository.definition.table, this.getConnection())
|
|
7471
|
+
);
|
|
7472
|
+
const callbackResult = callback(nested);
|
|
7473
|
+
const result = callbackResult instanceof _ModelQueryBuilder ? callbackResult : nested;
|
|
7474
|
+
return result.getTableQueryBuilder().getPlan().predicates;
|
|
7475
|
+
}
|
|
7476
|
+
replayNestedPredicates(query, predicates) {
|
|
7477
|
+
let next = query;
|
|
7478
|
+
for (const predicate of predicates) {
|
|
7479
|
+
next = new TableQueryBuilder(
|
|
7480
|
+
this.repository.definition.table,
|
|
7481
|
+
this.getConnection(),
|
|
7482
|
+
{
|
|
7483
|
+
...next.getPlan(),
|
|
7484
|
+
predicates: Object.freeze([...next.getPlan().predicates, predicate])
|
|
7485
|
+
}
|
|
7486
|
+
);
|
|
7487
|
+
}
|
|
7488
|
+
return next;
|
|
7489
|
+
}
|
|
7364
7490
|
from(table) {
|
|
7365
7491
|
return this.clone(this.tableQuery.from(table));
|
|
7366
7492
|
}
|
|
7367
7493
|
where(columnOrCallback, operator, value) {
|
|
7368
7494
|
if (typeof columnOrCallback === "function") {
|
|
7369
|
-
const
|
|
7370
|
-
this.repository,
|
|
7371
|
-
new TableQueryBuilder(this.repository.definition.table, this.getConnection())
|
|
7372
|
-
);
|
|
7373
|
-
const callbackResult = columnOrCallback(nested);
|
|
7374
|
-
const result = callbackResult instanceof _ModelQueryBuilder ? callbackResult : nested;
|
|
7375
|
-
const predicates = result.getTableQueryBuilder().getPlan().predicates;
|
|
7495
|
+
const predicates = this.collectNestedPredicates(columnOrCallback);
|
|
7376
7496
|
if (predicates.length === 0) {
|
|
7377
7497
|
return this;
|
|
7378
7498
|
}
|
|
7379
|
-
return this.clone(this.tableQuery.where((query) =>
|
|
7380
|
-
let next = query;
|
|
7381
|
-
for (const predicate of predicates) {
|
|
7382
|
-
next = new TableQueryBuilder(
|
|
7383
|
-
this.repository.definition.table,
|
|
7384
|
-
this.getConnection(),
|
|
7385
|
-
{
|
|
7386
|
-
...next.getPlan(),
|
|
7387
|
-
predicates: Object.freeze([...next.getPlan().predicates, predicate])
|
|
7388
|
-
}
|
|
7389
|
-
);
|
|
7390
|
-
}
|
|
7391
|
-
return next;
|
|
7392
|
-
}));
|
|
7499
|
+
return this.clone(this.tableQuery.where((query) => this.replayNestedPredicates(query, predicates)));
|
|
7393
7500
|
}
|
|
7394
7501
|
return this.clone(this.tableQuery.where(columnOrCallback, operator, value));
|
|
7395
7502
|
}
|
|
7396
7503
|
orWhere(columnOrCallback, operator, value) {
|
|
7397
7504
|
if (typeof columnOrCallback === "function") {
|
|
7398
|
-
const
|
|
7399
|
-
this.repository,
|
|
7400
|
-
new TableQueryBuilder(this.repository.definition.table, this.getConnection())
|
|
7401
|
-
);
|
|
7402
|
-
const callbackResult = columnOrCallback(nested);
|
|
7403
|
-
const result = callbackResult instanceof _ModelQueryBuilder ? callbackResult : nested;
|
|
7404
|
-
const predicates = result.getTableQueryBuilder().getPlan().predicates;
|
|
7505
|
+
const predicates = this.collectNestedPredicates(columnOrCallback);
|
|
7405
7506
|
if (predicates.length === 0) {
|
|
7406
7507
|
return this;
|
|
7407
7508
|
}
|
|
7408
|
-
return this.clone(this.tableQuery.orWhere((query) =>
|
|
7409
|
-
let next = query;
|
|
7410
|
-
for (const predicate of predicates) {
|
|
7411
|
-
next = new TableQueryBuilder(
|
|
7412
|
-
this.repository.definition.table,
|
|
7413
|
-
this.getConnection(),
|
|
7414
|
-
{
|
|
7415
|
-
...next.getPlan(),
|
|
7416
|
-
predicates: Object.freeze([...next.getPlan().predicates, predicate])
|
|
7417
|
-
}
|
|
7418
|
-
);
|
|
7419
|
-
}
|
|
7420
|
-
return next;
|
|
7421
|
-
}));
|
|
7509
|
+
return this.clone(this.tableQuery.orWhere((query) => this.replayNestedPredicates(query, predicates)));
|
|
7422
7510
|
}
|
|
7423
7511
|
return this.clone(this.tableQuery.orWhere(columnOrCallback, operator, value));
|
|
7424
7512
|
}
|
|
7425
7513
|
whereNot(callback) {
|
|
7426
|
-
const
|
|
7427
|
-
this.repository,
|
|
7428
|
-
new TableQueryBuilder(this.repository.definition.table, this.getConnection())
|
|
7429
|
-
);
|
|
7430
|
-
const callbackResult = callback(nested);
|
|
7431
|
-
const result = callbackResult instanceof _ModelQueryBuilder ? callbackResult : nested;
|
|
7432
|
-
const predicates = result.getTableQueryBuilder().getPlan().predicates;
|
|
7514
|
+
const predicates = this.collectNestedPredicates(callback);
|
|
7433
7515
|
if (predicates.length === 0) {
|
|
7434
7516
|
return this;
|
|
7435
7517
|
}
|
|
7436
|
-
return this.clone(this.tableQuery.whereNot((query) =>
|
|
7437
|
-
let next = query;
|
|
7438
|
-
for (const predicate of predicates) {
|
|
7439
|
-
next = new TableQueryBuilder(
|
|
7440
|
-
this.repository.definition.table,
|
|
7441
|
-
this.getConnection(),
|
|
7442
|
-
{
|
|
7443
|
-
...next.getPlan(),
|
|
7444
|
-
predicates: Object.freeze([...next.getPlan().predicates, predicate])
|
|
7445
|
-
}
|
|
7446
|
-
);
|
|
7447
|
-
}
|
|
7448
|
-
return next;
|
|
7449
|
-
}));
|
|
7518
|
+
return this.clone(this.tableQuery.whereNot((query) => this.replayNestedPredicates(query, predicates)));
|
|
7450
7519
|
}
|
|
7451
7520
|
orWhereNot(callback) {
|
|
7452
|
-
const
|
|
7453
|
-
this.repository,
|
|
7454
|
-
new TableQueryBuilder(this.repository.definition.table, this.getConnection())
|
|
7455
|
-
);
|
|
7456
|
-
const callbackResult = callback(nested);
|
|
7457
|
-
const result = callbackResult instanceof _ModelQueryBuilder ? callbackResult : nested;
|
|
7458
|
-
const predicates = result.getTableQueryBuilder().getPlan().predicates;
|
|
7521
|
+
const predicates = this.collectNestedPredicates(callback);
|
|
7459
7522
|
if (predicates.length === 0) {
|
|
7460
7523
|
return this;
|
|
7461
7524
|
}
|
|
7462
|
-
return this.clone(this.tableQuery.orWhereNot((query) =>
|
|
7463
|
-
let next = query;
|
|
7464
|
-
for (const predicate of predicates) {
|
|
7465
|
-
next = new TableQueryBuilder(
|
|
7466
|
-
this.repository.definition.table,
|
|
7467
|
-
this.getConnection(),
|
|
7468
|
-
{
|
|
7469
|
-
...next.getPlan(),
|
|
7470
|
-
predicates: Object.freeze([...next.getPlan().predicates, predicate])
|
|
7471
|
-
}
|
|
7472
|
-
);
|
|
7473
|
-
}
|
|
7474
|
-
return next;
|
|
7475
|
-
}));
|
|
7525
|
+
return this.clone(this.tableQuery.orWhereNot((query) => this.replayNestedPredicates(query, predicates)));
|
|
7476
7526
|
}
|
|
7477
7527
|
whereExists(subquery) {
|
|
7478
7528
|
return this.clone(this.tableQuery.whereExists(this.normalizeExistsSubquery(subquery)));
|
|
@@ -7846,10 +7896,16 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7846
7896
|
await this.repository.loadRelationAggregates(entities, this.aggregateLoads);
|
|
7847
7897
|
return this.repository.createCollection(entities);
|
|
7848
7898
|
}
|
|
7899
|
+
async getJson() {
|
|
7900
|
+
return (await this.get()).toJSON();
|
|
7901
|
+
}
|
|
7849
7902
|
async first() {
|
|
7850
7903
|
const [entity] = await this.limit(1).get();
|
|
7851
7904
|
return entity;
|
|
7852
7905
|
}
|
|
7906
|
+
async firstJson() {
|
|
7907
|
+
return (await this.first())?.toJSON();
|
|
7908
|
+
}
|
|
7853
7909
|
async sole() {
|
|
7854
7910
|
const entities = await this.limit(2).get();
|
|
7855
7911
|
if (entities.length === 0) {
|
|
@@ -7860,6 +7916,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7860
7916
|
}
|
|
7861
7917
|
return entities[0];
|
|
7862
7918
|
}
|
|
7919
|
+
async soleJson() {
|
|
7920
|
+
return (await this.sole()).toJSON();
|
|
7921
|
+
}
|
|
7863
7922
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
7864
7923
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7865
7924
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
@@ -7881,6 +7940,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7881
7940
|
hasMorePages: offset + data.length < total
|
|
7882
7941
|
});
|
|
7883
7942
|
}
|
|
7943
|
+
async paginateJson(perPage = 15, page = 1, options = {}) {
|
|
7944
|
+
return (await this.paginate(perPage, page, options)).toJSON();
|
|
7945
|
+
}
|
|
7884
7946
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
7885
7947
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7886
7948
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
@@ -7901,6 +7963,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7901
7963
|
hasMorePages
|
|
7902
7964
|
});
|
|
7903
7965
|
}
|
|
7966
|
+
async simplePaginateJson(perPage = 15, page = 1, options = {}) {
|
|
7967
|
+
return (await this.simplePaginate(perPage, page, options)).toJSON();
|
|
7968
|
+
}
|
|
7904
7969
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
7905
7970
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
7906
7971
|
const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new HydrationError(message));
|
|
@@ -7917,6 +7982,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
7917
7982
|
prevCursor: cursor
|
|
7918
7983
|
});
|
|
7919
7984
|
}
|
|
7985
|
+
async cursorPaginateJson(perPage = 15, cursor = null, options = {}) {
|
|
7986
|
+
return (await this.cursorPaginate(perPage, cursor, options)).toJSON();
|
|
7987
|
+
}
|
|
7920
7988
|
async chunk(size, callback) {
|
|
7921
7989
|
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
7922
7990
|
const entities = await this.getUnpaginatedEntities();
|
|
@@ -8062,6 +8130,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8062
8130
|
}
|
|
8063
8131
|
return entity;
|
|
8064
8132
|
}
|
|
8133
|
+
async findOrFailJson(value, column2) {
|
|
8134
|
+
return (await this.findOrFail(value, column2)).toJSON();
|
|
8135
|
+
}
|
|
8065
8136
|
async update(values) {
|
|
8066
8137
|
return this.tableQuery.update(this.repository.sanitizeWritePayload(values, "update"));
|
|
8067
8138
|
}
|
|
@@ -8168,6 +8239,9 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8168
8239
|
);
|
|
8169
8240
|
}
|
|
8170
8241
|
normalizeEagerLoads(first, second, rest = []) {
|
|
8242
|
+
if (Array.isArray(first)) {
|
|
8243
|
+
return first.map((relation) => ({ relation }));
|
|
8244
|
+
}
|
|
8171
8245
|
if (typeof first === "string") {
|
|
8172
8246
|
if (typeof second === "function") {
|
|
8173
8247
|
return [{ relation: first, constraint: second }];
|
|
@@ -8432,6 +8506,13 @@ function resolveModelConnection(definition) {
|
|
|
8432
8506
|
}
|
|
8433
8507
|
return DB.connection(definition.connectionName);
|
|
8434
8508
|
}
|
|
8509
|
+
function resolveActiveConnection(connection) {
|
|
8510
|
+
const active = connectionAsyncContext.getActive();
|
|
8511
|
+
if (active && active.connectionName === connection.getConnectionName() && active.connection.getContextId() === connection.getContextId()) {
|
|
8512
|
+
return active.connection;
|
|
8513
|
+
}
|
|
8514
|
+
return connection;
|
|
8515
|
+
}
|
|
8435
8516
|
var ModelRepository = class _ModelRepository {
|
|
8436
8517
|
constructor(definition, connection) {
|
|
8437
8518
|
this.connection = connection;
|
|
@@ -8443,10 +8524,10 @@ var ModelRepository = class _ModelRepository {
|
|
|
8443
8524
|
return new _ModelRepository(definition, connection ?? resolveModelConnection(definition));
|
|
8444
8525
|
}
|
|
8445
8526
|
getConnection() {
|
|
8446
|
-
return this.connection;
|
|
8527
|
+
return resolveActiveConnection(this.connection);
|
|
8447
8528
|
}
|
|
8448
8529
|
getConnectionName() {
|
|
8449
|
-
return this.
|
|
8530
|
+
return this.getConnection().getConnectionName();
|
|
8450
8531
|
}
|
|
8451
8532
|
getDeletedAtColumn() {
|
|
8452
8533
|
return this.definition.deletedAtColumn;
|
|
@@ -8550,7 +8631,18 @@ var ModelRepository = class _ModelRepository {
|
|
|
8550
8631
|
if (existing) {
|
|
8551
8632
|
return existing;
|
|
8552
8633
|
}
|
|
8553
|
-
|
|
8634
|
+
try {
|
|
8635
|
+
return await this.create({ ...match, ...values });
|
|
8636
|
+
} catch (error) {
|
|
8637
|
+
if (!isUniqueConstraintError(error)) {
|
|
8638
|
+
throw error;
|
|
8639
|
+
}
|
|
8640
|
+
const concurrent = await query.first();
|
|
8641
|
+
if (concurrent) {
|
|
8642
|
+
return concurrent;
|
|
8643
|
+
}
|
|
8644
|
+
throw error;
|
|
8645
|
+
}
|
|
8554
8646
|
}
|
|
8555
8647
|
make(values = {}) {
|
|
8556
8648
|
return new Entity(this, this.sanitizeWritePayload(this.applyPendingAttributes(values), "create"), false);
|
|
@@ -9229,10 +9321,11 @@ var ModelRepository = class _ModelRepository {
|
|
|
9229
9321
|
});
|
|
9230
9322
|
}
|
|
9231
9323
|
async runWriteUnit(callback) {
|
|
9232
|
-
|
|
9324
|
+
const connection = this.getConnection();
|
|
9325
|
+
if (connection.getScope().kind !== "root") {
|
|
9233
9326
|
return callback();
|
|
9234
9327
|
}
|
|
9235
|
-
return
|
|
9328
|
+
return connection.transaction(async () => callback());
|
|
9236
9329
|
}
|
|
9237
9330
|
async forceDeleteEntityQuietly(entity) {
|
|
9238
9331
|
return withoutModelEvents(() => this.forceDeleteEntity(entity));
|
|
@@ -9266,7 +9359,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9266
9359
|
if (entries.length === 0) {
|
|
9267
9360
|
return;
|
|
9268
9361
|
}
|
|
9269
|
-
await this.
|
|
9362
|
+
await this.getConnection().transaction(async (tx) => {
|
|
9270
9363
|
const currentRows = await this.getPivotRows(context, tx, entries.map((entry) => entry.id));
|
|
9271
9364
|
const currentMap = this.indexPivotRows(currentRows, this.getPivotRelatedIdColumn(context.relation));
|
|
9272
9365
|
for (const entry of entries) {
|
|
@@ -9283,7 +9376,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9283
9376
|
}
|
|
9284
9377
|
async detachRelation(entity, relationName, ids) {
|
|
9285
9378
|
const context = this.getPivotMutationContext(entity, relationName);
|
|
9286
|
-
return this.
|
|
9379
|
+
return this.getConnection().transaction(async (tx) => {
|
|
9287
9380
|
if (typeof ids === "undefined" || ids === null) {
|
|
9288
9381
|
return this.deletePivotRows(context, tx);
|
|
9289
9382
|
}
|
|
@@ -9300,7 +9393,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9300
9393
|
this.assertValidPivotEntries(relationName, entries, context.relation);
|
|
9301
9394
|
const desiredMap = new Map(entries.map((entry) => [String(entry.id), entry]));
|
|
9302
9395
|
const result = { attached: [], detached: [], updated: [] };
|
|
9303
|
-
await this.
|
|
9396
|
+
await this.getConnection().transaction(async (tx) => {
|
|
9304
9397
|
const currentRows = await this.getPivotRows(context, tx);
|
|
9305
9398
|
const currentMap = this.indexPivotRows(currentRows, this.getPivotRelatedIdColumn(context.relation));
|
|
9306
9399
|
for (const entry of entries) {
|
|
@@ -9329,10 +9422,10 @@ var ModelRepository = class _ModelRepository {
|
|
|
9329
9422
|
const context = this.getPivotMutationContext(entity, relationName);
|
|
9330
9423
|
this.assertValidPivotAttributes(relationName, attributes, context.relation);
|
|
9331
9424
|
if (Object.keys(attributes).length === 0) return 0;
|
|
9332
|
-
const [existing] = await this.getPivotRows(context, this.
|
|
9425
|
+
const [existing] = await this.getPivotRows(context, this.getConnection(), [id]);
|
|
9333
9426
|
if (!existing) return 0;
|
|
9334
9427
|
if (!this.pivotAttributesChanged(existing, attributes, context.relation)) return 0;
|
|
9335
|
-
await this.updatePivotRow(context, this.
|
|
9428
|
+
await this.updatePivotRow(context, this.getConnection(), id, attributes);
|
|
9336
9429
|
return 1;
|
|
9337
9430
|
}
|
|
9338
9431
|
async toggleRelation(entity, relationName, ids) {
|
|
@@ -9343,7 +9436,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9343
9436
|
if (entries.length === 0) {
|
|
9344
9437
|
return result;
|
|
9345
9438
|
}
|
|
9346
|
-
await this.
|
|
9439
|
+
await this.getConnection().transaction(async (tx) => {
|
|
9347
9440
|
const currentRows = await this.getPivotRows(context, tx, entries.map((entry) => entry.id));
|
|
9348
9441
|
const currentMap = this.indexPivotRows(currentRows, this.getPivotRelatedIdColumn(context.relation));
|
|
9349
9442
|
for (const entry of entries) {
|
|
@@ -9404,7 +9497,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9404
9497
|
createQuery(applySoftDeletes, applyGlobalScopes, applyDefaultRelations, excludedGlobalScopes = /* @__PURE__ */ new Set()) {
|
|
9405
9498
|
let query = new ModelQueryBuilder(
|
|
9406
9499
|
this,
|
|
9407
|
-
new TableQueryBuilder(this.definition.table, this.
|
|
9500
|
+
new TableQueryBuilder(this.definition.table, this.getConnection())
|
|
9408
9501
|
);
|
|
9409
9502
|
const deletedAtColumn = this.getDeletedAtColumn();
|
|
9410
9503
|
if (applySoftDeletes && deletedAtColumn) {
|
|
@@ -9554,7 +9647,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9554
9647
|
}
|
|
9555
9648
|
return;
|
|
9556
9649
|
}
|
|
9557
|
-
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.
|
|
9650
|
+
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
9558
9651
|
if (pivotRows.length === 0) {
|
|
9559
9652
|
for (const entity of entities) {
|
|
9560
9653
|
entity.setRelation(relationName, []);
|
|
@@ -9731,17 +9824,17 @@ var ModelRepository = class _ModelRepository {
|
|
|
9731
9824
|
}
|
|
9732
9825
|
case "belongsToMany": {
|
|
9733
9826
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9734
|
-
const pivotSubquery = this.createBelongsToManyPivotQuery(relation, this.
|
|
9827
|
+
const pivotSubquery = this.createBelongsToManyPivotQuery(relation, this.getConnection()).select(relation.relatedPivotKey).whereColumn(relation.foreignPivotKey, "=", this.qualifyParentColumn(relation.parentKey));
|
|
9735
9828
|
return [this.applyRelationConstraint(relation, related, constraint).getTableQueryBuilder().whereInSub(relation.relatedKey, pivotSubquery)];
|
|
9736
9829
|
}
|
|
9737
9830
|
case "morphToMany": {
|
|
9738
9831
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9739
|
-
const pivotSubquery = this.createMorphToManyPivotQuery(relation, this.
|
|
9832
|
+
const pivotSubquery = this.createMorphToManyPivotQuery(relation, this.getConnection()).select(relation.foreignPivotKey).where(relation.morphTypeColumn, this.getMorphTypeValue()).whereColumn(relation.morphIdColumn, "=", this.qualifyParentColumn(relation.parentKey));
|
|
9740
9833
|
return [this.applyRelationConstraint(relation, related, constraint).getTableQueryBuilder().whereInSub(relation.relatedKey, pivotSubquery)];
|
|
9741
9834
|
}
|
|
9742
9835
|
case "morphedByMany": {
|
|
9743
9836
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9744
|
-
const pivotSubquery = this.createMorphedByManyPivotQuery(relation, related.definition.morphClass, this.
|
|
9837
|
+
const pivotSubquery = this.createMorphedByManyPivotQuery(relation, related.definition.morphClass, this.getConnection()).select(relation.morphIdColumn).whereColumn(relation.foreignPivotKey, "=", this.qualifyParentColumn(relation.parentKey));
|
|
9745
9838
|
return [this.applyRelationConstraint(relation, related, constraint).getTableQueryBuilder().whereInSub(relation.relatedKey, pivotSubquery)];
|
|
9746
9839
|
}
|
|
9747
9840
|
}
|
|
@@ -10305,7 +10398,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10305
10398
|
if (parentKeys.length === 0) {
|
|
10306
10399
|
return /* @__PURE__ */ new Set();
|
|
10307
10400
|
}
|
|
10308
|
-
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.
|
|
10401
|
+
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
10309
10402
|
const relatedIds = [...new Set(
|
|
10310
10403
|
pivotRows.map((row) => row[relation.relatedPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10311
10404
|
)];
|
|
@@ -10338,7 +10431,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10338
10431
|
if (parentKeys.length === 0) {
|
|
10339
10432
|
return /* @__PURE__ */ new Map();
|
|
10340
10433
|
}
|
|
10341
|
-
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.
|
|
10434
|
+
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
10342
10435
|
const relatedIds = [...new Set(
|
|
10343
10436
|
pivotRows.map((row) => row[relation.relatedPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10344
10437
|
)];
|
|
@@ -10381,7 +10474,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10381
10474
|
if (parentKeys.length === 0) {
|
|
10382
10475
|
return /* @__PURE__ */ new Map();
|
|
10383
10476
|
}
|
|
10384
|
-
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.
|
|
10477
|
+
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
10385
10478
|
const relatedIds = [...new Set(
|
|
10386
10479
|
pivotRows.map((row) => row[relation.relatedPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10387
10480
|
)];
|
|
@@ -10414,7 +10507,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10414
10507
|
if (parentKeys.length === 0) {
|
|
10415
10508
|
return /* @__PURE__ */ new Map();
|
|
10416
10509
|
}
|
|
10417
|
-
const pivotRows = await this.createMorphToManyPivotQuery(relation, this.
|
|
10510
|
+
const pivotRows = await this.createMorphToManyPivotQuery(relation, this.getConnection()).where(relation.morphTypeColumn, this.getMorphTypeValue()).where(relation.morphIdColumn, "in", parentKeys).get();
|
|
10418
10511
|
const relatedIds = [...new Set(
|
|
10419
10512
|
pivotRows.map((row) => row[relation.foreignPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10420
10513
|
)];
|
|
@@ -10448,7 +10541,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10448
10541
|
return /* @__PURE__ */ new Map();
|
|
10449
10542
|
}
|
|
10450
10543
|
const related = this.resolveRelatedRepository(relation.related);
|
|
10451
|
-
const pivotRows = await this.createMorphedByManyPivotQuery(relation, related.definition.morphClass, this.
|
|
10544
|
+
const pivotRows = await this.createMorphedByManyPivotQuery(relation, related.definition.morphClass, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
10452
10545
|
const relatedIds = [...new Set(
|
|
10453
10546
|
pivotRows.map((row) => row[relation.morphIdColumn]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10454
10547
|
)];
|
|
@@ -10943,7 +11036,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
10943
11036
|
return normalizeDialectWriteValue(this.getSchemaDialectName(), column2, value);
|
|
10944
11037
|
}
|
|
10945
11038
|
getSchemaDialectName() {
|
|
10946
|
-
return this.
|
|
11039
|
+
return this.getConnection().getDriver();
|
|
10947
11040
|
}
|
|
10948
11041
|
applyCastGet(cast, value) {
|
|
10949
11042
|
const builtInCast = this.parseBuiltInCast(cast);
|
|
@@ -11093,37 +11186,25 @@ var ModelRepository = class _ModelRepository {
|
|
|
11093
11186
|
return parameter.replaceAll(/[YmdHis]/g, (token) => parts[token]);
|
|
11094
11187
|
}
|
|
11095
11188
|
};
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
function resolveDefinition(reference) {
|
|
11099
|
-
return "definition" in reference ? reference.definition : reference;
|
|
11189
|
+
function getErrorCode(error) {
|
|
11190
|
+
return error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
11100
11191
|
}
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11192
|
+
function getErrorCause(error) {
|
|
11193
|
+
return error && typeof error === "object" && "cause" in error ? error.cause : void 0;
|
|
11194
|
+
}
|
|
11195
|
+
function isUniqueConstraintError(error) {
|
|
11196
|
+
let current = error;
|
|
11197
|
+
while (current) {
|
|
11198
|
+
const code = getErrorCode(current);
|
|
11199
|
+
if (code === "23505" || code === 1062 || code === "1062" || code === "ER_DUP_ENTRY" || code === "SQLITE_CONSTRAINT" || code === "SQLITE_CONSTRAINT_UNIQUE" || code === "SQLITE_CONSTRAINT_PRIMARYKEY") {
|
|
11200
|
+
return true;
|
|
11108
11201
|
}
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
return this.models.has(name);
|
|
11114
|
-
}
|
|
11115
|
-
get(name) {
|
|
11116
|
-
return this.models.get(name);
|
|
11117
|
-
}
|
|
11118
|
-
list() {
|
|
11119
|
-
return [...this.models.values()];
|
|
11120
|
-
}
|
|
11121
|
-
clear() {
|
|
11122
|
-
this.models.clear();
|
|
11202
|
+
if (current instanceof Error && /unique constraint|duplicate entry|unique constraint failed/i.test(current.message)) {
|
|
11203
|
+
return true;
|
|
11204
|
+
}
|
|
11205
|
+
current = getErrorCause(current);
|
|
11123
11206
|
}
|
|
11124
|
-
|
|
11125
|
-
function createModelRegistry() {
|
|
11126
|
-
return new ModelRegistry();
|
|
11207
|
+
return false;
|
|
11127
11208
|
}
|
|
11128
11209
|
|
|
11129
11210
|
// src/core/QueryScheduler.ts
|
|
@@ -11152,22 +11233,26 @@ var QueryScheduler = class {
|
|
|
11152
11233
|
this.concurrentState = {
|
|
11153
11234
|
active: 0,
|
|
11154
11235
|
queued: 0,
|
|
11155
|
-
limit: concurrencyLimit
|
|
11236
|
+
limit: concurrencyLimit,
|
|
11237
|
+
waiters: []
|
|
11156
11238
|
};
|
|
11157
11239
|
this.serializedState = {
|
|
11158
11240
|
active: 0,
|
|
11159
11241
|
queued: 0,
|
|
11160
|
-
limit: 1
|
|
11242
|
+
limit: 1,
|
|
11243
|
+
waiters: []
|
|
11161
11244
|
};
|
|
11162
11245
|
this.workerState = {
|
|
11163
11246
|
active: 0,
|
|
11164
11247
|
queued: 0,
|
|
11165
|
-
limit: concurrencyLimit
|
|
11248
|
+
limit: concurrencyLimit,
|
|
11249
|
+
waiters: []
|
|
11166
11250
|
};
|
|
11167
11251
|
}
|
|
11168
11252
|
async schedule(options, callback) {
|
|
11169
11253
|
const schedulingMode = this.preview(options);
|
|
11170
11254
|
const state = this.resolveState(schedulingMode);
|
|
11255
|
+
let slotReserved = false;
|
|
11171
11256
|
if (state.active >= state.limit) {
|
|
11172
11257
|
if (state.queued >= this.queueLimit) {
|
|
11173
11258
|
throw new DatabaseError(
|
|
@@ -11175,20 +11260,12 @@ var QueryScheduler = class {
|
|
|
11175
11260
|
"QUERY_SCHEDULER_BACKPRESSURE"
|
|
11176
11261
|
);
|
|
11177
11262
|
}
|
|
11178
|
-
await
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
resolve();
|
|
11184
|
-
return;
|
|
11185
|
-
}
|
|
11186
|
-
queueMicrotask(poll);
|
|
11187
|
-
};
|
|
11188
|
-
queueMicrotask(poll);
|
|
11189
|
-
});
|
|
11263
|
+
await this.waitForSlot(state);
|
|
11264
|
+
slotReserved = true;
|
|
11265
|
+
}
|
|
11266
|
+
if (!slotReserved) {
|
|
11267
|
+
state.active += 1;
|
|
11190
11268
|
}
|
|
11191
|
-
state.active += 1;
|
|
11192
11269
|
try {
|
|
11193
11270
|
return {
|
|
11194
11271
|
result: await callback(schedulingMode),
|
|
@@ -11196,6 +11273,7 @@ var QueryScheduler = class {
|
|
|
11196
11273
|
};
|
|
11197
11274
|
} finally {
|
|
11198
11275
|
state.active -= 1;
|
|
11276
|
+
this.wakeNext(state);
|
|
11199
11277
|
}
|
|
11200
11278
|
}
|
|
11201
11279
|
preview(options) {
|
|
@@ -11222,6 +11300,22 @@ var QueryScheduler = class {
|
|
|
11222
11300
|
}
|
|
11223
11301
|
return this.serializedState;
|
|
11224
11302
|
}
|
|
11303
|
+
waitForSlot(state) {
|
|
11304
|
+
state.queued += 1;
|
|
11305
|
+
return new Promise((resolve) => {
|
|
11306
|
+
state.waiters.push(() => {
|
|
11307
|
+
state.queued -= 1;
|
|
11308
|
+
state.active += 1;
|
|
11309
|
+
resolve();
|
|
11310
|
+
});
|
|
11311
|
+
});
|
|
11312
|
+
}
|
|
11313
|
+
wakeNext(state) {
|
|
11314
|
+
if (state.active >= state.limit) {
|
|
11315
|
+
return;
|
|
11316
|
+
}
|
|
11317
|
+
state.waiters.shift()?.();
|
|
11318
|
+
}
|
|
11225
11319
|
};
|
|
11226
11320
|
function createQueryScheduler(options) {
|
|
11227
11321
|
return new QueryScheduler(options);
|
|
@@ -11251,7 +11345,9 @@ function createCapabilities(overrides = {}) {
|
|
|
11251
11345
|
}
|
|
11252
11346
|
|
|
11253
11347
|
// src/core/DatabaseContext.ts
|
|
11348
|
+
var nextDatabaseContextId = 0;
|
|
11254
11349
|
var DatabaseContext = class _DatabaseContext {
|
|
11350
|
+
_contextId;
|
|
11255
11351
|
_connectionName;
|
|
11256
11352
|
_schemaName;
|
|
11257
11353
|
_adapter;
|
|
@@ -11271,6 +11367,7 @@ var DatabaseContext = class _DatabaseContext {
|
|
|
11271
11367
|
constructor(options) {
|
|
11272
11368
|
if (!options.adapter) throw new ConfigurationError("DatabaseContext requires an adapter.");
|
|
11273
11369
|
if (!options.dialect) throw new ConfigurationError("DatabaseContext requires a dialect.");
|
|
11370
|
+
this._contextId = "contextId" in options ? options.contextId : nextDatabaseContextId += 1;
|
|
11274
11371
|
this._connectionName = options.connectionName || "default";
|
|
11275
11372
|
this._schemaName = "schemaName" in options ? options.schemaName : void 0;
|
|
11276
11373
|
this._adapter = options.adapter;
|
|
@@ -11286,6 +11383,7 @@ var DatabaseContext = class _DatabaseContext {
|
|
|
11286
11383
|
this._modelRegistry = ("modelRegistry" in options ? options.modelRegistry : void 0) ?? createModelRegistry();
|
|
11287
11384
|
this._runtime = "runtime" in options ? options.runtime : {
|
|
11288
11385
|
savepointCounter: 0,
|
|
11386
|
+
rootTransactionTail: Promise.resolve(),
|
|
11289
11387
|
scheduler: createQueryScheduler({
|
|
11290
11388
|
connectionName: this._connectionName,
|
|
11291
11389
|
supportsConcurrentQueries: this._dialect.capabilities.concurrentQueries,
|
|
@@ -11316,6 +11414,9 @@ var DatabaseContext = class _DatabaseContext {
|
|
|
11316
11414
|
getConnectionName() {
|
|
11317
11415
|
return this._connectionName;
|
|
11318
11416
|
}
|
|
11417
|
+
getContextId() {
|
|
11418
|
+
return this._contextId;
|
|
11419
|
+
}
|
|
11319
11420
|
getSchemaName() {
|
|
11320
11421
|
return this._schemaName;
|
|
11321
11422
|
}
|
|
@@ -11438,40 +11539,72 @@ var DatabaseContext = class _DatabaseContext {
|
|
|
11438
11539
|
}
|
|
11439
11540
|
async _runRootTransaction(callback, options) {
|
|
11440
11541
|
const runWithinScope = this._adapter.runWithTransactionScope?.bind(this._adapter) ?? (async (runner) => runner());
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11542
|
+
const entry = {
|
|
11543
|
+
scope: "transaction",
|
|
11544
|
+
depth: 1
|
|
11545
|
+
};
|
|
11546
|
+
let tx;
|
|
11547
|
+
let committed = false;
|
|
11548
|
+
const runTransaction = async () => {
|
|
11446
11549
|
await this._logger?.onTransactionStart?.(entry);
|
|
11447
|
-
await this._callTransactionHook("begin", () => this._adapter.beginTransaction(options), options);
|
|
11448
|
-
const tx = this._createChildContext(
|
|
11449
|
-
{ kind: "transaction", depth: 1 },
|
|
11450
|
-
this._createTransactionCallbackState()
|
|
11451
|
-
);
|
|
11452
|
-
let committed = false;
|
|
11453
11550
|
try {
|
|
11454
|
-
const result = await
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11551
|
+
const result = await runWithinScope(async () => {
|
|
11552
|
+
await this._callTransactionHook("begin", () => this._adapter.beginTransaction(options), options);
|
|
11553
|
+
tx = this._createChildContext(
|
|
11554
|
+
{ kind: "transaction", depth: 1 },
|
|
11555
|
+
this._createTransactionCallbackState()
|
|
11556
|
+
);
|
|
11557
|
+
try {
|
|
11558
|
+
const value = await this._runTransactionCallback(tx, callback);
|
|
11559
|
+
await this._callTransactionHook("commit", () => this._adapter.commit(options), options);
|
|
11560
|
+
committed = true;
|
|
11561
|
+
return value;
|
|
11562
|
+
} catch (error) {
|
|
11563
|
+
if (committed) {
|
|
11564
|
+
throw error;
|
|
11565
|
+
}
|
|
11566
|
+
try {
|
|
11567
|
+
await this._callTransactionHook("rollback", () => this._adapter.rollback(options), options);
|
|
11568
|
+
} catch (rollbackError) {
|
|
11569
|
+
await this._logger?.onTransactionRollback?.({ ...entry, error: rollbackError });
|
|
11570
|
+
throw rollbackError;
|
|
11571
|
+
}
|
|
11572
|
+
throw error;
|
|
11573
|
+
}
|
|
11574
|
+
});
|
|
11575
|
+
await tx?._flushTransactionCallbacks("afterCommit");
|
|
11458
11576
|
await this._logger?.onTransactionCommit?.(entry);
|
|
11459
11577
|
return result;
|
|
11460
11578
|
} catch (error) {
|
|
11461
11579
|
if (committed) {
|
|
11462
11580
|
throw error;
|
|
11463
11581
|
}
|
|
11464
|
-
|
|
11465
|
-
await this._callTransactionHook("rollback", () => this._adapter.rollback(options), options);
|
|
11466
|
-
} catch (rollbackError) {
|
|
11467
|
-
await this._logger?.onTransactionRollback?.({ ...entry, error: rollbackError });
|
|
11468
|
-
throw rollbackError;
|
|
11469
|
-
}
|
|
11470
|
-
await tx._flushTransactionCallbacks("afterRollback");
|
|
11582
|
+
await tx?._flushTransactionCallbacks("afterRollback");
|
|
11471
11583
|
await this._logger?.onTransactionRollback?.({ ...entry, error });
|
|
11472
11584
|
throw error;
|
|
11473
11585
|
}
|
|
11474
|
-
}
|
|
11586
|
+
};
|
|
11587
|
+
if (this._adapter.runWithTransactionScope) {
|
|
11588
|
+
return runTransaction();
|
|
11589
|
+
}
|
|
11590
|
+
return this._runSerializedRootTransaction(runTransaction);
|
|
11591
|
+
}
|
|
11592
|
+
async _runSerializedRootTransaction(callback) {
|
|
11593
|
+
const previous = this._runtime.rootTransactionTail;
|
|
11594
|
+
let release;
|
|
11595
|
+
const current = previous.then(() => new Promise((resolve) => {
|
|
11596
|
+
release = resolve;
|
|
11597
|
+
}));
|
|
11598
|
+
this._runtime.rootTransactionTail = current;
|
|
11599
|
+
await previous;
|
|
11600
|
+
try {
|
|
11601
|
+
return await callback();
|
|
11602
|
+
} finally {
|
|
11603
|
+
release();
|
|
11604
|
+
if (this._runtime.rootTransactionTail === current) {
|
|
11605
|
+
this._runtime.rootTransactionTail = Promise.resolve();
|
|
11606
|
+
}
|
|
11607
|
+
}
|
|
11475
11608
|
}
|
|
11476
11609
|
async _runNestedTransaction(callback, options) {
|
|
11477
11610
|
if (!this._dialect.capabilities.savepoints) {
|
|
@@ -11538,6 +11671,7 @@ var DatabaseContext = class _DatabaseContext {
|
|
|
11538
11671
|
}
|
|
11539
11672
|
_createChildContext(scope, transactionCallbacks) {
|
|
11540
11673
|
return new _DatabaseContext({
|
|
11674
|
+
contextId: this._contextId,
|
|
11541
11675
|
adapter: this._adapter,
|
|
11542
11676
|
dialect: this._dialect,
|
|
11543
11677
|
driver: this._driver,
|
|
@@ -11828,6 +11962,15 @@ function createConnectionManager(options) {
|
|
|
11828
11962
|
return new ConnectionManager(options);
|
|
11829
11963
|
}
|
|
11830
11964
|
|
|
11965
|
+
// src/drivers/savepoints.ts
|
|
11966
|
+
var SAVEPOINT_NAME_PATTERN = /^[A-Z_]\w*$/i;
|
|
11967
|
+
function normalizeSavepointName(name) {
|
|
11968
|
+
if (!SAVEPOINT_NAME_PATTERN.test(name)) {
|
|
11969
|
+
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11970
|
+
}
|
|
11971
|
+
return name;
|
|
11972
|
+
}
|
|
11973
|
+
|
|
11831
11974
|
// src/drivers/index.ts
|
|
11832
11975
|
function isModuleNotFoundError(error) {
|
|
11833
11976
|
return !!error && typeof error === "object" && "code" in error && error.code === "ERR_MODULE_NOT_FOUND";
|
|
@@ -11953,22 +12096,13 @@ var SQLiteAdapter = class extends LazyDriverAdapter {
|
|
|
11953
12096
|
return module.createSQLiteAdapter(this.options);
|
|
11954
12097
|
}
|
|
11955
12098
|
async createSavepoint(name, options) {
|
|
11956
|
-
|
|
11957
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11958
|
-
}
|
|
11959
|
-
await super.createSavepoint(name, options);
|
|
12099
|
+
await super.createSavepoint(normalizeSavepointName(name), options);
|
|
11960
12100
|
}
|
|
11961
12101
|
async rollbackToSavepoint(name, options) {
|
|
11962
|
-
|
|
11963
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11964
|
-
}
|
|
11965
|
-
await super.rollbackToSavepoint(name, options);
|
|
12102
|
+
await super.rollbackToSavepoint(normalizeSavepointName(name), options);
|
|
11966
12103
|
}
|
|
11967
12104
|
async releaseSavepoint(name, options) {
|
|
11968
|
-
|
|
11969
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
11970
|
-
}
|
|
11971
|
-
await super.releaseSavepoint(name, options);
|
|
12105
|
+
await super.releaseSavepoint(normalizeSavepointName(name), options);
|
|
11972
12106
|
}
|
|
11973
12107
|
};
|
|
11974
12108
|
function createSQLiteAdapter(options = {}) {
|
|
@@ -11991,32 +12125,14 @@ var PostgresAdapter = class extends LazyDriverAdapter {
|
|
|
11991
12125
|
const createPostgresAdapter2 = module.createPostgresAdapter;
|
|
11992
12126
|
return createPostgresAdapter2(this.options);
|
|
11993
12127
|
}
|
|
11994
|
-
releaseScopedTransaction(state) {
|
|
11995
|
-
if (state.released) {
|
|
11996
|
-
return;
|
|
11997
|
-
}
|
|
11998
|
-
if (state.leased) {
|
|
11999
|
-
state.client.release?.();
|
|
12000
|
-
}
|
|
12001
|
-
state.released = true;
|
|
12002
|
-
}
|
|
12003
12128
|
async createSavepoint(name, options) {
|
|
12004
|
-
|
|
12005
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12006
|
-
}
|
|
12007
|
-
await super.createSavepoint(name, options);
|
|
12129
|
+
await super.createSavepoint(normalizeSavepointName(name), options);
|
|
12008
12130
|
}
|
|
12009
12131
|
async rollbackToSavepoint(name, options) {
|
|
12010
|
-
|
|
12011
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12012
|
-
}
|
|
12013
|
-
await super.rollbackToSavepoint(name, options);
|
|
12132
|
+
await super.rollbackToSavepoint(normalizeSavepointName(name), options);
|
|
12014
12133
|
}
|
|
12015
12134
|
async releaseSavepoint(name, options) {
|
|
12016
|
-
|
|
12017
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12018
|
-
}
|
|
12019
|
-
await super.releaseSavepoint(name, options);
|
|
12135
|
+
await super.releaseSavepoint(normalizeSavepointName(name), options);
|
|
12020
12136
|
}
|
|
12021
12137
|
};
|
|
12022
12138
|
function createPostgresAdapter(options = {}) {
|
|
@@ -12039,32 +12155,14 @@ var MySQLAdapter = class extends LazyDriverAdapter {
|
|
|
12039
12155
|
const createMySQLAdapter2 = module.createMySQLAdapter;
|
|
12040
12156
|
return createMySQLAdapter2(this.options);
|
|
12041
12157
|
}
|
|
12042
|
-
releaseScopedTransaction(state) {
|
|
12043
|
-
if (state.released) {
|
|
12044
|
-
return;
|
|
12045
|
-
}
|
|
12046
|
-
if (state.leased) {
|
|
12047
|
-
state.client.release?.();
|
|
12048
|
-
}
|
|
12049
|
-
state.released = true;
|
|
12050
|
-
}
|
|
12051
12158
|
async createSavepoint(name, options) {
|
|
12052
|
-
|
|
12053
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12054
|
-
}
|
|
12055
|
-
await super.createSavepoint(name, options);
|
|
12159
|
+
await super.createSavepoint(normalizeSavepointName(name), options);
|
|
12056
12160
|
}
|
|
12057
12161
|
async rollbackToSavepoint(name, options) {
|
|
12058
|
-
|
|
12059
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12060
|
-
}
|
|
12061
|
-
await super.rollbackToSavepoint(name, options);
|
|
12162
|
+
await super.rollbackToSavepoint(normalizeSavepointName(name), options);
|
|
12062
12163
|
}
|
|
12063
12164
|
async releaseSavepoint(name, options) {
|
|
12064
|
-
|
|
12065
|
-
throw new TransactionError(`Invalid savepoint name "${name}".`);
|
|
12066
|
-
}
|
|
12067
|
-
await super.releaseSavepoint(name, options);
|
|
12165
|
+
await super.releaseSavepoint(normalizeSavepointName(name), options);
|
|
12068
12166
|
}
|
|
12069
12167
|
};
|
|
12070
12168
|
function createMySQLAdapter(options = {}) {
|
|
@@ -12075,7 +12173,6 @@ function createMySQLAdapter(options = {}) {
|
|
|
12075
12173
|
var DEFAULT_RUNTIME_CONNECTION = Object.freeze({
|
|
12076
12174
|
driver: "sqlite",
|
|
12077
12175
|
url: "./data/database.sqlite",
|
|
12078
|
-
schema: "public",
|
|
12079
12176
|
logging: false
|
|
12080
12177
|
});
|
|
12081
12178
|
function asRecord(value) {
|
|
@@ -12087,6 +12184,9 @@ function normalizeConnectionInput(input) {
|
|
|
12087
12184
|
}
|
|
12088
12185
|
return input ?? {};
|
|
12089
12186
|
}
|
|
12187
|
+
function hasRuntimeConnectionEntries(entries) {
|
|
12188
|
+
return entries.length > 0;
|
|
12189
|
+
}
|
|
12090
12190
|
function inferDatabaseDriver(value) {
|
|
12091
12191
|
if (!value) return void 0;
|
|
12092
12192
|
const normalized = value.trim().toLowerCase();
|
|
@@ -12159,31 +12259,6 @@ function resolveConnectionConfig(name, input) {
|
|
|
12159
12259
|
};
|
|
12160
12260
|
return createRuntimeConnectionOptions(driver, connection, logging, schemaName, name);
|
|
12161
12261
|
}
|
|
12162
|
-
function mergeConnectionGroups(...groups) {
|
|
12163
|
-
const merged = {};
|
|
12164
|
-
for (const group of groups) {
|
|
12165
|
-
if (!group?.connections) {
|
|
12166
|
-
continue;
|
|
12167
|
-
}
|
|
12168
|
-
Object.assign(merged, group.connections);
|
|
12169
|
-
}
|
|
12170
|
-
return merged;
|
|
12171
|
-
}
|
|
12172
|
-
function resolveConfiguredDefaultConnection(...groups) {
|
|
12173
|
-
for (const group of groups) {
|
|
12174
|
-
const configured = group?.defaultConnection;
|
|
12175
|
-
if (configured) {
|
|
12176
|
-
return configured;
|
|
12177
|
-
}
|
|
12178
|
-
}
|
|
12179
|
-
return void 0;
|
|
12180
|
-
}
|
|
12181
|
-
function resolveImplicitDefaultConnectionName(connectionNames) {
|
|
12182
|
-
if (connectionNames.includes("default")) {
|
|
12183
|
-
return "default";
|
|
12184
|
-
}
|
|
12185
|
-
return connectionNames[0] ?? "default";
|
|
12186
|
-
}
|
|
12187
12262
|
function isSupportedDatabaseDriver(value) {
|
|
12188
12263
|
return value === "sqlite" || value === "postgres" || value === "mysql";
|
|
12189
12264
|
}
|
|
@@ -12340,9 +12415,9 @@ function createRuntimeConnectionOptions(driver, connection, dbLogging, schemaNam
|
|
|
12340
12415
|
}
|
|
12341
12416
|
function resolveRuntimeConnectionManagerOptions(config) {
|
|
12342
12417
|
const topLevelDb = asRecord(config.db);
|
|
12343
|
-
const
|
|
12344
|
-
const
|
|
12345
|
-
if (
|
|
12418
|
+
const connections = topLevelDb?.connections ?? {};
|
|
12419
|
+
const connectionEntries = Object.entries(connections);
|
|
12420
|
+
if (!hasRuntimeConnectionEntries(connectionEntries)) {
|
|
12346
12421
|
return createConnectionManager({
|
|
12347
12422
|
defaultConnection: "default",
|
|
12348
12423
|
connections: {
|
|
@@ -12350,15 +12425,15 @@ function resolveRuntimeConnectionManagerOptions(config) {
|
|
|
12350
12425
|
}
|
|
12351
12426
|
});
|
|
12352
12427
|
}
|
|
12353
|
-
const configuredDefault =
|
|
12354
|
-
const defaultConnection = configuredDefault
|
|
12355
|
-
const
|
|
12428
|
+
const configuredDefault = topLevelDb?.defaultConnection;
|
|
12429
|
+
const defaultConnection = configuredDefault ? configuredDefault : Object.hasOwn(connections, "default") ? "default" : connectionEntries[0][0];
|
|
12430
|
+
const resolvedConnections = connectionEntries.map(([name, input]) => [
|
|
12356
12431
|
name,
|
|
12357
12432
|
resolveConnectionConfig(name, input)
|
|
12358
12433
|
]);
|
|
12359
12434
|
return createConnectionManager({
|
|
12360
12435
|
defaultConnection,
|
|
12361
|
-
connections: Object.fromEntries(
|
|
12436
|
+
connections: Object.fromEntries(resolvedConnections)
|
|
12362
12437
|
});
|
|
12363
12438
|
}
|
|
12364
12439
|
|
|
@@ -12431,12 +12506,12 @@ function generateMigrationTemplate(name, options = {}) {
|
|
|
12431
12506
|
};
|
|
12432
12507
|
}
|
|
12433
12508
|
function renderMigrationTemplate(options) {
|
|
12509
|
+
return wrapMigrationTemplate(renderMigrationBody(options));
|
|
12510
|
+
}
|
|
12511
|
+
function renderMigrationBody(options) {
|
|
12434
12512
|
switch (options.kind) {
|
|
12435
12513
|
case "create_table":
|
|
12436
12514
|
return [
|
|
12437
|
-
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
12438
|
-
"",
|
|
12439
|
-
"export default defineMigration({",
|
|
12440
12515
|
" async up({ schema }: MigrationContext) {",
|
|
12441
12516
|
` await schema.createTable('${options.tableName}', (table) => {`,
|
|
12442
12517
|
" table.id()",
|
|
@@ -12445,15 +12520,10 @@ function renderMigrationTemplate(options) {
|
|
|
12445
12520
|
" },",
|
|
12446
12521
|
" async down({ schema }: MigrationContext) {",
|
|
12447
12522
|
` await schema.dropTable('${options.tableName}')`,
|
|
12448
|
-
" },"
|
|
12449
|
-
|
|
12450
|
-
""
|
|
12451
|
-
].join("\n");
|
|
12523
|
+
" },"
|
|
12524
|
+
];
|
|
12452
12525
|
case "alter_table":
|
|
12453
12526
|
return [
|
|
12454
|
-
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
12455
|
-
"",
|
|
12456
|
-
"export default defineMigration({",
|
|
12457
12527
|
" async up({ schema }: MigrationContext) {",
|
|
12458
12528
|
` await schema.table('${options.tableName}', (table) => {`,
|
|
12459
12529
|
" void table",
|
|
@@ -12463,29 +12533,19 @@ function renderMigrationTemplate(options) {
|
|
|
12463
12533
|
` await schema.table('${options.tableName}', (table) => {`,
|
|
12464
12534
|
" void table",
|
|
12465
12535
|
" })",
|
|
12466
|
-
" },"
|
|
12467
|
-
|
|
12468
|
-
""
|
|
12469
|
-
].join("\n");
|
|
12536
|
+
" },"
|
|
12537
|
+
];
|
|
12470
12538
|
case "drop_table":
|
|
12471
12539
|
return [
|
|
12472
|
-
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
12473
|
-
"",
|
|
12474
|
-
"export default defineMigration({",
|
|
12475
12540
|
" async up({ schema }: MigrationContext) {",
|
|
12476
12541
|
` await schema.dropTable('${options.tableName}')`,
|
|
12477
12542
|
" },",
|
|
12478
12543
|
" async down() {",
|
|
12479
12544
|
` throw new Error('Recreate "${options.tableName}" manually in this migration if rollback support is required.')`,
|
|
12480
|
-
" },"
|
|
12481
|
-
|
|
12482
|
-
""
|
|
12483
|
-
].join("\n");
|
|
12545
|
+
" },"
|
|
12546
|
+
];
|
|
12484
12547
|
case "blank":
|
|
12485
12548
|
return [
|
|
12486
|
-
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
12487
|
-
"",
|
|
12488
|
-
"export default defineMigration({",
|
|
12489
12549
|
" async up({ schema, db }: MigrationContext) {",
|
|
12490
12550
|
" void schema",
|
|
12491
12551
|
" void db",
|
|
@@ -12493,12 +12553,20 @@ function renderMigrationTemplate(options) {
|
|
|
12493
12553
|
" async down({ schema, db }: MigrationContext) {",
|
|
12494
12554
|
" void schema",
|
|
12495
12555
|
" void db",
|
|
12496
|
-
" },"
|
|
12497
|
-
|
|
12498
|
-
""
|
|
12499
|
-
].join("\n");
|
|
12556
|
+
" },"
|
|
12557
|
+
];
|
|
12500
12558
|
}
|
|
12501
12559
|
}
|
|
12560
|
+
function wrapMigrationTemplate(body) {
|
|
12561
|
+
return [
|
|
12562
|
+
"import { defineMigration, type MigrationContext } from '@holo-js/db'",
|
|
12563
|
+
"",
|
|
12564
|
+
"export default defineMigration({",
|
|
12565
|
+
...body,
|
|
12566
|
+
"})",
|
|
12567
|
+
""
|
|
12568
|
+
].join("\n");
|
|
12569
|
+
}
|
|
12502
12570
|
|
|
12503
12571
|
// src/seeders/defineSeeder.ts
|
|
12504
12572
|
function defineSeeder(seeder) {
|
|
@@ -13197,12 +13265,14 @@ function validateUniqueIdConfig(table, _modelName, config) {
|
|
|
13197
13265
|
}
|
|
13198
13266
|
}
|
|
13199
13267
|
|
|
13200
|
-
// src/model/
|
|
13268
|
+
// src/model/defineModelHelpers.ts
|
|
13269
|
+
import { singularize } from "inflection";
|
|
13201
13270
|
function buildModelTable(tableName, builder) {
|
|
13202
13271
|
return builder(new TableDefinitionBuilder(tableName)).build();
|
|
13203
13272
|
}
|
|
13204
13273
|
function inferModelName(tableName) {
|
|
13205
|
-
const
|
|
13274
|
+
const unqualifiedName = tableName.split(".").at(-1) ?? tableName;
|
|
13275
|
+
const singular = singularize(unqualifiedName);
|
|
13206
13276
|
return singular.split(/[_-]/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
13207
13277
|
}
|
|
13208
13278
|
function inferPrimaryKey(table) {
|
|
@@ -13212,6 +13282,25 @@ function inferPrimaryKey(table) {
|
|
|
13212
13282
|
}
|
|
13213
13283
|
return primaryKey.name;
|
|
13214
13284
|
}
|
|
13285
|
+
function getRuntimeSchemaTable(tableName, connectionName) {
|
|
13286
|
+
try {
|
|
13287
|
+
return DB.getManager().connection(connectionName).getSchemaRegistry().get(tableName);
|
|
13288
|
+
} catch (error) {
|
|
13289
|
+
if (error instanceof ConfigurationError && error.code === "CONFIGURATION_ERROR" && error.message.includes("ConnectionManager") && error.message.includes("not configured")) {
|
|
13290
|
+
return void 0;
|
|
13291
|
+
}
|
|
13292
|
+
throw error;
|
|
13293
|
+
}
|
|
13294
|
+
}
|
|
13295
|
+
function resolveGeneratedModelTable(tableName, connectionName) {
|
|
13296
|
+
const table = getGeneratedTableDefinition(tableName) ?? getRuntimeSchemaTable(tableName, connectionName);
|
|
13297
|
+
if (!table) {
|
|
13298
|
+
throw new SchemaError(
|
|
13299
|
+
`Model "${tableName}" is not present in the generated schema registry. Run "holo migrate" to refresh the internal generated schema metadata.`
|
|
13300
|
+
);
|
|
13301
|
+
}
|
|
13302
|
+
return table;
|
|
13303
|
+
}
|
|
13215
13304
|
function resolveDeletedAtColumn(table, options) {
|
|
13216
13305
|
if (!options.softDeletes) {
|
|
13217
13306
|
return void 0;
|
|
@@ -13247,6 +13336,45 @@ function validateTouches(modelName, relations, touches) {
|
|
|
13247
13336
|
}
|
|
13248
13337
|
return Object.freeze([...touches]);
|
|
13249
13338
|
}
|
|
13339
|
+
|
|
13340
|
+
// src/model/defineModel.ts
|
|
13341
|
+
var HOLO_MODEL_REFERENCE_REGISTRY = /* @__PURE__ */ Symbol.for("holo-js.db.model-reference-registry");
|
|
13342
|
+
function createSharedModelDefinitionFields(inferredName, relations, touches, options) {
|
|
13343
|
+
return {
|
|
13344
|
+
kind: "model",
|
|
13345
|
+
name: inferredName,
|
|
13346
|
+
connectionName: options.connectionName,
|
|
13347
|
+
morphClass: options.morphClass ?? inferredName,
|
|
13348
|
+
with: Object.freeze([...options.with ?? []]),
|
|
13349
|
+
pendingAttributes: Object.freeze({ ...options.pendingAttributes ?? {} }),
|
|
13350
|
+
preventLazyLoading: options.preventLazyLoading ?? false,
|
|
13351
|
+
preventAccessingMissingAttributes: options.preventAccessingMissingAttributes ?? false,
|
|
13352
|
+
automaticEagerLoading: options.automaticEagerLoading ?? false,
|
|
13353
|
+
timestamps: options.timestamps ?? true,
|
|
13354
|
+
fillable: Object.freeze([...options.fillable ?? []]),
|
|
13355
|
+
hasExplicitFillable: typeof options.fillable !== "undefined",
|
|
13356
|
+
guarded: Object.freeze([...options.guarded ?? []]),
|
|
13357
|
+
scopes: options.scopes ?? {},
|
|
13358
|
+
globalScopes: { ...options.globalScopes ?? {} },
|
|
13359
|
+
relations,
|
|
13360
|
+
casts: { ...options.casts ?? {} },
|
|
13361
|
+
accessors: { ...options.accessors ?? {} },
|
|
13362
|
+
mutators: { ...options.mutators ?? {} },
|
|
13363
|
+
hidden: Object.freeze([...options.hidden ?? []]),
|
|
13364
|
+
visible: Object.freeze([...options.visible ?? []]),
|
|
13365
|
+
appended: Object.freeze([...options.appended ?? []]),
|
|
13366
|
+
serializeDate: options.serializeDate,
|
|
13367
|
+
collection: options.collection,
|
|
13368
|
+
prunable: options.prunable,
|
|
13369
|
+
massPrunable: options.massPrunable ?? false,
|
|
13370
|
+
touches,
|
|
13371
|
+
traits: Object.freeze([...options.traits ?? []]),
|
|
13372
|
+
replicationExcludes: Object.freeze([...options.replicationExcludes ?? []]),
|
|
13373
|
+
softDeletes: options.softDeletes ?? false,
|
|
13374
|
+
events: normalizeEventHandlers(options.events),
|
|
13375
|
+
observers: Object.freeze([...options.observers ?? []])
|
|
13376
|
+
};
|
|
13377
|
+
}
|
|
13250
13378
|
function defineModel(tableOrName, builderOrOptions, options) {
|
|
13251
13379
|
if (typeof tableOrName !== "string") {
|
|
13252
13380
|
return defineModelFromResolvedTable(tableOrName, builderOrOptions ?? {});
|
|
@@ -13257,13 +13385,73 @@ function defineModel(tableOrName, builderOrOptions, options) {
|
|
|
13257
13385
|
options ?? {}
|
|
13258
13386
|
);
|
|
13259
13387
|
}
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13388
|
+
return defineModelFromGeneratedTableName(
|
|
13389
|
+
tableOrName,
|
|
13390
|
+
builderOrOptions ?? {}
|
|
13391
|
+
);
|
|
13392
|
+
}
|
|
13393
|
+
function defineModelFromGeneratedTableName(tableName, options = {}) {
|
|
13394
|
+
const inferredName = options.name ?? inferModelName(tableName);
|
|
13395
|
+
const relations = { ...options.relations ?? {} };
|
|
13396
|
+
const touches = validateTouches(inferredName, relations, options.touches ?? []);
|
|
13397
|
+
const resolveTableDefinition = () => resolveGeneratedModelTable(tableName, options.connectionName);
|
|
13398
|
+
const resolvePrimaryKeyFromTable = (table) => options.primaryKey ?? inferPrimaryKey(table);
|
|
13399
|
+
const resolveUniqueIdFromTable = (table) => {
|
|
13400
|
+
return resolveUniqueIdConfig(
|
|
13401
|
+
options.traits,
|
|
13402
|
+
resolvePrimaryKeyFromTable(table),
|
|
13403
|
+
options.uniqueIds,
|
|
13404
|
+
options.newUniqueId
|
|
13264
13405
|
);
|
|
13265
|
-
}
|
|
13266
|
-
|
|
13406
|
+
};
|
|
13407
|
+
const resolveTable = () => {
|
|
13408
|
+
const table = resolveTableDefinition();
|
|
13409
|
+
validateUniqueIdConfig(table, inferredName, resolveUniqueIdFromTable(table));
|
|
13410
|
+
return table;
|
|
13411
|
+
};
|
|
13412
|
+
const resolvePrimaryKey = () => resolvePrimaryKeyFromTable(resolveTable());
|
|
13413
|
+
const resolveCreatedAtColumn = () => {
|
|
13414
|
+
const timestamps = options.timestamps ?? true;
|
|
13415
|
+
return timestamps ? resolveTimestampColumn(resolveTable(), options.createdAtColumn, "created_at") : void 0;
|
|
13416
|
+
};
|
|
13417
|
+
const resolveUpdatedAtColumn = () => {
|
|
13418
|
+
const timestamps = options.timestamps ?? true;
|
|
13419
|
+
return timestamps ? resolveTimestampColumn(resolveTable(), options.updatedAtColumn, "updated_at") : void 0;
|
|
13420
|
+
};
|
|
13421
|
+
const resolveDeletedAt = () => resolveDeletedAtColumn(resolveTable(), options);
|
|
13422
|
+
const resolveUniqueId = () => {
|
|
13423
|
+
return resolveUniqueIdFromTable(resolveTable());
|
|
13424
|
+
};
|
|
13425
|
+
const definition = {
|
|
13426
|
+
...createSharedModelDefinitionFields(inferredName, relations, touches, options)
|
|
13427
|
+
};
|
|
13428
|
+
Object.defineProperties(definition, {
|
|
13429
|
+
table: {
|
|
13430
|
+
enumerable: true,
|
|
13431
|
+
get: resolveTable
|
|
13432
|
+
},
|
|
13433
|
+
primaryKey: {
|
|
13434
|
+
enumerable: true,
|
|
13435
|
+
get: resolvePrimaryKey
|
|
13436
|
+
},
|
|
13437
|
+
createdAtColumn: {
|
|
13438
|
+
enumerable: true,
|
|
13439
|
+
get: resolveCreatedAtColumn
|
|
13440
|
+
},
|
|
13441
|
+
updatedAtColumn: {
|
|
13442
|
+
enumerable: true,
|
|
13443
|
+
get: resolveUpdatedAtColumn
|
|
13444
|
+
},
|
|
13445
|
+
deletedAtColumn: {
|
|
13446
|
+
enumerable: true,
|
|
13447
|
+
get: resolveDeletedAt
|
|
13448
|
+
},
|
|
13449
|
+
uniqueIdConfig: {
|
|
13450
|
+
enumerable: true,
|
|
13451
|
+
get: resolveUniqueId
|
|
13452
|
+
}
|
|
13453
|
+
});
|
|
13454
|
+
return createStaticModelApi(Object.freeze(definition));
|
|
13267
13455
|
}
|
|
13268
13456
|
function defineModelFromResolvedTable(table, options = {}) {
|
|
13269
13457
|
const deletedAtColumn = resolveDeletedAtColumn(table, options);
|
|
@@ -13282,45 +13470,17 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13282
13470
|
const relations = { ...options.relations ?? {} };
|
|
13283
13471
|
const touches = validateTouches(inferredName, relations, options.touches ?? []);
|
|
13284
13472
|
const definition = Object.freeze({
|
|
13285
|
-
|
|
13473
|
+
...createSharedModelDefinitionFields(inferredName, relations, touches, options),
|
|
13286
13474
|
table,
|
|
13287
|
-
name: inferredName,
|
|
13288
13475
|
primaryKey,
|
|
13289
|
-
connectionName: options.connectionName,
|
|
13290
|
-
morphClass: options.morphClass ?? inferredName,
|
|
13291
|
-
with: Object.freeze([...options.with ?? []]),
|
|
13292
|
-
pendingAttributes: Object.freeze({ ...options.pendingAttributes ?? {} }),
|
|
13293
|
-
preventLazyLoading: options.preventLazyLoading ?? false,
|
|
13294
|
-
preventAccessingMissingAttributes: options.preventAccessingMissingAttributes ?? false,
|
|
13295
|
-
automaticEagerLoading: options.automaticEagerLoading ?? false,
|
|
13296
|
-
timestamps,
|
|
13297
13476
|
createdAtColumn,
|
|
13298
13477
|
updatedAtColumn,
|
|
13299
|
-
fillable: Object.freeze([...options.fillable ?? []]),
|
|
13300
|
-
hasExplicitFillable: typeof options.fillable !== "undefined",
|
|
13301
|
-
guarded: Object.freeze([...options.guarded ?? []]),
|
|
13302
|
-
scopes: options.scopes ?? {},
|
|
13303
|
-
globalScopes: { ...options.globalScopes ?? {} },
|
|
13304
|
-
relations,
|
|
13305
|
-
casts: { ...options.casts ?? {} },
|
|
13306
|
-
accessors: { ...options.accessors ?? {} },
|
|
13307
|
-
mutators: { ...options.mutators ?? {} },
|
|
13308
|
-
hidden: Object.freeze([...options.hidden ?? []]),
|
|
13309
|
-
visible: Object.freeze([...options.visible ?? []]),
|
|
13310
|
-
appended: Object.freeze([...options.appended ?? []]),
|
|
13311
|
-
serializeDate: options.serializeDate,
|
|
13312
|
-
collection: options.collection,
|
|
13313
|
-
prunable: options.prunable,
|
|
13314
|
-
massPrunable: options.massPrunable ?? false,
|
|
13315
|
-
touches,
|
|
13316
|
-
traits: Object.freeze([...options.traits ?? []]),
|
|
13317
13478
|
uniqueIdConfig,
|
|
13318
|
-
|
|
13319
|
-
softDeletes: options.softDeletes ?? false,
|
|
13320
|
-
deletedAtColumn,
|
|
13321
|
-
events: normalizeEventHandlers(options.events),
|
|
13322
|
-
observers: Object.freeze([...options.observers ?? []])
|
|
13479
|
+
deletedAtColumn
|
|
13323
13480
|
});
|
|
13481
|
+
return createStaticModelApi(definition);
|
|
13482
|
+
}
|
|
13483
|
+
function createStaticModelApi(definition) {
|
|
13324
13484
|
const model = {
|
|
13325
13485
|
definition,
|
|
13326
13486
|
query() {
|
|
@@ -13338,8 +13498,8 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13338
13498
|
newQueryWithoutRelationships() {
|
|
13339
13499
|
return this.getRepository().newQueryWithoutRelationships();
|
|
13340
13500
|
},
|
|
13341
|
-
from(
|
|
13342
|
-
return this.query().from(
|
|
13501
|
+
from(table) {
|
|
13502
|
+
return this.query().from(table);
|
|
13343
13503
|
},
|
|
13344
13504
|
debug() {
|
|
13345
13505
|
return this.query().debug();
|
|
@@ -13467,17 +13627,17 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13467
13627
|
whereNone(columns, operator, value) {
|
|
13468
13628
|
return this.query().whereNone(columns, operator, value);
|
|
13469
13629
|
},
|
|
13470
|
-
join(
|
|
13471
|
-
return this.query().join(
|
|
13630
|
+
join(table, leftColumn, operator, rightColumn) {
|
|
13631
|
+
return this.query().join(table, leftColumn, operator, rightColumn);
|
|
13472
13632
|
},
|
|
13473
|
-
leftJoin(
|
|
13474
|
-
return this.query().leftJoin(
|
|
13633
|
+
leftJoin(table, leftColumn, operator, rightColumn) {
|
|
13634
|
+
return this.query().leftJoin(table, leftColumn, operator, rightColumn);
|
|
13475
13635
|
},
|
|
13476
|
-
rightJoin(
|
|
13477
|
-
return this.query().rightJoin(
|
|
13636
|
+
rightJoin(table, leftColumn, operator, rightColumn) {
|
|
13637
|
+
return this.query().rightJoin(table, leftColumn, operator, rightColumn);
|
|
13478
13638
|
},
|
|
13479
|
-
crossJoin(
|
|
13480
|
-
return this.query().crossJoin(
|
|
13639
|
+
crossJoin(table) {
|
|
13640
|
+
return this.query().crossJoin(table);
|
|
13481
13641
|
},
|
|
13482
13642
|
joinSub(query, alias, leftColumn, operator, rightColumn) {
|
|
13483
13643
|
return this.query().joinSub(query, alias, leftColumn, operator, rightColumn);
|
|
@@ -13548,11 +13708,11 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13548
13708
|
orWhereJsonLength(columnPath, operator, value) {
|
|
13549
13709
|
return this.query().orWhereJsonLength(columnPath, operator, value);
|
|
13550
13710
|
},
|
|
13551
|
-
whereFullText(columns, value,
|
|
13552
|
-
return this.query().whereFullText(columns, value,
|
|
13711
|
+
whereFullText(columns, value, options = {}) {
|
|
13712
|
+
return this.query().whereFullText(columns, value, options);
|
|
13553
13713
|
},
|
|
13554
|
-
orWhereFullText(columns, value,
|
|
13555
|
-
return this.query().orWhereFullText(columns, value,
|
|
13714
|
+
orWhereFullText(columns, value, options = {}) {
|
|
13715
|
+
return this.query().orWhereFullText(columns, value, options);
|
|
13556
13716
|
},
|
|
13557
13717
|
whereVectorSimilarTo(column2, vector, minSimilarity = 0) {
|
|
13558
13718
|
return this.query().whereVectorSimilarTo(column2, vector, minSimilarity);
|
|
@@ -13560,6 +13720,9 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13560
13720
|
orWhereVectorSimilarTo(column2, vector, minSimilarity = 0) {
|
|
13561
13721
|
return this.query().orWhereVectorSimilarTo(column2, vector, minSimilarity);
|
|
13562
13722
|
},
|
|
13723
|
+
orderBy(column2, direction = "asc") {
|
|
13724
|
+
return this.query().orderBy(column2, direction);
|
|
13725
|
+
},
|
|
13563
13726
|
latest(column2) {
|
|
13564
13727
|
return this.query().latest(column2);
|
|
13565
13728
|
},
|
|
@@ -13585,7 +13748,10 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13585
13748
|
return this.query().sharedLock();
|
|
13586
13749
|
},
|
|
13587
13750
|
with(first, second, ...rest) {
|
|
13588
|
-
if (
|
|
13751
|
+
if (Array.isArray(first)) {
|
|
13752
|
+
return this.query().with(first);
|
|
13753
|
+
}
|
|
13754
|
+
if (typeof first === "object") {
|
|
13589
13755
|
return this.query().with(first);
|
|
13590
13756
|
}
|
|
13591
13757
|
if (typeof second === "function") {
|
|
@@ -13671,32 +13837,53 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13671
13837
|
findOrFail(value) {
|
|
13672
13838
|
return this.getRepository().findOrFail(value);
|
|
13673
13839
|
},
|
|
13840
|
+
findOrFailJson(value) {
|
|
13841
|
+
return this.query().findOrFailJson(value);
|
|
13842
|
+
},
|
|
13674
13843
|
first() {
|
|
13675
13844
|
return this.getRepository().first();
|
|
13676
13845
|
},
|
|
13846
|
+
firstJson() {
|
|
13847
|
+
return this.query().firstJson();
|
|
13848
|
+
},
|
|
13677
13849
|
firstOrFail() {
|
|
13678
13850
|
return this.getRepository().firstOrFail();
|
|
13679
13851
|
},
|
|
13680
13852
|
sole() {
|
|
13681
13853
|
return this.getRepository().sole();
|
|
13682
13854
|
},
|
|
13855
|
+
soleJson() {
|
|
13856
|
+
return this.query().soleJson();
|
|
13857
|
+
},
|
|
13683
13858
|
firstWhere(column2, operator, value) {
|
|
13684
13859
|
return this.getRepository().firstWhere(column2, operator, value);
|
|
13685
13860
|
},
|
|
13686
13861
|
get() {
|
|
13687
13862
|
return this.getRepository().get();
|
|
13688
13863
|
},
|
|
13864
|
+
getJson() {
|
|
13865
|
+
return this.query().getJson();
|
|
13866
|
+
},
|
|
13689
13867
|
all() {
|
|
13690
13868
|
return this.getRepository().all();
|
|
13691
13869
|
},
|
|
13692
|
-
paginate(perPage = 15, page = 1,
|
|
13693
|
-
return this.query().paginate(perPage, page,
|
|
13870
|
+
paginate(perPage = 15, page = 1, options = {}) {
|
|
13871
|
+
return this.query().paginate(perPage, page, options);
|
|
13872
|
+
},
|
|
13873
|
+
paginateJson(perPage = 15, page = 1, options = {}) {
|
|
13874
|
+
return this.query().paginateJson(perPage, page, options);
|
|
13875
|
+
},
|
|
13876
|
+
simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
13877
|
+
return this.query().simplePaginate(perPage, page, options);
|
|
13878
|
+
},
|
|
13879
|
+
simplePaginateJson(perPage = 15, page = 1, options = {}) {
|
|
13880
|
+
return this.query().simplePaginateJson(perPage, page, options);
|
|
13694
13881
|
},
|
|
13695
|
-
|
|
13696
|
-
return this.query().
|
|
13882
|
+
cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
13883
|
+
return this.query().cursorPaginate(perPage, cursor, options);
|
|
13697
13884
|
},
|
|
13698
|
-
|
|
13699
|
-
return this.query().
|
|
13885
|
+
cursorPaginateJson(perPage = 15, cursor = null, options = {}) {
|
|
13886
|
+
return this.query().cursorPaginateJson(perPage, cursor, options);
|
|
13700
13887
|
},
|
|
13701
13888
|
chunk(size, callback) {
|
|
13702
13889
|
return this.query().chunk(size, callback);
|
|
@@ -13824,9 +14011,94 @@ function defineModelFromResolvedTable(table, options = {}) {
|
|
|
13824
14011
|
const scoped = scope;
|
|
13825
14012
|
model[name] = (...args) => scoped(model.query(), ...args);
|
|
13826
14013
|
}
|
|
14014
|
+
registerGlobalModel(model);
|
|
13827
14015
|
registerMorphModel(definition.morphClass, model);
|
|
14016
|
+
getHoloModelReferenceRegistry().add(model);
|
|
13828
14017
|
return Object.freeze(model);
|
|
13829
14018
|
}
|
|
14019
|
+
function getHoloModelReferenceRegistry() {
|
|
14020
|
+
const registryGlobal = globalThis;
|
|
14021
|
+
const existing = registryGlobal[HOLO_MODEL_REFERENCE_REGISTRY];
|
|
14022
|
+
if (existing) {
|
|
14023
|
+
return existing;
|
|
14024
|
+
}
|
|
14025
|
+
const registry = /* @__PURE__ */ new WeakSet();
|
|
14026
|
+
Object.defineProperty(globalThis, HOLO_MODEL_REFERENCE_REGISTRY, {
|
|
14027
|
+
value: registry
|
|
14028
|
+
});
|
|
14029
|
+
return registry;
|
|
14030
|
+
}
|
|
14031
|
+
|
|
14032
|
+
// src/model/serialize.ts
|
|
14033
|
+
function isSerializableModel(value) {
|
|
14034
|
+
return Boolean(value && typeof value === "object" && typeof value.toJSON === "function");
|
|
14035
|
+
}
|
|
14036
|
+
function serializeModels(value) {
|
|
14037
|
+
if (value instanceof Date || value === null || typeof value !== "object") {
|
|
14038
|
+
return value;
|
|
14039
|
+
}
|
|
14040
|
+
if (isSerializableModel(value)) {
|
|
14041
|
+
return value.toJSON();
|
|
14042
|
+
}
|
|
14043
|
+
if (Array.isArray(value)) {
|
|
14044
|
+
return value.map((item) => serializeModels(item));
|
|
14045
|
+
}
|
|
14046
|
+
return Object.fromEntries(
|
|
14047
|
+
Object.entries(value).map(([key, entry]) => [key, serializeModels(entry)])
|
|
14048
|
+
);
|
|
14049
|
+
}
|
|
14050
|
+
|
|
14051
|
+
// src/model/slug.ts
|
|
14052
|
+
var reservedSlugs = /* @__PURE__ */ new Map();
|
|
14053
|
+
var slugReservationQueues = /* @__PURE__ */ new Map();
|
|
14054
|
+
function slugify(value, separator, fallback) {
|
|
14055
|
+
const normalized = value.toLowerCase().trim().replace(/[^a-z0-9]+/g, separator).replace(new RegExp(`^${escapeRegExp(separator)}+|${escapeRegExp(separator)}+$`, "g"), "");
|
|
14056
|
+
return normalized || fallback;
|
|
14057
|
+
}
|
|
14058
|
+
function escapeRegExp(value) {
|
|
14059
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14060
|
+
}
|
|
14061
|
+
async function reserveNextSlug(key, callback) {
|
|
14062
|
+
const previous = slugReservationQueues.get(key) ?? Promise.resolve();
|
|
14063
|
+
let release;
|
|
14064
|
+
const current = previous.then(() => new Promise((resolve) => {
|
|
14065
|
+
release = resolve;
|
|
14066
|
+
}));
|
|
14067
|
+
slugReservationQueues.set(key, current);
|
|
14068
|
+
await previous;
|
|
14069
|
+
try {
|
|
14070
|
+
return await callback();
|
|
14071
|
+
} finally {
|
|
14072
|
+
release();
|
|
14073
|
+
if (slugReservationQueues.get(key) === current) {
|
|
14074
|
+
slugReservationQueues.delete(key);
|
|
14075
|
+
}
|
|
14076
|
+
}
|
|
14077
|
+
}
|
|
14078
|
+
async function uniqueSlug(model, value, options = {}) {
|
|
14079
|
+
const column2 = options.column ?? "slug";
|
|
14080
|
+
const separator = options.separator ?? "-";
|
|
14081
|
+
const fallback = options.fallback ?? "entry";
|
|
14082
|
+
const base = slugify(value, separator, fallback);
|
|
14083
|
+
const key = `${model.definition.connectionName ?? "default"}:${model.definition.name}:${column2}:${base}`;
|
|
14084
|
+
return await reserveNextSlug(key, async () => {
|
|
14085
|
+
const query = model.whereLike(column2, `${base}%`).when(typeof options.ignore !== "undefined", (builder) => builder.where(model.definition.primaryKey, "!=", options.ignore));
|
|
14086
|
+
const existing = await query.pluck(column2);
|
|
14087
|
+
const reserved = reservedSlugs.get(key) ?? /* @__PURE__ */ new Set();
|
|
14088
|
+
const taken = new Set(reserved);
|
|
14089
|
+
for (const slug of existing) {
|
|
14090
|
+
taken.add(slug);
|
|
14091
|
+
}
|
|
14092
|
+
for (let index = 1; ; index += 1) {
|
|
14093
|
+
const candidate = index === 1 ? base : `${base}${separator}${index}`;
|
|
14094
|
+
if (!taken.has(candidate)) {
|
|
14095
|
+
reserved.add(candidate);
|
|
14096
|
+
reservedSlugs.set(key, reserved);
|
|
14097
|
+
return candidate;
|
|
14098
|
+
}
|
|
14099
|
+
}
|
|
14100
|
+
});
|
|
14101
|
+
}
|
|
13830
14102
|
|
|
13831
14103
|
// src/model/relations.ts
|
|
13832
14104
|
function defaultMorphTypeColumn(name) {
|
|
@@ -13835,6 +14107,21 @@ function defaultMorphTypeColumn(name) {
|
|
|
13835
14107
|
function defaultMorphIdColumn(name) {
|
|
13836
14108
|
return `${name}_id`;
|
|
13837
14109
|
}
|
|
14110
|
+
function resolveRegisteredModel(name) {
|
|
14111
|
+
const model = getGlobalModel(name);
|
|
14112
|
+
if (!model) {
|
|
14113
|
+
throw new RelationError(
|
|
14114
|
+
`Relation target "${name}" is not registered. Import the related model once during boot or use your framework's model discovery.`
|
|
14115
|
+
);
|
|
14116
|
+
}
|
|
14117
|
+
return model;
|
|
14118
|
+
}
|
|
14119
|
+
function normalizeRelatedResolver(related) {
|
|
14120
|
+
if (typeof related === "string") {
|
|
14121
|
+
return () => resolveRegisteredModel(related);
|
|
14122
|
+
}
|
|
14123
|
+
return related;
|
|
14124
|
+
}
|
|
13838
14125
|
function decoratePivotRelation(relation) {
|
|
13839
14126
|
const clone = (overrides) => {
|
|
13840
14127
|
return decoratePivotRelation(Object.freeze({
|
|
@@ -13891,7 +14178,7 @@ function belongsTo(related, foreignKeyOrOptions, ownerKey = "id") {
|
|
|
13891
14178
|
const resolvedOwnerKey = typeof foreignKeyOrOptions === "string" ? ownerKey : foreignKeyOrOptions.ownerKey ?? "id";
|
|
13892
14179
|
return Object.freeze({
|
|
13893
14180
|
kind: "belongsTo",
|
|
13894
|
-
related,
|
|
14181
|
+
related: normalizeRelatedResolver(related),
|
|
13895
14182
|
foreignKey,
|
|
13896
14183
|
ownerKey: resolvedOwnerKey
|
|
13897
14184
|
});
|
|
@@ -13901,7 +14188,7 @@ function hasMany(related, foreignKeyOrOptions, localKey = "id") {
|
|
|
13901
14188
|
const resolvedLocalKey = typeof foreignKeyOrOptions === "string" ? localKey : foreignKeyOrOptions.localKey ?? "id";
|
|
13902
14189
|
return Object.freeze({
|
|
13903
14190
|
kind: "hasMany",
|
|
13904
|
-
related,
|
|
14191
|
+
related: normalizeRelatedResolver(related),
|
|
13905
14192
|
foreignKey,
|
|
13906
14193
|
localKey: resolvedLocalKey
|
|
13907
14194
|
});
|
|
@@ -13911,7 +14198,7 @@ function hasOne(related, foreignKeyOrOptions, localKey = "id") {
|
|
|
13911
14198
|
const resolvedLocalKey = typeof foreignKeyOrOptions === "string" ? localKey : foreignKeyOrOptions.localKey ?? "id";
|
|
13912
14199
|
return Object.freeze({
|
|
13913
14200
|
kind: "hasOne",
|
|
13914
|
-
related,
|
|
14201
|
+
related: normalizeRelatedResolver(related),
|
|
13915
14202
|
foreignKey,
|
|
13916
14203
|
localKey: resolvedLocalKey
|
|
13917
14204
|
});
|
|
@@ -13986,7 +14273,7 @@ function belongsToMany(related, pivotTableOrOptions, foreignPivotKey, relatedPiv
|
|
|
13986
14273
|
const resolvedRelatedKey = typeof pivotTableOrOptions === "object" && "pivotTable" in pivotTableOrOptions ? pivotTableOrOptions.relatedKey ?? "id" : relatedKey;
|
|
13987
14274
|
return decoratePivotRelation(Object.freeze({
|
|
13988
14275
|
kind: "belongsToMany",
|
|
13989
|
-
related,
|
|
14276
|
+
related: normalizeRelatedResolver(related),
|
|
13990
14277
|
pivotTable,
|
|
13991
14278
|
foreignPivotKey: resolvedForeignPivotKey,
|
|
13992
14279
|
relatedPivotKey: resolvedRelatedPivotKey,
|
|
@@ -14073,7 +14360,7 @@ function hasManyThrough(related, through, firstKey, secondKey, localKey = "id",
|
|
|
14073
14360
|
var DEFAULT_HOLO_PROJECT_PATHS = Object.freeze({
|
|
14074
14361
|
models: "server/models",
|
|
14075
14362
|
migrations: "server/db/migrations",
|
|
14076
|
-
generatedSchema: "
|
|
14363
|
+
generatedSchema: ".holo-js/generated/schema.generated.ts",
|
|
14077
14364
|
seeders: "server/db/seeders",
|
|
14078
14365
|
observers: "server/db/observers",
|
|
14079
14366
|
factories: "server/db/factories",
|
|
@@ -14250,8 +14537,10 @@ export {
|
|
|
14250
14537
|
renameTableOperation,
|
|
14251
14538
|
renderGeneratedSchemaModule,
|
|
14252
14539
|
renderGeneratedSchemaPlaceholder,
|
|
14540
|
+
renderGeneratedSchemaRuntimeModule,
|
|
14253
14541
|
resetDB,
|
|
14254
14542
|
resetDatabaseQueryCacheBridge,
|
|
14543
|
+
resetGlobalModelRegistry,
|
|
14255
14544
|
resetMorphRegistry,
|
|
14256
14545
|
resolveDialectColumnType,
|
|
14257
14546
|
resolveDialectIdStrategyType,
|
|
@@ -14259,6 +14548,8 @@ export {
|
|
|
14259
14548
|
resolveMorphModel,
|
|
14260
14549
|
resolveRuntimeConnectionManagerOptions,
|
|
14261
14550
|
scopeRelation,
|
|
14551
|
+
serializeModels,
|
|
14552
|
+
uniqueSlug,
|
|
14262
14553
|
unsafeSql,
|
|
14263
14554
|
validateQueryPlan,
|
|
14264
14555
|
withLimit,
|