bun-query-builder 0.1.63 → 0.2.0
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/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 +405 -276
- package/dist/config.d.ts +13 -0
- package/dist/db.d.ts +12 -0
- package/dist/inflect.d.ts +17 -0
- package/dist/migrations.d.ts +26 -0
- package/dist/src/index.js +392 -260
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -11641,9 +11641,18 @@ var init_dist = __esm(() => {
|
|
|
11641
11641
|
});
|
|
11642
11642
|
|
|
11643
11643
|
// src/config.ts
|
|
11644
|
+
import process19 from "process";
|
|
11644
11645
|
function isMysqlLike(dialect = config5.dialect) {
|
|
11645
11646
|
return dialect === "mysql" || dialect === "singlestore";
|
|
11646
11647
|
}
|
|
11648
|
+
function resolveDialect(explicit) {
|
|
11649
|
+
if (explicit)
|
|
11650
|
+
return explicit;
|
|
11651
|
+
const fromEnv = process19.env.DB_DIALECT || process19.env.DB_CONNECTION;
|
|
11652
|
+
if (fromEnv)
|
|
11653
|
+
return fromEnv;
|
|
11654
|
+
return config5.dialect || "postgres";
|
|
11655
|
+
}
|
|
11647
11656
|
function getPlaceholder(index) {
|
|
11648
11657
|
if (config5.dialect === "postgres") {
|
|
11649
11658
|
return `$${index}`;
|
|
@@ -11802,7 +11811,7 @@ var {SQL } = globalThis.Bun;
|
|
|
11802
11811
|
import { Database } from "bun:sqlite";
|
|
11803
11812
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
11804
11813
|
import { dirname as dirname5 } from "path";
|
|
11805
|
-
import
|
|
11814
|
+
import process21 from "process";
|
|
11806
11815
|
|
|
11807
11816
|
class SQLiteWrapper {
|
|
11808
11817
|
db;
|
|
@@ -12080,9 +12089,13 @@ function sqliteFileFromUrl(url) {
|
|
|
12080
12089
|
const path = stripped.startsWith("///") ? stripped.slice(2) : stripped.startsWith("//") ? stripped.slice(2) : stripped;
|
|
12081
12090
|
return path || ":memory:";
|
|
12082
12091
|
}
|
|
12092
|
+
function resolveDatabaseName(dbConfig = config5.database) {
|
|
12093
|
+
const raw = process21.env.DB_DATABASE || dbConfig?.database || "";
|
|
12094
|
+
return String(raw).replace(/^['"]|['"]$/g, "");
|
|
12095
|
+
}
|
|
12083
12096
|
function createConnectionString(dialect, dbConfig) {
|
|
12084
|
-
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") &&
|
|
12085
|
-
const e =
|
|
12097
|
+
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process21.env.DB_CONNECTION === dialect) {
|
|
12098
|
+
const e = process21.env;
|
|
12086
12099
|
const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
|
|
12087
12100
|
const envUser = e.DB_USERNAME || dbConfig.username;
|
|
12088
12101
|
const envPass = e.DB_PASSWORD ?? dbConfig.password ?? "";
|
|
@@ -12096,7 +12109,7 @@ function createConnectionString(dialect, dbConfig) {
|
|
|
12096
12109
|
return dialect === "sqlite" ? sqliteFileFromUrl(dbConfig.url) : dbConfig.url;
|
|
12097
12110
|
}
|
|
12098
12111
|
const { database, username, password, host = "localhost", port, ssl } = dbConfig;
|
|
12099
|
-
const sslQ = ssl ||
|
|
12112
|
+
const sslQ = ssl || process21.env.DB_SSL === "true" || process21.env.DB_SSL === "1" ? "?ssl=true" : "";
|
|
12100
12113
|
switch (dialect) {
|
|
12101
12114
|
case "postgres":
|
|
12102
12115
|
return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
|
|
@@ -12370,6 +12383,17 @@ var init_benchmark = __esm(() => {
|
|
|
12370
12383
|
});
|
|
12371
12384
|
|
|
12372
12385
|
// src/inflect.ts
|
|
12386
|
+
function toTableName(modelName) {
|
|
12387
|
+
const snake = String(modelName).replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
12388
|
+
if (snake.endsWith("y") && !/[aeou]y$/.test(snake))
|
|
12389
|
+
return `${snake.slice(0, -1)}ies`;
|
|
12390
|
+
if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh"))
|
|
12391
|
+
return `${snake}es`;
|
|
12392
|
+
return `${snake}s`;
|
|
12393
|
+
}
|
|
12394
|
+
function tableNameFor(model) {
|
|
12395
|
+
return typeof model?.table === "string" && model.table.length > 0 ? model.table : toTableName(String(model?.name ?? ""));
|
|
12396
|
+
}
|
|
12373
12397
|
function stripTrailingS(name) {
|
|
12374
12398
|
return name.endsWith("s") ? name.slice(0, -1) : name;
|
|
12375
12399
|
}
|
|
@@ -16590,7 +16614,7 @@ var init_cache = __esm(() => {
|
|
|
16590
16614
|
});
|
|
16591
16615
|
|
|
16592
16616
|
// src/actions/console.ts
|
|
16593
|
-
import
|
|
16617
|
+
import process22 from "process";
|
|
16594
16618
|
import { createInterface } from "readline";
|
|
16595
16619
|
async function startConsole() {
|
|
16596
16620
|
console.log("-- Query Builder Interactive Console");
|
|
@@ -16599,8 +16623,8 @@ async function startConsole() {
|
|
|
16599
16623
|
console.log();
|
|
16600
16624
|
const qb = createQueryBuilder();
|
|
16601
16625
|
const rl = createInterface({
|
|
16602
|
-
input:
|
|
16603
|
-
output:
|
|
16626
|
+
input: process22.stdin,
|
|
16627
|
+
output: process22.stdout,
|
|
16604
16628
|
prompt: "qb> "
|
|
16605
16629
|
});
|
|
16606
16630
|
let multilineBuffer = "";
|
|
@@ -16651,7 +16675,7 @@ Tips:
|
|
|
16651
16675
|
if (cmd === ".exit" || cmd === ".quit") {
|
|
16652
16676
|
console.log("Goodbye!");
|
|
16653
16677
|
rl.close();
|
|
16654
|
-
|
|
16678
|
+
process22.exit(0);
|
|
16655
16679
|
} else if (cmd === ".help") {
|
|
16656
16680
|
console.log(helpText);
|
|
16657
16681
|
} else if (cmd === ".clear") {
|
|
@@ -16722,7 +16746,7 @@ Tips:
|
|
|
16722
16746
|
rl.on("close", () => {
|
|
16723
16747
|
console.log(`
|
|
16724
16748
|
Goodbye!`);
|
|
16725
|
-
|
|
16749
|
+
process22.exit(0);
|
|
16726
16750
|
});
|
|
16727
16751
|
rl.prompt();
|
|
16728
16752
|
}
|
|
@@ -17100,9 +17124,8 @@ var init_db_info = __esm(() => {
|
|
|
17100
17124
|
});
|
|
17101
17125
|
|
|
17102
17126
|
// src/actions/db-optimize.ts
|
|
17103
|
-
import process22 from "process";
|
|
17104
17127
|
async function dbOptimize(options = {}) {
|
|
17105
|
-
const dialect = options.dialect
|
|
17128
|
+
const dialect = resolveDialect(options.dialect);
|
|
17106
17129
|
const aggressive = options.aggressive || false;
|
|
17107
17130
|
if (options.verbose) {
|
|
17108
17131
|
console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
|
|
@@ -17142,7 +17165,7 @@ async function dbOptimize(options = {}) {
|
|
|
17142
17165
|
await bunSql`ANALYZE TABLE ${bunSql(table)}`;
|
|
17143
17166
|
}
|
|
17144
17167
|
} else {
|
|
17145
|
-
const dbName =
|
|
17168
|
+
const dbName = resolveDatabaseName();
|
|
17146
17169
|
const tables = await bunSql`
|
|
17147
17170
|
SELECT table_name
|
|
17148
17171
|
FROM information_schema.tables
|
|
@@ -17195,9 +17218,8 @@ var init_db_optimize = __esm(() => {
|
|
|
17195
17218
|
});
|
|
17196
17219
|
|
|
17197
17220
|
// src/actions/db-wipe.ts
|
|
17198
|
-
import process23 from "process";
|
|
17199
17221
|
async function dbWipe(options = {}) {
|
|
17200
|
-
const dialect = options.dialect
|
|
17222
|
+
const dialect = resolveDialect(options.dialect);
|
|
17201
17223
|
if (options.verbose) {
|
|
17202
17224
|
console.log(`Wiping all tables from ${dialect} database...`);
|
|
17203
17225
|
}
|
|
@@ -17211,7 +17233,7 @@ async function dbWipe(options = {}) {
|
|
|
17211
17233
|
`;
|
|
17212
17234
|
tables = result.map((row) => row.tablename);
|
|
17213
17235
|
} else if (isMysqlLike(dialect)) {
|
|
17214
|
-
const dbName =
|
|
17236
|
+
const dbName = resolveDatabaseName();
|
|
17215
17237
|
const result = await bunSql`
|
|
17216
17238
|
SELECT table_name
|
|
17217
17239
|
FROM information_schema.tables
|
|
@@ -17648,6 +17670,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17648
17670
|
return "decimal";
|
|
17649
17671
|
if (base === "date")
|
|
17650
17672
|
return "date";
|
|
17673
|
+
if (base === "timestamptz" || /\bwith time zone\b/.test(t))
|
|
17674
|
+
return "timestamptz";
|
|
17651
17675
|
if (/^(?:timestamp|datetime)/.test(base))
|
|
17652
17676
|
return "datetime";
|
|
17653
17677
|
if (/^time/.test(base))
|
|
@@ -17903,7 +17927,7 @@ var init_introspect_db = __esm(() => {
|
|
|
17903
17927
|
// src/actions/make-model.ts
|
|
17904
17928
|
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10 } from "fs";
|
|
17905
17929
|
import { dirname as dirname7, join as join7 } from "path";
|
|
17906
|
-
import
|
|
17930
|
+
import process23 from "process";
|
|
17907
17931
|
function findWorkspaceRoot(startPath) {
|
|
17908
17932
|
let currentPath = startPath;
|
|
17909
17933
|
while (currentPath !== dirname7(currentPath)) {
|
|
@@ -17912,10 +17936,10 @@ function findWorkspaceRoot(startPath) {
|
|
|
17912
17936
|
}
|
|
17913
17937
|
currentPath = dirname7(currentPath);
|
|
17914
17938
|
}
|
|
17915
|
-
return
|
|
17939
|
+
return process23.cwd();
|
|
17916
17940
|
}
|
|
17917
17941
|
async function makeModel(name, options = {}) {
|
|
17918
|
-
const workspaceRoot = findWorkspaceRoot(
|
|
17942
|
+
const workspaceRoot = findWorkspaceRoot(process23.cwd());
|
|
17919
17943
|
const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
|
|
17920
17944
|
if (!existsSync14(modelsDir)) {
|
|
17921
17945
|
mkdirSync7(modelsDir, { recursive: true });
|
|
@@ -18111,7 +18135,7 @@ class MySQLDriver {
|
|
|
18111
18135
|
)`;
|
|
18112
18136
|
}
|
|
18113
18137
|
getExecutedMigrationsQuery() {
|
|
18114
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18138
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18115
18139
|
}
|
|
18116
18140
|
recordMigrationQuery() {
|
|
18117
18141
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18292,7 +18316,7 @@ class PostgresDriver {
|
|
|
18292
18316
|
)`;
|
|
18293
18317
|
}
|
|
18294
18318
|
getExecutedMigrationsQuery() {
|
|
18295
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18319
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18296
18320
|
}
|
|
18297
18321
|
recordMigrationQuery() {
|
|
18298
18322
|
return "INSERT INTO migrations (migration) VALUES ($1)";
|
|
@@ -18537,7 +18561,7 @@ class SQLiteDriver {
|
|
|
18537
18561
|
)`;
|
|
18538
18562
|
}
|
|
18539
18563
|
getExecutedMigrationsQuery() {
|
|
18540
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18564
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18541
18565
|
}
|
|
18542
18566
|
recordMigrationQuery() {
|
|
18543
18567
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18590,6 +18614,24 @@ var init_drivers = __esm(() => {
|
|
|
18590
18614
|
init_singlestore();
|
|
18591
18615
|
});
|
|
18592
18616
|
|
|
18617
|
+
// src/workspace.ts
|
|
18618
|
+
import { existsSync as existsSync16 } from "fs";
|
|
18619
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
18620
|
+
import process24 from "process";
|
|
18621
|
+
function findWorkspaceRoot2(startPath = process24.cwd()) {
|
|
18622
|
+
let currentPath = startPath;
|
|
18623
|
+
while (currentPath !== dirname8(currentPath)) {
|
|
18624
|
+
if (existsSync16(join9(currentPath, "package.json")))
|
|
18625
|
+
return currentPath;
|
|
18626
|
+
currentPath = dirname8(currentPath);
|
|
18627
|
+
}
|
|
18628
|
+
return process24.cwd();
|
|
18629
|
+
}
|
|
18630
|
+
function getSqlDirectory(workspaceRoot) {
|
|
18631
|
+
return join9(workspaceRoot ?? findWorkspaceRoot2(), "database", "migrations");
|
|
18632
|
+
}
|
|
18633
|
+
var init_workspace = () => {};
|
|
18634
|
+
|
|
18593
18635
|
// src/actions/migrate.ts
|
|
18594
18636
|
var exports_migrate = {};
|
|
18595
18637
|
__export(exports_migrate, {
|
|
@@ -18601,23 +18643,48 @@ __export(exports_migrate, {
|
|
|
18601
18643
|
copyModelsToGenerated: () => copyModelsToGenerated,
|
|
18602
18644
|
clearGeneratedDirectory: () => clearGeneratedDirectory
|
|
18603
18645
|
});
|
|
18604
|
-
import { existsSync as
|
|
18646
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
|
|
18605
18647
|
import { tmpdir } from "os";
|
|
18606
|
-
import { join as
|
|
18648
|
+
import { join as join10 } from "path";
|
|
18607
18649
|
import process25 from "process";
|
|
18650
|
+
async function settleAppliedFiles(qb, dialect, files) {
|
|
18651
|
+
if (files.length === 0)
|
|
18652
|
+
return;
|
|
18653
|
+
const sqlDir = ensureSqlDirectory(getWorkspaceRoot());
|
|
18654
|
+
try {
|
|
18655
|
+
await createMigrationsTable(qb, dialect);
|
|
18656
|
+
for (const file2 of files) {
|
|
18657
|
+
await recordMigration(qb, file2, dialect);
|
|
18658
|
+
info(`-- \u2713 Recorded applied migration: ${file2}`);
|
|
18659
|
+
}
|
|
18660
|
+
} catch (err) {
|
|
18661
|
+
info(`-- Could not record applied migrations (the schema change itself succeeded): ${err instanceof Error ? err.message : String(err)}`);
|
|
18662
|
+
}
|
|
18663
|
+
}
|
|
18664
|
+
function isGeneratedMigration(sqlDir, file2) {
|
|
18665
|
+
try {
|
|
18666
|
+
return isGeneratedMigrationSql(readFileSync3(join10(sqlDir, file2), "utf8"));
|
|
18667
|
+
} catch {
|
|
18668
|
+
return false;
|
|
18669
|
+
}
|
|
18670
|
+
}
|
|
18671
|
+
function isAlreadyAppliedError(err) {
|
|
18672
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18673
|
+
return /duplicate column name/i.test(message) || /duplicate key name/i.test(message) || /\balready exists\b/i.test(message);
|
|
18674
|
+
}
|
|
18608
18675
|
function info(message) {
|
|
18609
18676
|
if (config5.verbose)
|
|
18610
18677
|
console.log(message);
|
|
18611
18678
|
}
|
|
18612
18679
|
function getSnapshotDir(workspaceRoot) {
|
|
18613
|
-
return
|
|
18680
|
+
return join10(workspaceRoot, config5.snapshotDir || ".qb");
|
|
18614
18681
|
}
|
|
18615
18682
|
function getSnapshotPath(workspaceRoot, dialect) {
|
|
18616
|
-
return
|
|
18683
|
+
return join10(getSnapshotDir(workspaceRoot), `model-snapshot.${dialect}.json`);
|
|
18617
18684
|
}
|
|
18618
18685
|
function loadPlanSnapshot(workspaceRoot, dialect) {
|
|
18619
18686
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18620
|
-
if (!
|
|
18687
|
+
if (!existsSync17(snapshotPath)) {
|
|
18621
18688
|
return;
|
|
18622
18689
|
}
|
|
18623
18690
|
try {
|
|
@@ -18640,7 +18707,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18640
18707
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18641
18708
|
const snapshotDir = getSnapshotDir(workspaceRoot);
|
|
18642
18709
|
const hash = hashMigrationPlan(plan);
|
|
18643
|
-
if (
|
|
18710
|
+
if (existsSync17(snapshotPath)) {
|
|
18644
18711
|
try {
|
|
18645
18712
|
const current = JSON.parse(readFileSync3(snapshotPath, "utf8"));
|
|
18646
18713
|
if (current?.hash === hash && current?.dialect === dialect && current?.plan) {
|
|
@@ -18649,7 +18716,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18649
18716
|
}
|
|
18650
18717
|
} catch {}
|
|
18651
18718
|
}
|
|
18652
|
-
if (!
|
|
18719
|
+
if (!existsSync17(snapshotDir)) {
|
|
18653
18720
|
mkdirSync8(snapshotDir, { recursive: true });
|
|
18654
18721
|
info(`-- Created snapshot directory: ${snapshotDir}`);
|
|
18655
18722
|
}
|
|
@@ -18667,11 +18734,11 @@ function saveMigrationSnapshot(plan, options = {}) {
|
|
|
18667
18734
|
savePlanSnapshot(options.workspaceRoot ?? getWorkspaceRoot(), dialect, plan);
|
|
18668
18735
|
}
|
|
18669
18736
|
function getWorkspaceRoot() {
|
|
18670
|
-
return
|
|
18737
|
+
return findWorkspaceRoot2();
|
|
18671
18738
|
}
|
|
18672
18739
|
function ensureSqlDirectory(workspaceRoot) {
|
|
18673
18740
|
const sqlDir = getSqlDirectory(workspaceRoot);
|
|
18674
|
-
if (!
|
|
18741
|
+
if (!existsSync17(sqlDir)) {
|
|
18675
18742
|
mkdirSync8(sqlDir, { recursive: true });
|
|
18676
18743
|
info(`-- Created SQL directory: ${sqlDir}`);
|
|
18677
18744
|
}
|
|
@@ -18680,21 +18747,22 @@ function ensureSqlDirectory(workspaceRoot) {
|
|
|
18680
18747
|
async function generateMigration(dir, opts = {}) {
|
|
18681
18748
|
await getConfig();
|
|
18682
18749
|
if (!dir) {
|
|
18683
|
-
dir =
|
|
18750
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18684
18751
|
}
|
|
18685
18752
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18686
18753
|
const workspaceRoot = getWorkspaceRoot();
|
|
18687
18754
|
const models = await loadModels({ modelsDir: dir });
|
|
18688
18755
|
const plan = buildMigrationPlan2(models, { dialect });
|
|
18689
18756
|
let previous;
|
|
18757
|
+
let reconciledFromDatabase = false;
|
|
18690
18758
|
if (!opts.full) {
|
|
18691
18759
|
previous = loadPlanSnapshot(workspaceRoot, dialect);
|
|
18692
18760
|
if (previous) {
|
|
18693
18761
|
info("-- Comparing with stored model snapshot");
|
|
18694
18762
|
} else {
|
|
18695
|
-
const defaultStatePath =
|
|
18763
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18696
18764
|
const statePath = String(opts.state || defaultStatePath);
|
|
18697
|
-
if (
|
|
18765
|
+
if (existsSync17(statePath)) {
|
|
18698
18766
|
try {
|
|
18699
18767
|
const raw2 = readFileSync3(statePath, "utf8");
|
|
18700
18768
|
const parsed = JSON.parse(raw2);
|
|
@@ -18711,6 +18779,7 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18711
18779
|
const scoped = livePlan.tables.filter((t) => modelTables.has(t.table));
|
|
18712
18780
|
if (scoped.length > 0) {
|
|
18713
18781
|
previous = { dialect: livePlan.dialect, tables: scoped };
|
|
18782
|
+
reconciledFromDatabase = true;
|
|
18714
18783
|
info(`-- No snapshot; reconciling against live database (${scoped.length} matching table${scoped.length === 1 ? "" : "s"})`);
|
|
18715
18784
|
}
|
|
18716
18785
|
} catch (err) {
|
|
@@ -18724,25 +18793,34 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18724
18793
|
} else {
|
|
18725
18794
|
info("-- Full migration requested, ignoring any previous state");
|
|
18726
18795
|
}
|
|
18727
|
-
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, {
|
|
18796
|
+
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, {
|
|
18797
|
+
applyRenames: opts.applyRenames,
|
|
18798
|
+
dryRun: opts.dryRun,
|
|
18799
|
+
preserveUnknownColumns: reconciledFromDatabase
|
|
18800
|
+
});
|
|
18728
18801
|
const sqlStatements = diff.statements;
|
|
18729
18802
|
const operations = diff.operations;
|
|
18730
18803
|
const sql = sqlStatements.join(`
|
|
18731
18804
|
`);
|
|
18732
18805
|
const hasChanges = sqlStatements.some((stmt) => /\b(?:CREATE|ALTER|DROP)\b/i.test(stmt));
|
|
18733
18806
|
if (opts.apply) {
|
|
18734
|
-
const dirPath = mkdtempSync(
|
|
18735
|
-
const filePath =
|
|
18807
|
+
const dirPath = mkdtempSync(join10(tmpdir(), "qb-migrate-"));
|
|
18808
|
+
const filePath = join10(dirPath, "migration.sql");
|
|
18736
18809
|
try {
|
|
18737
18810
|
if (hasChanges) {
|
|
18738
18811
|
writeFileSync11(filePath, sql);
|
|
18812
|
+
const qb = createQueryBuilder();
|
|
18813
|
+
await qb.file(filePath);
|
|
18739
18814
|
info("-- Migration applied");
|
|
18815
|
+
await settleAppliedFiles(qb, dialect, lastCreatedMigrationFiles());
|
|
18740
18816
|
} else {
|
|
18741
18817
|
info("-- No changes; nothing to apply");
|
|
18742
18818
|
}
|
|
18743
18819
|
} catch (err) {
|
|
18744
18820
|
console.error("-- Migration failed:", err);
|
|
18745
18821
|
throw err;
|
|
18822
|
+
} finally {
|
|
18823
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
18746
18824
|
}
|
|
18747
18825
|
}
|
|
18748
18826
|
if (!opts.dryRun)
|
|
@@ -18751,9 +18829,6 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18751
18829
|
}
|
|
18752
18830
|
async function executeMigration(dir) {
|
|
18753
18831
|
await getConfig();
|
|
18754
|
-
if (!dir) {
|
|
18755
|
-
dir = join9(process25.cwd(), "app/Models");
|
|
18756
|
-
}
|
|
18757
18832
|
const workspaceRoot = getWorkspaceRoot();
|
|
18758
18833
|
const sqlDir = ensureSqlDirectory(workspaceRoot);
|
|
18759
18834
|
const dialect = config5.dialect || "postgres";
|
|
@@ -18768,42 +18843,25 @@ async function executeMigration(dir) {
|
|
|
18768
18843
|
const qb = createQueryBuilder();
|
|
18769
18844
|
await createMigrationsTable(qb, dialect);
|
|
18770
18845
|
const executedMigrations = await getExecutedMigrations(qb, dialect);
|
|
18771
|
-
const
|
|
18772
|
-
|
|
18773
|
-
for (const file2 of scriptFiles) {
|
|
18774
|
-
if (file2.includes("alter-") && file2.includes("-table")) {
|
|
18775
|
-
transientMigrations.push(file2);
|
|
18776
|
-
} else if (!executedMigrations.includes(file2)) {
|
|
18777
|
-
permanentMigrations.push(file2);
|
|
18778
|
-
}
|
|
18779
|
-
}
|
|
18780
|
-
const totalPending = permanentMigrations.length + transientMigrations.length;
|
|
18781
|
-
if (totalPending === 0) {
|
|
18846
|
+
const pending = scriptFiles.filter((file2) => !executedMigrations.includes(file2));
|
|
18847
|
+
if (pending.length === 0) {
|
|
18782
18848
|
info("-- No pending migrations to execute");
|
|
18783
18849
|
return true;
|
|
18784
18850
|
}
|
|
18785
|
-
info(`-- Executing ${
|
|
18786
|
-
for (const file2 of
|
|
18787
|
-
const filePath =
|
|
18851
|
+
info(`-- Executing ${pending.length} migration${pending.length === 1 ? "" : "s"}`);
|
|
18852
|
+
for (const file2 of pending) {
|
|
18853
|
+
const filePath = join10(sqlDir, file2);
|
|
18788
18854
|
info(`-- Executing: ${file2}`);
|
|
18789
18855
|
try {
|
|
18790
18856
|
await qb.file(filePath);
|
|
18791
18857
|
await recordMigration(qb, file2, dialect);
|
|
18792
18858
|
info(`-- \u2713 Migration ${file2} executed and recorded`);
|
|
18793
18859
|
} catch (err) {
|
|
18794
|
-
|
|
18795
|
-
|
|
18796
|
-
|
|
18797
|
-
|
|
18798
|
-
|
|
18799
|
-
const filePath = join9(sqlDir, file2);
|
|
18800
|
-
info(`-- Executing: ${file2} (transient)`);
|
|
18801
|
-
try {
|
|
18802
|
-
await qb.file(filePath);
|
|
18803
|
-
info(`-- \u2713 Migration ${file2} executed (not recorded)`);
|
|
18804
|
-
unlinkSync(filePath);
|
|
18805
|
-
info(`-- \uD83D\uDDD1\uFE0F Deleted transient migration: ${file2}`);
|
|
18806
|
-
} catch (err) {
|
|
18860
|
+
if (isGeneratedMigration(sqlDir, file2) && isAlreadyAppliedError(err)) {
|
|
18861
|
+
await recordMigration(qb, file2, dialect);
|
|
18862
|
+
info(`-- \u2713 Migration ${file2} was already applied; recorded it (${err instanceof Error ? err.message : String(err)})`);
|
|
18863
|
+
continue;
|
|
18864
|
+
}
|
|
18807
18865
|
console.error(`-- \u2717 Migration ${file2} failed:`, err);
|
|
18808
18866
|
throw err;
|
|
18809
18867
|
}
|
|
@@ -18818,7 +18876,7 @@ async function executeMigration(dir) {
|
|
|
18818
18876
|
async function resetDatabase(dir, opts = {}) {
|
|
18819
18877
|
await getConfig();
|
|
18820
18878
|
if (!dir) {
|
|
18821
|
-
dir =
|
|
18879
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18822
18880
|
}
|
|
18823
18881
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18824
18882
|
const driver = getDialectDriver(dialect);
|
|
@@ -18915,42 +18973,50 @@ async function resetDatabase(dir, opts = {}) {
|
|
|
18915
18973
|
}
|
|
18916
18974
|
async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
|
|
18917
18975
|
if (!dir) {
|
|
18918
|
-
dir =
|
|
18976
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18919
18977
|
}
|
|
18920
18978
|
if (!workspaceRoot) {
|
|
18921
18979
|
workspaceRoot = getWorkspaceRoot();
|
|
18922
18980
|
}
|
|
18923
18981
|
const dialect = String(opts.dialect || config5.dialect || "postgres");
|
|
18924
18982
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18925
|
-
if (
|
|
18983
|
+
if (existsSync17(snapshotPath)) {
|
|
18926
18984
|
unlinkSync(snapshotPath);
|
|
18927
18985
|
info(`-- Removed model snapshot file: ${snapshotPath}`);
|
|
18928
18986
|
}
|
|
18929
|
-
const defaultStatePath =
|
|
18987
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18930
18988
|
const statePath = String(opts.state || defaultStatePath);
|
|
18931
|
-
if (
|
|
18989
|
+
if (existsSync17(statePath)) {
|
|
18932
18990
|
unlinkSync(statePath);
|
|
18933
18991
|
info(`-- Removed legacy migration state file: ${statePath}`);
|
|
18934
18992
|
}
|
|
18935
|
-
|
|
18936
|
-
|
|
18937
|
-
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
|
|
18941
|
-
|
|
18942
|
-
|
|
18993
|
+
removeGeneratedMigrationFiles(getSqlDirectory(workspaceRoot));
|
|
18994
|
+
}
|
|
18995
|
+
function removeGeneratedMigrationFiles(sqlDir) {
|
|
18996
|
+
if (!existsSync17(sqlDir))
|
|
18997
|
+
return;
|
|
18998
|
+
let removed = 0;
|
|
18999
|
+
const kept = [];
|
|
19000
|
+
for (const file2 of readdirSync6(sqlDir).filter((f) => f.endsWith(".sql"))) {
|
|
19001
|
+
if (!isGeneratedMigration(sqlDir, file2)) {
|
|
19002
|
+
kept.push(file2);
|
|
19003
|
+
continue;
|
|
18943
19004
|
}
|
|
18944
|
-
|
|
19005
|
+
unlinkSync(join10(sqlDir, file2));
|
|
19006
|
+
info(`-- Removed generated migration file: ${file2}`);
|
|
19007
|
+
removed += 1;
|
|
18945
19008
|
}
|
|
19009
|
+
info(`-- Cleaned up ${removed} generated migration file${removed === 1 ? "" : "s"} from migrations directory`);
|
|
19010
|
+
if (kept.length > 0)
|
|
19011
|
+
info(`-- Kept ${kept.length} hand-written migration${kept.length === 1 ? "" : "s"}: ${kept.slice(0, 5).join(", ")}${kept.length > 5 ? `, +${kept.length - 5} more` : ""}`);
|
|
18946
19012
|
}
|
|
18947
19013
|
async function copyModelsToGenerated(_dir, _workspaceRoot) {}
|
|
18948
19014
|
async function clearGeneratedDirectory(workspaceRoot) {
|
|
18949
19015
|
if (!workspaceRoot) {
|
|
18950
19016
|
workspaceRoot = getWorkspaceRoot();
|
|
18951
19017
|
}
|
|
18952
|
-
const generatedDir =
|
|
18953
|
-
if (
|
|
19018
|
+
const generatedDir = join10(workspaceRoot, "generated");
|
|
19019
|
+
if (existsSync17(generatedDir)) {
|
|
18954
19020
|
try {
|
|
18955
19021
|
rmSync(generatedDir, { recursive: true, force: true });
|
|
18956
19022
|
info("-- Cleared generated directory");
|
|
@@ -18959,12 +19025,6 @@ async function clearGeneratedDirectory(workspaceRoot) {
|
|
|
18959
19025
|
}
|
|
18960
19026
|
}
|
|
18961
19027
|
}
|
|
18962
|
-
function getSqlDirectory(workspaceRoot) {
|
|
18963
|
-
if (!workspaceRoot) {
|
|
18964
|
-
workspaceRoot = getWorkspaceRoot();
|
|
18965
|
-
}
|
|
18966
|
-
return join9(workspaceRoot, "database", "migrations");
|
|
18967
|
-
}
|
|
18968
19028
|
async function createMigrationsTable(qb, dialect) {
|
|
18969
19029
|
const driver = getDialectDriver(dialect);
|
|
18970
19030
|
const createTableSql = driver.createMigrationsTable();
|
|
@@ -19003,6 +19063,7 @@ var init_migrate = __esm(() => {
|
|
|
19003
19063
|
init_drivers();
|
|
19004
19064
|
init_src2();
|
|
19005
19065
|
init_introspect_db();
|
|
19066
|
+
init_workspace();
|
|
19006
19067
|
});
|
|
19007
19068
|
|
|
19008
19069
|
// src/actions/migrate-generate.ts
|
|
@@ -19014,28 +19075,49 @@ var init_migrate_generate = __esm(() => {
|
|
|
19014
19075
|
});
|
|
19015
19076
|
|
|
19016
19077
|
// src/actions/migrate-rollback.ts
|
|
19017
|
-
import { existsSync as
|
|
19018
|
-
import {
|
|
19019
|
-
import process26 from "process";
|
|
19078
|
+
import { existsSync as existsSync18, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
19079
|
+
import { join as join11 } from "path";
|
|
19020
19080
|
function splitSqlStatements2(sql) {
|
|
19021
19081
|
const out = [];
|
|
19022
19082
|
let buf = "";
|
|
19023
|
-
let
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19030
|
-
|
|
19031
|
-
|
|
19032
|
-
|
|
19083
|
+
let quote = null;
|
|
19084
|
+
for (let i = 0;i < sql.length; i++) {
|
|
19085
|
+
const ch = sql[i];
|
|
19086
|
+
if (quote) {
|
|
19087
|
+
buf += ch;
|
|
19088
|
+
if (ch === quote) {
|
|
19089
|
+
if (sql[i + 1] === quote) {
|
|
19090
|
+
buf += sql[i + 1];
|
|
19091
|
+
i++;
|
|
19092
|
+
} else {
|
|
19093
|
+
quote = null;
|
|
19094
|
+
}
|
|
19095
|
+
}
|
|
19096
|
+
continue;
|
|
19097
|
+
}
|
|
19098
|
+
if (ch === "'" || ch === '"' || ch === "`") {
|
|
19099
|
+
quote = ch;
|
|
19100
|
+
buf += ch;
|
|
19101
|
+
continue;
|
|
19102
|
+
}
|
|
19103
|
+
if (ch === "-" && sql[i + 1] === "-") {
|
|
19104
|
+
const newline = sql.indexOf(`
|
|
19105
|
+
`, i);
|
|
19106
|
+
i = newline === -1 ? sql.length : newline;
|
|
19107
|
+
continue;
|
|
19108
|
+
}
|
|
19109
|
+
if (ch === "/" && sql[i + 1] === "*") {
|
|
19110
|
+
const close = sql.indexOf("*/", i + 2);
|
|
19111
|
+
i = close === -1 ? sql.length : close + 1;
|
|
19112
|
+
continue;
|
|
19113
|
+
}
|
|
19114
|
+
if (ch === ";") {
|
|
19033
19115
|
if (buf.trim())
|
|
19034
19116
|
out.push(buf.trim());
|
|
19035
19117
|
buf = "";
|
|
19036
|
-
|
|
19037
|
-
buf += ch;
|
|
19118
|
+
continue;
|
|
19038
19119
|
}
|
|
19120
|
+
buf += ch;
|
|
19039
19121
|
}
|
|
19040
19122
|
if (buf.trim())
|
|
19041
19123
|
out.push(buf.trim());
|
|
@@ -19049,8 +19131,20 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19049
19131
|
let m;
|
|
19050
19132
|
if (m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
|
|
19051
19133
|
down.push(`DROP TABLE IF EXISTS ${q(m[1])}`);
|
|
19052
|
-
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+
|
|
19053
|
-
|
|
19134
|
+
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+CONSTRAINT\s+["`']?(\w+)["`']?([\s\S]*)$/i.exec(stmt)) {
|
|
19135
|
+
if (dialect === "sqlite") {
|
|
19136
|
+
skipped.push(stmt);
|
|
19137
|
+
} else if (isMysqlLike(dialect) && /\bFOREIGN\s+KEY\b/i.test(m[3] ?? "")) {
|
|
19138
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP FOREIGN KEY ${q(m[2])}`);
|
|
19139
|
+
} else {
|
|
19140
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP CONSTRAINT ${q(m[2])}`);
|
|
19141
|
+
}
|
|
19142
|
+
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+["`']?(\w+)["`']?|["`'](\w+)["`']|(\w+))/i.exec(stmt)) {
|
|
19143
|
+
const column = m[2] ?? m[3] ?? m[4];
|
|
19144
|
+
if (m[4] && /^(?:PRIMARY|UNIQUE|INDEX|KEY|FOREIGN|CHECK|FULLTEXT|SPATIAL)$/i.test(m[4]))
|
|
19145
|
+
skipped.push(stmt);
|
|
19146
|
+
else
|
|
19147
|
+
down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(column)}`);
|
|
19054
19148
|
} else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
|
|
19055
19149
|
down.push(isMysqlLike(dialect) && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
|
|
19056
19150
|
} else {
|
|
@@ -19059,22 +19153,6 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19059
19153
|
}
|
|
19060
19154
|
return { down: down.reverse(), skipped };
|
|
19061
19155
|
}
|
|
19062
|
-
function findWorkspaceRoot2(startPath) {
|
|
19063
|
-
let currentPath = startPath;
|
|
19064
|
-
while (currentPath !== dirname8(currentPath)) {
|
|
19065
|
-
if (existsSync17(join10(currentPath, "package.json"))) {
|
|
19066
|
-
return currentPath;
|
|
19067
|
-
}
|
|
19068
|
-
currentPath = dirname8(currentPath);
|
|
19069
|
-
}
|
|
19070
|
-
return process26.cwd();
|
|
19071
|
-
}
|
|
19072
|
-
function getSqlDirectory2(workspaceRoot) {
|
|
19073
|
-
if (!workspaceRoot) {
|
|
19074
|
-
workspaceRoot = findWorkspaceRoot2(process26.cwd());
|
|
19075
|
-
}
|
|
19076
|
-
return join10(workspaceRoot, "database", "migrations");
|
|
19077
|
-
}
|
|
19078
19156
|
async function migrateRollback(options = {}) {
|
|
19079
19157
|
const steps = options.steps || 1;
|
|
19080
19158
|
const reverseSchema = options.reverseSchema !== false;
|
|
@@ -19107,12 +19185,12 @@ async function migrateRollback(options = {}) {
|
|
|
19107
19185
|
console.log(` - ${migration.migration}`);
|
|
19108
19186
|
}
|
|
19109
19187
|
console.log();
|
|
19110
|
-
const sqlDir =
|
|
19188
|
+
const sqlDir = getSqlDirectory();
|
|
19111
19189
|
let reversedAny = false;
|
|
19112
19190
|
for (const migration of migrationsToRollback) {
|
|
19113
19191
|
try {
|
|
19114
|
-
const filePath =
|
|
19115
|
-
if (reverseSchema &&
|
|
19192
|
+
const filePath = join11(sqlDir, migration.migration);
|
|
19193
|
+
if (reverseSchema && existsSync18(filePath)) {
|
|
19116
19194
|
const forwardSql = readFileSync4(filePath, "utf8");
|
|
19117
19195
|
const { down, skipped } = deriveDownStatements(forwardSql);
|
|
19118
19196
|
for (const stmt of down) {
|
|
@@ -19123,10 +19201,10 @@ async function migrateRollback(options = {}) {
|
|
|
19123
19201
|
if (skipped.length > 0)
|
|
19124
19202
|
console.log(`-- \u26A0\uFE0F ${skipped.length} statement(s) in ${migration.migration} could not be auto-reversed (data/complex DDL) \u2014 reverse manually.`);
|
|
19125
19203
|
}
|
|
19126
|
-
const deleteSql = `DELETE FROM migrations WHERE migration = $1`;
|
|
19204
|
+
const deleteSql = `DELETE FROM migrations WHERE migration = ${getPlaceholder(1)}`;
|
|
19127
19205
|
await qb.unsafe(deleteSql, [migration.migration]);
|
|
19128
19206
|
console.log(`-- \u2713 Removed migration record: ${migration.migration}`);
|
|
19129
|
-
if (
|
|
19207
|
+
if (options.deleteFiles && existsSync18(filePath)) {
|
|
19130
19208
|
unlinkSync2(filePath);
|
|
19131
19209
|
console.log(`-- \uD83D\uDDD1\uFE0F Deleted migration file: ${migration.migration}`);
|
|
19132
19210
|
}
|
|
@@ -19149,37 +19227,20 @@ async function migrateRollback(options = {}) {
|
|
|
19149
19227
|
var init_migrate_rollback = __esm(() => {
|
|
19150
19228
|
init_config();
|
|
19151
19229
|
init_src2();
|
|
19230
|
+
init_workspace();
|
|
19152
19231
|
});
|
|
19153
19232
|
|
|
19154
19233
|
// src/actions/migrate-status.ts
|
|
19155
|
-
import { existsSync as
|
|
19156
|
-
import { dirname as dirname9, join as join11 } from "path";
|
|
19157
|
-
import process27 from "process";
|
|
19158
|
-
function findWorkspaceRoot3(startPath) {
|
|
19159
|
-
let currentPath = startPath;
|
|
19160
|
-
while (currentPath !== dirname9(currentPath)) {
|
|
19161
|
-
if (existsSync18(join11(currentPath, "package.json"))) {
|
|
19162
|
-
return currentPath;
|
|
19163
|
-
}
|
|
19164
|
-
currentPath = dirname9(currentPath);
|
|
19165
|
-
}
|
|
19166
|
-
return process27.cwd();
|
|
19167
|
-
}
|
|
19168
|
-
function getSqlDirectory3(workspaceRoot) {
|
|
19169
|
-
if (!workspaceRoot) {
|
|
19170
|
-
workspaceRoot = findWorkspaceRoot3(process27.cwd());
|
|
19171
|
-
}
|
|
19172
|
-
return join11(workspaceRoot, "database", "migrations");
|
|
19173
|
-
}
|
|
19234
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8 } from "fs";
|
|
19174
19235
|
async function migrateStatus() {
|
|
19175
19236
|
const dialect = config5.dialect || "postgres";
|
|
19176
19237
|
const driver = getDialectDriver(dialect);
|
|
19177
|
-
const sqlDir =
|
|
19238
|
+
const sqlDir = getSqlDirectory();
|
|
19178
19239
|
console.log("-- Migration Status");
|
|
19179
19240
|
console.log(`-- Dialect: ${dialect}`);
|
|
19180
19241
|
console.log(`-- SQL directory: ${sqlDir}`);
|
|
19181
19242
|
console.log();
|
|
19182
|
-
if (!
|
|
19243
|
+
if (!existsSync19(sqlDir)) {
|
|
19183
19244
|
console.log("-- No SQL directory found. No migrations have been created yet.");
|
|
19184
19245
|
return [];
|
|
19185
19246
|
}
|
|
@@ -19200,27 +19261,16 @@ async function migrateStatus() {
|
|
|
19200
19261
|
console.log();
|
|
19201
19262
|
}
|
|
19202
19263
|
const executedMap = new Map(executedMigrations.map((m) => [m.migration, m.executed_at]));
|
|
19203
|
-
const statuses = migrationFiles.map((file2) => {
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19208
|
-
};
|
|
19209
|
-
}
|
|
19210
|
-
const executedAt = executedMap.get(file2);
|
|
19211
|
-
return {
|
|
19212
|
-
file: file2,
|
|
19213
|
-
status: executedAt ? "executed" : "pending",
|
|
19214
|
-
executedAt
|
|
19215
|
-
};
|
|
19216
|
-
});
|
|
19264
|
+
const statuses = migrationFiles.map((file2) => ({
|
|
19265
|
+
file: file2,
|
|
19266
|
+
status: executedMap.has(file2) ? "executed" : "pending",
|
|
19267
|
+
executedAt: executedMap.get(file2)
|
|
19268
|
+
}));
|
|
19217
19269
|
const executed = statuses.filter((s) => s.status === "executed");
|
|
19218
19270
|
const pending = statuses.filter((s) => s.status === "pending");
|
|
19219
|
-
const transient = statuses.filter((s) => s.status === "transient");
|
|
19220
19271
|
console.log(`-- Total migrations: ${migrationFiles.length}`);
|
|
19221
19272
|
console.log(`-- Executed: ${executed.length}`);
|
|
19222
19273
|
console.log(`-- Pending: ${pending.length}`);
|
|
19223
|
-
console.log(`-- Transient: ${transient.length}`);
|
|
19224
19274
|
console.log();
|
|
19225
19275
|
if (executed.length > 0) {
|
|
19226
19276
|
console.log("\u2713 Executed Migrations:");
|
|
@@ -19236,13 +19286,6 @@ async function migrateStatus() {
|
|
|
19236
19286
|
}
|
|
19237
19287
|
console.log();
|
|
19238
19288
|
}
|
|
19239
|
-
if (transient.length > 0) {
|
|
19240
|
-
console.log("\u26A1 Transient Migrations (ALTER TABLE - not tracked):");
|
|
19241
|
-
for (const migration of transient) {
|
|
19242
|
-
console.log(` - ${migration.file}`);
|
|
19243
|
-
}
|
|
19244
|
-
console.log();
|
|
19245
|
-
}
|
|
19246
19289
|
return statuses;
|
|
19247
19290
|
} catch (err) {
|
|
19248
19291
|
console.error("-- Failed to get migration status:", err);
|
|
@@ -19256,14 +19299,15 @@ var init_migrate_status = __esm(() => {
|
|
|
19256
19299
|
init_config();
|
|
19257
19300
|
init_drivers();
|
|
19258
19301
|
init_src2();
|
|
19302
|
+
init_workspace();
|
|
19259
19303
|
});
|
|
19260
19304
|
|
|
19261
19305
|
// src/actions/model-show.ts
|
|
19262
19306
|
import { readdirSync as readdirSync9 } from "fs";
|
|
19263
19307
|
import { extname as extname2, join as join12 } from "path";
|
|
19264
|
-
import
|
|
19308
|
+
import process26 from "process";
|
|
19265
19309
|
async function modelShow(modelName, options = {}) {
|
|
19266
|
-
const dir = options.dir || join12(
|
|
19310
|
+
const dir = options.dir || join12(process26.cwd(), "app/Models");
|
|
19267
19311
|
try {
|
|
19268
19312
|
const files = readdirSync9(dir);
|
|
19269
19313
|
const modelFile = files.find((f) => {
|
|
@@ -19477,9 +19521,9 @@ var init_query_explain_all = __esm(() => {
|
|
|
19477
19521
|
// src/actions/relation-diagram.ts
|
|
19478
19522
|
import { writeFileSync as writeFileSync12 } from "fs";
|
|
19479
19523
|
import { join as join14 } from "path";
|
|
19480
|
-
import
|
|
19524
|
+
import process27 from "process";
|
|
19481
19525
|
async function relationDiagram(options = {}) {
|
|
19482
|
-
const dir = options.dir || join14(
|
|
19526
|
+
const dir = options.dir || join14(process27.cwd(), "app/Models");
|
|
19483
19527
|
const format = options.format || "mermaid";
|
|
19484
19528
|
try {
|
|
19485
19529
|
const models = await loadModels({ modelsDir: dir });
|
|
@@ -19599,25 +19643,25 @@ var init_relation_diagram = __esm(() => {
|
|
|
19599
19643
|
});
|
|
19600
19644
|
|
|
19601
19645
|
// src/actions/seed.ts
|
|
19602
|
-
import { existsSync as
|
|
19646
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
|
|
19603
19647
|
import { dirname as dirname10, join as join15 } from "path";
|
|
19604
|
-
import
|
|
19605
|
-
function
|
|
19648
|
+
import process28 from "process";
|
|
19649
|
+
function findWorkspaceRoot3(startPath) {
|
|
19606
19650
|
let currentPath = startPath;
|
|
19607
19651
|
while (currentPath !== dirname10(currentPath)) {
|
|
19608
|
-
if (
|
|
19652
|
+
if (existsSync20(join15(currentPath, "package.json"))) {
|
|
19609
19653
|
return currentPath;
|
|
19610
19654
|
}
|
|
19611
19655
|
currentPath = dirname10(currentPath);
|
|
19612
19656
|
}
|
|
19613
|
-
return
|
|
19657
|
+
return process28.cwd();
|
|
19614
19658
|
}
|
|
19615
19659
|
async function loadSeeders(seedersDir) {
|
|
19616
|
-
if (!
|
|
19660
|
+
if (!existsSync20(seedersDir)) {
|
|
19617
19661
|
console.log(`-- Seeders directory not found: ${seedersDir}`);
|
|
19618
19662
|
return [];
|
|
19619
19663
|
}
|
|
19620
|
-
const files = readdirSync11(seedersDir);
|
|
19664
|
+
const files = readdirSync11(seedersDir).sort((a, b) => a.localeCompare(b));
|
|
19621
19665
|
const seederFiles = files.filter((file2) => (file2.endsWith(".ts") || file2.endsWith(".js")) && file2 !== "index.ts" && file2 !== "index.js");
|
|
19622
19666
|
const seeders = [];
|
|
19623
19667
|
for (const file2 of seederFiles) {
|
|
@@ -19630,6 +19674,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19630
19674
|
if (instance && typeof instance.run === "function") {
|
|
19631
19675
|
seeders.push({
|
|
19632
19676
|
name: file2.replace(/\.(ts|js)$/, ""),
|
|
19677
|
+
className: String(SeederClass.name || ""),
|
|
19633
19678
|
instance
|
|
19634
19679
|
});
|
|
19635
19680
|
}
|
|
@@ -19642,7 +19687,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19642
19687
|
return seeders;
|
|
19643
19688
|
}
|
|
19644
19689
|
async function runSeeders(config6 = {}) {
|
|
19645
|
-
const workspaceRoot =
|
|
19690
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19646
19691
|
const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19647
19692
|
const verbose = config6.verbose ?? true;
|
|
19648
19693
|
if (verbose) {
|
|
@@ -19677,17 +19722,18 @@ async function runSeeders(config6 = {}) {
|
|
|
19677
19722
|
}
|
|
19678
19723
|
}
|
|
19679
19724
|
async function runSeeder(className, options = {}) {
|
|
19680
|
-
const workspaceRoot =
|
|
19725
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19681
19726
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19682
19727
|
const verbose = options.verbose ?? true;
|
|
19683
19728
|
if (verbose) {
|
|
19684
19729
|
console.log(`-- Running seeder: ${className}`);
|
|
19685
19730
|
}
|
|
19686
19731
|
const seeders = await loadSeeders(seedersDir);
|
|
19687
|
-
const seeder = seeders.find((s) => s.name === className);
|
|
19732
|
+
const seeder = seeders.find((s) => s.className === className) ?? seeders.find((s) => s.name === className);
|
|
19688
19733
|
if (!seeder) {
|
|
19689
|
-
|
|
19690
|
-
|
|
19734
|
+
const known = seeders.map((s) => s.className || s.name).join(", ") || "none";
|
|
19735
|
+
console.error(`-- Seeder not found: ${className}. Available: ${known}`);
|
|
19736
|
+
throw new Error(`Seeder not found: ${className}. Available: ${known}`);
|
|
19691
19737
|
}
|
|
19692
19738
|
const qb = createQueryBuilder();
|
|
19693
19739
|
try {
|
|
@@ -19701,9 +19747,9 @@ async function runSeeder(className, options = {}) {
|
|
|
19701
19747
|
}
|
|
19702
19748
|
}
|
|
19703
19749
|
async function makeSeeder(name) {
|
|
19704
|
-
const workspaceRoot =
|
|
19750
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19705
19751
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19706
|
-
if (!
|
|
19752
|
+
if (!existsSync20(seedersDir)) {
|
|
19707
19753
|
mkdirSync9(seedersDir, { recursive: true });
|
|
19708
19754
|
console.log(`-- Created seeders directory: ${seedersDir}`);
|
|
19709
19755
|
}
|
|
@@ -19711,7 +19757,7 @@ async function makeSeeder(name) {
|
|
|
19711
19757
|
const className = `${baseName}Seeder`;
|
|
19712
19758
|
const fileName = `${className}.ts`;
|
|
19713
19759
|
const filePath = join15(seedersDir, fileName);
|
|
19714
|
-
if (
|
|
19760
|
+
if (existsSync20(filePath)) {
|
|
19715
19761
|
console.error(`-- Seeder already exists: ${filePath}`);
|
|
19716
19762
|
throw new Error(`Seeder already exists: ${filePath}`);
|
|
19717
19763
|
}
|
|
@@ -19765,7 +19811,7 @@ export default class ${className} extends Seeder {
|
|
|
19765
19811
|
console.log(`-- \u2713 Created seeder: ${filePath}`);
|
|
19766
19812
|
}
|
|
19767
19813
|
async function freshDatabase(options = {}) {
|
|
19768
|
-
const workspaceRoot =
|
|
19814
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19769
19815
|
const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
|
|
19770
19816
|
const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19771
19817
|
const verbose = options.verbose ?? true;
|
|
@@ -19825,22 +19871,22 @@ var init_unsafe = __esm(() => {
|
|
|
19825
19871
|
});
|
|
19826
19872
|
|
|
19827
19873
|
// src/actions/validate.ts
|
|
19828
|
-
import { existsSync as
|
|
19874
|
+
import { existsSync as existsSync21 } from "fs";
|
|
19829
19875
|
import { dirname as dirname11, join as join16 } from "path";
|
|
19830
|
-
import
|
|
19831
|
-
function
|
|
19876
|
+
import process29 from "process";
|
|
19877
|
+
function findWorkspaceRoot4(startPath) {
|
|
19832
19878
|
let currentPath = startPath;
|
|
19833
19879
|
while (currentPath !== dirname11(currentPath)) {
|
|
19834
|
-
if (
|
|
19880
|
+
if (existsSync21(join16(currentPath, "package.json"))) {
|
|
19835
19881
|
return currentPath;
|
|
19836
19882
|
}
|
|
19837
19883
|
currentPath = dirname11(currentPath);
|
|
19838
19884
|
}
|
|
19839
|
-
return
|
|
19885
|
+
return process29.cwd();
|
|
19840
19886
|
}
|
|
19841
19887
|
async function validateSchema(dir) {
|
|
19842
19888
|
if (!dir) {
|
|
19843
|
-
dir = join16(
|
|
19889
|
+
dir = join16(findWorkspaceRoot4(process29.cwd()), "app/Models");
|
|
19844
19890
|
}
|
|
19845
19891
|
const dialect = config5.dialect || "postgres";
|
|
19846
19892
|
console.log("-- Validating Schema");
|
|
@@ -25091,18 +25137,11 @@ function toSnakeCase(str) {
|
|
|
25091
25137
|
snakeCaseCache.set(str, cached);
|
|
25092
25138
|
return cached;
|
|
25093
25139
|
}
|
|
25094
|
-
function
|
|
25140
|
+
function toTableName2(modelName) {
|
|
25095
25141
|
let cached = tableNameCache.get(modelName);
|
|
25096
25142
|
if (cached !== undefined)
|
|
25097
25143
|
return cached;
|
|
25098
|
-
|
|
25099
|
-
if (snake.endsWith("y") && !snake.endsWith("ay") && !snake.endsWith("ey") && !snake.endsWith("oy") && !snake.endsWith("uy")) {
|
|
25100
|
-
cached = snake.slice(0, -1) + "ies";
|
|
25101
|
-
} else if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh")) {
|
|
25102
|
-
cached = `${snake}es`;
|
|
25103
|
-
} else {
|
|
25104
|
-
cached = `${snake}s`;
|
|
25105
|
-
}
|
|
25144
|
+
cached = toTableName(modelName);
|
|
25106
25145
|
tableNameCache.set(modelName, cached);
|
|
25107
25146
|
return cached;
|
|
25108
25147
|
}
|
|
@@ -25187,14 +25226,14 @@ function resolveRelation(definition, relationName) {
|
|
|
25187
25226
|
const hasManyModel = findModelName(definition.hasMany);
|
|
25188
25227
|
if (hasManyModel) {
|
|
25189
25228
|
const relatedModel = getModelFromRegistry(hasManyModel);
|
|
25190
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25229
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasManyModel);
|
|
25191
25230
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25192
25231
|
return { type: "hasMany", relatedModelName: hasManyModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25193
25232
|
}
|
|
25194
25233
|
const hasOneModel = findModelName(definition.hasOne);
|
|
25195
25234
|
if (hasOneModel) {
|
|
25196
25235
|
const relatedModel = getModelFromRegistry(hasOneModel);
|
|
25197
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25236
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasOneModel);
|
|
25198
25237
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25199
25238
|
return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25200
25239
|
}
|
|
@@ -25202,7 +25241,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25202
25241
|
if (belongsToEntry) {
|
|
25203
25242
|
const belongsToModel = belongsToEntry.model;
|
|
25204
25243
|
const relatedModel = getModelFromRegistry(belongsToModel);
|
|
25205
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25244
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(belongsToModel);
|
|
25206
25245
|
const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
|
|
25207
25246
|
const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
|
|
25208
25247
|
return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
|
|
@@ -25212,7 +25251,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25212
25251
|
const isConfig = typeof found.entry === "object";
|
|
25213
25252
|
const relatedModelName = isConfig ? found.entry.model : found.entry;
|
|
25214
25253
|
const relatedModel = getModelFromRegistry(relatedModelName);
|
|
25215
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25254
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(relatedModelName);
|
|
25216
25255
|
const config6 = isConfig ? found.entry : null;
|
|
25217
25256
|
let pivotTable;
|
|
25218
25257
|
let pivotModelName;
|
|
@@ -25224,7 +25263,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25224
25263
|
if (!throughModel) {
|
|
25225
25264
|
throw new Error(`[orm] belongsToMany relation '${relationName}' on '${parentName}' references unknown through model '${config6.through}'. Make sure '${config6.through}' is registered.`);
|
|
25226
25265
|
}
|
|
25227
|
-
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table ||
|
|
25266
|
+
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName2(config6.through);
|
|
25228
25267
|
} else {
|
|
25229
25268
|
const a2 = singularizeWord(parentTable);
|
|
25230
25269
|
const b2 = singularizeWord(relatedTable);
|
|
@@ -25275,10 +25314,10 @@ function resolveRelation(definition, relationName) {
|
|
|
25275
25314
|
return null;
|
|
25276
25315
|
const throughModel = getModelFromRegistry(throughModelName);
|
|
25277
25316
|
const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
|
|
25278
|
-
const throughTable = throughModel?.getTable?.() || throughDef?.table ||
|
|
25317
|
+
const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName2(throughModelName);
|
|
25279
25318
|
const throughPk = throughDef?.primaryKey || "id";
|
|
25280
25319
|
const targetModel = getModelFromRegistry(targetModelName);
|
|
25281
|
-
const targetTable = targetModel?.getTable?.() ||
|
|
25320
|
+
const targetTable = targetModel?.getTable?.() || toTableName2(targetModelName);
|
|
25282
25321
|
return {
|
|
25283
25322
|
type,
|
|
25284
25323
|
relatedModelName: targetModelName,
|
|
@@ -27875,7 +27914,7 @@ function buildDatabaseSchema(models) {
|
|
|
27875
27914
|
for (const modelName of Object.keys(models)) {
|
|
27876
27915
|
const rawModel = models[modelName];
|
|
27877
27916
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27878
|
-
const table =
|
|
27917
|
+
const table = tableNameFor(m2);
|
|
27879
27918
|
const attrs = m2.attributes ?? {};
|
|
27880
27919
|
const columns = {};
|
|
27881
27920
|
for (const key of Object.keys(attrs))
|
|
@@ -27887,30 +27926,53 @@ function buildDatabaseSchema(models) {
|
|
|
27887
27926
|
}
|
|
27888
27927
|
return schema;
|
|
27889
27928
|
}
|
|
27929
|
+
var init_factory = () => {};
|
|
27890
27930
|
|
|
27891
27931
|
// src/loader.ts
|
|
27892
|
-
import { readdirSync as readdirSync12
|
|
27893
|
-
import { basename, extname as extname4 } from "path";
|
|
27894
|
-
import
|
|
27895
|
-
|
|
27896
|
-
const
|
|
27897
|
-
|
|
27898
|
-
|
|
27899
|
-
const
|
|
27932
|
+
import { readdirSync as readdirSync12 } from "fs";
|
|
27933
|
+
import { basename, extname as extname4, isAbsolute as isAbsolute3, join as join17 } from "path";
|
|
27934
|
+
import process30 from "process";
|
|
27935
|
+
function isModelFile(name) {
|
|
27936
|
+
const ext = extname4(name);
|
|
27937
|
+
if (!MODEL_EXTENSIONS.has(ext))
|
|
27938
|
+
return false;
|
|
27939
|
+
const base = basename(name, ext);
|
|
27940
|
+
if (base.startsWith("_") || base === "index")
|
|
27941
|
+
return false;
|
|
27942
|
+
return !base.endsWith(".d");
|
|
27943
|
+
}
|
|
27944
|
+
function isModelDefinition(def) {
|
|
27945
|
+
if (!def || typeof def !== "object")
|
|
27946
|
+
return false;
|
|
27947
|
+
const d2 = def;
|
|
27948
|
+
return typeof d2.name === "string" || typeof d2.table === "string";
|
|
27949
|
+
}
|
|
27950
|
+
function collectModelFiles(dir) {
|
|
27951
|
+
const files = [];
|
|
27952
|
+
const entries = readdirSync12(dir, { withFileTypes: true }).sort((a2, b2) => a2.name.localeCompare(b2.name));
|
|
27900
27953
|
for (const entry of entries) {
|
|
27901
|
-
const full =
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
continue;
|
|
27905
|
-
const ext = extname4(full);
|
|
27906
|
-
if (![".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"].includes(ext))
|
|
27954
|
+
const full = join17(dir, entry.name);
|
|
27955
|
+
if (entry.isDirectory()) {
|
|
27956
|
+
files.push(...collectModelFiles(full));
|
|
27907
27957
|
continue;
|
|
27958
|
+
}
|
|
27959
|
+
if (isModelFile(entry.name))
|
|
27960
|
+
files.push(full);
|
|
27961
|
+
}
|
|
27962
|
+
return files;
|
|
27963
|
+
}
|
|
27964
|
+
async function loadModels(options) {
|
|
27965
|
+
const cwd = options.cwd ?? process30.cwd();
|
|
27966
|
+
const dir = isAbsolute3(options.modelsDir) ? options.modelsDir : join17(cwd, options.modelsDir);
|
|
27967
|
+
const result = {};
|
|
27968
|
+
for (const full of collectModelFiles(dir)) {
|
|
27908
27969
|
const cacheBuster = `?t=${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
27909
27970
|
const mod = await import(`${full}${cacheBuster}`);
|
|
27910
27971
|
const rawDef = mod.default ?? mod;
|
|
27911
27972
|
const def = rawDef.definition ?? rawDef.getDefinition?.() ?? rawDef;
|
|
27912
|
-
|
|
27913
|
-
|
|
27973
|
+
if (!isModelDefinition(def))
|
|
27974
|
+
continue;
|
|
27975
|
+
const name = def.name ?? basename(full, extname4(full));
|
|
27914
27976
|
result[name] = {
|
|
27915
27977
|
...def,
|
|
27916
27978
|
name
|
|
@@ -27918,7 +27980,10 @@ async function loadModels(options) {
|
|
|
27918
27980
|
}
|
|
27919
27981
|
return result;
|
|
27920
27982
|
}
|
|
27921
|
-
var
|
|
27983
|
+
var MODEL_EXTENSIONS;
|
|
27984
|
+
var init_loader = __esm(() => {
|
|
27985
|
+
MODEL_EXTENSIONS = new Set([".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"]);
|
|
27986
|
+
});
|
|
27922
27987
|
|
|
27923
27988
|
// src/meta.ts
|
|
27924
27989
|
function buildSchemaMeta(models) {
|
|
@@ -27930,7 +27995,7 @@ function buildSchemaMeta(models) {
|
|
|
27930
27995
|
for (const name of Object.keys(models)) {
|
|
27931
27996
|
const rawModel = models[name];
|
|
27932
27997
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27933
|
-
const table =
|
|
27998
|
+
const table = tableNameFor(m2);
|
|
27934
27999
|
modelToTable[name] = table;
|
|
27935
28000
|
tableToModel[table] = name;
|
|
27936
28001
|
primaryKeys[table] = m2.primaryKey ?? "id";
|
|
@@ -28004,9 +28069,9 @@ function buildSchemaMeta(models) {
|
|
|
28004
28069
|
var init_meta = () => {};
|
|
28005
28070
|
|
|
28006
28071
|
// src/migrations.ts
|
|
28007
|
-
import { existsSync as
|
|
28008
|
-
import { dirname as dirname12, join as
|
|
28009
|
-
import
|
|
28072
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10, readdirSync as readdirSync13, readFileSync as readFileSync6, writeFileSync as writeFileSync14 } from "fs";
|
|
28073
|
+
import { dirname as dirname12, join as join18 } from "path";
|
|
28074
|
+
import process31 from "process";
|
|
28010
28075
|
function info2(message) {
|
|
28011
28076
|
if (config5.verbose)
|
|
28012
28077
|
console.log(message);
|
|
@@ -28017,36 +28082,80 @@ function snakeCase(str) {
|
|
|
28017
28082
|
function singularizeTable(table) {
|
|
28018
28083
|
return singularizerFor(config5.relations?.singularizeStrategy)(table);
|
|
28019
28084
|
}
|
|
28020
|
-
function
|
|
28085
|
+
function lastCreatedMigrationFiles() {
|
|
28086
|
+
return [...createdMigrationFiles];
|
|
28087
|
+
}
|
|
28088
|
+
function findWorkspaceRoot5(startPath) {
|
|
28021
28089
|
let currentPath = startPath;
|
|
28022
28090
|
while (currentPath !== dirname12(currentPath)) {
|
|
28023
|
-
if (
|
|
28091
|
+
if (existsSync23(join18(currentPath, "package.json"))) {
|
|
28024
28092
|
return currentPath;
|
|
28025
28093
|
}
|
|
28026
28094
|
currentPath = dirname12(currentPath);
|
|
28027
28095
|
}
|
|
28028
|
-
return
|
|
28096
|
+
return process31.cwd();
|
|
28029
28097
|
}
|
|
28030
28098
|
function ensureSqlDirectory2() {
|
|
28031
|
-
const workspaceRoot =
|
|
28032
|
-
const sqlDir =
|
|
28033
|
-
if (!
|
|
28099
|
+
const workspaceRoot = findWorkspaceRoot5(process31.cwd());
|
|
28100
|
+
const sqlDir = join18(workspaceRoot, "database", "migrations");
|
|
28101
|
+
if (!existsSync23(sqlDir)) {
|
|
28034
28102
|
mkdirSync10(sqlDir, { recursive: true });
|
|
28035
28103
|
info2(`-- Created SQL directory: ${sqlDir}`);
|
|
28036
28104
|
}
|
|
28037
28105
|
return sqlDir;
|
|
28038
28106
|
}
|
|
28107
|
+
function isGeneratedMigrationSql(sql2) {
|
|
28108
|
+
return sql2.trimStart().startsWith(GENERATED_MARKER);
|
|
28109
|
+
}
|
|
28110
|
+
function migrationBody(sql2) {
|
|
28111
|
+
return sql2.split(`
|
|
28112
|
+
`).filter((line) => !line.trimStart().startsWith("--")).join(`
|
|
28113
|
+
`).replace(/\s+/g, " ").trim().replace(/;+$/, "");
|
|
28114
|
+
}
|
|
28115
|
+
function existingMigrationBodies(sqlDir) {
|
|
28116
|
+
const bodies = new Set;
|
|
28117
|
+
let files;
|
|
28118
|
+
try {
|
|
28119
|
+
files = readdirSync13(sqlDir).filter((f2) => f2.endsWith(".sql"));
|
|
28120
|
+
} catch {
|
|
28121
|
+
return bodies;
|
|
28122
|
+
}
|
|
28123
|
+
for (const file2 of files) {
|
|
28124
|
+
try {
|
|
28125
|
+
bodies.add(migrationBody(readFileSync6(join18(sqlDir, file2), "utf8")));
|
|
28126
|
+
} catch {}
|
|
28127
|
+
}
|
|
28128
|
+
return bodies;
|
|
28129
|
+
}
|
|
28039
28130
|
function createMigrationFile(statement, fileName) {
|
|
28040
28131
|
if (!statement)
|
|
28041
28132
|
return false;
|
|
28042
28133
|
const sqlDir = ensureSqlDirectory2();
|
|
28134
|
+
if (existingCorpusBodies === null)
|
|
28135
|
+
existingCorpusBodies = existingMigrationBodies(sqlDir);
|
|
28136
|
+
const body = migrationBody(statement);
|
|
28137
|
+
if (body.length > 0 && existingCorpusBodies.has(body)) {
|
|
28138
|
+
info2(`-- Migration already in the corpus, not writing it again: ${fileName}`);
|
|
28139
|
+
return false;
|
|
28140
|
+
}
|
|
28043
28141
|
migrationCounter++;
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28142
|
+
let sequence = useDeterministicNames ? String(migrationCounter).padStart(10, "0") : String(Math.floor(Date.now() / 1000) + migrationCounter);
|
|
28143
|
+
let fullFileName = `${sequence}-${fileName}.sql`;
|
|
28144
|
+
if (!useDeterministicNames) {
|
|
28145
|
+
let next = Number(sequence);
|
|
28146
|
+
while (existsSync23(join18(sqlDir, fullFileName))) {
|
|
28147
|
+
next += 1;
|
|
28148
|
+
sequence = String(next);
|
|
28149
|
+
fullFileName = `${sequence}-${fileName}.sql`;
|
|
28150
|
+
}
|
|
28151
|
+
}
|
|
28152
|
+
const filePath = join18(sqlDir, fullFileName);
|
|
28153
|
+
writeFileSync14(filePath, `${GENERATED_MARKER}
|
|
28154
|
+
${statement}`);
|
|
28048
28155
|
info2(`-- Migration file created: ${fullFileName}`);
|
|
28049
28156
|
migrationsCreatedCount++;
|
|
28157
|
+
createdMigrationFiles.push(fullFileName);
|
|
28158
|
+
existingCorpusBodies?.add(body);
|
|
28050
28159
|
return true;
|
|
28051
28160
|
}
|
|
28052
28161
|
function guessTypeFromName(columnName) {
|
|
@@ -28221,7 +28330,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28221
28330
|
const tables = [];
|
|
28222
28331
|
for (const modelName of Object.keys(models)) {
|
|
28223
28332
|
const model = models[modelName];
|
|
28224
|
-
const table =
|
|
28333
|
+
const table = tableNameFor(model);
|
|
28225
28334
|
const primaryKey = model.primaryKey ?? "id";
|
|
28226
28335
|
const _autoIncrement = model.autoIncrement !== false;
|
|
28227
28336
|
const attrs = model.attributes ?? {};
|
|
@@ -28313,9 +28422,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28313
28422
|
if (columns.some((c2) => c2.name === fkColumnName))
|
|
28314
28423
|
continue;
|
|
28315
28424
|
const refTable = meta.modelToTable[rel.model];
|
|
28316
|
-
|
|
28317
|
-
continue;
|
|
28318
|
-
const refPk = meta.primaryKeys[refTable] ?? "id";
|
|
28425
|
+
const refPk = refTable ? meta.primaryKeys[refTable] ?? "id" : undefined;
|
|
28319
28426
|
columns.push({
|
|
28320
28427
|
name: fkColumnName,
|
|
28321
28428
|
type: "bigint",
|
|
@@ -28323,7 +28430,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28323
28430
|
isUnique: false,
|
|
28324
28431
|
isNullable: true,
|
|
28325
28432
|
hasDefault: false,
|
|
28326
|
-
references: { table: refTable, column: refPk, onDelete: rel.onDelete }
|
|
28433
|
+
references: refTable && refPk ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
|
|
28327
28434
|
});
|
|
28328
28435
|
}
|
|
28329
28436
|
const traits = model.traits;
|
|
@@ -28404,7 +28511,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28404
28511
|
for (const modelName of Object.keys(models)) {
|
|
28405
28512
|
const model = models[modelName];
|
|
28406
28513
|
const traits = model?.traits ?? {};
|
|
28407
|
-
const modelTable =
|
|
28514
|
+
const modelTable = tableNameFor(model);
|
|
28408
28515
|
const singular = singularizeTable(modelTable);
|
|
28409
28516
|
if (traits.likeable) {
|
|
28410
28517
|
const opts = typeof traits.likeable === "object" ? traits.likeable : {};
|
|
@@ -28471,7 +28578,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28471
28578
|
const btm = model?.belongsToMany;
|
|
28472
28579
|
if (!btm || typeof btm !== "object" || Array.isArray(btm))
|
|
28473
28580
|
continue;
|
|
28474
|
-
const parentTable =
|
|
28581
|
+
const parentTable = tableNameFor(model);
|
|
28475
28582
|
const parentSingular = singularizeTable(parentTable);
|
|
28476
28583
|
for (const [relKey, value] of Object.entries(btm)) {
|
|
28477
28584
|
const cfg = value;
|
|
@@ -28532,6 +28639,8 @@ function generateSql(plan, opts = {}) {
|
|
|
28532
28639
|
migrationCounter = 0;
|
|
28533
28640
|
migrationsCreatedCount = 0;
|
|
28534
28641
|
migrationsUpdatedCount = 0;
|
|
28642
|
+
createdMigrationFiles = [];
|
|
28643
|
+
existingCorpusBodies = null;
|
|
28535
28644
|
useDeterministicNames = true;
|
|
28536
28645
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28537
28646
|
const statements = [];
|
|
@@ -28793,12 +28902,13 @@ function referencesAreDifferent(r1, r2) {
|
|
|
28793
28902
|
const act = (a2) => (a2 ?? "no action").toLowerCase();
|
|
28794
28903
|
return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
|
|
28795
28904
|
}
|
|
28905
|
+
function indexKey(index) {
|
|
28906
|
+
return `${index.type}:${index.name}:${index.columns.join(",")}`;
|
|
28907
|
+
}
|
|
28796
28908
|
function mapIndexesByKey(indexes) {
|
|
28797
28909
|
const map = {};
|
|
28798
|
-
for (const i2 of indexes)
|
|
28799
|
-
|
|
28800
|
-
map[key] = i2;
|
|
28801
|
-
}
|
|
28910
|
+
for (const i2 of indexes)
|
|
28911
|
+
map[indexKey(i2)] = i2;
|
|
28802
28912
|
return map;
|
|
28803
28913
|
}
|
|
28804
28914
|
function generateDiffOperations(previous, next, opts = {}) {
|
|
@@ -28813,10 +28923,13 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28813
28923
|
return { statements: statements2, operations: operations2 };
|
|
28814
28924
|
}
|
|
28815
28925
|
const applyRenames = opts.applyRenames !== false;
|
|
28926
|
+
const preserveUnknownColumns = opts.preserveUnknownColumns === true;
|
|
28816
28927
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28817
28928
|
migrationCounter = 0;
|
|
28818
28929
|
migrationsCreatedCount = 0;
|
|
28819
28930
|
migrationsUpdatedCount = 0;
|
|
28931
|
+
createdMigrationFiles = [];
|
|
28932
|
+
existingCorpusBodies = null;
|
|
28820
28933
|
useDeterministicNames = false;
|
|
28821
28934
|
const chunks = [];
|
|
28822
28935
|
const operations = [];
|
|
@@ -28915,22 +29028,32 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28915
29028
|
}
|
|
28916
29029
|
for (const tableName of Object.keys(nextTables)) {
|
|
28917
29030
|
const prev = prevTables[tableName];
|
|
28918
|
-
|
|
29031
|
+
let curr = nextTables[tableName];
|
|
28919
29032
|
if (!prev)
|
|
28920
29033
|
continue;
|
|
28921
29034
|
const prevCols = mapColumnsByName(prev.columns);
|
|
28922
|
-
const currCols = mapColumnsByName(curr.columns);
|
|
28923
29035
|
const prevIdx = mapIndexesByKey(prev.indexes);
|
|
28924
|
-
|
|
29036
|
+
let currCols = mapColumnsByName(curr.columns);
|
|
29037
|
+
let currIdx = mapIndexesByKey(curr.indexes);
|
|
28925
29038
|
let renames = [];
|
|
28926
29039
|
let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
|
|
28927
29040
|
let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
|
|
28928
|
-
if (applyRenames) {
|
|
29041
|
+
if (applyRenames && !preserveUnknownColumns) {
|
|
28929
29042
|
const detected = detectColumnRenames(prevCols, currCols, dialect);
|
|
28930
29043
|
renames = detected.renames;
|
|
28931
29044
|
removedCols = detected.removed;
|
|
28932
29045
|
addedCols = detected.added;
|
|
28933
29046
|
}
|
|
29047
|
+
if (preserveUnknownColumns && removedCols.length > 0) {
|
|
29048
|
+
const preserved = removedCols.map((name) => prevCols[name]);
|
|
29049
|
+
const preservedNames = new Set(removedCols);
|
|
29050
|
+
const keptIndexes = prev.indexes.filter((idx) => idx.columns.some((c2) => preservedNames.has(c2)) && !currIdx[indexKey(idx)]);
|
|
29051
|
+
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`);
|
|
29052
|
+
curr = { ...curr, columns: [...curr.columns, ...preserved], indexes: [...curr.indexes, ...keptIndexes] };
|
|
29053
|
+
currCols = mapColumnsByName(curr.columns);
|
|
29054
|
+
currIdx = mapIndexesByKey(curr.indexes);
|
|
29055
|
+
removedCols = [];
|
|
29056
|
+
}
|
|
28934
29057
|
const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
|
|
28935
29058
|
const fkChangedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && referencesAreDifferent(prevCols[n2].references, currCols[n2].references));
|
|
28936
29059
|
if (dialect === "sqlite") {
|
|
@@ -29078,11 +29201,12 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
29078
29201
|
function generateDiffSql(previous, next, opts = {}) {
|
|
29079
29202
|
return generateDiffOperations(previous, next, opts).statements;
|
|
29080
29203
|
}
|
|
29081
|
-
var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true;
|
|
29204
|
+
var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true, createdMigrationFiles, existingCorpusBodies = null, GENERATED_MARKER = "-- qb:generated";
|
|
29082
29205
|
var init_migrations = __esm(() => {
|
|
29083
29206
|
init_config();
|
|
29084
29207
|
init_drivers();
|
|
29085
29208
|
init_meta();
|
|
29209
|
+
createdMigrationFiles = [];
|
|
29086
29210
|
});
|
|
29087
29211
|
|
|
29088
29212
|
// src/schema.ts
|
|
@@ -29116,6 +29240,7 @@ var init_src2 = __esm(() => {
|
|
|
29116
29240
|
init_dynamodb_single_table();
|
|
29117
29241
|
init_dynamodb_tooling_adapter();
|
|
29118
29242
|
init_dynamodb();
|
|
29243
|
+
init_factory();
|
|
29119
29244
|
init_loader();
|
|
29120
29245
|
init_meta();
|
|
29121
29246
|
init_migrations();
|
|
@@ -29125,11 +29250,11 @@ var init_src2 = __esm(() => {
|
|
|
29125
29250
|
});
|
|
29126
29251
|
|
|
29127
29252
|
// ../../node_modules/@stacksjs/clapp/dist/index.js
|
|
29128
|
-
import { existsSync as
|
|
29253
|
+
import { existsSync as existsSync25 } from "fs";
|
|
29129
29254
|
import fs from "fs/promises";
|
|
29130
29255
|
import os from "os";
|
|
29131
29256
|
import path from "path";
|
|
29132
|
-
import
|
|
29257
|
+
import process33 from "process";
|
|
29133
29258
|
import { EventEmitter } from "events";
|
|
29134
29259
|
import process52 from "process";
|
|
29135
29260
|
import process210 from "process";
|
|
@@ -29153,10 +29278,10 @@ class Telemetry {
|
|
|
29153
29278
|
this.configPath = path.join(configDir, "telemetry.json");
|
|
29154
29279
|
}
|
|
29155
29280
|
async isEnabled() {
|
|
29156
|
-
if (
|
|
29281
|
+
if (process33.env.DO_NOT_TRACK === "1" || process33.env.DO_NOT_TRACK === "true") {
|
|
29157
29282
|
return false;
|
|
29158
29283
|
}
|
|
29159
|
-
if (
|
|
29284
|
+
if (process33.env.NO_TELEMETRY === "1" || process33.env.NO_TELEMETRY === "true") {
|
|
29160
29285
|
return false;
|
|
29161
29286
|
}
|
|
29162
29287
|
const config6 = await this.loadConfig();
|
|
@@ -29185,7 +29310,7 @@ class Telemetry {
|
|
|
29185
29310
|
...data,
|
|
29186
29311
|
timestamp: Date.now(),
|
|
29187
29312
|
platform: os.platform(),
|
|
29188
|
-
nodeVersion:
|
|
29313
|
+
nodeVersion: process33.version
|
|
29189
29314
|
};
|
|
29190
29315
|
this.events.push(telemetryEvent);
|
|
29191
29316
|
if (this.events.length >= 10) {
|
|
@@ -29241,7 +29366,7 @@ class Telemetry {
|
|
|
29241
29366
|
const config6 = await this.loadConfig();
|
|
29242
29367
|
return {
|
|
29243
29368
|
enabled: config6.enabled,
|
|
29244
|
-
doNotTrack:
|
|
29369
|
+
doNotTrack: process33.env.DO_NOT_TRACK === "1" || process33.env.DO_NOT_TRACK === "true",
|
|
29245
29370
|
eventsQueued: this.events.length,
|
|
29246
29371
|
lastSent: config6.lastSent
|
|
29247
29372
|
};
|
|
@@ -29251,7 +29376,7 @@ class Telemetry {
|
|
|
29251
29376
|
return this.config;
|
|
29252
29377
|
}
|
|
29253
29378
|
try {
|
|
29254
|
-
if (
|
|
29379
|
+
if (existsSync25(this.configPath)) {
|
|
29255
29380
|
const data = await fs.readFile(this.configPath, "utf-8");
|
|
29256
29381
|
this.config = JSON.parse(data);
|
|
29257
29382
|
return this.config;
|
|
@@ -31163,7 +31288,7 @@ function getPrefix() {
|
|
|
31163
31288
|
}
|
|
31164
31289
|
var prefix = getPrefix();
|
|
31165
31290
|
// package.json
|
|
31166
|
-
var version2 = "0.
|
|
31291
|
+
var version2 = "0.2.0";
|
|
31167
31292
|
|
|
31168
31293
|
// bin/cli.ts
|
|
31169
31294
|
init_actions();
|
|
@@ -31218,7 +31343,7 @@ cli.command("unsafe <sql>", "Execute an unsafe SQL string (one statement with pa
|
|
|
31218
31343
|
cli.command("file <path>", "Execute a SQL file (supports $1, $2 params)").option("--params <json>", "JSON array of parameters").example("query-builder file ./migrations/seed.sql").example('query-builder file ./reports/top.sql --params "[30]"').action(async (path2, opts) => {
|
|
31219
31344
|
await file(path2, opts);
|
|
31220
31345
|
});
|
|
31221
|
-
cli.command("migrate <dir>", "Generate SQL migrations from models").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31346
|
+
cli.command("migrate <dir>", "Generate SQL migrations from models").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--state <path>", "Path to migration state file (defaults to <dir>/.qb-migrations.<dialect>.json)").option("--apply", "Execute the generated SQL against the database").option("--full", "Force full migration SQL instead of incremental diff").example("query-builder migrate ./app/Models --dialect postgres").action(async (dir, opts) => {
|
|
31222
31347
|
try {
|
|
31223
31348
|
await generateMigration(dir, {
|
|
31224
31349
|
dialect: opts.dialect,
|
|
@@ -31262,7 +31387,7 @@ cli.command("relation:diagram", "Generate relationship diagram from models").opt
|
|
|
31262
31387
|
proc.default.exitCode = 1;
|
|
31263
31388
|
}
|
|
31264
31389
|
});
|
|
31265
|
-
cli.command("migrate:fresh <dir>", "Reset database and run all migrations").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31390
|
+
cli.command("migrate:fresh <dir>", "Reset database and run all migrations").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--state <path>", "Path to migration state file (defaults to <dir>/.qb-migrations.<dialect>.json)").option("--full", "Force full migration SQL instead of incremental diff").example("query-builder migrate:fresh ./app/Models --dialect postgres").action(async (dir, opts) => {
|
|
31266
31391
|
try {
|
|
31267
31392
|
console.log("-- Resetting database...");
|
|
31268
31393
|
await resetDatabase(dir, {
|
|
@@ -31283,7 +31408,7 @@ cli.command("migrate:fresh <dir>", "Reset database and run all migrations").opti
|
|
|
31283
31408
|
proc.default.exitCode = 1;
|
|
31284
31409
|
}
|
|
31285
31410
|
});
|
|
31286
|
-
cli.command("reset <dir>", "Drop all tables and reset database").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31411
|
+
cli.command("reset <dir>", "Drop all tables and reset database").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--state <path>", "Path to migration state file (defaults to <dir>/.qb-migrations.<dialect>.json)").example("query-builder reset ./app/Models --dialect postgres").action(async (dir, opts) => {
|
|
31287
31412
|
try {
|
|
31288
31413
|
await resetDatabase(dir, {
|
|
31289
31414
|
dialect: opts.dialect,
|
|
@@ -31387,16 +31512,20 @@ cli.command("migrate:list", "List all migrations (alias for migrate:status)").ex
|
|
|
31387
31512
|
proc.default.exitCode = 1;
|
|
31388
31513
|
}
|
|
31389
31514
|
});
|
|
31390
|
-
cli.command("migrate:rollback", "Rollback migrations").option("--steps <n>", "Number of migrations to rollback", { default: 1 }).example("query-builder migrate:rollback").example("query-builder migrate:rollback --steps 2").action(async (opts) => {
|
|
31515
|
+
cli.command("migrate:rollback", "Rollback migrations").option("--steps <n>", "Number of migrations to rollback", { default: 1 }).option("--no-reverse-schema", "Only remove the migration records; leave the schema alone").option("--delete-files", "Also delete the rolled-back migration files from disk").example("query-builder migrate:rollback").example("query-builder migrate:rollback --steps 2").example("query-builder migrate:rollback --no-reverse-schema").action(async (opts) => {
|
|
31391
31516
|
try {
|
|
31392
|
-
await migrateRollback({
|
|
31517
|
+
await migrateRollback({
|
|
31518
|
+
steps: Number(opts.steps),
|
|
31519
|
+
reverseSchema: opts.reverseSchema,
|
|
31520
|
+
deleteFiles: Boolean(opts.deleteFiles)
|
|
31521
|
+
});
|
|
31393
31522
|
} catch (err) {
|
|
31394
31523
|
console.error("-- Rollback failed:", err);
|
|
31395
31524
|
const proc = await import("process");
|
|
31396
31525
|
proc.default.exitCode = 1;
|
|
31397
31526
|
}
|
|
31398
31527
|
});
|
|
31399
|
-
cli.command("migrate:generate [dir]", "Generate migration from model changes").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31528
|
+
cli.command("migrate:generate [dir]", "Generate migration from model changes").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--state <path>", "Path to migration state file").option("--apply", "Execute the generated SQL").option("--full", "Force full migration SQL").example("query-builder migrate:generate").example("query-builder migrate:generate ./app/Models --dialect postgres").action(async (dir, opts) => {
|
|
31400
31529
|
try {
|
|
31401
31530
|
await migrateGenerate(dir, {
|
|
31402
31531
|
dialect: opts?.dialect,
|
|
@@ -31428,7 +31557,7 @@ cli.command("db:stats", "Show database statistics (alias for db:info)").example(
|
|
|
31428
31557
|
proc.default.exitCode = 1;
|
|
31429
31558
|
}
|
|
31430
31559
|
});
|
|
31431
|
-
cli.command("db:wipe", "Drop all tables from the database").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31560
|
+
cli.command("db:wipe", "Drop all tables from the database").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--force", "Skip confirmation prompt").option("--verbose", "Enable verbose output").example("query-builder db:wipe").example("query-builder db:wipe --force").action(async (opts) => {
|
|
31432
31561
|
try {
|
|
31433
31562
|
await dbWipe({
|
|
31434
31563
|
dialect: opts.dialect,
|
|
@@ -31441,7 +31570,7 @@ cli.command("db:wipe", "Drop all tables from the database").option("--dialect <d
|
|
|
31441
31570
|
proc.default.exitCode = 1;
|
|
31442
31571
|
}
|
|
31443
31572
|
});
|
|
31444
|
-
cli.command("db:optimize", "Optimize database tables (VACUUM, ANALYZE, OPTIMIZE)").option("--dialect <d>", "Dialect (postgres|mysql|sqlite)
|
|
31573
|
+
cli.command("db:optimize", "Optimize database tables (VACUUM, ANALYZE, OPTIMIZE)").option("--dialect <d>", "Dialect (postgres|mysql|sqlite) \u2014 defaults to the configured dialect").option("--aggressive", "Use aggressive optimization (VACUUM FULL for postgres)").option("--tables <tables>", "Comma-separated list of tables to optimize").option("--verbose", "Enable verbose output").example("query-builder db:optimize").example("query-builder db:optimize --aggressive").example("query-builder db:optimize --tables users,posts").action(async (opts) => {
|
|
31445
31574
|
try {
|
|
31446
31575
|
await dbOptimize({
|
|
31447
31576
|
dialect: opts.dialect,
|