bun-query-builder 0.1.62 → 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 +432 -293
- package/dist/config.d.ts +30 -3
- package/dist/db.d.ts +18 -0
- package/dist/inflect.d.ts +17 -0
- package/dist/migrations.d.ts +26 -0
- package/dist/src/index.js +419 -277
- 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}`;
|
|
@@ -11662,26 +11671,23 @@ function getPlaceholders(count, startIndex = 1) {
|
|
|
11662
11671
|
return count === 1 ? "?" : `?${", ?".repeat(count - 1)}`;
|
|
11663
11672
|
}
|
|
11664
11673
|
async function getConfig() {
|
|
11665
|
-
if (!
|
|
11666
|
-
|
|
11674
|
+
if (!configState.fileLoaded) {
|
|
11675
|
+
configState.fileLoaded = true;
|
|
11676
|
+
const loaded = await loadConfig6({
|
|
11667
11677
|
name: "query-builder",
|
|
11668
11678
|
alias: "qb",
|
|
11669
11679
|
defaultConfig: defaultConfig4
|
|
11670
11680
|
});
|
|
11671
|
-
|
|
11681
|
+
const applicable = {};
|
|
11682
|
+
for (const [key, value] of Object.entries(loaded ?? {})) {
|
|
11683
|
+
if (!configState.explicit.has(key))
|
|
11684
|
+
applicable[key] = value;
|
|
11685
|
+
}
|
|
11686
|
+
applyConfig(applicable);
|
|
11672
11687
|
}
|
|
11673
11688
|
return config5;
|
|
11674
11689
|
}
|
|
11675
|
-
function
|
|
11676
|
-
if (userConfig.dialect && _lastConfiguredDialect && userConfig.dialect !== _lastConfiguredDialect) {
|
|
11677
|
-
const key = `${_lastConfiguredDialect}->${userConfig.dialect}`;
|
|
11678
|
-
if (!_warnedDialectConflicts.has(key)) {
|
|
11679
|
-
_warnedDialectConflicts.add(key);
|
|
11680
|
-
console.warn(`[query-builder] setConfig({ dialect: '${userConfig.dialect}' }) overrides a previous ` + `setConfig({ dialect: '${_lastConfiguredDialect}' }). ` + `Config is process-wide; in-flight queries from the previous configuration may break. ` + `Run conflicting connections in separate processes \u2014 see stacksjs/stacks#1862 #18.`);
|
|
11681
|
-
}
|
|
11682
|
-
}
|
|
11683
|
-
if (userConfig.dialect)
|
|
11684
|
-
_lastConfiguredDialect = userConfig.dialect;
|
|
11690
|
+
function applyConfig(userConfig) {
|
|
11685
11691
|
Object.assign(config5, userConfig);
|
|
11686
11692
|
if (userConfig.database) {
|
|
11687
11693
|
config5.database = { ...config5.database, ...userConfig.database };
|
|
@@ -11695,11 +11701,22 @@ function setConfig(userConfig) {
|
|
|
11695
11701
|
if (userConfig.softDeletes) {
|
|
11696
11702
|
config5.softDeletes = { ...config5.softDeletes, ...userConfig.softDeletes };
|
|
11697
11703
|
}
|
|
11698
|
-
|
|
11699
|
-
|
|
11704
|
+
}
|
|
11705
|
+
function setConfig(userConfig) {
|
|
11706
|
+
if (userConfig.dialect && _lastConfiguredDialect && userConfig.dialect !== _lastConfiguredDialect) {
|
|
11707
|
+
const key = `${_lastConfiguredDialect}->${userConfig.dialect}`;
|
|
11708
|
+
if (!_warnedDialectConflicts.has(key)) {
|
|
11709
|
+
_warnedDialectConflicts.add(key);
|
|
11710
|
+
console.warn(`[query-builder] setConfig({ dialect: '${userConfig.dialect}' }) overrides a previous ` + `setConfig({ dialect: '${_lastConfiguredDialect}' }). ` + `Config is process-wide; in-flight queries from the previous configuration may break. ` + `Run conflicting connections in separate processes \u2014 see stacksjs/stacks#1862 #18.`);
|
|
11711
|
+
}
|
|
11700
11712
|
}
|
|
11713
|
+
if (userConfig.dialect)
|
|
11714
|
+
_lastConfiguredDialect = userConfig.dialect;
|
|
11715
|
+
for (const key of Object.keys(userConfig))
|
|
11716
|
+
configState.explicit.add(key);
|
|
11717
|
+
applyConfig(userConfig);
|
|
11701
11718
|
}
|
|
11702
|
-
var defaultConfig4, CONFIG_SINGLETON_KEY, config5,
|
|
11719
|
+
var defaultConfig4, CONFIG_SINGLETON_KEY, config5, CONFIG_STATE_KEY, configState, _lastConfiguredDialect = null, _warnedDialectConflicts;
|
|
11703
11720
|
var init_config = __esm(() => {
|
|
11704
11721
|
init_dist();
|
|
11705
11722
|
defaultConfig4 = {
|
|
@@ -11762,6 +11779,8 @@ var init_config = __esm(() => {
|
|
|
11762
11779
|
};
|
|
11763
11780
|
CONFIG_SINGLETON_KEY = Symbol.for("bun-query-builder.config");
|
|
11764
11781
|
config5 = globalThis[CONFIG_SINGLETON_KEY] ??= { ...defaultConfig4 };
|
|
11782
|
+
CONFIG_STATE_KEY = Symbol.for("bun-query-builder.config-state");
|
|
11783
|
+
configState = globalThis[CONFIG_STATE_KEY] ??= { explicit: new Set, fileLoaded: false };
|
|
11765
11784
|
_warnedDialectConflicts = new Set;
|
|
11766
11785
|
});
|
|
11767
11786
|
|
|
@@ -11792,7 +11811,7 @@ var {SQL } = globalThis.Bun;
|
|
|
11792
11811
|
import { Database } from "bun:sqlite";
|
|
11793
11812
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
11794
11813
|
import { dirname as dirname5 } from "path";
|
|
11795
|
-
import
|
|
11814
|
+
import process21 from "process";
|
|
11796
11815
|
|
|
11797
11816
|
class SQLiteWrapper {
|
|
11798
11817
|
db;
|
|
@@ -12070,9 +12089,13 @@ function sqliteFileFromUrl(url) {
|
|
|
12070
12089
|
const path = stripped.startsWith("///") ? stripped.slice(2) : stripped.startsWith("//") ? stripped.slice(2) : stripped;
|
|
12071
12090
|
return path || ":memory:";
|
|
12072
12091
|
}
|
|
12092
|
+
function resolveDatabaseName(dbConfig = config5.database) {
|
|
12093
|
+
const raw = process21.env.DB_DATABASE || dbConfig?.database || "";
|
|
12094
|
+
return String(raw).replace(/^['"]|['"]$/g, "");
|
|
12095
|
+
}
|
|
12073
12096
|
function createConnectionString(dialect, dbConfig) {
|
|
12074
|
-
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") &&
|
|
12075
|
-
const e =
|
|
12097
|
+
if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process21.env.DB_CONNECTION === dialect) {
|
|
12098
|
+
const e = process21.env;
|
|
12076
12099
|
const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
|
|
12077
12100
|
const envUser = e.DB_USERNAME || dbConfig.username;
|
|
12078
12101
|
const envPass = e.DB_PASSWORD ?? dbConfig.password ?? "";
|
|
@@ -12086,7 +12109,7 @@ function createConnectionString(dialect, dbConfig) {
|
|
|
12086
12109
|
return dialect === "sqlite" ? sqliteFileFromUrl(dbConfig.url) : dbConfig.url;
|
|
12087
12110
|
}
|
|
12088
12111
|
const { database, username, password, host = "localhost", port, ssl } = dbConfig;
|
|
12089
|
-
const sslQ = ssl ||
|
|
12112
|
+
const sslQ = ssl || process21.env.DB_SSL === "true" || process21.env.DB_SSL === "1" ? "?ssl=true" : "";
|
|
12090
12113
|
switch (dialect) {
|
|
12091
12114
|
case "postgres":
|
|
12092
12115
|
return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
|
|
@@ -12360,6 +12383,17 @@ var init_benchmark = __esm(() => {
|
|
|
12360
12383
|
});
|
|
12361
12384
|
|
|
12362
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
|
+
}
|
|
12363
12397
|
function stripTrailingS(name) {
|
|
12364
12398
|
return name.endsWith("s") ? name.slice(0, -1) : name;
|
|
12365
12399
|
}
|
|
@@ -16580,7 +16614,7 @@ var init_cache = __esm(() => {
|
|
|
16580
16614
|
});
|
|
16581
16615
|
|
|
16582
16616
|
// src/actions/console.ts
|
|
16583
|
-
import
|
|
16617
|
+
import process22 from "process";
|
|
16584
16618
|
import { createInterface } from "readline";
|
|
16585
16619
|
async function startConsole() {
|
|
16586
16620
|
console.log("-- Query Builder Interactive Console");
|
|
@@ -16589,8 +16623,8 @@ async function startConsole() {
|
|
|
16589
16623
|
console.log();
|
|
16590
16624
|
const qb = createQueryBuilder();
|
|
16591
16625
|
const rl = createInterface({
|
|
16592
|
-
input:
|
|
16593
|
-
output:
|
|
16626
|
+
input: process22.stdin,
|
|
16627
|
+
output: process22.stdout,
|
|
16594
16628
|
prompt: "qb> "
|
|
16595
16629
|
});
|
|
16596
16630
|
let multilineBuffer = "";
|
|
@@ -16641,7 +16675,7 @@ Tips:
|
|
|
16641
16675
|
if (cmd === ".exit" || cmd === ".quit") {
|
|
16642
16676
|
console.log("Goodbye!");
|
|
16643
16677
|
rl.close();
|
|
16644
|
-
|
|
16678
|
+
process22.exit(0);
|
|
16645
16679
|
} else if (cmd === ".help") {
|
|
16646
16680
|
console.log(helpText);
|
|
16647
16681
|
} else if (cmd === ".clear") {
|
|
@@ -16712,7 +16746,7 @@ Tips:
|
|
|
16712
16746
|
rl.on("close", () => {
|
|
16713
16747
|
console.log(`
|
|
16714
16748
|
Goodbye!`);
|
|
16715
|
-
|
|
16749
|
+
process22.exit(0);
|
|
16716
16750
|
});
|
|
16717
16751
|
rl.prompt();
|
|
16718
16752
|
}
|
|
@@ -17090,9 +17124,8 @@ var init_db_info = __esm(() => {
|
|
|
17090
17124
|
});
|
|
17091
17125
|
|
|
17092
17126
|
// src/actions/db-optimize.ts
|
|
17093
|
-
import process22 from "process";
|
|
17094
17127
|
async function dbOptimize(options = {}) {
|
|
17095
|
-
const dialect = options.dialect
|
|
17128
|
+
const dialect = resolveDialect(options.dialect);
|
|
17096
17129
|
const aggressive = options.aggressive || false;
|
|
17097
17130
|
if (options.verbose) {
|
|
17098
17131
|
console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
|
|
@@ -17132,7 +17165,7 @@ async function dbOptimize(options = {}) {
|
|
|
17132
17165
|
await bunSql`ANALYZE TABLE ${bunSql(table)}`;
|
|
17133
17166
|
}
|
|
17134
17167
|
} else {
|
|
17135
|
-
const dbName =
|
|
17168
|
+
const dbName = resolveDatabaseName();
|
|
17136
17169
|
const tables = await bunSql`
|
|
17137
17170
|
SELECT table_name
|
|
17138
17171
|
FROM information_schema.tables
|
|
@@ -17185,9 +17218,8 @@ var init_db_optimize = __esm(() => {
|
|
|
17185
17218
|
});
|
|
17186
17219
|
|
|
17187
17220
|
// src/actions/db-wipe.ts
|
|
17188
|
-
import process23 from "process";
|
|
17189
17221
|
async function dbWipe(options = {}) {
|
|
17190
|
-
const dialect = options.dialect
|
|
17222
|
+
const dialect = resolveDialect(options.dialect);
|
|
17191
17223
|
if (options.verbose) {
|
|
17192
17224
|
console.log(`Wiping all tables from ${dialect} database...`);
|
|
17193
17225
|
}
|
|
@@ -17201,7 +17233,7 @@ async function dbWipe(options = {}) {
|
|
|
17201
17233
|
`;
|
|
17202
17234
|
tables = result.map((row) => row.tablename);
|
|
17203
17235
|
} else if (isMysqlLike(dialect)) {
|
|
17204
|
-
const dbName =
|
|
17236
|
+
const dbName = resolveDatabaseName();
|
|
17205
17237
|
const result = await bunSql`
|
|
17206
17238
|
SELECT table_name
|
|
17207
17239
|
FROM information_schema.tables
|
|
@@ -17638,6 +17670,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17638
17670
|
return "decimal";
|
|
17639
17671
|
if (base === "date")
|
|
17640
17672
|
return "date";
|
|
17673
|
+
if (base === "timestamptz" || /\bwith time zone\b/.test(t))
|
|
17674
|
+
return "timestamptz";
|
|
17641
17675
|
if (/^(?:timestamp|datetime)/.test(base))
|
|
17642
17676
|
return "datetime";
|
|
17643
17677
|
if (/^time/.test(base))
|
|
@@ -17893,7 +17927,7 @@ var init_introspect_db = __esm(() => {
|
|
|
17893
17927
|
// src/actions/make-model.ts
|
|
17894
17928
|
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10 } from "fs";
|
|
17895
17929
|
import { dirname as dirname7, join as join7 } from "path";
|
|
17896
|
-
import
|
|
17930
|
+
import process23 from "process";
|
|
17897
17931
|
function findWorkspaceRoot(startPath) {
|
|
17898
17932
|
let currentPath = startPath;
|
|
17899
17933
|
while (currentPath !== dirname7(currentPath)) {
|
|
@@ -17902,10 +17936,10 @@ function findWorkspaceRoot(startPath) {
|
|
|
17902
17936
|
}
|
|
17903
17937
|
currentPath = dirname7(currentPath);
|
|
17904
17938
|
}
|
|
17905
|
-
return
|
|
17939
|
+
return process23.cwd();
|
|
17906
17940
|
}
|
|
17907
17941
|
async function makeModel(name, options = {}) {
|
|
17908
|
-
const workspaceRoot = findWorkspaceRoot(
|
|
17942
|
+
const workspaceRoot = findWorkspaceRoot(process23.cwd());
|
|
17909
17943
|
const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
|
|
17910
17944
|
if (!existsSync14(modelsDir)) {
|
|
17911
17945
|
mkdirSync7(modelsDir, { recursive: true });
|
|
@@ -18101,7 +18135,7 @@ class MySQLDriver {
|
|
|
18101
18135
|
)`;
|
|
18102
18136
|
}
|
|
18103
18137
|
getExecutedMigrationsQuery() {
|
|
18104
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18138
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18105
18139
|
}
|
|
18106
18140
|
recordMigrationQuery() {
|
|
18107
18141
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18282,7 +18316,7 @@ class PostgresDriver {
|
|
|
18282
18316
|
)`;
|
|
18283
18317
|
}
|
|
18284
18318
|
getExecutedMigrationsQuery() {
|
|
18285
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18319
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18286
18320
|
}
|
|
18287
18321
|
recordMigrationQuery() {
|
|
18288
18322
|
return "INSERT INTO migrations (migration) VALUES ($1)";
|
|
@@ -18527,7 +18561,7 @@ class SQLiteDriver {
|
|
|
18527
18561
|
)`;
|
|
18528
18562
|
}
|
|
18529
18563
|
getExecutedMigrationsQuery() {
|
|
18530
|
-
return "SELECT migration FROM migrations ORDER BY executed_at";
|
|
18564
|
+
return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
|
|
18531
18565
|
}
|
|
18532
18566
|
recordMigrationQuery() {
|
|
18533
18567
|
return "INSERT INTO migrations (migration) VALUES (?)";
|
|
@@ -18580,6 +18614,24 @@ var init_drivers = __esm(() => {
|
|
|
18580
18614
|
init_singlestore();
|
|
18581
18615
|
});
|
|
18582
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
|
+
|
|
18583
18635
|
// src/actions/migrate.ts
|
|
18584
18636
|
var exports_migrate = {};
|
|
18585
18637
|
__export(exports_migrate, {
|
|
@@ -18591,23 +18643,48 @@ __export(exports_migrate, {
|
|
|
18591
18643
|
copyModelsToGenerated: () => copyModelsToGenerated,
|
|
18592
18644
|
clearGeneratedDirectory: () => clearGeneratedDirectory
|
|
18593
18645
|
});
|
|
18594
|
-
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";
|
|
18595
18647
|
import { tmpdir } from "os";
|
|
18596
|
-
import { join as
|
|
18648
|
+
import { join as join10 } from "path";
|
|
18597
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
|
+
}
|
|
18598
18675
|
function info(message) {
|
|
18599
18676
|
if (config5.verbose)
|
|
18600
18677
|
console.log(message);
|
|
18601
18678
|
}
|
|
18602
18679
|
function getSnapshotDir(workspaceRoot) {
|
|
18603
|
-
return
|
|
18680
|
+
return join10(workspaceRoot, config5.snapshotDir || ".qb");
|
|
18604
18681
|
}
|
|
18605
18682
|
function getSnapshotPath(workspaceRoot, dialect) {
|
|
18606
|
-
return
|
|
18683
|
+
return join10(getSnapshotDir(workspaceRoot), `model-snapshot.${dialect}.json`);
|
|
18607
18684
|
}
|
|
18608
18685
|
function loadPlanSnapshot(workspaceRoot, dialect) {
|
|
18609
18686
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18610
|
-
if (!
|
|
18687
|
+
if (!existsSync17(snapshotPath)) {
|
|
18611
18688
|
return;
|
|
18612
18689
|
}
|
|
18613
18690
|
try {
|
|
@@ -18630,7 +18707,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18630
18707
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18631
18708
|
const snapshotDir = getSnapshotDir(workspaceRoot);
|
|
18632
18709
|
const hash = hashMigrationPlan(plan);
|
|
18633
|
-
if (
|
|
18710
|
+
if (existsSync17(snapshotPath)) {
|
|
18634
18711
|
try {
|
|
18635
18712
|
const current = JSON.parse(readFileSync3(snapshotPath, "utf8"));
|
|
18636
18713
|
if (current?.hash === hash && current?.dialect === dialect && current?.plan) {
|
|
@@ -18639,7 +18716,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
|
|
|
18639
18716
|
}
|
|
18640
18717
|
} catch {}
|
|
18641
18718
|
}
|
|
18642
|
-
if (!
|
|
18719
|
+
if (!existsSync17(snapshotDir)) {
|
|
18643
18720
|
mkdirSync8(snapshotDir, { recursive: true });
|
|
18644
18721
|
info(`-- Created snapshot directory: ${snapshotDir}`);
|
|
18645
18722
|
}
|
|
@@ -18657,11 +18734,11 @@ function saveMigrationSnapshot(plan, options = {}) {
|
|
|
18657
18734
|
savePlanSnapshot(options.workspaceRoot ?? getWorkspaceRoot(), dialect, plan);
|
|
18658
18735
|
}
|
|
18659
18736
|
function getWorkspaceRoot() {
|
|
18660
|
-
return
|
|
18737
|
+
return findWorkspaceRoot2();
|
|
18661
18738
|
}
|
|
18662
18739
|
function ensureSqlDirectory(workspaceRoot) {
|
|
18663
18740
|
const sqlDir = getSqlDirectory(workspaceRoot);
|
|
18664
|
-
if (!
|
|
18741
|
+
if (!existsSync17(sqlDir)) {
|
|
18665
18742
|
mkdirSync8(sqlDir, { recursive: true });
|
|
18666
18743
|
info(`-- Created SQL directory: ${sqlDir}`);
|
|
18667
18744
|
}
|
|
@@ -18670,21 +18747,22 @@ function ensureSqlDirectory(workspaceRoot) {
|
|
|
18670
18747
|
async function generateMigration(dir, opts = {}) {
|
|
18671
18748
|
await getConfig();
|
|
18672
18749
|
if (!dir) {
|
|
18673
|
-
dir =
|
|
18750
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18674
18751
|
}
|
|
18675
18752
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18676
18753
|
const workspaceRoot = getWorkspaceRoot();
|
|
18677
18754
|
const models = await loadModels({ modelsDir: dir });
|
|
18678
18755
|
const plan = buildMigrationPlan2(models, { dialect });
|
|
18679
18756
|
let previous;
|
|
18757
|
+
let reconciledFromDatabase = false;
|
|
18680
18758
|
if (!opts.full) {
|
|
18681
18759
|
previous = loadPlanSnapshot(workspaceRoot, dialect);
|
|
18682
18760
|
if (previous) {
|
|
18683
18761
|
info("-- Comparing with stored model snapshot");
|
|
18684
18762
|
} else {
|
|
18685
|
-
const defaultStatePath =
|
|
18763
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18686
18764
|
const statePath = String(opts.state || defaultStatePath);
|
|
18687
|
-
if (
|
|
18765
|
+
if (existsSync17(statePath)) {
|
|
18688
18766
|
try {
|
|
18689
18767
|
const raw2 = readFileSync3(statePath, "utf8");
|
|
18690
18768
|
const parsed = JSON.parse(raw2);
|
|
@@ -18701,6 +18779,7 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18701
18779
|
const scoped = livePlan.tables.filter((t) => modelTables.has(t.table));
|
|
18702
18780
|
if (scoped.length > 0) {
|
|
18703
18781
|
previous = { dialect: livePlan.dialect, tables: scoped };
|
|
18782
|
+
reconciledFromDatabase = true;
|
|
18704
18783
|
info(`-- No snapshot; reconciling against live database (${scoped.length} matching table${scoped.length === 1 ? "" : "s"})`);
|
|
18705
18784
|
}
|
|
18706
18785
|
} catch (err) {
|
|
@@ -18714,25 +18793,34 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18714
18793
|
} else {
|
|
18715
18794
|
info("-- Full migration requested, ignoring any previous state");
|
|
18716
18795
|
}
|
|
18717
|
-
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
|
+
});
|
|
18718
18801
|
const sqlStatements = diff.statements;
|
|
18719
18802
|
const operations = diff.operations;
|
|
18720
18803
|
const sql = sqlStatements.join(`
|
|
18721
18804
|
`);
|
|
18722
18805
|
const hasChanges = sqlStatements.some((stmt) => /\b(?:CREATE|ALTER|DROP)\b/i.test(stmt));
|
|
18723
18806
|
if (opts.apply) {
|
|
18724
|
-
const dirPath = mkdtempSync(
|
|
18725
|
-
const filePath =
|
|
18807
|
+
const dirPath = mkdtempSync(join10(tmpdir(), "qb-migrate-"));
|
|
18808
|
+
const filePath = join10(dirPath, "migration.sql");
|
|
18726
18809
|
try {
|
|
18727
18810
|
if (hasChanges) {
|
|
18728
18811
|
writeFileSync11(filePath, sql);
|
|
18812
|
+
const qb = createQueryBuilder();
|
|
18813
|
+
await qb.file(filePath);
|
|
18729
18814
|
info("-- Migration applied");
|
|
18815
|
+
await settleAppliedFiles(qb, dialect, lastCreatedMigrationFiles());
|
|
18730
18816
|
} else {
|
|
18731
18817
|
info("-- No changes; nothing to apply");
|
|
18732
18818
|
}
|
|
18733
18819
|
} catch (err) {
|
|
18734
18820
|
console.error("-- Migration failed:", err);
|
|
18735
18821
|
throw err;
|
|
18822
|
+
} finally {
|
|
18823
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
18736
18824
|
}
|
|
18737
18825
|
}
|
|
18738
18826
|
if (!opts.dryRun)
|
|
@@ -18741,9 +18829,6 @@ async function generateMigration(dir, opts = {}) {
|
|
|
18741
18829
|
}
|
|
18742
18830
|
async function executeMigration(dir) {
|
|
18743
18831
|
await getConfig();
|
|
18744
|
-
if (!dir) {
|
|
18745
|
-
dir = join9(process25.cwd(), "app/Models");
|
|
18746
|
-
}
|
|
18747
18832
|
const workspaceRoot = getWorkspaceRoot();
|
|
18748
18833
|
const sqlDir = ensureSqlDirectory(workspaceRoot);
|
|
18749
18834
|
const dialect = config5.dialect || "postgres";
|
|
@@ -18758,42 +18843,25 @@ async function executeMigration(dir) {
|
|
|
18758
18843
|
const qb = createQueryBuilder();
|
|
18759
18844
|
await createMigrationsTable(qb, dialect);
|
|
18760
18845
|
const executedMigrations = await getExecutedMigrations(qb, dialect);
|
|
18761
|
-
const
|
|
18762
|
-
|
|
18763
|
-
for (const file2 of scriptFiles) {
|
|
18764
|
-
if (file2.includes("alter-") && file2.includes("-table")) {
|
|
18765
|
-
transientMigrations.push(file2);
|
|
18766
|
-
} else if (!executedMigrations.includes(file2)) {
|
|
18767
|
-
permanentMigrations.push(file2);
|
|
18768
|
-
}
|
|
18769
|
-
}
|
|
18770
|
-
const totalPending = permanentMigrations.length + transientMigrations.length;
|
|
18771
|
-
if (totalPending === 0) {
|
|
18846
|
+
const pending = scriptFiles.filter((file2) => !executedMigrations.includes(file2));
|
|
18847
|
+
if (pending.length === 0) {
|
|
18772
18848
|
info("-- No pending migrations to execute");
|
|
18773
18849
|
return true;
|
|
18774
18850
|
}
|
|
18775
|
-
info(`-- Executing ${
|
|
18776
|
-
for (const file2 of
|
|
18777
|
-
const filePath =
|
|
18851
|
+
info(`-- Executing ${pending.length} migration${pending.length === 1 ? "" : "s"}`);
|
|
18852
|
+
for (const file2 of pending) {
|
|
18853
|
+
const filePath = join10(sqlDir, file2);
|
|
18778
18854
|
info(`-- Executing: ${file2}`);
|
|
18779
18855
|
try {
|
|
18780
18856
|
await qb.file(filePath);
|
|
18781
18857
|
await recordMigration(qb, file2, dialect);
|
|
18782
18858
|
info(`-- \u2713 Migration ${file2} executed and recorded`);
|
|
18783
18859
|
} catch (err) {
|
|
18784
|
-
|
|
18785
|
-
|
|
18786
|
-
|
|
18787
|
-
|
|
18788
|
-
|
|
18789
|
-
const filePath = join9(sqlDir, file2);
|
|
18790
|
-
info(`-- Executing: ${file2} (transient)`);
|
|
18791
|
-
try {
|
|
18792
|
-
await qb.file(filePath);
|
|
18793
|
-
info(`-- \u2713 Migration ${file2} executed (not recorded)`);
|
|
18794
|
-
unlinkSync(filePath);
|
|
18795
|
-
info(`-- \uD83D\uDDD1\uFE0F Deleted transient migration: ${file2}`);
|
|
18796
|
-
} 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
|
+
}
|
|
18797
18865
|
console.error(`-- \u2717 Migration ${file2} failed:`, err);
|
|
18798
18866
|
throw err;
|
|
18799
18867
|
}
|
|
@@ -18808,7 +18876,7 @@ async function executeMigration(dir) {
|
|
|
18808
18876
|
async function resetDatabase(dir, opts = {}) {
|
|
18809
18877
|
await getConfig();
|
|
18810
18878
|
if (!dir) {
|
|
18811
|
-
dir =
|
|
18879
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18812
18880
|
}
|
|
18813
18881
|
const dialect = opts.dialect || config5.dialect || "postgres";
|
|
18814
18882
|
const driver = getDialectDriver(dialect);
|
|
@@ -18905,42 +18973,50 @@ async function resetDatabase(dir, opts = {}) {
|
|
|
18905
18973
|
}
|
|
18906
18974
|
async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
|
|
18907
18975
|
if (!dir) {
|
|
18908
|
-
dir =
|
|
18976
|
+
dir = join10(process25.cwd(), "app/Models");
|
|
18909
18977
|
}
|
|
18910
18978
|
if (!workspaceRoot) {
|
|
18911
18979
|
workspaceRoot = getWorkspaceRoot();
|
|
18912
18980
|
}
|
|
18913
18981
|
const dialect = String(opts.dialect || config5.dialect || "postgres");
|
|
18914
18982
|
const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
|
|
18915
|
-
if (
|
|
18983
|
+
if (existsSync17(snapshotPath)) {
|
|
18916
18984
|
unlinkSync(snapshotPath);
|
|
18917
18985
|
info(`-- Removed model snapshot file: ${snapshotPath}`);
|
|
18918
18986
|
}
|
|
18919
|
-
const defaultStatePath =
|
|
18987
|
+
const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
|
|
18920
18988
|
const statePath = String(opts.state || defaultStatePath);
|
|
18921
|
-
if (
|
|
18989
|
+
if (existsSync17(statePath)) {
|
|
18922
18990
|
unlinkSync(statePath);
|
|
18923
18991
|
info(`-- Removed legacy migration state file: ${statePath}`);
|
|
18924
18992
|
}
|
|
18925
|
-
|
|
18926
|
-
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
|
|
18930
|
-
|
|
18931
|
-
|
|
18932
|
-
|
|
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;
|
|
18933
19004
|
}
|
|
18934
|
-
|
|
19005
|
+
unlinkSync(join10(sqlDir, file2));
|
|
19006
|
+
info(`-- Removed generated migration file: ${file2}`);
|
|
19007
|
+
removed += 1;
|
|
18935
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` : ""}`);
|
|
18936
19012
|
}
|
|
18937
19013
|
async function copyModelsToGenerated(_dir, _workspaceRoot) {}
|
|
18938
19014
|
async function clearGeneratedDirectory(workspaceRoot) {
|
|
18939
19015
|
if (!workspaceRoot) {
|
|
18940
19016
|
workspaceRoot = getWorkspaceRoot();
|
|
18941
19017
|
}
|
|
18942
|
-
const generatedDir =
|
|
18943
|
-
if (
|
|
19018
|
+
const generatedDir = join10(workspaceRoot, "generated");
|
|
19019
|
+
if (existsSync17(generatedDir)) {
|
|
18944
19020
|
try {
|
|
18945
19021
|
rmSync(generatedDir, { recursive: true, force: true });
|
|
18946
19022
|
info("-- Cleared generated directory");
|
|
@@ -18949,12 +19025,6 @@ async function clearGeneratedDirectory(workspaceRoot) {
|
|
|
18949
19025
|
}
|
|
18950
19026
|
}
|
|
18951
19027
|
}
|
|
18952
|
-
function getSqlDirectory(workspaceRoot) {
|
|
18953
|
-
if (!workspaceRoot) {
|
|
18954
|
-
workspaceRoot = getWorkspaceRoot();
|
|
18955
|
-
}
|
|
18956
|
-
return join9(workspaceRoot, "database", "migrations");
|
|
18957
|
-
}
|
|
18958
19028
|
async function createMigrationsTable(qb, dialect) {
|
|
18959
19029
|
const driver = getDialectDriver(dialect);
|
|
18960
19030
|
const createTableSql = driver.createMigrationsTable();
|
|
@@ -18993,6 +19063,7 @@ var init_migrate = __esm(() => {
|
|
|
18993
19063
|
init_drivers();
|
|
18994
19064
|
init_src2();
|
|
18995
19065
|
init_introspect_db();
|
|
19066
|
+
init_workspace();
|
|
18996
19067
|
});
|
|
18997
19068
|
|
|
18998
19069
|
// src/actions/migrate-generate.ts
|
|
@@ -19004,28 +19075,49 @@ var init_migrate_generate = __esm(() => {
|
|
|
19004
19075
|
});
|
|
19005
19076
|
|
|
19006
19077
|
// src/actions/migrate-rollback.ts
|
|
19007
|
-
import { existsSync as
|
|
19008
|
-
import {
|
|
19009
|
-
import process26 from "process";
|
|
19078
|
+
import { existsSync as existsSync18, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
19079
|
+
import { join as join11 } from "path";
|
|
19010
19080
|
function splitSqlStatements2(sql) {
|
|
19011
19081
|
const out = [];
|
|
19012
19082
|
let buf = "";
|
|
19013
|
-
let
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
|
|
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 === ";") {
|
|
19023
19115
|
if (buf.trim())
|
|
19024
19116
|
out.push(buf.trim());
|
|
19025
19117
|
buf = "";
|
|
19026
|
-
|
|
19027
|
-
buf += ch;
|
|
19118
|
+
continue;
|
|
19028
19119
|
}
|
|
19120
|
+
buf += ch;
|
|
19029
19121
|
}
|
|
19030
19122
|
if (buf.trim())
|
|
19031
19123
|
out.push(buf.trim());
|
|
@@ -19039,8 +19131,20 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19039
19131
|
let m;
|
|
19040
19132
|
if (m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
|
|
19041
19133
|
down.push(`DROP TABLE IF EXISTS ${q(m[1])}`);
|
|
19042
|
-
} else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+
|
|
19043
|
-
|
|
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)}`);
|
|
19044
19148
|
} else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
|
|
19045
19149
|
down.push(isMysqlLike(dialect) && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
|
|
19046
19150
|
} else {
|
|
@@ -19049,22 +19153,6 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
|
|
|
19049
19153
|
}
|
|
19050
19154
|
return { down: down.reverse(), skipped };
|
|
19051
19155
|
}
|
|
19052
|
-
function findWorkspaceRoot2(startPath) {
|
|
19053
|
-
let currentPath = startPath;
|
|
19054
|
-
while (currentPath !== dirname8(currentPath)) {
|
|
19055
|
-
if (existsSync17(join10(currentPath, "package.json"))) {
|
|
19056
|
-
return currentPath;
|
|
19057
|
-
}
|
|
19058
|
-
currentPath = dirname8(currentPath);
|
|
19059
|
-
}
|
|
19060
|
-
return process26.cwd();
|
|
19061
|
-
}
|
|
19062
|
-
function getSqlDirectory2(workspaceRoot) {
|
|
19063
|
-
if (!workspaceRoot) {
|
|
19064
|
-
workspaceRoot = findWorkspaceRoot2(process26.cwd());
|
|
19065
|
-
}
|
|
19066
|
-
return join10(workspaceRoot, "database", "migrations");
|
|
19067
|
-
}
|
|
19068
19156
|
async function migrateRollback(options = {}) {
|
|
19069
19157
|
const steps = options.steps || 1;
|
|
19070
19158
|
const reverseSchema = options.reverseSchema !== false;
|
|
@@ -19097,12 +19185,12 @@ async function migrateRollback(options = {}) {
|
|
|
19097
19185
|
console.log(` - ${migration.migration}`);
|
|
19098
19186
|
}
|
|
19099
19187
|
console.log();
|
|
19100
|
-
const sqlDir =
|
|
19188
|
+
const sqlDir = getSqlDirectory();
|
|
19101
19189
|
let reversedAny = false;
|
|
19102
19190
|
for (const migration of migrationsToRollback) {
|
|
19103
19191
|
try {
|
|
19104
|
-
const filePath =
|
|
19105
|
-
if (reverseSchema &&
|
|
19192
|
+
const filePath = join11(sqlDir, migration.migration);
|
|
19193
|
+
if (reverseSchema && existsSync18(filePath)) {
|
|
19106
19194
|
const forwardSql = readFileSync4(filePath, "utf8");
|
|
19107
19195
|
const { down, skipped } = deriveDownStatements(forwardSql);
|
|
19108
19196
|
for (const stmt of down) {
|
|
@@ -19113,10 +19201,10 @@ async function migrateRollback(options = {}) {
|
|
|
19113
19201
|
if (skipped.length > 0)
|
|
19114
19202
|
console.log(`-- \u26A0\uFE0F ${skipped.length} statement(s) in ${migration.migration} could not be auto-reversed (data/complex DDL) \u2014 reverse manually.`);
|
|
19115
19203
|
}
|
|
19116
|
-
const deleteSql = `DELETE FROM migrations WHERE migration = $1`;
|
|
19204
|
+
const deleteSql = `DELETE FROM migrations WHERE migration = ${getPlaceholder(1)}`;
|
|
19117
19205
|
await qb.unsafe(deleteSql, [migration.migration]);
|
|
19118
19206
|
console.log(`-- \u2713 Removed migration record: ${migration.migration}`);
|
|
19119
|
-
if (
|
|
19207
|
+
if (options.deleteFiles && existsSync18(filePath)) {
|
|
19120
19208
|
unlinkSync2(filePath);
|
|
19121
19209
|
console.log(`-- \uD83D\uDDD1\uFE0F Deleted migration file: ${migration.migration}`);
|
|
19122
19210
|
}
|
|
@@ -19139,37 +19227,20 @@ async function migrateRollback(options = {}) {
|
|
|
19139
19227
|
var init_migrate_rollback = __esm(() => {
|
|
19140
19228
|
init_config();
|
|
19141
19229
|
init_src2();
|
|
19230
|
+
init_workspace();
|
|
19142
19231
|
});
|
|
19143
19232
|
|
|
19144
19233
|
// src/actions/migrate-status.ts
|
|
19145
|
-
import { existsSync as
|
|
19146
|
-
import { dirname as dirname9, join as join11 } from "path";
|
|
19147
|
-
import process27 from "process";
|
|
19148
|
-
function findWorkspaceRoot3(startPath) {
|
|
19149
|
-
let currentPath = startPath;
|
|
19150
|
-
while (currentPath !== dirname9(currentPath)) {
|
|
19151
|
-
if (existsSync18(join11(currentPath, "package.json"))) {
|
|
19152
|
-
return currentPath;
|
|
19153
|
-
}
|
|
19154
|
-
currentPath = dirname9(currentPath);
|
|
19155
|
-
}
|
|
19156
|
-
return process27.cwd();
|
|
19157
|
-
}
|
|
19158
|
-
function getSqlDirectory3(workspaceRoot) {
|
|
19159
|
-
if (!workspaceRoot) {
|
|
19160
|
-
workspaceRoot = findWorkspaceRoot3(process27.cwd());
|
|
19161
|
-
}
|
|
19162
|
-
return join11(workspaceRoot, "database", "migrations");
|
|
19163
|
-
}
|
|
19234
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8 } from "fs";
|
|
19164
19235
|
async function migrateStatus() {
|
|
19165
19236
|
const dialect = config5.dialect || "postgres";
|
|
19166
19237
|
const driver = getDialectDriver(dialect);
|
|
19167
|
-
const sqlDir =
|
|
19238
|
+
const sqlDir = getSqlDirectory();
|
|
19168
19239
|
console.log("-- Migration Status");
|
|
19169
19240
|
console.log(`-- Dialect: ${dialect}`);
|
|
19170
19241
|
console.log(`-- SQL directory: ${sqlDir}`);
|
|
19171
19242
|
console.log();
|
|
19172
|
-
if (!
|
|
19243
|
+
if (!existsSync19(sqlDir)) {
|
|
19173
19244
|
console.log("-- No SQL directory found. No migrations have been created yet.");
|
|
19174
19245
|
return [];
|
|
19175
19246
|
}
|
|
@@ -19190,27 +19261,16 @@ async function migrateStatus() {
|
|
|
19190
19261
|
console.log();
|
|
19191
19262
|
}
|
|
19192
19263
|
const executedMap = new Map(executedMigrations.map((m) => [m.migration, m.executed_at]));
|
|
19193
|
-
const statuses = migrationFiles.map((file2) => {
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
};
|
|
19199
|
-
}
|
|
19200
|
-
const executedAt = executedMap.get(file2);
|
|
19201
|
-
return {
|
|
19202
|
-
file: file2,
|
|
19203
|
-
status: executedAt ? "executed" : "pending",
|
|
19204
|
-
executedAt
|
|
19205
|
-
};
|
|
19206
|
-
});
|
|
19264
|
+
const statuses = migrationFiles.map((file2) => ({
|
|
19265
|
+
file: file2,
|
|
19266
|
+
status: executedMap.has(file2) ? "executed" : "pending",
|
|
19267
|
+
executedAt: executedMap.get(file2)
|
|
19268
|
+
}));
|
|
19207
19269
|
const executed = statuses.filter((s) => s.status === "executed");
|
|
19208
19270
|
const pending = statuses.filter((s) => s.status === "pending");
|
|
19209
|
-
const transient = statuses.filter((s) => s.status === "transient");
|
|
19210
19271
|
console.log(`-- Total migrations: ${migrationFiles.length}`);
|
|
19211
19272
|
console.log(`-- Executed: ${executed.length}`);
|
|
19212
19273
|
console.log(`-- Pending: ${pending.length}`);
|
|
19213
|
-
console.log(`-- Transient: ${transient.length}`);
|
|
19214
19274
|
console.log();
|
|
19215
19275
|
if (executed.length > 0) {
|
|
19216
19276
|
console.log("\u2713 Executed Migrations:");
|
|
@@ -19226,13 +19286,6 @@ async function migrateStatus() {
|
|
|
19226
19286
|
}
|
|
19227
19287
|
console.log();
|
|
19228
19288
|
}
|
|
19229
|
-
if (transient.length > 0) {
|
|
19230
|
-
console.log("\u26A1 Transient Migrations (ALTER TABLE - not tracked):");
|
|
19231
|
-
for (const migration of transient) {
|
|
19232
|
-
console.log(` - ${migration.file}`);
|
|
19233
|
-
}
|
|
19234
|
-
console.log();
|
|
19235
|
-
}
|
|
19236
19289
|
return statuses;
|
|
19237
19290
|
} catch (err) {
|
|
19238
19291
|
console.error("-- Failed to get migration status:", err);
|
|
@@ -19246,14 +19299,15 @@ var init_migrate_status = __esm(() => {
|
|
|
19246
19299
|
init_config();
|
|
19247
19300
|
init_drivers();
|
|
19248
19301
|
init_src2();
|
|
19302
|
+
init_workspace();
|
|
19249
19303
|
});
|
|
19250
19304
|
|
|
19251
19305
|
// src/actions/model-show.ts
|
|
19252
19306
|
import { readdirSync as readdirSync9 } from "fs";
|
|
19253
19307
|
import { extname as extname2, join as join12 } from "path";
|
|
19254
|
-
import
|
|
19308
|
+
import process26 from "process";
|
|
19255
19309
|
async function modelShow(modelName, options = {}) {
|
|
19256
|
-
const dir = options.dir || join12(
|
|
19310
|
+
const dir = options.dir || join12(process26.cwd(), "app/Models");
|
|
19257
19311
|
try {
|
|
19258
19312
|
const files = readdirSync9(dir);
|
|
19259
19313
|
const modelFile = files.find((f) => {
|
|
@@ -19467,9 +19521,9 @@ var init_query_explain_all = __esm(() => {
|
|
|
19467
19521
|
// src/actions/relation-diagram.ts
|
|
19468
19522
|
import { writeFileSync as writeFileSync12 } from "fs";
|
|
19469
19523
|
import { join as join14 } from "path";
|
|
19470
|
-
import
|
|
19524
|
+
import process27 from "process";
|
|
19471
19525
|
async function relationDiagram(options = {}) {
|
|
19472
|
-
const dir = options.dir || join14(
|
|
19526
|
+
const dir = options.dir || join14(process27.cwd(), "app/Models");
|
|
19473
19527
|
const format = options.format || "mermaid";
|
|
19474
19528
|
try {
|
|
19475
19529
|
const models = await loadModels({ modelsDir: dir });
|
|
@@ -19589,25 +19643,25 @@ var init_relation_diagram = __esm(() => {
|
|
|
19589
19643
|
});
|
|
19590
19644
|
|
|
19591
19645
|
// src/actions/seed.ts
|
|
19592
|
-
import { existsSync as
|
|
19646
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
|
|
19593
19647
|
import { dirname as dirname10, join as join15 } from "path";
|
|
19594
|
-
import
|
|
19595
|
-
function
|
|
19648
|
+
import process28 from "process";
|
|
19649
|
+
function findWorkspaceRoot3(startPath) {
|
|
19596
19650
|
let currentPath = startPath;
|
|
19597
19651
|
while (currentPath !== dirname10(currentPath)) {
|
|
19598
|
-
if (
|
|
19652
|
+
if (existsSync20(join15(currentPath, "package.json"))) {
|
|
19599
19653
|
return currentPath;
|
|
19600
19654
|
}
|
|
19601
19655
|
currentPath = dirname10(currentPath);
|
|
19602
19656
|
}
|
|
19603
|
-
return
|
|
19657
|
+
return process28.cwd();
|
|
19604
19658
|
}
|
|
19605
19659
|
async function loadSeeders(seedersDir) {
|
|
19606
|
-
if (!
|
|
19660
|
+
if (!existsSync20(seedersDir)) {
|
|
19607
19661
|
console.log(`-- Seeders directory not found: ${seedersDir}`);
|
|
19608
19662
|
return [];
|
|
19609
19663
|
}
|
|
19610
|
-
const files = readdirSync11(seedersDir);
|
|
19664
|
+
const files = readdirSync11(seedersDir).sort((a, b) => a.localeCompare(b));
|
|
19611
19665
|
const seederFiles = files.filter((file2) => (file2.endsWith(".ts") || file2.endsWith(".js")) && file2 !== "index.ts" && file2 !== "index.js");
|
|
19612
19666
|
const seeders = [];
|
|
19613
19667
|
for (const file2 of seederFiles) {
|
|
@@ -19620,6 +19674,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19620
19674
|
if (instance && typeof instance.run === "function") {
|
|
19621
19675
|
seeders.push({
|
|
19622
19676
|
name: file2.replace(/\.(ts|js)$/, ""),
|
|
19677
|
+
className: String(SeederClass.name || ""),
|
|
19623
19678
|
instance
|
|
19624
19679
|
});
|
|
19625
19680
|
}
|
|
@@ -19632,7 +19687,7 @@ async function loadSeeders(seedersDir) {
|
|
|
19632
19687
|
return seeders;
|
|
19633
19688
|
}
|
|
19634
19689
|
async function runSeeders(config6 = {}) {
|
|
19635
|
-
const workspaceRoot =
|
|
19690
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19636
19691
|
const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19637
19692
|
const verbose = config6.verbose ?? true;
|
|
19638
19693
|
if (verbose) {
|
|
@@ -19667,17 +19722,18 @@ async function runSeeders(config6 = {}) {
|
|
|
19667
19722
|
}
|
|
19668
19723
|
}
|
|
19669
19724
|
async function runSeeder(className, options = {}) {
|
|
19670
|
-
const workspaceRoot =
|
|
19725
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19671
19726
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19672
19727
|
const verbose = options.verbose ?? true;
|
|
19673
19728
|
if (verbose) {
|
|
19674
19729
|
console.log(`-- Running seeder: ${className}`);
|
|
19675
19730
|
}
|
|
19676
19731
|
const seeders = await loadSeeders(seedersDir);
|
|
19677
|
-
const seeder = seeders.find((s) => s.name === className);
|
|
19732
|
+
const seeder = seeders.find((s) => s.className === className) ?? seeders.find((s) => s.name === className);
|
|
19678
19733
|
if (!seeder) {
|
|
19679
|
-
|
|
19680
|
-
|
|
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}`);
|
|
19681
19737
|
}
|
|
19682
19738
|
const qb = createQueryBuilder();
|
|
19683
19739
|
try {
|
|
@@ -19691,9 +19747,9 @@ async function runSeeder(className, options = {}) {
|
|
|
19691
19747
|
}
|
|
19692
19748
|
}
|
|
19693
19749
|
async function makeSeeder(name) {
|
|
19694
|
-
const workspaceRoot =
|
|
19750
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19695
19751
|
const seedersDir = join15(workspaceRoot, "database/seeders");
|
|
19696
|
-
if (!
|
|
19752
|
+
if (!existsSync20(seedersDir)) {
|
|
19697
19753
|
mkdirSync9(seedersDir, { recursive: true });
|
|
19698
19754
|
console.log(`-- Created seeders directory: ${seedersDir}`);
|
|
19699
19755
|
}
|
|
@@ -19701,7 +19757,7 @@ async function makeSeeder(name) {
|
|
|
19701
19757
|
const className = `${baseName}Seeder`;
|
|
19702
19758
|
const fileName = `${className}.ts`;
|
|
19703
19759
|
const filePath = join15(seedersDir, fileName);
|
|
19704
|
-
if (
|
|
19760
|
+
if (existsSync20(filePath)) {
|
|
19705
19761
|
console.error(`-- Seeder already exists: ${filePath}`);
|
|
19706
19762
|
throw new Error(`Seeder already exists: ${filePath}`);
|
|
19707
19763
|
}
|
|
@@ -19755,7 +19811,7 @@ export default class ${className} extends Seeder {
|
|
|
19755
19811
|
console.log(`-- \u2713 Created seeder: ${filePath}`);
|
|
19756
19812
|
}
|
|
19757
19813
|
async function freshDatabase(options = {}) {
|
|
19758
|
-
const workspaceRoot =
|
|
19814
|
+
const workspaceRoot = findWorkspaceRoot3(process28.cwd());
|
|
19759
19815
|
const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
|
|
19760
19816
|
const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
|
|
19761
19817
|
const verbose = options.verbose ?? true;
|
|
@@ -19815,22 +19871,22 @@ var init_unsafe = __esm(() => {
|
|
|
19815
19871
|
});
|
|
19816
19872
|
|
|
19817
19873
|
// src/actions/validate.ts
|
|
19818
|
-
import { existsSync as
|
|
19874
|
+
import { existsSync as existsSync21 } from "fs";
|
|
19819
19875
|
import { dirname as dirname11, join as join16 } from "path";
|
|
19820
|
-
import
|
|
19821
|
-
function
|
|
19876
|
+
import process29 from "process";
|
|
19877
|
+
function findWorkspaceRoot4(startPath) {
|
|
19822
19878
|
let currentPath = startPath;
|
|
19823
19879
|
while (currentPath !== dirname11(currentPath)) {
|
|
19824
|
-
if (
|
|
19880
|
+
if (existsSync21(join16(currentPath, "package.json"))) {
|
|
19825
19881
|
return currentPath;
|
|
19826
19882
|
}
|
|
19827
19883
|
currentPath = dirname11(currentPath);
|
|
19828
19884
|
}
|
|
19829
|
-
return
|
|
19885
|
+
return process29.cwd();
|
|
19830
19886
|
}
|
|
19831
19887
|
async function validateSchema(dir) {
|
|
19832
19888
|
if (!dir) {
|
|
19833
|
-
dir = join16(
|
|
19889
|
+
dir = join16(findWorkspaceRoot4(process29.cwd()), "app/Models");
|
|
19834
19890
|
}
|
|
19835
19891
|
const dialect = config5.dialect || "postgres";
|
|
19836
19892
|
console.log("-- Validating Schema");
|
|
@@ -25081,18 +25137,11 @@ function toSnakeCase(str) {
|
|
|
25081
25137
|
snakeCaseCache.set(str, cached);
|
|
25082
25138
|
return cached;
|
|
25083
25139
|
}
|
|
25084
|
-
function
|
|
25140
|
+
function toTableName2(modelName) {
|
|
25085
25141
|
let cached = tableNameCache.get(modelName);
|
|
25086
25142
|
if (cached !== undefined)
|
|
25087
25143
|
return cached;
|
|
25088
|
-
|
|
25089
|
-
if (snake.endsWith("y") && !snake.endsWith("ay") && !snake.endsWith("ey") && !snake.endsWith("oy") && !snake.endsWith("uy")) {
|
|
25090
|
-
cached = snake.slice(0, -1) + "ies";
|
|
25091
|
-
} else if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh")) {
|
|
25092
|
-
cached = `${snake}es`;
|
|
25093
|
-
} else {
|
|
25094
|
-
cached = `${snake}s`;
|
|
25095
|
-
}
|
|
25144
|
+
cached = toTableName(modelName);
|
|
25096
25145
|
tableNameCache.set(modelName, cached);
|
|
25097
25146
|
return cached;
|
|
25098
25147
|
}
|
|
@@ -25177,14 +25226,14 @@ function resolveRelation(definition, relationName) {
|
|
|
25177
25226
|
const hasManyModel = findModelName(definition.hasMany);
|
|
25178
25227
|
if (hasManyModel) {
|
|
25179
25228
|
const relatedModel = getModelFromRegistry(hasManyModel);
|
|
25180
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25229
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasManyModel);
|
|
25181
25230
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25182
25231
|
return { type: "hasMany", relatedModelName: hasManyModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25183
25232
|
}
|
|
25184
25233
|
const hasOneModel = findModelName(definition.hasOne);
|
|
25185
25234
|
if (hasOneModel) {
|
|
25186
25235
|
const relatedModel = getModelFromRegistry(hasOneModel);
|
|
25187
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25236
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(hasOneModel);
|
|
25188
25237
|
const foreignKey = toSnakeCase(parentName) + "_id";
|
|
25189
25238
|
return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
|
|
25190
25239
|
}
|
|
@@ -25192,7 +25241,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25192
25241
|
if (belongsToEntry) {
|
|
25193
25242
|
const belongsToModel = belongsToEntry.model;
|
|
25194
25243
|
const relatedModel = getModelFromRegistry(belongsToModel);
|
|
25195
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25244
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(belongsToModel);
|
|
25196
25245
|
const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
|
|
25197
25246
|
const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
|
|
25198
25247
|
return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
|
|
@@ -25202,7 +25251,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25202
25251
|
const isConfig = typeof found.entry === "object";
|
|
25203
25252
|
const relatedModelName = isConfig ? found.entry.model : found.entry;
|
|
25204
25253
|
const relatedModel = getModelFromRegistry(relatedModelName);
|
|
25205
|
-
const relatedTable = relatedModel?.getTable?.() ||
|
|
25254
|
+
const relatedTable = relatedModel?.getTable?.() || toTableName2(relatedModelName);
|
|
25206
25255
|
const config6 = isConfig ? found.entry : null;
|
|
25207
25256
|
let pivotTable;
|
|
25208
25257
|
let pivotModelName;
|
|
@@ -25214,7 +25263,7 @@ function resolveRelation(definition, relationName) {
|
|
|
25214
25263
|
if (!throughModel) {
|
|
25215
25264
|
throw new Error(`[orm] belongsToMany relation '${relationName}' on '${parentName}' references unknown through model '${config6.through}'. Make sure '${config6.through}' is registered.`);
|
|
25216
25265
|
}
|
|
25217
|
-
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table ||
|
|
25266
|
+
pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName2(config6.through);
|
|
25218
25267
|
} else {
|
|
25219
25268
|
const a2 = singularizeWord(parentTable);
|
|
25220
25269
|
const b2 = singularizeWord(relatedTable);
|
|
@@ -25265,10 +25314,10 @@ function resolveRelation(definition, relationName) {
|
|
|
25265
25314
|
return null;
|
|
25266
25315
|
const throughModel = getModelFromRegistry(throughModelName);
|
|
25267
25316
|
const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
|
|
25268
|
-
const throughTable = throughModel?.getTable?.() || throughDef?.table ||
|
|
25317
|
+
const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName2(throughModelName);
|
|
25269
25318
|
const throughPk = throughDef?.primaryKey || "id";
|
|
25270
25319
|
const targetModel = getModelFromRegistry(targetModelName);
|
|
25271
|
-
const targetTable = targetModel?.getTable?.() ||
|
|
25320
|
+
const targetTable = targetModel?.getTable?.() || toTableName2(targetModelName);
|
|
25272
25321
|
return {
|
|
25273
25322
|
type,
|
|
25274
25323
|
relatedModelName: targetModelName,
|
|
@@ -27378,7 +27427,7 @@ function resolveKeyPattern(keyPatterns, data) {
|
|
|
27378
27427
|
}
|
|
27379
27428
|
return resolved;
|
|
27380
27429
|
}
|
|
27381
|
-
async function parseStacksModels(
|
|
27430
|
+
async function parseStacksModels(_config) {
|
|
27382
27431
|
return { models: new Map };
|
|
27383
27432
|
}
|
|
27384
27433
|
function toDynamoDBItem(item) {
|
|
@@ -27865,7 +27914,7 @@ function buildDatabaseSchema(models) {
|
|
|
27865
27914
|
for (const modelName of Object.keys(models)) {
|
|
27866
27915
|
const rawModel = models[modelName];
|
|
27867
27916
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27868
|
-
const table =
|
|
27917
|
+
const table = tableNameFor(m2);
|
|
27869
27918
|
const attrs = m2.attributes ?? {};
|
|
27870
27919
|
const columns = {};
|
|
27871
27920
|
for (const key of Object.keys(attrs))
|
|
@@ -27877,30 +27926,53 @@ function buildDatabaseSchema(models) {
|
|
|
27877
27926
|
}
|
|
27878
27927
|
return schema;
|
|
27879
27928
|
}
|
|
27929
|
+
var init_factory = () => {};
|
|
27880
27930
|
|
|
27881
27931
|
// src/loader.ts
|
|
27882
|
-
import { readdirSync as readdirSync12
|
|
27883
|
-
import { basename, extname as extname4 } from "path";
|
|
27884
|
-
import
|
|
27885
|
-
|
|
27886
|
-
const
|
|
27887
|
-
|
|
27888
|
-
|
|
27889
|
-
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));
|
|
27890
27953
|
for (const entry of entries) {
|
|
27891
|
-
const full =
|
|
27892
|
-
|
|
27893
|
-
|
|
27894
|
-
continue;
|
|
27895
|
-
const ext = extname4(full);
|
|
27896
|
-
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));
|
|
27897
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)) {
|
|
27898
27969
|
const cacheBuster = `?t=${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
27899
27970
|
const mod = await import(`${full}${cacheBuster}`);
|
|
27900
27971
|
const rawDef = mod.default ?? mod;
|
|
27901
27972
|
const def = rawDef.definition ?? rawDef.getDefinition?.() ?? rawDef;
|
|
27902
|
-
|
|
27903
|
-
|
|
27973
|
+
if (!isModelDefinition(def))
|
|
27974
|
+
continue;
|
|
27975
|
+
const name = def.name ?? basename(full, extname4(full));
|
|
27904
27976
|
result[name] = {
|
|
27905
27977
|
...def,
|
|
27906
27978
|
name
|
|
@@ -27908,7 +27980,10 @@ async function loadModels(options) {
|
|
|
27908
27980
|
}
|
|
27909
27981
|
return result;
|
|
27910
27982
|
}
|
|
27911
|
-
var
|
|
27983
|
+
var MODEL_EXTENSIONS;
|
|
27984
|
+
var init_loader = __esm(() => {
|
|
27985
|
+
MODEL_EXTENSIONS = new Set([".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"]);
|
|
27986
|
+
});
|
|
27912
27987
|
|
|
27913
27988
|
// src/meta.ts
|
|
27914
27989
|
function buildSchemaMeta(models) {
|
|
@@ -27920,7 +27995,7 @@ function buildSchemaMeta(models) {
|
|
|
27920
27995
|
for (const name of Object.keys(models)) {
|
|
27921
27996
|
const rawModel = models[name];
|
|
27922
27997
|
const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
|
|
27923
|
-
const table =
|
|
27998
|
+
const table = tableNameFor(m2);
|
|
27924
27999
|
modelToTable[name] = table;
|
|
27925
28000
|
tableToModel[table] = name;
|
|
27926
28001
|
primaryKeys[table] = m2.primaryKey ?? "id";
|
|
@@ -27994,9 +28069,9 @@ function buildSchemaMeta(models) {
|
|
|
27994
28069
|
var init_meta = () => {};
|
|
27995
28070
|
|
|
27996
28071
|
// src/migrations.ts
|
|
27997
|
-
import { existsSync as
|
|
27998
|
-
import { dirname as dirname12, join as
|
|
27999
|
-
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";
|
|
28000
28075
|
function info2(message) {
|
|
28001
28076
|
if (config5.verbose)
|
|
28002
28077
|
console.log(message);
|
|
@@ -28007,36 +28082,80 @@ function snakeCase(str) {
|
|
|
28007
28082
|
function singularizeTable(table) {
|
|
28008
28083
|
return singularizerFor(config5.relations?.singularizeStrategy)(table);
|
|
28009
28084
|
}
|
|
28010
|
-
function
|
|
28085
|
+
function lastCreatedMigrationFiles() {
|
|
28086
|
+
return [...createdMigrationFiles];
|
|
28087
|
+
}
|
|
28088
|
+
function findWorkspaceRoot5(startPath) {
|
|
28011
28089
|
let currentPath = startPath;
|
|
28012
28090
|
while (currentPath !== dirname12(currentPath)) {
|
|
28013
|
-
if (
|
|
28091
|
+
if (existsSync23(join18(currentPath, "package.json"))) {
|
|
28014
28092
|
return currentPath;
|
|
28015
28093
|
}
|
|
28016
28094
|
currentPath = dirname12(currentPath);
|
|
28017
28095
|
}
|
|
28018
|
-
return
|
|
28096
|
+
return process31.cwd();
|
|
28019
28097
|
}
|
|
28020
28098
|
function ensureSqlDirectory2() {
|
|
28021
|
-
const workspaceRoot =
|
|
28022
|
-
const sqlDir =
|
|
28023
|
-
if (!
|
|
28099
|
+
const workspaceRoot = findWorkspaceRoot5(process31.cwd());
|
|
28100
|
+
const sqlDir = join18(workspaceRoot, "database", "migrations");
|
|
28101
|
+
if (!existsSync23(sqlDir)) {
|
|
28024
28102
|
mkdirSync10(sqlDir, { recursive: true });
|
|
28025
28103
|
info2(`-- Created SQL directory: ${sqlDir}`);
|
|
28026
28104
|
}
|
|
28027
28105
|
return sqlDir;
|
|
28028
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
|
+
}
|
|
28029
28130
|
function createMigrationFile(statement, fileName) {
|
|
28030
28131
|
if (!statement)
|
|
28031
28132
|
return false;
|
|
28032
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
|
+
}
|
|
28033
28141
|
migrationCounter++;
|
|
28034
|
-
|
|
28035
|
-
|
|
28036
|
-
|
|
28037
|
-
|
|
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}`);
|
|
28038
28155
|
info2(`-- Migration file created: ${fullFileName}`);
|
|
28039
28156
|
migrationsCreatedCount++;
|
|
28157
|
+
createdMigrationFiles.push(fullFileName);
|
|
28158
|
+
existingCorpusBodies?.add(body);
|
|
28040
28159
|
return true;
|
|
28041
28160
|
}
|
|
28042
28161
|
function guessTypeFromName(columnName) {
|
|
@@ -28211,7 +28330,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28211
28330
|
const tables = [];
|
|
28212
28331
|
for (const modelName of Object.keys(models)) {
|
|
28213
28332
|
const model = models[modelName];
|
|
28214
|
-
const table =
|
|
28333
|
+
const table = tableNameFor(model);
|
|
28215
28334
|
const primaryKey = model.primaryKey ?? "id";
|
|
28216
28335
|
const _autoIncrement = model.autoIncrement !== false;
|
|
28217
28336
|
const attrs = model.attributes ?? {};
|
|
@@ -28303,9 +28422,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28303
28422
|
if (columns.some((c2) => c2.name === fkColumnName))
|
|
28304
28423
|
continue;
|
|
28305
28424
|
const refTable = meta.modelToTable[rel.model];
|
|
28306
|
-
|
|
28307
|
-
continue;
|
|
28308
|
-
const refPk = meta.primaryKeys[refTable] ?? "id";
|
|
28425
|
+
const refPk = refTable ? meta.primaryKeys[refTable] ?? "id" : undefined;
|
|
28309
28426
|
columns.push({
|
|
28310
28427
|
name: fkColumnName,
|
|
28311
28428
|
type: "bigint",
|
|
@@ -28313,7 +28430,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28313
28430
|
isUnique: false,
|
|
28314
28431
|
isNullable: true,
|
|
28315
28432
|
hasDefault: false,
|
|
28316
|
-
references: { table: refTable, column: refPk, onDelete: rel.onDelete }
|
|
28433
|
+
references: refTable && refPk ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
|
|
28317
28434
|
});
|
|
28318
28435
|
}
|
|
28319
28436
|
const traits = model.traits;
|
|
@@ -28394,7 +28511,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28394
28511
|
for (const modelName of Object.keys(models)) {
|
|
28395
28512
|
const model = models[modelName];
|
|
28396
28513
|
const traits = model?.traits ?? {};
|
|
28397
|
-
const modelTable =
|
|
28514
|
+
const modelTable = tableNameFor(model);
|
|
28398
28515
|
const singular = singularizeTable(modelTable);
|
|
28399
28516
|
if (traits.likeable) {
|
|
28400
28517
|
const opts = typeof traits.likeable === "object" ? traits.likeable : {};
|
|
@@ -28461,7 +28578,7 @@ function buildMigrationPlan2(models, options) {
|
|
|
28461
28578
|
const btm = model?.belongsToMany;
|
|
28462
28579
|
if (!btm || typeof btm !== "object" || Array.isArray(btm))
|
|
28463
28580
|
continue;
|
|
28464
|
-
const parentTable =
|
|
28581
|
+
const parentTable = tableNameFor(model);
|
|
28465
28582
|
const parentSingular = singularizeTable(parentTable);
|
|
28466
28583
|
for (const [relKey, value] of Object.entries(btm)) {
|
|
28467
28584
|
const cfg = value;
|
|
@@ -28522,6 +28639,8 @@ function generateSql(plan, opts = {}) {
|
|
|
28522
28639
|
migrationCounter = 0;
|
|
28523
28640
|
migrationsCreatedCount = 0;
|
|
28524
28641
|
migrationsUpdatedCount = 0;
|
|
28642
|
+
createdMigrationFiles = [];
|
|
28643
|
+
existingCorpusBodies = null;
|
|
28525
28644
|
useDeterministicNames = true;
|
|
28526
28645
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28527
28646
|
const statements = [];
|
|
@@ -28783,12 +28902,13 @@ function referencesAreDifferent(r1, r2) {
|
|
|
28783
28902
|
const act = (a2) => (a2 ?? "no action").toLowerCase();
|
|
28784
28903
|
return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
|
|
28785
28904
|
}
|
|
28905
|
+
function indexKey(index) {
|
|
28906
|
+
return `${index.type}:${index.name}:${index.columns.join(",")}`;
|
|
28907
|
+
}
|
|
28786
28908
|
function mapIndexesByKey(indexes) {
|
|
28787
28909
|
const map = {};
|
|
28788
|
-
for (const i2 of indexes)
|
|
28789
|
-
|
|
28790
|
-
map[key] = i2;
|
|
28791
|
-
}
|
|
28910
|
+
for (const i2 of indexes)
|
|
28911
|
+
map[indexKey(i2)] = i2;
|
|
28792
28912
|
return map;
|
|
28793
28913
|
}
|
|
28794
28914
|
function generateDiffOperations(previous, next, opts = {}) {
|
|
@@ -28803,10 +28923,13 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28803
28923
|
return { statements: statements2, operations: operations2 };
|
|
28804
28924
|
}
|
|
28805
28925
|
const applyRenames = opts.applyRenames !== false;
|
|
28926
|
+
const preserveUnknownColumns = opts.preserveUnknownColumns === true;
|
|
28806
28927
|
const emit = opts.dryRun ? () => false : createMigrationFile;
|
|
28807
28928
|
migrationCounter = 0;
|
|
28808
28929
|
migrationsCreatedCount = 0;
|
|
28809
28930
|
migrationsUpdatedCount = 0;
|
|
28931
|
+
createdMigrationFiles = [];
|
|
28932
|
+
existingCorpusBodies = null;
|
|
28810
28933
|
useDeterministicNames = false;
|
|
28811
28934
|
const chunks = [];
|
|
28812
28935
|
const operations = [];
|
|
@@ -28905,22 +29028,32 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
28905
29028
|
}
|
|
28906
29029
|
for (const tableName of Object.keys(nextTables)) {
|
|
28907
29030
|
const prev = prevTables[tableName];
|
|
28908
|
-
|
|
29031
|
+
let curr = nextTables[tableName];
|
|
28909
29032
|
if (!prev)
|
|
28910
29033
|
continue;
|
|
28911
29034
|
const prevCols = mapColumnsByName(prev.columns);
|
|
28912
|
-
const currCols = mapColumnsByName(curr.columns);
|
|
28913
29035
|
const prevIdx = mapIndexesByKey(prev.indexes);
|
|
28914
|
-
|
|
29036
|
+
let currCols = mapColumnsByName(curr.columns);
|
|
29037
|
+
let currIdx = mapIndexesByKey(curr.indexes);
|
|
28915
29038
|
let renames = [];
|
|
28916
29039
|
let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
|
|
28917
29040
|
let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
|
|
28918
|
-
if (applyRenames) {
|
|
29041
|
+
if (applyRenames && !preserveUnknownColumns) {
|
|
28919
29042
|
const detected = detectColumnRenames(prevCols, currCols, dialect);
|
|
28920
29043
|
renames = detected.renames;
|
|
28921
29044
|
removedCols = detected.removed;
|
|
28922
29045
|
addedCols = detected.added;
|
|
28923
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
|
+
}
|
|
28924
29057
|
const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
|
|
28925
29058
|
const fkChangedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && referencesAreDifferent(prevCols[n2].references, currCols[n2].references));
|
|
28926
29059
|
if (dialect === "sqlite") {
|
|
@@ -29068,11 +29201,12 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
29068
29201
|
function generateDiffSql(previous, next, opts = {}) {
|
|
29069
29202
|
return generateDiffOperations(previous, next, opts).statements;
|
|
29070
29203
|
}
|
|
29071
|
-
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";
|
|
29072
29205
|
var init_migrations = __esm(() => {
|
|
29073
29206
|
init_config();
|
|
29074
29207
|
init_drivers();
|
|
29075
29208
|
init_meta();
|
|
29209
|
+
createdMigrationFiles = [];
|
|
29076
29210
|
});
|
|
29077
29211
|
|
|
29078
29212
|
// src/schema.ts
|
|
@@ -29106,6 +29240,7 @@ var init_src2 = __esm(() => {
|
|
|
29106
29240
|
init_dynamodb_single_table();
|
|
29107
29241
|
init_dynamodb_tooling_adapter();
|
|
29108
29242
|
init_dynamodb();
|
|
29243
|
+
init_factory();
|
|
29109
29244
|
init_loader();
|
|
29110
29245
|
init_meta();
|
|
29111
29246
|
init_migrations();
|
|
@@ -29115,11 +29250,11 @@ var init_src2 = __esm(() => {
|
|
|
29115
29250
|
});
|
|
29116
29251
|
|
|
29117
29252
|
// ../../node_modules/@stacksjs/clapp/dist/index.js
|
|
29118
|
-
import { existsSync as
|
|
29253
|
+
import { existsSync as existsSync25 } from "fs";
|
|
29119
29254
|
import fs from "fs/promises";
|
|
29120
29255
|
import os from "os";
|
|
29121
29256
|
import path from "path";
|
|
29122
|
-
import
|
|
29257
|
+
import process33 from "process";
|
|
29123
29258
|
import { EventEmitter } from "events";
|
|
29124
29259
|
import process52 from "process";
|
|
29125
29260
|
import process210 from "process";
|
|
@@ -29143,10 +29278,10 @@ class Telemetry {
|
|
|
29143
29278
|
this.configPath = path.join(configDir, "telemetry.json");
|
|
29144
29279
|
}
|
|
29145
29280
|
async isEnabled() {
|
|
29146
|
-
if (
|
|
29281
|
+
if (process33.env.DO_NOT_TRACK === "1" || process33.env.DO_NOT_TRACK === "true") {
|
|
29147
29282
|
return false;
|
|
29148
29283
|
}
|
|
29149
|
-
if (
|
|
29284
|
+
if (process33.env.NO_TELEMETRY === "1" || process33.env.NO_TELEMETRY === "true") {
|
|
29150
29285
|
return false;
|
|
29151
29286
|
}
|
|
29152
29287
|
const config6 = await this.loadConfig();
|
|
@@ -29175,7 +29310,7 @@ class Telemetry {
|
|
|
29175
29310
|
...data,
|
|
29176
29311
|
timestamp: Date.now(),
|
|
29177
29312
|
platform: os.platform(),
|
|
29178
|
-
nodeVersion:
|
|
29313
|
+
nodeVersion: process33.version
|
|
29179
29314
|
};
|
|
29180
29315
|
this.events.push(telemetryEvent);
|
|
29181
29316
|
if (this.events.length >= 10) {
|
|
@@ -29231,7 +29366,7 @@ class Telemetry {
|
|
|
29231
29366
|
const config6 = await this.loadConfig();
|
|
29232
29367
|
return {
|
|
29233
29368
|
enabled: config6.enabled,
|
|
29234
|
-
doNotTrack:
|
|
29369
|
+
doNotTrack: process33.env.DO_NOT_TRACK === "1" || process33.env.DO_NOT_TRACK === "true",
|
|
29235
29370
|
eventsQueued: this.events.length,
|
|
29236
29371
|
lastSent: config6.lastSent
|
|
29237
29372
|
};
|
|
@@ -29241,7 +29376,7 @@ class Telemetry {
|
|
|
29241
29376
|
return this.config;
|
|
29242
29377
|
}
|
|
29243
29378
|
try {
|
|
29244
|
-
if (
|
|
29379
|
+
if (existsSync25(this.configPath)) {
|
|
29245
29380
|
const data = await fs.readFile(this.configPath, "utf-8");
|
|
29246
29381
|
this.config = JSON.parse(data);
|
|
29247
29382
|
return this.config;
|
|
@@ -31153,7 +31288,7 @@ function getPrefix() {
|
|
|
31153
31288
|
}
|
|
31154
31289
|
var prefix = getPrefix();
|
|
31155
31290
|
// package.json
|
|
31156
|
-
var version2 = "0.
|
|
31291
|
+
var version2 = "0.2.0";
|
|
31157
31292
|
|
|
31158
31293
|
// bin/cli.ts
|
|
31159
31294
|
init_actions();
|
|
@@ -31208,7 +31343,7 @@ cli.command("unsafe <sql>", "Execute an unsafe SQL string (one statement with pa
|
|
|
31208
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) => {
|
|
31209
31344
|
await file(path2, opts);
|
|
31210
31345
|
});
|
|
31211
|
-
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) => {
|
|
31212
31347
|
try {
|
|
31213
31348
|
await generateMigration(dir, {
|
|
31214
31349
|
dialect: opts.dialect,
|
|
@@ -31252,7 +31387,7 @@ cli.command("relation:diagram", "Generate relationship diagram from models").opt
|
|
|
31252
31387
|
proc.default.exitCode = 1;
|
|
31253
31388
|
}
|
|
31254
31389
|
});
|
|
31255
|
-
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) => {
|
|
31256
31391
|
try {
|
|
31257
31392
|
console.log("-- Resetting database...");
|
|
31258
31393
|
await resetDatabase(dir, {
|
|
@@ -31273,7 +31408,7 @@ cli.command("migrate:fresh <dir>", "Reset database and run all migrations").opti
|
|
|
31273
31408
|
proc.default.exitCode = 1;
|
|
31274
31409
|
}
|
|
31275
31410
|
});
|
|
31276
|
-
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) => {
|
|
31277
31412
|
try {
|
|
31278
31413
|
await resetDatabase(dir, {
|
|
31279
31414
|
dialect: opts.dialect,
|
|
@@ -31377,16 +31512,20 @@ cli.command("migrate:list", "List all migrations (alias for migrate:status)").ex
|
|
|
31377
31512
|
proc.default.exitCode = 1;
|
|
31378
31513
|
}
|
|
31379
31514
|
});
|
|
31380
|
-
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) => {
|
|
31381
31516
|
try {
|
|
31382
|
-
await migrateRollback({
|
|
31517
|
+
await migrateRollback({
|
|
31518
|
+
steps: Number(opts.steps),
|
|
31519
|
+
reverseSchema: opts.reverseSchema,
|
|
31520
|
+
deleteFiles: Boolean(opts.deleteFiles)
|
|
31521
|
+
});
|
|
31383
31522
|
} catch (err) {
|
|
31384
31523
|
console.error("-- Rollback failed:", err);
|
|
31385
31524
|
const proc = await import("process");
|
|
31386
31525
|
proc.default.exitCode = 1;
|
|
31387
31526
|
}
|
|
31388
31527
|
});
|
|
31389
|
-
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) => {
|
|
31390
31529
|
try {
|
|
31391
31530
|
await migrateGenerate(dir, {
|
|
31392
31531
|
dialect: opts?.dialect,
|
|
@@ -31418,7 +31557,7 @@ cli.command("db:stats", "Show database statistics (alias for db:info)").example(
|
|
|
31418
31557
|
proc.default.exitCode = 1;
|
|
31419
31558
|
}
|
|
31420
31559
|
});
|
|
31421
|
-
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) => {
|
|
31422
31561
|
try {
|
|
31423
31562
|
await dbWipe({
|
|
31424
31563
|
dialect: opts.dialect,
|
|
@@ -31431,7 +31570,7 @@ cli.command("db:wipe", "Drop all tables from the database").option("--dialect <d
|
|
|
31431
31570
|
proc.default.exitCode = 1;
|
|
31432
31571
|
}
|
|
31433
31572
|
});
|
|
31434
|
-
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) => {
|
|
31435
31574
|
try {
|
|
31436
31575
|
await dbOptimize({
|
|
31437
31576
|
dialect: opts.dialect,
|