bun-query-builder 0.1.63 → 0.2.2
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/actions/introspect-db.d.ts +9 -0
- package/dist/actions/migrate-rollback.d.ts +10 -2
- package/dist/actions/migrate-status.d.ts +1 -1
- package/dist/actions/migrate.d.ts +4 -0
- package/dist/actions/seed.d.ts +8 -1
- package/dist/bin/cli.js +624 -331
- package/dist/client.d.ts +2 -2
- package/dist/config.d.ts +13 -0
- package/dist/db.d.ts +12 -0
- package/dist/drivers/index-name.d.ts +1 -0
- package/dist/inflect.d.ts +17 -0
- package/dist/migrations.d.ts +26 -0
- package/dist/src/index.js +611 -315
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -11640,9 +11640,18 @@ var init_dist = __esm(() => {
|
|
|
11640
11640
|
});
|
|
11641
11641
|
|
|
11642
11642
|
// src/config.ts
|
|
11643
|
+
import process19 from "process";
|
|
11643
11644
|
function isMysqlLike(dialect = config5.dialect) {
|
|
11644
11645
|
return dialect === "mysql" || dialect === "singlestore";
|
|
11645
11646
|
}
|
|
11647
|
+
function resolveDialect(explicit) {
|
|
11648
|
+
if (explicit)
|
|
11649
|
+
return explicit;
|
|
11650
|
+
const fromEnv = process19.env.DB_DIALECT || process19.env.DB_CONNECTION;
|
|
11651
|
+
if (fromEnv)
|
|
11652
|
+
return fromEnv;
|
|
11653
|
+
return config5.dialect || "postgres";
|
|
11654
|
+
}
|
|
11646
11655
|
function getPlaceholder(index) {
|
|
11647
11656
|
if (config5.dialect === "postgres") {
|
|
11648
11657
|
return `$${index}`;
|
|
@@ -11801,7 +11810,7 @@ var {SQL } = globalThis.Bun;
|
|
|
11801
11810
|
import { Database } from "bun:sqlite";
|
|
11802
11811
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
11803
11812
|
import { dirname as dirname5 } from "path";
|
|
11804
|
-
import
|
|
11813
|
+
import process21 from "process";
|
|
11805
11814
|
|
|
11806
11815
|
class SQLiteWrapper {
|
|
11807
11816
|
db;
|
|
@@ -12079,9 +12088,13 @@ function sqliteFileFromUrl(url) {
|
|
|
12079
12088
|
const path = stripped.startsWith("///") ? stripped.slice(2) : stripped.startsWith("//") ? stripped.slice(2) : stripped;
|
|
12080
12089
|
return path || ":memory:";
|
|
12081
12090
|
}
|
|
12091
|
+
function resolveDatabaseName(dbConfig = config5.database) {
|
|
12092
|
+
const raw = process21.env.DB_DATABASE || dbConfig?.database || "";
|
|
12093
|
+
return String(raw).replace(/^['"]|['"]$/g, "");
|
|
12094
|
+
}
|
|
12082
12095
|
function createConnectionString(dialect, dbConfig) {
|
|
12083
|
-
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") &&
|
|
12084
|
-
const e =
|
|
12096
|
+
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process21.env.DB_CONNECTION === dialect) {
|
|
12097
|
+
const e = process21.env;
|
|
12085
12098
|
const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
|
|
12086
12099
|
const envUser = e.DB_USERNAME || dbConfig.username;
|
|
12087
12100
|
const envPass = e.DB_PASSWORD ?? dbConfig.password ?? "";
|
|
@@ -12095,7 +12108,7 @@ function createConnectionString(dialect, dbConfig) {
|
|
|
12095
12108
|
return dialect === "sqlite" ? sqliteFileFromUrl(dbConfig.url) : dbConfig.url;
|
|
12096
12109
|
}
|
|
12097
12110
|
const { database, username, password, host = "localhost", port, ssl } = dbConfig;
|
|
12098
|
-
const sslQ = ssl ||
|
|
12111
|
+
const sslQ = ssl || process21.env.DB_SSL === "true" || process21.env.DB_SSL === "1" ? "?ssl=true" : "";
|
|
12099
12112
|
switch (dialect) {
|
|
12100
12113
|
case "postgres":
|
|
12101
12114
|
return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
|
|
@@ -12369,6 +12382,17 @@ var init_benchmark = __esm(() => {
|
|
|
12369
12382
|
});
|
|
12370
12383
|
|
|
12371
12384
|
// src/inflect.ts
|
|
12385
|
+
function toTableName(modelName) {
|
|
12386
|
+
const snake = String(modelName).replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
12387
|
+
if (snake.endsWith("y") && !/[aeou]y$/.test(snake))
|
|
12388
|
+
return `${snake.slice(0, -1)}ies`;
|
|
12389
|
+
if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh"))
|
|
12390
|
+
return `${snake}es`;
|
|
12391
|
+
return `${snake}s`;
|
|
12392
|
+
}
|
|
12393
|
+
function tableNameFor(model) {
|
|
12394
|
+
return typeof model?.table === "string" && model.table.length > 0 ? model.table : toTableName(String(model?.name ?? ""));
|
|
12395
|
+
}
|
|
12372
12396
|
function stripTrailingS(name) {
|
|
12373
12397
|
return name.endsWith("s") ? name.slice(0, -1) : name;
|
|
12374
12398
|
}
|
|
@@ -12483,6 +12507,24 @@ var init_pivot = __esm(() => {
|
|
|
12483
12507
|
function isRawExpression(expr) {
|
|
12484
12508
|
return typeof expr === "object" && expr !== null && "raw" in expr && typeof expr.raw === "string";
|
|
12485
12509
|
}
|
|
12510
|
+
function isBoundSqlExpression(expr) {
|
|
12511
|
+
return typeof expr === "object" && expr !== null && "sql" in expr && typeof expr.sql === "string" && (!("parameters" in expr) || Array.isArray(expr.parameters));
|
|
12512
|
+
}
|
|
12513
|
+
function renderBoundSqlExpression(expression, startIndex) {
|
|
12514
|
+
const parameters = expression.parameters ?? [];
|
|
12515
|
+
if (config5.dialect !== "postgres" || parameters.length === 0)
|
|
12516
|
+
return { text: expression.sql, parameters };
|
|
12517
|
+
let parameterIndex = 0;
|
|
12518
|
+
const text = expression.sql.replace(/\?/g, (placeholder) => {
|
|
12519
|
+
if (parameterIndex >= parameters.length)
|
|
12520
|
+
return placeholder;
|
|
12521
|
+
return getPlaceholder(startIndex + parameterIndex++);
|
|
12522
|
+
});
|
|
12523
|
+
if (parameterIndex !== parameters.length) {
|
|
12524
|
+
throw new TypeError(`[query-builder] SQL expression declares ${parameters.length} parameters but contains only ${parameterIndex} placeholders`);
|
|
12525
|
+
}
|
|
12526
|
+
return { text, parameters };
|
|
12527
|
+
}
|
|
12486
12528
|
function raw(strings, ...values) {
|
|
12487
12529
|
if (typeof strings === "string")
|
|
12488
12530
|
return { raw: strings };
|
|
@@ -12956,6 +12998,31 @@ function createQueryBuilder(state) {
|
|
|
12956
12998
|
throw err;
|
|
12957
12999
|
});
|
|
12958
13000
|
}
|
|
13001
|
+
function mutationCount(result) {
|
|
13002
|
+
if (typeof result === "number")
|
|
13003
|
+
return Number.isFinite(result) ? result : 0;
|
|
13004
|
+
if (typeof result === "bigint")
|
|
13005
|
+
return Number(result);
|
|
13006
|
+
if (!result || typeof result !== "object")
|
|
13007
|
+
return 0;
|
|
13008
|
+
const record = result;
|
|
13009
|
+
for (const key of [
|
|
13010
|
+
"changes",
|
|
13011
|
+
"affectedRows",
|
|
13012
|
+
"count",
|
|
13013
|
+
"rowCount",
|
|
13014
|
+
"numAffectedRows",
|
|
13015
|
+
"numUpdatedRows",
|
|
13016
|
+
"numDeletedRows",
|
|
13017
|
+
"numInsertedOrUpdatedRows"
|
|
13018
|
+
]) {
|
|
13019
|
+
if (record[key] !== undefined && record[key] !== null)
|
|
13020
|
+
return mutationCount(record[key]);
|
|
13021
|
+
}
|
|
13022
|
+
if (Array.isArray(result))
|
|
13023
|
+
return result.reduce((total, item) => total + mutationCount(item), 0);
|
|
13024
|
+
return 0;
|
|
13025
|
+
}
|
|
12959
13026
|
function makeExecutableQuery(q, text) {
|
|
12960
13027
|
const sqlText = text ?? computeSqlText(q);
|
|
12961
13028
|
return {
|
|
@@ -14051,7 +14118,16 @@ function createQueryBuilder(state) {
|
|
|
14051
14118
|
built = null;
|
|
14052
14119
|
return this;
|
|
14053
14120
|
}
|
|
14054
|
-
|
|
14121
|
+
if (typeof expr === "function") {
|
|
14122
|
+
throw new TypeError("where(callback) is not supported. This builder has no expression callback, and " + "ignoring one silently would leave the query matching every row the filter was " + "meant to exclude. Use whereNested(subquery), whereAny(...), or the orWhere* " + "helpers to build a grouped condition.");
|
|
14123
|
+
}
|
|
14124
|
+
if (expr === undefined || expr === null) {
|
|
14125
|
+
throw new TypeError("where() was called with no condition.");
|
|
14126
|
+
}
|
|
14127
|
+
if (typeof expr === "string") {
|
|
14128
|
+
throw new TypeError(`where(${JSON.stringify(expr)}) is missing an operator and a value. Pass ` + "where(column, operator, value), or whereRaw() for a raw fragment.");
|
|
14129
|
+
}
|
|
14130
|
+
throw new TypeError(`where() does not understand a condition of type ${typeof expr}.`);
|
|
14055
14131
|
},
|
|
14056
14132
|
whereNull(column) {
|
|
14057
14133
|
validateIdentifier(String(column), "whereNull(column)");
|
|
@@ -15656,8 +15732,17 @@ function createQueryBuilder(state) {
|
|
|
15656
15732
|
const setClauses = Array.from({ length: len });
|
|
15657
15733
|
for (let i = 0;i < len; i++) {
|
|
15658
15734
|
const key = keys[i];
|
|
15659
|
-
|
|
15660
|
-
|
|
15735
|
+
const value = values[key];
|
|
15736
|
+
if (isRawExpression(value)) {
|
|
15737
|
+
setClauses[i] = `${quoteId(key)} = ${value.raw}`;
|
|
15738
|
+
} else if (isBoundSqlExpression(value)) {
|
|
15739
|
+
const expression = renderBoundSqlExpression(value, params.length + 1);
|
|
15740
|
+
setClauses[i] = `${quoteId(key)} = ${expression.text}`;
|
|
15741
|
+
params.push(...expression.parameters);
|
|
15742
|
+
} else {
|
|
15743
|
+
setClauses[i] = `${quoteId(key)} = ${getPlaceholder(params.length + 1)}`;
|
|
15744
|
+
params.push(value);
|
|
15745
|
+
}
|
|
15661
15746
|
}
|
|
15662
15747
|
sqlText = `${sqlText} SET ${setClauses.join(", ")}`;
|
|
15663
15748
|
built = _sql.unsafe(sqlText, params);
|
|
@@ -15665,17 +15750,29 @@ function createQueryBuilder(state) {
|
|
|
15665
15750
|
},
|
|
15666
15751
|
where(expr, op, value) {
|
|
15667
15752
|
const getWhereKeyword = () => SQL_PATTERNS.WHERE.test(sqlText) ? "AND" : "WHERE";
|
|
15668
|
-
if (typeof expr === "string"
|
|
15753
|
+
if (op !== undefined && (typeof expr === "string" || isRawExpression(expr) || isBoundSqlExpression(expr))) {
|
|
15754
|
+
const safeOperator = assertSafeWhereOperator(op, "updateTable.where");
|
|
15755
|
+
let left;
|
|
15756
|
+
if (typeof expr === "string") {
|
|
15757
|
+
left = quoteId(expr);
|
|
15758
|
+
} else if (isRawExpression(expr)) {
|
|
15759
|
+
left = expr.raw;
|
|
15760
|
+
} else {
|
|
15761
|
+
const expression = renderBoundSqlExpression(expr, params.length + 1);
|
|
15762
|
+
left = expression.text;
|
|
15763
|
+
params.push(...expression.parameters);
|
|
15764
|
+
}
|
|
15669
15765
|
const paramIndex = params.length + 1;
|
|
15670
|
-
sqlText = `${sqlText} ${getWhereKeyword()} ${
|
|
15766
|
+
sqlText = `${sqlText} ${getWhereKeyword()} ${left} ${safeOperator} ${getPlaceholder(paramIndex)}`;
|
|
15671
15767
|
params.push(value);
|
|
15672
15768
|
built = _sql.unsafe(sqlText, params);
|
|
15673
15769
|
return this;
|
|
15674
15770
|
}
|
|
15675
15771
|
if (Array.isArray(expr)) {
|
|
15676
15772
|
const [col, op2, val] = expr;
|
|
15773
|
+
const safeOperator = assertSafeWhereOperator(op2, "updateTable.where");
|
|
15677
15774
|
const paramIndex = params.length + 1;
|
|
15678
|
-
sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${
|
|
15775
|
+
sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${safeOperator} ${getPlaceholder(paramIndex)}`;
|
|
15679
15776
|
params.push(val);
|
|
15680
15777
|
built = _sql.unsafe(sqlText, params);
|
|
15681
15778
|
return this;
|
|
@@ -15734,15 +15831,16 @@ function createQueryBuilder(state) {
|
|
|
15734
15831
|
}
|
|
15735
15832
|
return makeExecutableQuery(built, sqlText);
|
|
15736
15833
|
},
|
|
15737
|
-
execute() {
|
|
15738
|
-
|
|
15834
|
+
async execute() {
|
|
15835
|
+
const result = await runWithHooks(built, "update");
|
|
15836
|
+
return mutationCount(result);
|
|
15739
15837
|
},
|
|
15740
15838
|
async executeTakeFirst() {
|
|
15741
|
-
const result = await runWithHooks(built, "update");
|
|
15839
|
+
const result = mutationCount(await runWithHooks(built, "update"));
|
|
15742
15840
|
return { numUpdatedRows: result };
|
|
15743
15841
|
},
|
|
15744
15842
|
async executeTakeFirstOrThrow() {
|
|
15745
|
-
const result = await runWithHooks(built, "update");
|
|
15843
|
+
const result = mutationCount(await runWithHooks(built, "update"));
|
|
15746
15844
|
if (result === 0)
|
|
15747
15845
|
throw new Error("No rows updated");
|
|
15748
15846
|
return { numUpdatedRows: result };
|
|
@@ -15863,18 +15961,18 @@ function createQueryBuilder(state) {
|
|
|
15863
15961
|
} catch (err) {
|
|
15864
15962
|
throw err;
|
|
15865
15963
|
}
|
|
15866
|
-
const result = await runWithHooks(ensureDelBuilt(), "delete");
|
|
15964
|
+
const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
|
|
15867
15965
|
try {
|
|
15868
15966
|
await config5.hooks?.afterDelete?.({ table: String(table), where: whereCondition, result });
|
|
15869
15967
|
} catch {}
|
|
15870
15968
|
return result;
|
|
15871
15969
|
},
|
|
15872
15970
|
async executeTakeFirst() {
|
|
15873
|
-
const result = await runWithHooks(ensureDelBuilt(), "delete");
|
|
15971
|
+
const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
|
|
15874
15972
|
return { numDeletedRows: result };
|
|
15875
15973
|
},
|
|
15876
15974
|
async executeTakeFirstOrThrow() {
|
|
15877
|
-
const result = await runWithHooks(ensureDelBuilt(), "delete");
|
|
15975
|
+
const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
|
|
15878
15976
|
if (result === 0)
|
|
15879
15977
|
throw new Error("No rows deleted");
|
|
15880
15978
|
return { numDeletedRows: result };
|
|
@@ -16589,7 +16687,7 @@ var init_cache = __esm(() => {
|
|
|
16589
16687
|
});
|
|
16590
16688
|
|
|
16591
16689
|
// src/actions/console.ts
|
|
16592
|
-
import
|
|
16690
|
+
import process22 from "process";
|
|
16593
16691
|
import { createInterface } from "readline";
|
|
16594
16692
|
async function startConsole() {
|
|
16595
16693
|
console.log("-- Query Builder Interactive Console");
|
|
@@ -16598,8 +16696,8 @@ async function startConsole() {
|
|
|
16598
16696
|
console.log();
|
|
16599
16697
|
const qb = createQueryBuilder();
|
|
16600
16698
|
const rl = createInterface({
|
|
16601
|
-
input:
|
|
16602
|
-
output:
|
|
16699
|
+
input: process22.stdin,
|
|
16700
|
+
output: process22.stdout,
|
|
16603
16701
|
prompt: "qb> "
|
|
16604
16702
|
});
|
|
16605
16703
|
let multilineBuffer = "";
|
|
@@ -16650,7 +16748,7 @@ Tips:
|
|
|
16650
16748
|
if (cmd === ".exit" || cmd === ".quit") {
|
|
16651
16749
|
console.log("Goodbye!");
|
|
16652
16750
|
rl.close();
|
|
16653
|
-
|
|
16751
|
+
process22.exit(0);
|
|
16654
16752
|
} else if (cmd === ".help") {
|
|
16655
16753
|
console.log(helpText);
|
|
16656
16754
|
} else if (cmd === ".clear") {
|
|
@@ -16721,7 +16819,7 @@ Tips:
|
|
|
16721
16819
|
rl.on("close", () => {
|
|
16722
16820
|
console.log(`
|
|
16723
16821
|
Goodbye!`);
|
|
16724
|
-
|
|
16822
|
+
process22.exit(0);
|
|
16725
16823
|
});
|
|
16726
16824
|
rl.prompt();
|
|
16727
16825
|
}
|
|
@@ -17099,9 +17197,8 @@ var init_db_info = __esm(() => {
|
|
|
17099
17197
|
});
|
|
17100
17198
|
|
|
17101
17199
|
// src/actions/db-optimize.ts
|
|
17102
|
-
import process22 from "process";
|
|
17103
17200
|
async function dbOptimize(options = {}) {
|
|
17104
|
-
const dialect = options.dialect
|
|
17201
|
+
const dialect = resolveDialect(options.dialect);
|
|
17105
17202
|
const aggressive = options.aggressive || false;
|
|
17106
17203
|
if (options.verbose) {
|
|
17107
17204
|
console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
|
|
@@ -17141,7 +17238,7 @@ async function dbOptimize(options = {}) {
|
|
|
17141
17238
|
await bunSql`ANALYZE TABLE ${bunSql(table)}`;
|
|
17142
17239
|
}
|
|
17143
17240
|
} else {
|
|
17144
|
-
const dbName =
|
|
17241
|
+
const dbName = resolveDatabaseName();
|
|
17145
17242
|
const tables = await bunSql`
|
|
17146
17243
|
SELECT table_name
|
|
17147
17244
|
FROM information_schema.tables
|
|
@@ -17194,9 +17291,8 @@ var init_db_optimize = __esm(() => {
|
|
|
17194
17291
|
});
|
|
17195
17292
|
|
|
17196
17293
|
// src/actions/db-wipe.ts
|
|
17197
|
-
import process23 from "process";
|
|
17198
17294
|
async function dbWipe(options = {}) {
|
|
17199
|
-
const dialect = options.dialect
|
|
17295
|
+
const dialect = resolveDialect(options.dialect);
|
|
17200
17296
|
if (options.verbose) {
|
|
17201
17297
|
console.log(`Wiping all tables from ${dialect} database...`);
|
|
17202
17298
|
}
|
|
@@ -17210,7 +17306,7 @@ async function dbWipe(options = {}) {
|
|
|
17210
17306
|
`;
|
|
17211
17307
|
tables = result.map((row) => row.tablename);
|
|
17212
17308
|
} else if (isMysqlLike(dialect)) {
|
|
17213
|
-
const dbName =
|
|
17309
|
+
const dbName = resolveDatabaseName();
|
|
17214
17310
|
const result = await bunSql`
|
|
17215
17311
|
SELECT table_name
|
|
17216
17312
|
FROM information_schema.tables
|
|
@@ -17647,6 +17743,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17647
17743
|
return "decimal";
|
|
17648
17744
|
if (base === "date")
|
|
17649
17745
|
return "date";
|
|
17746
|
+
if (base === "timestamptz" || /\bwith time zone\b/.test(t))
|
|
17747
|
+
return "timestamptz";
|
|
17650
17748
|
if (/^(?:timestamp|datetime)/.test(base))
|
|
17651
17749
|
return "datetime";
|
|
17652
17750
|
if (/^time/.test(base))
|
|
@@ -17657,10 +17755,6 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17657
17755
|
return "enum";
|
|
17658
17756
|
return "string";
|
|
17659
17757
|
}
|
|
17660
|
-
function stripIndexPrefix(physicalName, table) {
|
|
17661
|
-
const prefix = `${table}_`;
|
|
17662
|
-
return physicalName.startsWith(prefix) ? physicalName.slice(prefix.length) : physicalName;
|
|
17663
|
-
}
|
|
17664
17758
|
function asAction(raw2) {
|
|
17665
17759
|
const v = String(raw2 ?? "").toLowerCase().trim();
|
|
17666
17760
|
if (v === "cascade" || v === "restrict" || v === "set null")
|
|
@@ -17696,7 +17790,7 @@ async function buildSqliteTable(qb, table) {
|
|
|
17696
17790
|
const isUnique = Number(idx.unique) === 1;
|
|
17697
17791
|
if (isUnique && columns2.length === 1)
|
|
17698
17792
|
uniqueColumns.add(columns2[0]);
|
|
17699
|
-
indexes.push({ name:
|
|
17793
|
+
indexes.push({ name: physName, columns: columns2, type: isUnique ? "unique" : "index" });
|
|
17700
17794
|
}
|
|
17701
17795
|
const columns = colRows.map((r) => {
|
|
17702
17796
|
const name = String(r.name);
|
|
@@ -17733,7 +17827,31 @@ function normalizeRawDefault(raw2) {
|
|
|
17733
17827
|
return raw2;
|
|
17734
17828
|
return String(raw2);
|
|
17735
17829
|
}
|
|
17736
|
-
async function
|
|
17830
|
+
async function pgEnumLabels(qb) {
|
|
17831
|
+
const rows = await qb.unsafe(`SELECT t.typname AS type_name, e.enumlabel AS label
|
|
17832
|
+
FROM pg_type t
|
|
17833
|
+
JOIN pg_enum e ON e.enumtypid = t.oid
|
|
17834
|
+
JOIN pg_namespace n ON n.oid = t.typnamespace
|
|
17835
|
+
WHERE n.nspname = 'public'
|
|
17836
|
+
ORDER BY t.typname, e.enumsortorder`);
|
|
17837
|
+
const labels = new Map;
|
|
17838
|
+
for (const row of rows) {
|
|
17839
|
+
const name = String(row.type_name);
|
|
17840
|
+
const existing = labels.get(name);
|
|
17841
|
+
if (existing)
|
|
17842
|
+
existing.push(String(row.label));
|
|
17843
|
+
else
|
|
17844
|
+
labels.set(name, [String(row.label)]);
|
|
17845
|
+
}
|
|
17846
|
+
return labels;
|
|
17847
|
+
}
|
|
17848
|
+
function pgColumnType(dataType, udtName, enums) {
|
|
17849
|
+
const enumValues = enums.get(udtName);
|
|
17850
|
+
const type = sqlTypeToNormalized(String(dataType || udtName || ""), "postgres", { enumValues });
|
|
17851
|
+
return enumValues ? { type, enumValues, enumTypeName: udtName } : { type };
|
|
17852
|
+
}
|
|
17853
|
+
async function buildPgTable(qb, table, enumLabels) {
|
|
17854
|
+
const enums = enumLabels ?? await pgEnumLabels(qb);
|
|
17737
17855
|
const colRows = await qb.unsafe(`SELECT c.column_name, c.data_type, c.udt_name, c.is_nullable, c.column_default, c.character_maximum_length,
|
|
17738
17856
|
(SELECT COUNT(*) FROM information_schema.table_constraints tc
|
|
17739
17857
|
JOIN information_schema.key_column_usage k ON k.constraint_name = tc.constraint_name
|
|
@@ -17781,7 +17899,7 @@ async function buildPgTable(qb, table) {
|
|
|
17781
17899
|
const hasDefault = rawDefault != null && !isSerial;
|
|
17782
17900
|
return {
|
|
17783
17901
|
name,
|
|
17784
|
-
|
|
17902
|
+
...pgColumnType(String(r.data_type ?? ""), r.udt_name == null ? "" : String(r.udt_name), enums),
|
|
17785
17903
|
isPrimaryKey,
|
|
17786
17904
|
isUnique: uniqueColumns.has(name),
|
|
17787
17905
|
isNullable: isPrimaryKey ? false : String(r.is_nullable).toUpperCase() === "YES",
|
|
@@ -17867,7 +17985,7 @@ function groupPhysicalIndexes(table, rows) {
|
|
|
17867
17985
|
if (entry.isUnique && entry.columns.length === 1)
|
|
17868
17986
|
uniqueColumns.add(entry.columns[0]);
|
|
17869
17987
|
indexes.push({
|
|
17870
|
-
name:
|
|
17988
|
+
name: physName,
|
|
17871
17989
|
columns: entry.columns,
|
|
17872
17990
|
type: entry.isUnique ? "unique" : "index",
|
|
17873
17991
|
where: entry.where
|
|
@@ -17880,13 +17998,14 @@ async function buildPlanFromDatabase(dialect, opts = {}) {
|
|
|
17880
17998
|
const qb = createQueryBuilder();
|
|
17881
17999
|
const allTables = opts.tables?.length ? opts.tables : await listTables(qb, d);
|
|
17882
18000
|
const tables = allTables.filter((t) => t !== "migrations");
|
|
18001
|
+
const enumLabels = d === "postgres" ? await pgEnumLabels(qb) : undefined;
|
|
17883
18002
|
const out = [];
|
|
17884
18003
|
for (const table of tables) {
|
|
17885
18004
|
let plan;
|
|
17886
18005
|
if (d === "sqlite")
|
|
17887
18006
|
plan = await buildSqliteTable(qb, table);
|
|
17888
18007
|
else if (d === "postgres")
|
|
17889
|
-
plan = await buildPgTable(qb, table);
|
|
18008
|
+
plan = await buildPgTable(qb, table, enumLabels);
|
|
17890
18009
|
else
|
|
17891
18010
|
plan = await buildMysqlTable(qb, table);
|
|
17892
18011
|
if (plan.columns.length > 0)
|
|
@@ -17902,7 +18021,7 @@ var init_introspect_db = __esm(() => {
|
|
|
17902
18021
|
// src/actions/make-model.ts
|
|
17903
18022
|
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10 } from "fs";
|
|
17904
18023
|
import { dirname as dirname7, join as join7 } from "path";
|
|
17905
|
-
import
|
|
18024
|
+
import process23 from "process";
|
|
17906
18025
|
function findWorkspaceRoot(startPath) {
|
|
17907
18026
|
let currentPath = startPath;
|
|
17908
18027
|
while (currentPath !== dirname7(currentPath)) {
|
|
@@ -17911,10 +18030,10 @@ function findWorkspaceRoot(startPath) {
|
|
|
17911
18030
|
}
|
|
17912
18031
|
currentPath = dirname7(currentPath);
|
|
17913
18032
|
}
|
|
17914
|
-
return
|
|
18033
|
+
return process23.cwd();
|
|
17915
18034
|
}
|
|
17916
18035
|
async function makeModel(name, options = {}) {
|
|
17917
|
-
const workspaceRoot = findWorkspaceRoot(
|
|
18036
|
+
const workspaceRoot = findWorkspaceRoot(process23.cwd());
|
|
17918
18037
|
const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
|
|
17919
18038
|
if (!existsSync14(modelsDir)) {
|
|
17920
18039
|
mkdirSync7(modelsDir, { recursive: true });
|
|
@@ -17957,6 +18076,12 @@ export default model
|
|
|
17957
18076
|
}
|
|
17958
18077
|
var init_make_model = () => {};
|
|
17959
18078
|
|
|
18079
|
+
// src/drivers/index-name.ts
|
|
18080
|
+
function qualifiedIndexName(tableName, indexName) {
|
|
18081
|
+
const prefix = `${tableName}_`;
|
|
18082
|
+
return indexName.startsWith(prefix) ? indexName : `${prefix}${indexName}`;
|
|
18083
|
+
}
|
|
18084
|
+
|
|
17960
18085
|
// src/drivers/mysql.ts
|
|
17961
18086
|
class MySQLDriver {
|
|
17962
18087
|
quoteIdentifier(id) {
|
|
@@ -18043,7 +18168,7 @@ class MySQLDriver {
|
|
|
18043
18168
|
throw new Error(`[migrations] Partial indexes (CompositeIndex.where) are not supported on MySQL. Index '${index.name}' on table '${tableName}' uses WHERE clause: ${index.where}`);
|
|
18044
18169
|
}
|
|
18045
18170
|
const kind = index.type === "unique" ? "UNIQUE " : "";
|
|
18046
|
-
const idxName =
|
|
18171
|
+
const idxName = qualifiedIndexName(tableName, index.name);
|
|
18047
18172
|
const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
|
|
18048
18173
|
return `CREATE ${kind}INDEX ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns});`;
|
|
18049
18174
|
}
|
|
@@ -18096,7 +18221,7 @@ class MySQLDriver {
|
|
|
18096
18221
|
return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
|
|
18097
18222
|
}
|
|
18098
18223
|
dropIndex(tableName, indexName) {
|
|
18099
|
-
const fullIndexName =
|
|
18224
|
+
const fullIndexName = qualifiedIndexName(tableName, indexName);
|
|
18100
18225
|
return `DROP INDEX ${this.quoteIdentifier(fullIndexName)} ON ${this.quoteIdentifier(tableName)};`;
|
|
18101
18226
|
}
|
|
18102
18227
|
dropEnumType(_enumTypeName) {
|
|
@@ -18110,7 +18235,7 @@ class MySQLDriver {
|
|
|
18110
18235
|
)`;
|
|
18111
18236
|
}
|
|
18112
18237
|
getExecutedMigrationsQuery() {
|
|
18113
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18238
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18114
18239
|
}
|
|
18115
18240
|
recordMigrationQuery() {
|
|
18116
18241
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18143,6 +18268,7 @@ class MySQLDriver {
|
|
|
18143
18268
|
return parts.join(" ");
|
|
18144
18269
|
}
|
|
18145
18270
|
}
|
|
18271
|
+
var init_mysql = () => {};
|
|
18146
18272
|
|
|
18147
18273
|
// src/drivers/postgres.ts
|
|
18148
18274
|
class PostgresDriver {
|
|
@@ -18177,7 +18303,7 @@ class PostgresDriver {
|
|
|
18177
18303
|
return "jsonb";
|
|
18178
18304
|
case "enum":
|
|
18179
18305
|
if (column.enumValues && column.enumValues.length > 0) {
|
|
18180
|
-
return this.quoteIdentifier(column.enumTypeName
|
|
18306
|
+
return column.enumTypeName ? this.quoteIdentifier(column.enumTypeName) : "text";
|
|
18181
18307
|
}
|
|
18182
18308
|
return "text";
|
|
18183
18309
|
default:
|
|
@@ -18231,7 +18357,7 @@ class PostgresDriver {
|
|
|
18231
18357
|
}
|
|
18232
18358
|
createIndex(tableName, index) {
|
|
18233
18359
|
const kind = index.type === "unique" ? "UNIQUE " : "";
|
|
18234
|
-
const idxName =
|
|
18360
|
+
const idxName = qualifiedIndexName(tableName, index.name);
|
|
18235
18361
|
const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
|
|
18236
18362
|
const where = index.where ? ` WHERE ${index.where}` : "";
|
|
18237
18363
|
return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
|
|
@@ -18259,7 +18385,17 @@ class PostgresDriver {
|
|
|
18259
18385
|
}
|
|
18260
18386
|
modifyColumn(tableName, column) {
|
|
18261
18387
|
const typeSql = this.getColumnType(column);
|
|
18262
|
-
|
|
18388
|
+
const table = this.quoteIdentifier(tableName);
|
|
18389
|
+
const name = this.quoteIdentifier(column.name);
|
|
18390
|
+
const statements = [
|
|
18391
|
+
`ALTER TABLE ${table} ALTER COLUMN ${name} TYPE ${typeSql} USING ${name}::${typeSql};`
|
|
18392
|
+
];
|
|
18393
|
+
if (!column.isPrimaryKey)
|
|
18394
|
+
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${name} ${column.isNullable ? "DROP NOT NULL" : "SET NOT NULL"};`);
|
|
18395
|
+
const defaultValue = this.getDefaultValue(column);
|
|
18396
|
+
statements.push(defaultValue ? `ALTER TABLE ${table} ALTER COLUMN ${name} SET ${defaultValue};` : `ALTER TABLE ${table} ALTER COLUMN ${name} DROP DEFAULT;`);
|
|
18397
|
+
return statements.join(`
|
|
18398
|
+
`);
|
|
18263
18399
|
}
|
|
18264
18400
|
renameColumn(tableName, from, to) {
|
|
18265
18401
|
return `ALTER TABLE ${this.quoteIdentifier(tableName)} RENAME COLUMN ${this.quoteIdentifier(from)} TO ${this.quoteIdentifier(to)};`;
|
|
@@ -18277,7 +18413,7 @@ class PostgresDriver {
|
|
|
18277
18413
|
return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
|
|
18278
18414
|
}
|
|
18279
18415
|
dropIndex(tableName, indexName) {
|
|
18280
|
-
const fullIndexName =
|
|
18416
|
+
const fullIndexName = qualifiedIndexName(tableName, indexName);
|
|
18281
18417
|
return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
|
|
18282
18418
|
}
|
|
18283
18419
|
dropEnumType(enumTypeName) {
|
|
@@ -18291,7 +18427,7 @@ class PostgresDriver {
|
|
|
18291
18427
|
)`;
|
|
18292
18428
|
}
|
|
18293
18429
|
getExecutedMigrationsQuery() {
|
|
18294
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18430
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18295
18431
|
}
|
|
18296
18432
|
recordMigrationQuery() {
|
|
18297
18433
|
return "INSERT INTO migrations (migration) VALUES ($1)";
|
|
@@ -18320,10 +18456,12 @@ class PostgresDriver {
|
|
|
18320
18456
|
return parts.join(" ");
|
|
18321
18457
|
}
|
|
18322
18458
|
}
|
|
18459
|
+
var init_postgres = () => {};
|
|
18323
18460
|
|
|
18324
18461
|
// src/drivers/singlestore.ts
|
|
18325
18462
|
var SingleStoreDriver;
|
|
18326
18463
|
var init_singlestore = __esm(() => {
|
|
18464
|
+
init_mysql();
|
|
18327
18465
|
SingleStoreDriver = class SingleStoreDriver extends MySQLDriver {
|
|
18328
18466
|
createTable(table) {
|
|
18329
18467
|
const columns = table.columns.map((c) => this.renderColumn(c)).join(`,
|
|
@@ -18457,7 +18595,7 @@ class SQLiteDriver {
|
|
|
18457
18595
|
}
|
|
18458
18596
|
createIndex(tableName, index) {
|
|
18459
18597
|
const kind = index.type === "unique" ? "UNIQUE " : "";
|
|
18460
|
-
const idxName =
|
|
18598
|
+
const idxName = qualifiedIndexName(tableName, index.name);
|
|
18461
18599
|
const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
|
|
18462
18600
|
const where = index.where ? ` WHERE ${index.where}` : "";
|
|
18463
18601
|
return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
|
|
@@ -18522,7 +18660,7 @@ class SQLiteDriver {
|
|
|
18522
18660
|
return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
|
|
18523
18661
|
}
|
|
18524
18662
|
dropIndex(tableName, indexName) {
|
|
18525
|
-
const fullIndexName =
|
|
18663
|
+
const fullIndexName = qualifiedIndexName(tableName, indexName);
|
|
18526
18664
|
return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
|
|
18527
18665
|
}
|
|
18528
18666
|
dropEnumType(_enumTypeName) {
|
|
@@ -18536,7 +18674,7 @@ class SQLiteDriver {
|
|
|
18536
18674
|
)`;
|
|
18537
18675
|
}
|
|
18538
18676
|
getExecutedMigrationsQuery() {
|
|
18539
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18677
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18540
18678
|
}
|
|
18541
18679
|
recordMigrationQuery() {
|
|
18542
18680
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18568,6 +18706,7 @@ class SQLiteDriver {
|
|
|
18568
18706
|
return parts.join(" ");
|
|
18569
18707
|
}
|
|
18570
18708
|
}
|
|
18709
|
+
var init_sqlite = () => {};
|
|
18571
18710
|
|
|
18572
18711
|
// src/drivers/index.ts
|
|
18573
18712
|
function getDialectDriver(dialect) {
|
|
@@ -18585,10 +18724,34 @@ function getDialectDriver(dialect) {
|
|
|
18585
18724
|
}
|
|
18586
18725
|
}
|
|
18587
18726
|
var init_drivers = __esm(() => {
|
|
18727
|
+
init_mysql();
|
|
18728
|
+
init_postgres();
|
|
18588
18729
|
init_singlestore();
|
|
18730
|
+
init_sqlite();
|
|
18731
|
+
init_mysql();
|
|
18732
|
+
init_postgres();
|
|
18589
18733
|
init_singlestore();
|
|
18734
|
+
init_sqlite();
|
|
18590
18735
|
});
|
|
18591
18736
|
|
|
18737
|
+
// src/workspace.ts
|
|
18738
|
+
import { existsSync as existsSync16 } from "fs";
|
|
18739
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
18740
|
+
import process24 from "process";
|
|
18741
|
+
function findWorkspaceRoot2(startPath = process24.cwd()) {
|
|
18742
|
+
let currentPath = startPath;
|
|
18743
|
+
while (currentPath !== dirname8(currentPath)) {
|
|
18744
|
+
if (existsSync16(join9(currentPath, "package.json")))
|
|
18745
|
+
return currentPath;
|
|
18746
|
+
currentPath = dirname8(currentPath);
|
|
18747
|
+
}
|
|
18748
|
+
return process24.cwd();
|
|
18749
|
+
}
|
|
18750
|
+
function getSqlDirectory(workspaceRoot) {
|
|
18751
|
+
return join9(workspaceRoot ?? findWorkspaceRoot2(), "database", "migrations");
|
|
18752
|
+
}
|
|
18753
|
+
var init_workspace = () => {};
|
|
18754
|
+
|
|
18592
18755
|
// src/actions/migrate.ts
|
|
18593
18756
|
var exports_migrate = {};
|
|
18594
18757
|
__export(exports_migrate, {
|
|
@@ -18600,23 +18763,48 @@ __export(exports_migrate, {
|
|
|
18600
18763
|
copyModelsToGenerated: () => copyModelsToGenerated,
|
|
18601
18764
|
clearGeneratedDirectory: () => clearGeneratedDirectory
|
|
18602
18765
|
});
|
|
18603
|
-
import { existsSync as
|
|
18766
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
|
|
18604
18767
|
import { tmpdir } from "os";
|
|
18605
|
-
import { join as
|
|
18768
|
+
import { join as join10 } from "path";
|
|
18606
18769
|
import process25 from "process";
|
|
18770
|
+
async function settleAppliedFiles(qb, dialect, files) {
|
|
18771
|
+
if (files.length === 0)
|
|
18772
|
+
return;
|
|
18773
|
+
const sqlDir = ensureSqlDirectory(getWorkspaceRoot());
|
|
18774
|
+
try {
|
|
18775
|
+
await createMigrationsTable(qb, dialect);
|
|
18776
|
+
for (const file2 of files) {
|
|
18777
|
+
await recordMigration(qb, file2, dialect);
|
|
18778
|
+
info(`-- \u2713 Recorded applied migration: ${file2}`);
|
|
18779
|
+
}
|
|
18780
|
+
} catch (err) {
|
|
18781
|
+
info(`-- Could not record applied migrations (the schema change itself succeeded): ${err instanceof Error ? err.message : String(err)}`);
|
|
18782
|
+
}
|
|
18783
|
+
}
|
|
18784
|
+
function isGeneratedMigration(sqlDir, file2) {
|
|
18785
|
+
try {
|
|
18786
|
+
return isGeneratedMigrationSql(readFileSync3(join10(sqlDir, file2), "utf8"));
|
|
18787
|
+
} catch {
|
|
18788
|
+
return false;
|
|
18789
|
+
}
|
|
18790
|
+
}
|
|
18791
|
+
function isAlreadyAppliedError(err) {
|
|
18792
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18793
|
+
return /duplicate column name/i.test(message) || /duplicate key name/i.test(message) || /\balready exists\b/i.test(message);
|
|
18794
|
+
}
|
|
18607
18795
|
function info(message) {
|
|
18608
18796
|
if (config5.verbose)
|
|
18609
18797
|
console.log(message);
|
|
18610
18798
|
}
|
|
18611
18799
|
function getSnapshotDir(workspaceRoot) {
|
|
18612
|
-
return
|
|
18800
|
+
return join10(workspaceRoot, config5.snapshotDir || ".qb");
|
|
18613
18801
|
}
|
|
18614
18802
|
function getSnapshotPath(workspaceRoot, dialect) {
|
|
18615
|
-
return
|
|
18803
|
+
return join10(getSnapshotDir(workspaceRoot), `model-snapshot.${dialect}.json`);
|
|
18616
18804
|
}
|
|
18617
18805
|
function loadPlanSnapshot(workspaceRoot, dialect) {
|
|
18618
18806
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18619
|
-
if (!
|
|
18807
|
+
if (!existsSync17(snapshotPath)) {
|
|
18620
18808
|
return;
|
|
18621
18809
|
}
|
|
18622
18810
|
try {
|
|
@@ -18639,7 +18827,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18639
18827
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18640
18828
|
const snapshotDir = getSnapshotDir(workspaceRoot);
|
|
18641
18829
|
const hash = hashMigrationPlan(plan);
|
|
18642
|
-
if (
|
|
18830
|
+
if (existsSync17(snapshotPath)) {
|
|
18643
18831
|
try {
|
|
18644
18832
|
const current = JSON.parse(readFileSync3(snapshotPath, "utf8"));
|
|
18645
18833
|
if (current?.hash === hash && current?.dialect === dialect && current?.plan) {
|
|
@@ -18648,7 +18836,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18648
18836
|
}
|
|
18649
18837
|
} catch {}
|
|
18650
18838
|
}
|
|
18651
|
-
if (!
|
|
18839
|
+
if (!existsSync17(snapshotDir)) {
|
|
18652
18840
|
mkdirSync8(snapshotDir, { recursive: true });
|
|
18653
18841
|
info(`-- Created snapshot directory: ${snapshotDir}`);
|
|
18654
18842
|
}
|
|
@@ -18666,11 +18854,11 @@ function saveMigrationSnapshot(plan, options = {}) {
|
|
|
18666
18854
|
savePlanSnapshot(options.workspaceRoot ?? getWorkspaceRoot(), dialect, plan);
|
|
18667
18855
|
}
|
|
18668
18856
|
function getWorkspaceRoot() {
|
|
18669
|
-
return
|
|
18857
|
+
return findWorkspaceRoot2();
|
|
18670
18858
|
}
|
|
18671
18859
|
function ensureSqlDirectory(workspaceRoot) {
|
|
18672
18860
|
const sqlDir = getSqlDirectory(workspaceRoot);
|
|
18673
|
-
if (!
|
|
18861
|
+
if (!existsSync17(sqlDir)) {
|
|
18674
18862
|
mkdirSync8(sqlDir, { recursive: true });
|
|
18675
18863
|
info(`-- Created SQL directory: ${sqlDir}`);
|
|
18676
18864
|
}
|
|
@@ -18679,21 +18867,22 @@ function ensureSqlDirectory(workspaceRoot) {
|
|
|
18679
18867
|
async function generateMigration(dir, opts = {}) {
|
|
18680
18868
|
await getConfig();
|
|
18681
18869
|
if (!dir) {
|
|
18682
|
-
dir =
|
|
18870
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18683
18871
|
}
|
|
18684
18872
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18685
18873
|
const workspaceRoot = getWorkspaceRoot();
|
|
18686
18874
|
const models = await loadModels({ modelsDir: dir });
|
|
18687
18875
|
const plan = buildMigrationPlan2(models, { dialect });
|
|
18688
18876
|
let previous;
|
|
18877
|
+
let reconciledFromDatabase = false;
|
|
18689
18878
|
if (!opts.full) {
|
|
18690
18879
|
previous = loadPlanSnapshot(workspaceRoot, dialect);
|
|
18691
18880
|
if (previous) {
|
|
18692
18881
|
info("-- Comparing with stored model snapshot");
|
|
18693
18882
|
} else {
|
|
18694
|
-
const defaultStatePath =
|
|
18883
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18695
18884
|
const statePath = String(opts.state || defaultStatePath);
|
|
18696
|
-
if (
|
|
18885
|
+
if (existsSync17(statePath)) {
|
|
18697
18886
|
try {
|
|
18698
18887
|
const raw2 = readFileSync3(statePath, "utf8");
|
|
18699
18888
|
const parsed = JSON.parse(raw2);
|
|
@@ -18710,6 +18899,7 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18710
18899
|
const scoped = livePlan.tables.filter((t) => modelTables.has(t.table));
|
|
18711
18900
|
if (scoped.length > 0) {
|
|
18712
18901
|
previous = { dialect: livePlan.dialect, tables: scoped };
|
|
18902
|
+
reconciledFromDatabase = true;
|
|
18713
18903
|
info(`-- No snapshot; reconciling against live database (${scoped.length} matching table${scoped.length === 1 ? "" : "s"})`);
|
|
18714
18904
|
}
|
|
18715
18905
|
} catch (err) {
|
|
@@ -18723,25 +18913,34 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18723
18913
|
} else {
|
|
18724
18914
|
info("-- Full migration requested, ignoring any previous state");
|
|
18725
18915
|
}
|
|
18726
|
-
const diff = opts.full ? { statements: generateSql(plan, { dryRun: opts.dryRun }), operations: plan.tables.map((t) => ({ kind: "create_table", table: t.table, destructive: false, sql: "" })) } : generateDiffOperations(previous, plan, {
|
|
18916
|
+
const diff = opts.full ? { statements: generateSql(plan, { dryRun: opts.dryRun }), operations: plan.tables.map((t) => ({ kind: "create_table", table: t.table, destructive: false, sql: "" })) } : generateDiffOperations(previous, plan, {
|
|
18917
|
+
applyRenames: opts.applyRenames,
|
|
18918
|
+
dryRun: opts.dryRun,
|
|
18919
|
+
preserveUnknownColumns: reconciledFromDatabase
|
|
18920
|
+
});
|
|
18727
18921
|
const sqlStatements = diff.statements;
|
|
18728
18922
|
const operations = diff.operations;
|
|
18729
18923
|
const sql = sqlStatements.join(`
|
|
18730
18924
|
`);
|
|
18731
18925
|
const hasChanges = sqlStatements.some((stmt) => /\b(?:CREATE|ALTER|DROP)\b/i.test(stmt));
|
|
18732
18926
|
if (opts.apply) {
|
|
18733
|
-
const dirPath = mkdtempSync(
|
|
18734
|
-
const filePath =
|
|
18927
|
+
const dirPath = mkdtempSync(join10(tmpdir(), "qb-migrate-"));
|
|
18928
|
+
const filePath = join10(dirPath, "migration.sql");
|
|
18735
18929
|
try {
|
|
18736
18930
|
if (hasChanges) {
|
|
18737
18931
|
writeFileSync11(filePath, sql);
|
|
18932
|
+
const qb = createQueryBuilder();
|
|
18933
|
+
await qb.file(filePath);
|
|
18738
18934
|
info("-- Migration applied");
|
|
18935
|
+
await settleAppliedFiles(qb, dialect, lastCreatedMigrationFiles());
|
|
18739
18936
|
} else {
|
|
18740
18937
|
info("-- No changes; nothing to apply");
|
|
18741
18938
|
}
|
|
18742
18939
|
} catch (err) {
|
|
18743
18940
|
console.error("-- Migration failed:", err);
|
|
18744
18941
|
throw err;
|
|
18942
|
+
} finally {
|
|
18943
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
18745
18944
|
}
|
|
18746
18945
|
}
|
|
18747
18946
|
if (!opts.dryRun)
|
|
@@ -18750,9 +18949,6 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18750
18949
|
}
|
|
18751
18950
|
async function executeMigration(dir) {
|
|
18752
18951
|
await getConfig();
|
|
18753
|
-
if (!dir) {
|
|
18754
|
-
dir = join9(process25.cwd(), "app/Models");
|
|
18755
|
-
}
|
|
18756
18952
|
const workspaceRoot = getWorkspaceRoot();
|
|
18757
18953
|
const sqlDir = ensureSqlDirectory(workspaceRoot);
|
|
18758
18954
|
const dialect = config5.dialect || "postgres";
|
|
@@ -18767,42 +18963,25 @@ async function executeMigration(dir) {
|
|
|
18767
18963
|
const qb = createQueryBuilder();
|
|
18768
18964
|
await createMigrationsTable(qb, dialect);
|
|
18769
18965
|
const executedMigrations = await getExecutedMigrations(qb, dialect);
|
|
18770
|
-
const
|
|
18771
|
-
|
|
18772
|
-
for (const file2 of scriptFiles) {
|
|
18773
|
-
if (file2.includes("alter-") && file2.includes("-table")) {
|
|
18774
|
-
transientMigrations.push(file2);
|
|
18775
|
-
} else if (!executedMigrations.includes(file2)) {
|
|
18776
|
-
permanentMigrations.push(file2);
|
|
18777
|
-
}
|
|
18778
|
-
}
|
|
18779
|
-
const totalPending = permanentMigrations.length + transientMigrations.length;
|
|
18780
|
-
if (totalPending === 0) {
|
|
18966
|
+
const pending = scriptFiles.filter((file2) => !executedMigrations.includes(file2));
|
|
18967
|
+
if (pending.length === 0) {
|
|
18781
18968
|
info("-- No pending migrations to execute");
|
|
18782
18969
|
return true;
|
|
18783
18970
|
}
|
|
18784
|
-
info(`-- Executing ${
|
|
18785
|
-
for (const file2 of
|
|
18786
|
-
const filePath =
|
|
18971
|
+
info(`-- Executing ${pending.length} migration${pending.length === 1 ? "" : "s"}`);
|
|
18972
|
+
for (const file2 of pending) {
|
|
18973
|
+
const filePath = join10(sqlDir, file2);
|
|
18787
18974
|
info(`-- Executing: ${file2}`);
|
|
18788
18975
|
try {
|
|
18789
18976
|
await qb.file(filePath);
|
|
18790
18977
|
await recordMigration(qb, file2, dialect);
|
|
18791
18978
|
info(`-- \u2713 Migration ${file2} executed and recorded`);
|
|
18792
18979
|
} catch (err) {
|
|
18793
|
-
|
|
18794
|
-
|
|
18795
|
-
|
|
18796
|
-
|
|
18797
|
-
|
|
18798
|
-
const filePath = join9(sqlDir, file2);
|
|
18799
|
-
info(`-- Executing: ${file2} (transient)`);
|
|
18800
|
-
try {
|
|
18801
|
-
await qb.file(filePath);
|
|
18802
|
-
info(`-- \u2713 Migration ${file2} executed (not recorded)`);
|
|
18803
|
-
unlinkSync(filePath);
|
|
18804
|
-
info(`-- \uD83D\uDDD1\uFE0F Deleted transient migration: ${file2}`);
|
|
18805
|
-
} catch (err) {
|
|
18980
|
+
if (isGeneratedMigration(sqlDir, file2) && isAlreadyAppliedError(err)) {
|
|
18981
|
+
await recordMigration(qb, file2, dialect);
|
|
18982
|
+
info(`-- \u2713 Migration ${file2} was already applied; recorded it (${err instanceof Error ? err.message : String(err)})`);
|
|
18983
|
+
continue;
|
|
18984
|
+
}
|
|
18806
18985
|
console.error(`-- \u2717 Migration ${file2} failed:`, err);
|
|
18807
18986
|
throw err;
|
|
18808
18987
|
}
|
|
@@ -18817,7 +18996,7 @@ async function executeMigration(dir) {
|
|
|
18817
18996
|
async function resetDatabase(dir, opts = {}) {
|
|
18818
18997
|
await getConfig();
|
|
18819
18998
|
if (!dir) {
|
|
18820
|
-
dir =
|
|
18999
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18821
19000
|
}
|
|
18822
19001
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18823
19002
|
const driver = getDialectDriver(dialect);
|
|
@@ -18914,42 +19093,50 @@ async function resetDatabase(dir, opts = {}) {
|
|
|
18914
19093
|
}
|
|
18915
19094
|
async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
|
|
18916
19095
|
if (!dir) {
|
|
18917
|
-
dir =
|
|
19096
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18918
19097
|
}
|
|
18919
19098
|
if (!workspaceRoot) {
|
|
18920
19099
|
workspaceRoot = getWorkspaceRoot();
|
|
18921
19100
|
}
|
|
18922
19101
|
const dialect = String(opts.dialect || config5.dialect || "postgres");
|
|
18923
19102
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18924
|
-
if (
|
|
19103
|
+
if (existsSync17(snapshotPath)) {
|
|
18925
19104
|
unlinkSync(snapshotPath);
|
|
18926
19105
|
info(`-- Removed model snapshot file: ${snapshotPath}`);
|
|
18927
19106
|
}
|
|
18928
|
-
const defaultStatePath =
|
|
19107
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18929
19108
|
const statePath = String(opts.state || defaultStatePath);
|
|
18930
|
-
if (
|
|
19109
|
+
if (existsSync17(statePath)) {
|
|
18931
19110
|
unlinkSync(statePath);
|
|
18932
19111
|
info(`-- Removed legacy migration state file: ${statePath}`);
|
|
18933
19112
|
}
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
18937
|
-
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
|
|
18941
|
-
|
|
19113
|
+
removeGeneratedMigrationFiles(getSqlDirectory(workspaceRoot));
|
|
19114
|
+
}
|
|
19115
|
+
function removeGeneratedMigrationFiles(sqlDir) {
|
|
19116
|
+
if (!existsSync17(sqlDir))
|
|
19117
|
+
return;
|
|
19118
|
+
let removed = 0;
|
|
19119
|
+
const kept = [];
|
|
19120
|
+
for (const file2 of readdirSync6(sqlDir).filter((f) => f.endsWith(".sql"))) {
|
|
19121
|
+
if (!isGeneratedMigration(sqlDir, file2)) {
|
|
19122
|
+
kept.push(file2);
|
|
19123
|
+
continue;
|
|
18942
19124
|
}
|
|
18943
|
-
|
|
19125
|
+
unlinkSync(join10(sqlDir, file2));
|
|
19126
|
+
info(`-- Removed generated migration file: ${file2}`);
|
|
19127
|
+
removed += 1;
|
|
18944
19128
|
}
|
|
19129
|
+
info(`-- Cleaned up ${removed} generated migration file${removed === 1 ? "" : "s"} from migrations directory`);
|
|
19130
|
+
if (kept.length > 0)
|
|
19131
|
+
info(`-- Kept ${kept.length} hand-written migration${kept.length === 1 ? "" : "s"}: ${kept.slice(0, 5).join(", ")}${kept.length > 5 ? `, +${kept.length - 5} more` : ""}`);
|
|
18945
19132
|
}
|
|
18946
19133
|
async function copyModelsToGenerated(_dir, _workspaceRoot) {}
|
|
18947
19134
|
async function clearGeneratedDirectory(workspaceRoot) {
|
|
18948
19135
|
if (!workspaceRoot) {
|
|
18949
19136
|
workspaceRoot = getWorkspaceRoot();
|
|
18950
19137
|
}
|
|
18951
|
-
const generatedDir =
|
|
18952
|
-
if (
|
|
19138
|
+
const generatedDir = join10(workspaceRoot, "generated");
|
|
19139
|
+
if (existsSync17(generatedDir)) {
|
|
18953
19140
|
try {
|
|
18954
19141
|
rmSync(generatedDir, { recursive: true, force: true });
|
|
18955
19142
|
info("-- Cleared generated directory");
|
|
@@ -18958,12 +19145,6 @@ async function clearGeneratedDirectory(workspaceRoot) {
|
|
|
18958
19145
|
}
|
|
18959
19146
|
}
|
|
18960
19147
|
}
|
|
18961
|
-
function getSqlDirectory(workspaceRoot) {
|
|
18962
|
-
if (!workspaceRoot) {
|
|
18963
|
-
workspaceRoot = getWorkspaceRoot();
|
|
18964
|
-
}
|
|
18965
|
-
return join9(workspaceRoot, "database", "migrations");
|
|
18966
|
-
}
|
|
18967
19148
|
async function createMigrationsTable(qb, dialect) {
|
|
18968
19149
|
const driver = getDialectDriver(dialect);
|
|
18969
19150
|
const createTableSql = driver.createMigrationsTable();
|
|
@@ -19002,6 +19183,7 @@ var init_migrate = __esm(() => {
|
|
|
19002
19183
|
init_drivers();
|
|
19003
19184
|
init_src2();
|
|
19004
19185
|
init_introspect_db();
|
|
19186
|
+
init_workspace();
|
|
19005
19187
|
});
|
|
19006
19188
|
|
|
19007
19189
|
// src/actions/migrate-generate.ts
|
|
@@ -19013,28 +19195,49 @@ var init_migrate_generate = __esm(() => {
|
|
|
19013
19195
|
});
|
|
19014
19196
|
|
|
19015
19197
|
// src/actions/migrate-rollback.ts
|
|
19016
|
-
import { existsSync as
|
|
19017
|
-
import {
|
|
19018
|
-
import process26 from "process";
|
|
19198
|
+
import { existsSync as existsSync18, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
19199
|
+
import { join as join11 } from "path";
|
|
19019
19200
|
function splitSqlStatements2(sql) {
|
|
19020
19201
|
const out = [];
|
|
19021
19202
|
let buf = "";
|
|
19022
|
-
let
|
|
19023
|
-
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19030
|
-
|
|
19031
|
-
|
|
19203
|
+
let quote = null;
|
|
19204
|
+
for (let i = 0;i < sql.length; i++) {
|
|
19205
|
+
const ch = sql[i];
|
|
19206
|
+
if (quote) {
|
|
19207
|
+
buf += ch;
|
|
19208
|
+
if (ch === quote) {
|
|
19209
|
+
if (sql[i + 1] === quote) {
|
|
19210
|
+
buf += sql[i + 1];
|
|
19211
|
+
i++;
|
|
19212
|
+
} else {
|
|
19213
|
+
quote = null;
|
|
19214
|
+
}
|
|
19215
|
+
}
|
|
19216
|
+
continue;
|
|
19217
|
+
}
|
|
19218
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
19219
|
+
quote = ch;
|
|
19220
|
+
buf += ch;
|
|
19221
|
+
continue;
|
|
19222
|
+
}
|
|
19223
|
+
if (ch === "-" && sql[i + 1] === "-") {
|
|
19224
|
+
const newline = sql.indexOf(`
|
|
19225
|
+
`, i);
|
|
19226
|
+
i = newline === -1 ? sql.length : newline;
|
|
19227
|
+
continue;
|
|
19228
|
+
}
|
|
19229
|
+
if (ch === "/" && sql[i + 1] === "*") {
|
|
19230
|
+
const close = sql.indexOf("*/", i + 2);
|
|
19231
|
+
i = close === -1 ? sql.length : close + 1;
|
|
19232
|
+
continue;
|
|
19233
|
+
}
|
|
19234
|
+
if (ch === ";") {
|
|
19032
19235
|
if (buf.trim())
|
|
19033
19236
|
out.push(buf.trim());
|
|
19034
19237
|
buf = "";
|
|
19035
|
-
|
|
19036
|
-
buf += ch;
|
|
19238
|
+
continue;
|
|
19037
19239
|
}
|
|
19240
|
+
buf += ch;
|
|
19038
19241
|
}
|
|
19039
19242
|
if (buf.trim())
|
|
19040
19243
|
out.push(buf.trim());
|
|
@@ -19048,8 +19251,20 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19048
19251
|
let m;
|
|
19049
19252
|
if (m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
|
|
19050
19253
|
down.push(`DROP TABLE IF EXISTS ${q(m[1])}`);
|
|
19051
|
-
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+
|
|
19052
|
-
|
|
19254
|
+
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+CONSTRAINT\s+["`']?(\w+)["`']?([\s\S]*)$/i.exec(stmt)) {
|
|
19255
|
+
if (dialect === "sqlite") {
|
|
19256
|
+
skipped.push(stmt);
|
|
19257
|
+
} else if (isMysqlLike(dialect) && /\bFOREIGN\s+KEY\b/i.test(m[3] ?? "")) {
|
|
19258
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP FOREIGN KEY ${q(m[2])}`);
|
|
19259
|
+
} else {
|
|
19260
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP CONSTRAINT ${q(m[2])}`);
|
|
19261
|
+
}
|
|
19262
|
+
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+["`']?(\w+)["`']?|["`'](\w+)["`']|(\w+))/i.exec(stmt)) {
|
|
19263
|
+
const column = m[2] ?? m[3] ?? m[4];
|
|
19264
|
+
if (m[4] && /^(?:PRIMARY|UNIQUE|INDEX|KEY|FOREIGN|CHECK|FULLTEXT|SPATIAL)$/i.test(m[4]))
|
|
19265
|
+
skipped.push(stmt);
|
|
19266
|
+
else
|
|
19267
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(column)}`);
|
|
19053
19268
|
} else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
|
|
19054
19269
|
down.push(isMysqlLike(dialect) && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
|
|
19055
19270
|
} else {
|
|
@@ -19058,22 +19273,6 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19058
19273
|
}
|
|
19059
19274
|
return { down: down.reverse(), skipped };
|
|
19060
19275
|
}
|
|
19061
|
-
function findWorkspaceRoot2(startPath) {
|
|
19062
|
-
let currentPath = startPath;
|
|
19063
|
-
while (currentPath !== dirname8(currentPath)) {
|
|
19064
|
-
if (existsSync17(join10(currentPath, "package.json"))) {
|
|
19065
|
-
return currentPath;
|
|
19066
|
-
}
|
|
19067
|
-
currentPath = dirname8(currentPath);
|
|
19068
|
-
}
|
|
19069
|
-
return process26.cwd();
|
|
19070
|
-
}
|
|
19071
|
-
function getSqlDirectory2(workspaceRoot) {
|
|
19072
|
-
if (!workspaceRoot) {
|
|
19073
|
-
workspaceRoot = findWorkspaceRoot2(process26.cwd());
|
|
19074
|
-
}
|
|
19075
|
-
return join10(workspaceRoot, "database", "migrations");
|
|
19076
|
-
}
|
|
19077
19276
|
async function migrateRollback(options = {}) {
|
|
19078
19277
|
const steps = options.steps || 1;
|
|
19079
19278
|
const reverseSchema = options.reverseSchema !== false;
|
|
@@ -19106,12 +19305,12 @@ async function migrateRollback(options = {}) {
|
|
|
19106
19305
|
console.log(` - ${migration.migration}`);
|
|
19107
19306
|
}
|
|
19108
19307
|
console.log();
|
|
19109
|
-
const sqlDir =
|
|
19308
|
+
const sqlDir = getSqlDirectory();
|
|
19110
19309
|
let reversedAny = false;
|
|
19111
19310
|
for (const migration of migrationsToRollback) {
|
|
19112
19311
|
try {
|
|
19113
|
-
const filePath =
|
|
19114
|
-
if (reverseSchema &&
|
|
19312
|
+
const filePath = join11(sqlDir, migration.migration);
|
|
19313
|
+
if (reverseSchema && existsSync18(filePath)) {
|
|
19115
19314
|
const forwardSql = readFileSync4(filePath, "utf8");
|
|
19116
19315
|
const { down, skipped } = deriveDownStatements(forwardSql);
|
|
19117
19316
|
for (const stmt of down) {
|
|
@@ -19122,10 +19321,10 @@ async function migrateRollback(options = {}) {
|
|
|
19122
19321
|
if (skipped.length > 0)
|
|
19123
19322
|
console.log(`-- \u26A0\uFE0F ${skipped.length} statement(s) in ${migration.migration} could not be auto-reversed (data/complex DDL) \u2014 reverse manually.`);
|
|
19124
19323
|
}
|
|
19125
|
-
const deleteSql = `DELETE FROM migrations WHERE migration = $1`;
|
|
19324
|
+
const deleteSql = `DELETE FROM migrations WHERE migration = ${getPlaceholder(1)}`;
|
|
19126
19325
|
await qb.unsafe(deleteSql, [migration.migration]);
|
|
19127
19326
|
console.log(`-- \u2713 Removed migration record: ${migration.migration}`);
|
|
19128
|
-
if (
|
|
19327
|
+
if (options.deleteFiles && existsSync18(filePath)) {
|
|
19129
19328
|
unlinkSync2(filePath);
|
|
19130
19329
|
console.log(`-- \uD83D\uDDD1\uFE0F Deleted migration file: ${migration.migration}`);
|
|
19131
19330
|
}
|
|
@@ -19148,37 +19347,20 @@ async function migrateRollback(options = {}) {
|
|
|
19148
19347
|
var init_migrate_rollback = __esm(() => {
|
|
19149
19348
|
init_config();
|
|
19150
19349
|
init_src2();
|
|
19350
|
+
init_workspace();
|
|
19151
19351
|
});
|
|
19152
19352
|
|
|
19153
19353
|
// src/actions/migrate-status.ts
|
|
19154
|
-
import { existsSync as
|
|
19155
|
-
import { dirname as dirname9, join as join11 } from "path";
|
|
19156
|
-
import process27 from "process";
|
|
19157
|
-
function findWorkspaceRoot3(startPath) {
|
|
19158
|
-
let currentPath = startPath;
|
|
19159
|
-
while (currentPath !== dirname9(currentPath)) {
|
|
19160
|
-
if (existsSync18(join11(currentPath, "package.json"))) {
|
|
19161
|
-
return currentPath;
|
|
19162
|
-
}
|
|
19163
|
-
currentPath = dirname9(currentPath);
|
|
19164
|
-
}
|
|
19165
|
-
return process27.cwd();
|
|
19166
|
-
}
|
|
19167
|
-
function getSqlDirectory3(workspaceRoot) {
|
|
19168
|
-
if (!workspaceRoot) {
|
|
19169
|
-
workspaceRoot = findWorkspaceRoot3(process27.cwd());
|
|
19170
|
-
}
|
|
19171
|
-
return join11(workspaceRoot, "database", "migrations");
|
|
19172
|
-
}
|
|
19354
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8 } from "fs";
|
|
19173
19355
|
async function migrateStatus() {
|
|
19174
19356
|
const dialect = config5.dialect || "postgres";
|
|
19175
19357
|
const driver = getDialectDriver(dialect);
|
|
19176
|
-
const sqlDir =
|
|
19358
|
+
const sqlDir = getSqlDirectory();
|
|
19177
19359
|
console.log("-- Migration Status");
|
|
19178
19360
|
console.log(`-- Dialect: ${dialect}`);
|
|
19179
19361
|
console.log(`-- SQL directory: ${sqlDir}`);
|
|
19180
19362
|
console.log();
|
|
19181
|
-
if (!
|
|
19363
|
+
if (!existsSync19(sqlDir)) {
|
|
19182
19364
|
console.log("-- No SQL directory found. No migrations have been created yet.");
|
|
19183
19365
|
return [];
|
|
19184
19366
|
}
|
|
@@ -19199,27 +19381,16 @@ async function migrateStatus() {
|
|
|
19199
19381
|
console.log();
|
|
19200
19382
|
}
|
|
19201
19383
|
const executedMap = new Map(executedMigrations.map((m) => [m.migration, m.executed_at]));
|
|
19202
|
-
const statuses = migrationFiles.map((file2) => {
|
|
19203
|
-
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
};
|
|
19208
|
-
}
|
|
19209
|
-
const executedAt = executedMap.get(file2);
|
|
19210
|
-
return {
|
|
19211
|
-
file: file2,
|
|
19212
|
-
status: executedAt ? "executed" : "pending",
|
|
19213
|
-
executedAt
|
|
19214
|
-
};
|
|
19215
|
-
});
|
|
19384
|
+
const statuses = migrationFiles.map((file2) => ({
|
|
19385
|
+
file: file2,
|
|
19386
|
+
status: executedMap.has(file2) ? "executed" : "pending",
|
|
19387
|
+
executedAt: executedMap.get(file2)
|
|
19388
|
+
}));
|
|
19216
19389
|
const executed = statuses.filter((s) => s.status === "executed");
|
|
19217
19390
|
const pending = statuses.filter((s) => s.status === "pending");
|
|
19218
|
-
const transient = statuses.filter((s) => s.status === "transient");
|
|
19219
19391
|
console.log(`-- Total migrations: ${migrationFiles.length}`);
|
|
19220
19392
|
console.log(`-- Executed: ${executed.length}`);
|
|
19221
19393
|
console.log(`-- Pending: ${pending.length}`);
|
|
19222
|
-
console.log(`-- Transient: ${transient.length}`);
|
|
19223
19394
|
console.log();
|
|
19224
19395
|
if (executed.length > 0) {
|
|
19225
19396
|
console.log("\u2713 Executed Migrations:");
|
|
@@ -19235,13 +19406,6 @@ async function migrateStatus() {
|
|
|
19235
19406
|
}
|
|
19236
19407
|
console.log();
|
|
19237
19408
|
}
|
|
19238
|
-
if (transient.length > 0) {
|
|
19239
|
-
console.log("\u26A1 Transient Migrations (ALTER TABLE - not tracked):");
|
|
19240
|
-
for (const migration of transient) {
|
|
19241
|
-
console.log(` - ${migration.file}`);
|
|
19242
|
-
}
|
|
19243
|
-
console.log();
|
|
19244
|
-
}
|
|
19245
19409
|
return statuses;
|
|
19246
19410
|
} catch (err) {
|
|
19247
19411
|
console.error("-- Failed to get migration status:", err);
|
|
@@ -19255,14 +19419,15 @@ var init_migrate_status = __esm(() => {
|
|
|
19255
19419
|
init_config();
|
|
19256
19420
|
init_drivers();
|
|
19257
19421
|
init_src2();
|
|
19422
|
+
init_workspace();
|
|
19258
19423
|
});
|
|
19259
19424
|
|
|
19260
19425
|
// src/actions/model-show.ts
|
|
19261
19426
|
import { readdirSync as readdirSync9 } from "fs";
|
|
19262
19427
|
import { extname as extname2, join as join12 } from "path";
|
|
19263
|
-
import
|
|
19428
|
+
import process26 from "process";
|
|
19264
19429
|
async function modelShow(modelName, options = {}) {
|
|
19265
|
-
const dir = options.dir || join12(
|
|
19430
|
+
const dir = options.dir || join12(process26.cwd(), "app/Models");
|
|
19266
19431
|
try {
|
|
19267
19432
|
const files = readdirSync9(dir);
|
|
19268
19433
|
const modelFile = files.find((f) => {
|
|
@@ -19476,9 +19641,9 @@ var init_query_explain_all = __esm(() => {
|
|
|
19476
19641
|
// src/actions/relation-diagram.ts
|
|
19477
19642
|
import { writeFileSync as writeFileSync12 } from "fs";
|
|
19478
19643
|
import { join as join14 } from "path";
|
|
19479
|
-
import
|
|
19644
|
+
import process27 from "process";
|
|
19480
19645
|
async function relationDiagram(options = {}) {
|
|
19481
|
-
const dir = options.dir || join14(
|
|
19646
|
+
const dir = options.dir || join14(process27.cwd(), "app/Models");
|
|
19482
19647
|
const format = options.format || "mermaid";
|
|
19483
19648
|
try {
|
|
19484
19649
|
const models = await loadModels({ modelsDir: dir });
|
|
@@ -19598,25 +19763,25 @@ var init_relation_diagram = __esm(() => {
|
|
|
19598
19763
|
});
|
|
19599
19764
|
|
|
19600
19765
|
// src/actions/seed.ts
|
|
19601
|
-
import { existsSync as
|
|
19766
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
|
|
19602
19767
|
import { dirname as dirname10, join as join15 } from "path";
|
|
19603
|
-
import
|
|
19604
|
-
function
|
|
19768
|
+
import process28 from "process";
|
|
19769
|
+
function findWorkspaceRoot3(startPath) {
|
|
19605
19770
|
let currentPath = startPath;
|
|
19606
19771
|
while (currentPath !== dirname10(currentPath)) {
|
|
19607
|
-
if (
|
|
19772
|
+
if (existsSync20(join15(currentPath, "package.json"))) {
|
|
19608
19773
|
return currentPath;
|
|
19609
19774
|
}
|
|
19610
19775
|
currentPath = dirname10(currentPath);
|
|
19611
19776
|
}
|
|
19612
|
-
return
|
|
19777
|
+
return process28.cwd();
|
|
19613
19778
|
}
|
|
19614
19779
|
async function loadSeeders(seedersDir) {
|
|
19615
|
-
if (!
|
|
19780
|
+
if (!existsSync20(seedersDir)) {
|
|
19616
19781
|
console.log(`-- Seeders directory not found: ${seedersDir}`);
|
|
19617
19782
|
return [];
|
|
19618
19783
|
}
|
|
19619
|
-
const files = readdirSync11(seedersDir);
|
|
19784
|
+
const files = readdirSync11(seedersDir).sort((a, b) => a.localeCompare(b));
|
|
19620
19785
|
const seederFiles = files.filter((file2) => (file2.endsWith(".ts") || file2.endsWith(".js")) && file2 !== "index.ts" && file2 !== "index.js");
|
|
19621
19786
|
const seeders = [];
|
|
19622
19787
|
for (const file2 of seederFiles) {
|
|
@@ -19629,6 +19794,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19629
19794
|
if (instance && typeof instance.run === "function") {
|
|
19630
19795
|
seeders.push({
|
|
19631
19796
|
name: file2.replace(/\.(ts|js)$/, ""),
|
|
19797
|
+
className: String(SeederClass.name || ""),
|
|
19632
19798
|
instance
|
|
19633
19799
|
});
|
|
19634
19800
|
}
|
|
@@ -19641,7 +19807,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19641
19807
|
return seeders;
|
|
19642
19808
|
}
|
|
19643
19809
|
async function runSeeders(config6 = {}) {
|
|
19644
|
-
const workspaceRoot =
|
|
19810
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19645
19811
|
const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19646
19812
|
const verbose = config6.verbose ?? true;
|
|
19647
19813
|
if (verbose) {
|
|
@@ -19676,17 +19842,18 @@ async function runSeeders(config6 = {}) {
|
|
|
19676
19842
|
}
|
|
19677
19843
|
}
|
|
19678
19844
|
async function runSeeder(className, options = {}) {
|
|
19679
|
-
const workspaceRoot =
|
|
19845
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19680
19846
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19681
19847
|
const verbose = options.verbose ?? true;
|
|
19682
19848
|
if (verbose) {
|
|
19683
19849
|
console.log(`-- Running seeder: ${className}`);
|
|
19684
19850
|
}
|
|
19685
19851
|
const seeders = await loadSeeders(seedersDir);
|
|
19686
|
-
const seeder = seeders.find((s) => s.name === className);
|
|
19852
|
+
const seeder = seeders.find((s) => s.className === className) ?? seeders.find((s) => s.name === className);
|
|
19687
19853
|
if (!seeder) {
|
|
19688
|
-
|
|
19689
|
-
|
|
19854
|
+
const known = seeders.map((s) => s.className || s.name).join(", ") || "none";
|
|
19855
|
+
console.error(`-- Seeder not found: ${className}. Available: ${known}`);
|
|
19856
|
+
throw new Error(`Seeder not found: ${className}. Available: ${known}`);
|
|
19690
19857
|
}
|
|
19691
19858
|
const qb = createQueryBuilder();
|
|
19692
19859
|
try {
|
|
@@ -19700,9 +19867,9 @@ async function runSeeder(className, options = {}) {
|
|
|
19700
19867
|
}
|
|
19701
19868
|
}
|
|
19702
19869
|
async function makeSeeder(name) {
|
|
19703
|
-
const workspaceRoot =
|
|
19870
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19704
19871
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19705
|
-
if (!
|
|
19872
|
+
if (!existsSync20(seedersDir)) {
|
|
19706
19873
|
mkdirSync9(seedersDir, { recursive: true });
|
|
19707
19874
|
console.log(`-- Created seeders directory: ${seedersDir}`);
|
|
19708
19875
|
}
|
|
@@ -19710,7 +19877,7 @@ async function makeSeeder(name) {
|
|
|
19710
19877
|
const className = `${baseName}Seeder`;
|
|
19711
19878
|
const fileName = `${className}.ts`;
|
|
19712
19879
|
const filePath = join15(seedersDir, fileName);
|
|
19713
|
-
if (
|
|
19880
|
+
if (existsSync20(filePath)) {
|
|
19714
19881
|
console.error(`-- Seeder already exists: ${filePath}`);
|
|
19715
19882
|
throw new Error(`Seeder already exists: ${filePath}`);
|
|
19716
19883
|
}
|
|
@@ -19764,7 +19931,7 @@ export default class ${className} extends Seeder {
|
|
|
19764
19931
|
console.log(`-- \u2713 Created seeder: ${filePath}`);
|
|
19765
19932
|
}
|
|
19766
19933
|
async function freshDatabase(options = {}) {
|
|
19767
|
-
const workspaceRoot =
|
|
19934
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19768
19935
|
const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
|
|
19769
19936
|
const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19770
19937
|
const verbose = options.verbose ?? true;
|
|
@@ -19824,22 +19991,22 @@ var init_unsafe = __esm(() => {
|
|
|
19824
19991
|
});
|
|
19825
19992
|
|
|
19826
19993
|
// src/actions/validate.ts
|
|
19827
|
-
import { existsSync as
|
|
19994
|
+
import { existsSync as existsSync21 } from "fs";
|
|
19828
19995
|
import { dirname as dirname11, join as join16 } from "path";
|
|
19829
|
-
import
|
|
19830
|
-
function
|
|
19996
|
+
import process29 from "process";
|
|
19997
|
+
function findWorkspaceRoot4(startPath) {
|
|
19831
19998
|
let currentPath = startPath;
|
|
19832
19999
|
while (currentPath !== dirname11(currentPath)) {
|
|
19833
|
-
if (
|
|
20000
|
+
if (existsSync21(join16(currentPath, "package.json"))) {
|
|
19834
20001
|
return currentPath;
|
|
19835
20002
|
}
|
|
19836
20003
|
currentPath = dirname11(currentPath);
|
|
19837
20004
|
}
|
|
19838
|
-
return
|
|
20005
|
+
return process29.cwd();
|
|
19839
20006
|
}
|
|
19840
20007
|
async function validateSchema(dir) {
|
|
19841
20008
|
if (!dir) {
|
|
19842
|
-
dir = join16(
|
|
20009
|
+
dir = join16(findWorkspaceRoot4(process29.cwd()), "app/Models");
|
|
19843
20010
|
}
|
|
19844
20011
|
const dialect = config5.dialect || "postgres";
|
|
19845
20012
|
console.log("-- Validating Schema");
|
|
@@ -25090,18 +25257,11 @@ function toSnakeCase(str) {
|
|
|
25090
25257
|
snakeCaseCache.set(str, cached);
|
|
25091
25258
|
return cached;
|
|
25092
25259
|
}
|
|
25093
|
-
function
|
|
25260
|
+
function toTableName2(modelName) {
|
|
25094
25261
|
let cached = tableNameCache.get(modelName);
|
|
25095
25262
|
if (cached !== undefined)
|
|
25096
25263
|
return cached;
|
|
25097
|
-
|
|
25098
|
-
if (snake.endsWith("y") && !snake.endsWith("ay") && !snake.endsWith("ey") && !snake.endsWith("oy") && !snake.endsWith("uy")) {
|
|
25099
|
-
cached = snake.slice(0, -1) + "ies";
|
|
25100
|
-
} else if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh")) {
|
|
25101
|
-
cached = `${snake}es`;
|
|
25102
|
-
} else {
|
|
25103
|
-
cached = `${snake}s`;
|
|
25104
|
-
}
|
|
25264
|
+
cached = toTableName(modelName);
|
|
25105
25265
|
tableNameCache.set(modelName, cached);
|
|
25106
25266
|
return cached;
|
|
25107
25267
|
}
|
|
@@ -25186,14 +25346,14 @@ function resolveRelation(definition, relationName) {
|
|
|
25186
25346
|
const hasManyModel = findModelName(definition.hasMany);
|
|
25187
25347
|
if (hasManyModel) {
|
|
25188
25348
|
const relatedModel = getModelFromRegistry(hasManyModel);
|
|
25189
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25349
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasManyModel);
|
|
25190
25350
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25191
25351
|
return { type: "hasMany", relatedModelName: hasManyModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25192
25352
|
}
|
|
25193
25353
|
const hasOneModel = findModelName(definition.hasOne);
|
|
25194
25354
|
if (hasOneModel) {
|
|
25195
25355
|
const relatedModel = getModelFromRegistry(hasOneModel);
|
|
25196
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25356
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasOneModel);
|
|
25197
25357
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25198
25358
|
return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25199
25359
|
}
|
|
@@ -25201,7 +25361,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25201
25361
|
if (belongsToEntry) {
|
|
25202
25362
|
const belongsToModel = belongsToEntry.model;
|
|
25203
25363
|
const relatedModel = getModelFromRegistry(belongsToModel);
|
|
25204
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25364
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(belongsToModel);
|
|
25205
25365
|
const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
|
|
25206
25366
|
const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
|
|
25207
25367
|
return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
|
|
@@ -25211,7 +25371,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25211
25371
|
const isConfig = typeof found.entry === "object";
|
|
25212
25372
|
const relatedModelName = isConfig ? found.entry.model : found.entry;
|
|
25213
25373
|
const relatedModel = getModelFromRegistry(relatedModelName);
|
|
25214
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25374
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(relatedModelName);
|
|
25215
25375
|
const config6 = isConfig ? found.entry : null;
|
|
25216
25376
|
let pivotTable;
|
|
25217
25377
|
let pivotModelName;
|
|
@@ -25223,7 +25383,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25223
25383
|
if (!throughModel) {
|
|
25224
25384
|
throw new Error(`[orm] belongsToMany relation '${relationName}' on '${parentName}' references unknown through model '${config6.through}'. Make sure '${config6.through}' is registered.`);
|
|
25225
25385
|
}
|
|
25226
|
-
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table ||
|
|
25386
|
+
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName2(config6.through);
|
|
25227
25387
|
} else {
|
|
25228
25388
|
const a2 = singularizeWord(parentTable);
|
|
25229
25389
|
const b2 = singularizeWord(relatedTable);
|
|
@@ -25274,10 +25434,10 @@ function resolveRelation(definition, relationName) {
|
|
|
25274
25434
|
return null;
|
|
25275
25435
|
const throughModel = getModelFromRegistry(throughModelName);
|
|
25276
25436
|
const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
|
|
25277
|
-
const throughTable = throughModel?.getTable?.() || throughDef?.table ||
|
|
25437
|
+
const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName2(throughModelName);
|
|
25278
25438
|
const throughPk = throughDef?.primaryKey || "id";
|
|
25279
25439
|
const targetModel = getModelFromRegistry(targetModelName);
|
|
25280
|
-
const targetTable = targetModel?.getTable?.() ||
|
|
25440
|
+
const targetTable = targetModel?.getTable?.() || toTableName2(targetModelName);
|
|
25281
25441
|
return {
|
|
25282
25442
|
type,
|
|
25283
25443
|
relatedModelName: targetModelName,
|
|
@@ -27874,7 +28034,7 @@ function buildDatabaseSchema(models) {
|
|
|
27874
28034
|
for (const modelName of Object.keys(models)) {
|
|
27875
28035
|
const rawModel = models[modelName];
|
|
27876
28036
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27877
|
-
const table =
|
|
28037
|
+
const table = tableNameFor(m2);
|
|
27878
28038
|
const attrs = m2.attributes ?? {};
|
|
27879
28039
|
const columns = {};
|
|
27880
28040
|
for (const key of Object.keys(attrs))
|
|
@@ -27886,30 +28046,53 @@ function buildDatabaseSchema(models) {
|
|
|
27886
28046
|
}
|
|
27887
28047
|
return schema;
|
|
27888
28048
|
}
|
|
28049
|
+
var init_factory = () => {};
|
|
27889
28050
|
|
|
27890
28051
|
// src/loader.ts
|
|
27891
|
-
import { readdirSync as readdirSync12
|
|
27892
|
-
import { basename, extname as extname4 } from "path";
|
|
27893
|
-
import
|
|
27894
|
-
|
|
27895
|
-
const
|
|
27896
|
-
|
|
27897
|
-
|
|
27898
|
-
const
|
|
28052
|
+
import { readdirSync as readdirSync12 } from "fs";
|
|
28053
|
+
import { basename, extname as extname4, isAbsolute as isAbsolute3, join as join17 } from "path";
|
|
28054
|
+
import process30 from "process";
|
|
28055
|
+
function isModelFile(name) {
|
|
28056
|
+
const ext = extname4(name);
|
|
28057
|
+
if (!MODEL_EXTENSIONS.has(ext))
|
|
28058
|
+
return false;
|
|
28059
|
+
const base = basename(name, ext);
|
|
28060
|
+
if (base.startsWith("_") || base === "index")
|
|
28061
|
+
return false;
|
|
28062
|
+
return !base.endsWith(".d");
|
|
28063
|
+
}
|
|
28064
|
+
function isModelDefinition(def) {
|
|
28065
|
+
if (!def || typeof def !== "object")
|
|
28066
|
+
return false;
|
|
28067
|
+
const d2 = def;
|
|
28068
|
+
return typeof d2.name === "string" || typeof d2.table === "string";
|
|
28069
|
+
}
|
|
28070
|
+
function collectModelFiles(dir) {
|
|
28071
|
+
const files = [];
|
|
28072
|
+
const entries = readdirSync12(dir, { withFileTypes: true }).sort((a2, b2) => a2.name.localeCompare(b2.name));
|
|
27899
28073
|
for (const entry of entries) {
|
|
27900
|
-
const full =
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
continue;
|
|
27904
|
-
const ext = extname4(full);
|
|
27905
|
-
if (![".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"].includes(ext))
|
|
28074
|
+
const full = join17(dir, entry.name);
|
|
28075
|
+
if (entry.isDirectory()) {
|
|
28076
|
+
files.push(...collectModelFiles(full));
|
|
27906
28077
|
continue;
|
|
28078
|
+
}
|
|
28079
|
+
if (isModelFile(entry.name))
|
|
28080
|
+
files.push(full);
|
|
28081
|
+
}
|
|
28082
|
+
return files;
|
|
28083
|
+
}
|
|
28084
|
+
async function loadModels(options) {
|
|
28085
|
+
const cwd = options.cwd ?? process30.cwd();
|
|
28086
|
+
const dir = isAbsolute3(options.modelsDir) ? options.modelsDir : join17(cwd, options.modelsDir);
|
|
28087
|
+
const result = {};
|
|
28088
|
+
for (const full of collectModelFiles(dir)) {
|
|
27907
28089
|
const cacheBuster = `?t=${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
27908
28090
|
const mod = await import(`${full}${cacheBuster}`);
|
|
27909
28091
|
const rawDef = mod.default ?? mod;
|
|
27910
28092
|
const def = rawDef.definition ?? rawDef.getDefinition?.() ?? rawDef;
|
|
27911
|
-
|
|
27912
|
-
|
|
28093
|
+
if (!isModelDefinition(def))
|
|
28094
|
+
continue;
|
|
28095
|
+
const name = def.name ?? basename(full, extname4(full));
|
|
27913
28096
|
result[name] = {
|
|
27914
28097
|
...def,
|
|
27915
28098
|
name
|
|
@@ -27917,7 +28100,10 @@ async function loadModels(options) {
|
|
|
27917
28100
|
}
|
|
27918
28101
|
return result;
|
|
27919
28102
|
}
|
|
27920
|
-
var
|
|
28103
|
+
var MODEL_EXTENSIONS;
|
|
28104
|
+
var init_loader = __esm(() => {
|
|
28105
|
+
MODEL_EXTENSIONS = new Set([".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"]);
|
|
28106
|
+
});
|
|
27921
28107
|
|
|
27922
28108
|
// src/meta.ts
|
|
27923
28109
|
function buildSchemaMeta(models) {
|
|
@@ -27929,7 +28115,7 @@ function buildSchemaMeta(models) {
|
|
|
27929
28115
|
for (const name of Object.keys(models)) {
|
|
27930
28116
|
const rawModel = models[name];
|
|
27931
28117
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27932
|
-
const table =
|
|
28118
|
+
const table = tableNameFor(m2);
|
|
27933
28119
|
modelToTable[name] = table;
|
|
27934
28120
|
tableToModel[table] = name;
|
|
27935
28121
|
primaryKeys[table] = m2.primaryKey ?? "id";
|
|
@@ -28003,9 +28189,9 @@ function buildSchemaMeta(models) {
|
|
|
28003
28189
|
var init_meta = () => {};
|
|
28004
28190
|
|
|
28005
28191
|
// src/migrations.ts
|
|
28006
|
-
import { existsSync as
|
|
28007
|
-
import { dirname as dirname12, join as
|
|
28008
|
-
import
|
|
28192
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10, readdirSync as readdirSync13, readFileSync as readFileSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
28193
|
+
import { dirname as dirname12, join as join18 } from "path";
|
|
28194
|
+
import process31 from "process";
|
|
28009
28195
|
function info2(message) {
|
|
28010
28196
|
if (config5.verbose)
|
|
28011
28197
|
console.log(message);
|
|
@@ -28016,36 +28202,80 @@ function snakeCase(str) {
|
|
|
28016
28202
|
function singularizeTable(table) {
|
|
28017
28203
|
return singularizerFor(config5.relations?.singularizeStrategy)(table);
|
|
28018
28204
|
}
|
|
28019
|
-
function
|
|
28205
|
+
function lastCreatedMigrationFiles() {
|
|
28206
|
+
return [...createdMigrationFiles];
|
|
28207
|
+
}
|
|
28208
|
+
function findWorkspaceRoot5(startPath) {
|
|
28020
28209
|
let currentPath = startPath;
|
|
28021
28210
|
while (currentPath !== dirname12(currentPath)) {
|
|
28022
|
-
if (
|
|
28211
|
+
if (existsSync23(join18(currentPath, "package.json"))) {
|
|
28023
28212
|
return currentPath;
|
|
28024
28213
|
}
|
|
28025
28214
|
currentPath = dirname12(currentPath);
|
|
28026
28215
|
}
|
|
28027
|
-
return
|
|
28216
|
+
return process31.cwd();
|
|
28028
28217
|
}
|
|
28029
28218
|
function ensureSqlDirectory2() {
|
|
28030
|
-
const workspaceRoot =
|
|
28031
|
-
const sqlDir =
|
|
28032
|
-
if (!
|
|
28219
|
+
const workspaceRoot = findWorkspaceRoot5(process31.cwd());
|
|
28220
|
+
const sqlDir = join18(workspaceRoot, "database", "migrations");
|
|
28221
|
+
if (!existsSync23(sqlDir)) {
|
|
28033
28222
|
mkdirSync10(sqlDir, { recursive: true });
|
|
28034
28223
|
info2(`-- Created SQL directory: ${sqlDir}`);
|
|
28035
28224
|
}
|
|
28036
28225
|
return sqlDir;
|
|
28037
28226
|
}
|
|
28227
|
+
function isGeneratedMigrationSql(sql2) {
|
|
28228
|
+
return sql2.trimStart().startsWith(GENERATED_MARKER);
|
|
28229
|
+
}
|
|
28230
|
+
function migrationBody(sql2) {
|
|
28231
|
+
return sql2.split(`
|
|
28232
|
+
`).filter((line) => !line.trimStart().startsWith("--")).join(`
|
|
28233
|
+
`).replace(/\s+/g, " ").trim().replace(/;+$/, "");
|
|
28234
|
+
}
|
|
28235
|
+
function existingMigrationBodies(sqlDir) {
|
|
28236
|
+
const bodies = new Set;
|
|
28237
|
+
let files;
|
|
28238
|
+
try {
|
|
28239
|
+
files = readdirSync13(sqlDir).filter((f2) => f2.endsWith(".sql"));
|
|
28240
|
+
} catch {
|
|
28241
|
+
return bodies;
|
|
28242
|
+
}
|
|
28243
|
+
for (const file2 of files) {
|
|
28244
|
+
try {
|
|
28245
|
+
bodies.add(migrationBody(readFileSync6(join18(sqlDir, file2), "utf8")));
|
|
28246
|
+
} catch {}
|
|
28247
|
+
}
|
|
28248
|
+
return bodies;
|
|
28249
|
+
}
|
|
28038
28250
|
function createMigrationFile(statement, fileName) {
|
|
28039
28251
|
if (!statement)
|
|
28040
28252
|
return false;
|
|
28041
28253
|
const sqlDir = ensureSqlDirectory2();
|
|
28254
|
+
if (existingCorpusBodies === null)
|
|
28255
|
+
existingCorpusBodies = existingMigrationBodies(sqlDir);
|
|
28256
|
+
const body = migrationBody(statement);
|
|
28257
|
+
if (body.length > 0 && existingCorpusBodies.has(body)) {
|
|
28258
|
+
info2(`-- Migration already in the corpus, not writing it again: ${fileName}`);
|
|
28259
|
+
return false;
|
|
28260
|
+
}
|
|
28042
28261
|
migrationCounter++;
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28262
|
+
let sequence = useDeterministicNames ? String(migrationCounter).padStart(10, "0") : String(Math.floor(Date.now() / 1000) + migrationCounter);
|
|
28263
|
+
let fullFileName = `${sequence}-${fileName}.sql`;
|
|
28264
|
+
if (!useDeterministicNames) {
|
|
28265
|
+
let next = Number(sequence);
|
|
28266
|
+
while (existsSync23(join18(sqlDir, fullFileName))) {
|
|
28267
|
+
next += 1;
|
|
28268
|
+
sequence = String(next);
|
|
28269
|
+
fullFileName = `${sequence}-${fileName}.sql`;
|
|
28270
|
+
}
|
|
28271
|
+
}
|
|
28272
|
+
const filePath = join18(sqlDir, fullFileName);
|
|
28273
|
+
writeFileSync14(filePath, `${GENERATED_MARKER}
|
|
28274
|
+
${statement}`);
|
|
28047
28275
|
info2(`-- Migration file created: ${fullFileName}`);
|
|
28048
28276
|
migrationsCreatedCount++;
|
|
28277
|
+
createdMigrationFiles.push(fullFileName);
|
|
28278
|
+
existingCorpusBodies?.add(body);
|
|
28049
28279
|
return true;
|
|
28050
28280
|
}
|
|
28051
28281
|
function guessTypeFromName(columnName) {
|
|
@@ -28220,7 +28450,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28220
28450
|
const tables = [];
|
|
28221
28451
|
for (const modelName of Object.keys(models)) {
|
|
28222
28452
|
const model = models[modelName];
|
|
28223
|
-
const table =
|
|
28453
|
+
const table = tableNameFor(model);
|
|
28224
28454
|
const primaryKey = model.primaryKey ?? "id";
|
|
28225
28455
|
const _autoIncrement = model.autoIncrement !== false;
|
|
28226
28456
|
const attrs = model.attributes ?? {};
|
|
@@ -28236,6 +28466,23 @@ function buildMigrationPlan2(models, options) {
|
|
|
28236
28466
|
hasDefault: false
|
|
28237
28467
|
});
|
|
28238
28468
|
}
|
|
28469
|
+
const declaredFkTargets = new Map;
|
|
28470
|
+
const declaresBelongsTo = normalizeRelationList(model.belongsTo).length > 0;
|
|
28471
|
+
const columnNames = new Set(Object.keys(attrs).map((name) => snakeCase(name)));
|
|
28472
|
+
const polymorphicColumns = new Set;
|
|
28473
|
+
for (const column of columnNames) {
|
|
28474
|
+
if (!column.endsWith("_type"))
|
|
28475
|
+
continue;
|
|
28476
|
+
const idColumn = `${column.slice(0, -"_type".length)}_id`;
|
|
28477
|
+
if (columnNames.has(idColumn))
|
|
28478
|
+
polymorphicColumns.add(idColumn);
|
|
28479
|
+
}
|
|
28480
|
+
for (const rel of normalizeRelationList(model.belongsTo)) {
|
|
28481
|
+
const column = rel.foreignKey ?? `${snakeCase(rel.model)}_id`;
|
|
28482
|
+
const table2 = meta.modelToTable[rel.model];
|
|
28483
|
+
if (table2)
|
|
28484
|
+
declaredFkTargets.set(column, table2);
|
|
28485
|
+
}
|
|
28239
28486
|
for (const attrName of Object.keys(attrs)) {
|
|
28240
28487
|
const attr = attrs[attrName];
|
|
28241
28488
|
const columnName = snakeCase(attrName);
|
|
@@ -28283,7 +28530,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28283
28530
|
enumValues,
|
|
28284
28531
|
maxLength: typeof maxLen === "number" && maxLen > 0 && maxLen <= 255 ? maxLen : undefined
|
|
28285
28532
|
};
|
|
28286
|
-
if (columnName.endsWith("_id") && attr.foreignKey !== false) {
|
|
28533
|
+
if (columnName.endsWith("_id") && attr.foreignKey !== false && !polymorphicColumns.has(columnName)) {
|
|
28287
28534
|
if (typeof attr.foreignKey === "object" && attr.foreignKey !== null) {
|
|
28288
28535
|
const fkConfig = attr.foreignKey;
|
|
28289
28536
|
col.references = {
|
|
@@ -28295,9 +28542,10 @@ function buildMigrationPlan2(models, options) {
|
|
|
28295
28542
|
if (fkConfig.nullable !== undefined)
|
|
28296
28543
|
col.isNullable = fkConfig.nullable;
|
|
28297
28544
|
} else {
|
|
28545
|
+
const declared = declaredFkTargets.get(columnName);
|
|
28298
28546
|
const base = columnName.replace(/_id$/, "");
|
|
28299
28547
|
const maybeModel = base.replace(/(^|_)([a-z])/g, (_2, __, c2) => c2.toUpperCase());
|
|
28300
|
-
const refTable = meta.modelToTable[maybeModel];
|
|
28548
|
+
const refTable = declared ?? (declaresBelongsTo ? undefined : meta.modelToTable[maybeModel]);
|
|
28301
28549
|
if (refTable) {
|
|
28302
28550
|
const refPk = meta.primaryKeys[refTable] ?? "id";
|
|
28303
28551
|
col.references = { table: refTable, column: refPk };
|
|
@@ -28312,9 +28560,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28312
28560
|
if (columns.some((c2) => c2.name === fkColumnName))
|
|
28313
28561
|
continue;
|
|
28314
28562
|
const refTable = meta.modelToTable[rel.model];
|
|
28315
|
-
|
|
28316
|
-
continue;
|
|
28317
|
-
const refPk = meta.primaryKeys[refTable] ?? "id";
|
|
28563
|
+
const refPk = refTable ? meta.primaryKeys[refTable] ?? "id" : undefined;
|
|
28318
28564
|
columns.push({
|
|
28319
28565
|
name: fkColumnName,
|
|
28320
28566
|
type: "bigint",
|
|
@@ -28322,7 +28568,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28322
28568
|
isUnique: false,
|
|
28323
28569
|
isNullable: true,
|
|
28324
28570
|
hasDefault: false,
|
|
28325
|
-
references: { table: refTable, column: refPk, onDelete: rel.onDelete }
|
|
28571
|
+
references: refTable && refPk && !polymorphicColumns.has(fkColumnName) ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
|
|
28326
28572
|
});
|
|
28327
28573
|
}
|
|
28328
28574
|
const traits = model.traits;
|
|
@@ -28403,7 +28649,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28403
28649
|
for (const modelName of Object.keys(models)) {
|
|
28404
28650
|
const model = models[modelName];
|
|
28405
28651
|
const traits = model?.traits ?? {};
|
|
28406
|
-
const modelTable =
|
|
28652
|
+
const modelTable = tableNameFor(model);
|
|
28407
28653
|
const singular = singularizeTable(modelTable);
|
|
28408
28654
|
if (traits.likeable) {
|
|
28409
28655
|
const opts = typeof traits.likeable === "object" ? traits.likeable : {};
|
|
@@ -28423,7 +28669,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28423
28669
|
}
|
|
28424
28670
|
if (traits.taggable) {
|
|
28425
28671
|
ensureTable({
|
|
28426
|
-
table: "
|
|
28672
|
+
table: "taggables",
|
|
28427
28673
|
columns: [
|
|
28428
28674
|
{ name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
|
|
28429
28675
|
{ name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
@@ -28431,37 +28677,61 @@ function buildMigrationPlan2(models, options) {
|
|
|
28431
28677
|
{ name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
|
|
28432
28678
|
{ name: "order", type: "integer", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: 0 },
|
|
28433
28679
|
{ name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
|
|
28680
|
+
{ name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
|
|
28681
|
+
{ name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28682
|
+
{ name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
|
|
28683
|
+
{ name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
|
|
28684
|
+
],
|
|
28685
|
+
indexes: [
|
|
28686
|
+
{ name: "taggables_target_index", columns: ["taggable_id", "taggable_type"], type: "index" },
|
|
28687
|
+
{ name: "taggables_type_slug_unique", columns: ["taggable_type", "slug"], type: "unique" }
|
|
28688
|
+
]
|
|
28689
|
+
});
|
|
28690
|
+
ensureTable({
|
|
28691
|
+
table: "taggable_models",
|
|
28692
|
+
columns: [
|
|
28693
|
+
{ name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
|
|
28694
|
+
{ name: "tag_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "taggables", column: "id" } },
|
|
28434
28695
|
{ name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28435
28696
|
{ name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28436
28697
|
{ name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
|
|
28437
28698
|
{ name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
|
|
28438
28699
|
],
|
|
28439
|
-
indexes: [
|
|
28700
|
+
indexes: [
|
|
28701
|
+
{ name: "taggable_models_owner_unique", columns: ["tag_id", "taggable_id", "taggable_type"], type: "unique" },
|
|
28702
|
+
{ name: "taggable_models_target_index", columns: ["taggable_id", "taggable_type"], type: "index" }
|
|
28703
|
+
]
|
|
28440
28704
|
});
|
|
28441
28705
|
}
|
|
28442
28706
|
if (traits.categorizable) {
|
|
28443
28707
|
ensureTable({
|
|
28444
|
-
table: "
|
|
28708
|
+
table: "categorizables",
|
|
28445
28709
|
columns: [
|
|
28446
28710
|
{ name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
|
|
28447
28711
|
{ name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28448
28712
|
{ name: "slug", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28449
28713
|
{ name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
|
|
28714
|
+
{ name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
|
|
28715
|
+
{ name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28450
28716
|
{ name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
|
|
28451
28717
|
{ name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
|
|
28452
28718
|
],
|
|
28453
|
-
indexes: [{ name: "
|
|
28719
|
+
indexes: [{ name: "categorizables_type_slug_unique", columns: ["categorizable_type", "slug"], type: "unique" }]
|
|
28454
28720
|
});
|
|
28455
28721
|
ensureTable({
|
|
28456
28722
|
table: "categorizable_models",
|
|
28457
28723
|
columns: [
|
|
28458
28724
|
{ name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
|
|
28459
|
-
{ name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "
|
|
28725
|
+
{ name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "categorizables", column: "id" } },
|
|
28460
28726
|
{ name: "categorizable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28461
28727
|
{ name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
|
|
28462
|
-
{ name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" }
|
|
28728
|
+
{ name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
|
|
28729
|
+
{ name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
|
|
28463
28730
|
],
|
|
28464
|
-
indexes: [
|
|
28731
|
+
indexes: [
|
|
28732
|
+
{ name: "categorizable_models_owner_unique", columns: ["category_id", "categorizable_id", "categorizable_type"], type: "unique" },
|
|
28733
|
+
{ name: "categorizable_models_target_index", columns: ["categorizable_id", "categorizable_type"], type: "index" }
|
|
28734
|
+
]
|
|
28465
28735
|
});
|
|
28466
28736
|
}
|
|
28467
28737
|
}
|
|
@@ -28470,7 +28740,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28470
28740
|
const btm = model?.belongsToMany;
|
|
28471
28741
|
if (!btm || typeof btm !== "object" || Array.isArray(btm))
|
|
28472
28742
|
continue;
|
|
28473
|
-
const parentTable =
|
|
28743
|
+
const parentTable = tableNameFor(model);
|
|
28474
28744
|
const parentSingular = singularizeTable(parentTable);
|
|
28475
28745
|
for (const [relKey, value] of Object.entries(btm)) {
|
|
28476
28746
|
const cfg = value;
|
|
@@ -28531,6 +28801,8 @@ function generateSql(plan, opts = {}) {
|
|
|
28531
28801
|
migrationCounter = 0;
|
|
28532
28802
|
migrationsCreatedCount = 0;
|
|
28533
28803
|
migrationsUpdatedCount = 0;
|
|
28804
|
+
createdMigrationFiles = [];
|
|
28805
|
+
existingCorpusBodies = null;
|
|
28534
28806
|
useDeterministicNames = true;
|
|
28535
28807
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28536
28808
|
const statements = [];
|
|
@@ -28792,12 +29064,13 @@ function referencesAreDifferent(r1, r2) {
|
|
|
28792
29064
|
const act = (a2) => (a2 ?? "no action").toLowerCase();
|
|
28793
29065
|
return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
|
|
28794
29066
|
}
|
|
28795
|
-
function
|
|
29067
|
+
function indexKey(index, table) {
|
|
29068
|
+
return `${index.type}:${qualifiedIndexName(table, index.name)}:${index.columns.join(",")}`;
|
|
29069
|
+
}
|
|
29070
|
+
function mapIndexesByKey(indexes, table) {
|
|
28796
29071
|
const map = {};
|
|
28797
|
-
for (const i2 of indexes)
|
|
28798
|
-
|
|
28799
|
-
map[key] = i2;
|
|
28800
|
-
}
|
|
29072
|
+
for (const i2 of indexes)
|
|
29073
|
+
map[indexKey(i2, table)] = i2;
|
|
28801
29074
|
return map;
|
|
28802
29075
|
}
|
|
28803
29076
|
function generateDiffOperations(previous, next, opts = {}) {
|
|
@@ -28812,10 +29085,13 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28812
29085
|
return { statements: statements2, operations: operations2 };
|
|
28813
29086
|
}
|
|
28814
29087
|
const applyRenames = opts.applyRenames !== false;
|
|
29088
|
+
const preserveUnknownColumns = opts.preserveUnknownColumns === true;
|
|
28815
29089
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28816
29090
|
migrationCounter = 0;
|
|
28817
29091
|
migrationsCreatedCount = 0;
|
|
28818
29092
|
migrationsUpdatedCount = 0;
|
|
29093
|
+
createdMigrationFiles = [];
|
|
29094
|
+
existingCorpusBodies = null;
|
|
28819
29095
|
useDeterministicNames = false;
|
|
28820
29096
|
const chunks = [];
|
|
28821
29097
|
const operations = [];
|
|
@@ -28894,42 +29170,52 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28894
29170
|
const prevCols = mapColumnsByName(prev.columns);
|
|
28895
29171
|
const currCols = mapColumnsByName(curr.columns);
|
|
28896
29172
|
for (const colName of Object.keys(currCols)) {
|
|
28897
|
-
|
|
28898
|
-
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
28902
|
-
|
|
28903
|
-
|
|
28904
|
-
|
|
28905
|
-
|
|
28906
|
-
|
|
28907
|
-
|
|
28908
|
-
|
|
28909
|
-
|
|
28910
|
-
}
|
|
29173
|
+
const c2 = currCols[colName];
|
|
29174
|
+
if (c2.type !== "enum" || !c2.enumValues || c2.enumValues.length === 0)
|
|
29175
|
+
continue;
|
|
29176
|
+
const enumTypeName = `${curr.table}_${c2.name}_type`;
|
|
29177
|
+
c2.enumTypeName = enumTypeName;
|
|
29178
|
+
if (prevCols[colName])
|
|
29179
|
+
continue;
|
|
29180
|
+
if (!enumTypes.has(enumTypeName)) {
|
|
29181
|
+
const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
|
|
29182
|
+
if (createEnumStatement) {
|
|
29183
|
+
chunks.push(createEnumStatement);
|
|
29184
|
+
operations.push({ kind: "create_enum", table: curr.table, column: c2.name, destructive: false, sql: createEnumStatement });
|
|
29185
|
+
emit(createEnumStatement, `create-${enumTypeName}-enum`);
|
|
28911
29186
|
}
|
|
29187
|
+
enumTypes.add(enumTypeName);
|
|
28912
29188
|
}
|
|
28913
29189
|
}
|
|
28914
29190
|
}
|
|
28915
29191
|
for (const tableName of Object.keys(nextTables)) {
|
|
28916
29192
|
const prev = prevTables[tableName];
|
|
28917
|
-
|
|
29193
|
+
let curr = nextTables[tableName];
|
|
28918
29194
|
if (!prev)
|
|
28919
29195
|
continue;
|
|
28920
29196
|
const prevCols = mapColumnsByName(prev.columns);
|
|
28921
|
-
const
|
|
28922
|
-
|
|
28923
|
-
|
|
29197
|
+
const prevIdx = mapIndexesByKey(prev.indexes, prev.table);
|
|
29198
|
+
let currCols = mapColumnsByName(curr.columns);
|
|
29199
|
+
let currIdx = mapIndexesByKey(curr.indexes, curr.table);
|
|
28924
29200
|
let renames = [];
|
|
28925
29201
|
let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
|
|
28926
29202
|
let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
|
|
28927
|
-
if (applyRenames) {
|
|
29203
|
+
if (applyRenames && !preserveUnknownColumns) {
|
|
28928
29204
|
const detected = detectColumnRenames(prevCols, currCols, dialect);
|
|
28929
29205
|
renames = detected.renames;
|
|
28930
29206
|
removedCols = detected.removed;
|
|
28931
29207
|
addedCols = detected.added;
|
|
28932
29208
|
}
|
|
29209
|
+
if (preserveUnknownColumns && removedCols.length > 0) {
|
|
29210
|
+
const preserved = removedCols.map((name) => prevCols[name]);
|
|
29211
|
+
const preservedNames = new Set(removedCols);
|
|
29212
|
+
const keptIndexes = prev.indexes.filter((idx) => idx.columns.some((c2) => preservedNames.has(c2)) && !currIdx[indexKey(idx)]);
|
|
29213
|
+
info2(`-- Keeping ${preserved.length} column(s) on "${curr.table}" no model declares: ${removedCols.join(", ")} \u2014 reconciled from the database, where an undeclared column is out of scope rather than removed`);
|
|
29214
|
+
curr = { ...curr, columns: [...curr.columns, ...preserved], indexes: [...curr.indexes, ...keptIndexes] };
|
|
29215
|
+
currCols = mapColumnsByName(curr.columns);
|
|
29216
|
+
currIdx = mapIndexesByKey(curr.indexes, curr.table);
|
|
29217
|
+
removedCols = [];
|
|
29218
|
+
}
|
|
28933
29219
|
const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
|
|
28934
29220
|
const fkChangedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && referencesAreDifferent(prevCols[n2].references, currCols[n2].references));
|
|
28935
29221
|
if (dialect === "sqlite") {
|
|
@@ -29077,11 +29363,13 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
29077
29363
|
function generateDiffSql(previous, next, opts = {}) {
|
|
29078
29364
|
return generateDiffOperations(previous, next, opts).statements;
|
|
29079
29365
|
}
|
|
29080
|
-
var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true;
|
|
29366
|
+
var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true, createdMigrationFiles, existingCorpusBodies = null, GENERATED_MARKER = "-- qb:generated";
|
|
29081
29367
|
var init_migrations = __esm(() => {
|
|
29082
29368
|
init_config();
|
|
29083
29369
|
init_drivers();
|
|
29370
|
+
init_sqlite();
|
|
29084
29371
|
init_meta();
|
|
29372
|
+
createdMigrationFiles = [];
|
|
29085
29373
|
});
|
|
29086
29374
|
|
|
29087
29375
|
// src/schema.ts
|
|
@@ -29115,6 +29403,7 @@ var init_src2 = __esm(() => {
|
|
|
29115
29403
|
init_dynamodb_single_table();
|
|
29116
29404
|
init_dynamodb_tooling_adapter();
|
|
29117
29405
|
init_dynamodb();
|
|
29406
|
+
init_factory();
|
|
29118
29407
|
init_loader();
|
|
29119
29408
|
init_meta();
|
|
29120
29409
|
init_migrations();
|
|
@@ -29130,9 +29419,11 @@ export {
|
|
|
29130
29419
|
validateSchema,
|
|
29131
29420
|
unsafe,
|
|
29132
29421
|
unmarshallItem,
|
|
29422
|
+
toTableName,
|
|
29133
29423
|
toModelInstance,
|
|
29134
29424
|
toDynamoDBItem,
|
|
29135
29425
|
tinker,
|
|
29426
|
+
tableNameFor,
|
|
29136
29427
|
tableInfo,
|
|
29137
29428
|
stripTrailingS,
|
|
29138
29429
|
startConsole,
|
|
@@ -29151,6 +29442,7 @@ export {
|
|
|
29151
29442
|
resolveSqlitePragmas,
|
|
29152
29443
|
resolvePivot,
|
|
29153
29444
|
resolveKeyPattern,
|
|
29445
|
+
resolveDialect,
|
|
29154
29446
|
resetDatabase,
|
|
29155
29447
|
resetConnection,
|
|
29156
29448
|
relationDiagram,
|
|
@@ -29163,6 +29455,7 @@ export {
|
|
|
29163
29455
|
dbOptimize as optimizeDatabase,
|
|
29164
29456
|
modelShow,
|
|
29165
29457
|
modelNameForTable,
|
|
29458
|
+
migrationBody,
|
|
29166
29459
|
migrateStatus,
|
|
29167
29460
|
migrateRollback,
|
|
29168
29461
|
migrateModels,
|
|
@@ -29172,8 +29465,10 @@ export {
|
|
|
29172
29465
|
makeSeeder,
|
|
29173
29466
|
makeModel,
|
|
29174
29467
|
loadModels,
|
|
29468
|
+
lastCreatedMigrationFiles,
|
|
29175
29469
|
iterateAllPivots,
|
|
29176
29470
|
isMysqlLike,
|
|
29471
|
+
isGeneratedMigrationSql,
|
|
29177
29472
|
isDefinitionEqual,
|
|
29178
29473
|
isBrowser,
|
|
29179
29474
|
introspectDatabase,
|
|
@@ -29268,6 +29563,7 @@ export {
|
|
|
29268
29563
|
MySQLDriver,
|
|
29269
29564
|
Model,
|
|
29270
29565
|
MIGRATIONS_TABLE,
|
|
29566
|
+
GENERATED_MARKER,
|
|
29271
29567
|
EntityQueryBuilder,
|
|
29272
29568
|
DynamoDBToolingAdapter,
|
|
29273
29569
|
DynamoDBQueryBuilder,
|