@noego/proper 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.d.mts +1 -0
- package/bin/cli.d.ts +1 -0
- package/bin/cli.js +426 -39
- package/bin/cli.js.map +1 -1
- package/bin/cli.mjs +433 -39
- package/bin/cli.mjs.map +1 -1
- package/bin/index.d.mts +179 -0
- package/bin/index.d.ts +179 -0
- package/bin/index.js +430 -37
- package/bin/index.js.map +1 -1
- package/bin/index.mjs +428 -36
- package/bin/index.mjs.map +1 -1
- package/lib/runner.d.mts +51 -0
- package/lib/runner.d.ts +51 -0
- package/lib/runner.js +257 -0
- package/lib/runner.js.map +1 -0
- package/lib/runner.mjs +230 -0
- package/lib/runner.mjs.map +1 -0
- package/package.json +12 -1
- package/readme.md +295 -39
package/bin/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/bin/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/bin/cli.js
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
8
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
7
9
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
11
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
10
25
|
var __objRest = (source, exclude) => {
|
|
11
26
|
var target = {};
|
|
12
27
|
for (var prop in source)
|
|
@@ -393,26 +408,50 @@ var SqlMigrationBuilder = class {
|
|
|
393
408
|
|
|
394
409
|
// framework/MigrationDirectoryReader.ts
|
|
395
410
|
var MigrationDirectoryReader = class {
|
|
396
|
-
constructor(directory, read_strategy, sqlrunner) {
|
|
411
|
+
constructor(directory, read_strategy, sqlrunner, dialect = "sql") {
|
|
397
412
|
this.directory = directory;
|
|
398
413
|
this.read_strategy = read_strategy;
|
|
399
414
|
this.sqlrunner = sqlrunner;
|
|
415
|
+
this.dialect = dialect;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Resolves the appropriate file for a migration based on dialect.
|
|
419
|
+
* Priority: dialect-specific file > generic file
|
|
420
|
+
*/
|
|
421
|
+
resolveFile(baseName, direction) {
|
|
422
|
+
const dialectExt = this.dialect === "sql" ? "mysql" : "sqlite";
|
|
423
|
+
const dialectFile = import_path.default.join(this.directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
424
|
+
if (import_fs.default.existsSync(dialectFile)) return dialectFile;
|
|
425
|
+
const genericFile = import_path.default.join(this.directory, `${baseName}.${direction}.sql`);
|
|
426
|
+
if (import_fs.default.existsSync(genericFile)) return genericFile;
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Checks if a file path is dialect-specific (contains .mysql. or .sqlite. in the name)
|
|
431
|
+
*/
|
|
432
|
+
isDialectSpecific(filePath) {
|
|
433
|
+
return /\.(mysql|sqlite)\.(up|down)\.sql$/i.test(filePath);
|
|
400
434
|
}
|
|
401
435
|
loadMigrations(table, connection) {
|
|
402
436
|
import_fs.default.existsSync(this.directory) || import_fs.default.mkdirSync(this.directory);
|
|
403
437
|
const dir_content = import_fs.default.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name);
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
file
|
|
410
|
-
};
|
|
411
|
-
}).sort();
|
|
438
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
439
|
+
dir_content.forEach((file) => {
|
|
440
|
+
const key = file.replace(/(?:\.(mysql|sqlite))?\.(up|down)\.(sql|js)/i, "").toLowerCase();
|
|
441
|
+
uniqueKeys.add(key);
|
|
442
|
+
});
|
|
412
443
|
const migration_sorter = {};
|
|
413
|
-
|
|
414
|
-
const builder =
|
|
415
|
-
this.
|
|
444
|
+
uniqueKeys.forEach((migration_key) => {
|
|
445
|
+
const builder = new SqlMigrationBuilder(migration_key);
|
|
446
|
+
const upFile = this.resolveFile(migration_key, "up");
|
|
447
|
+
const downFile = this.resolveFile(migration_key, "down");
|
|
448
|
+
if (upFile) {
|
|
449
|
+
this.loadMigration(builder, upFile);
|
|
450
|
+
}
|
|
451
|
+
if (downFile) {
|
|
452
|
+
this.loadMigration(builder, downFile);
|
|
453
|
+
}
|
|
454
|
+
migration_sorter[migration_key] = builder;
|
|
416
455
|
});
|
|
417
456
|
const keys = Object.keys(migration_sorter);
|
|
418
457
|
keys.sort();
|
|
@@ -439,12 +478,16 @@ var MigrationDirectoryReader = class {
|
|
|
439
478
|
}
|
|
440
479
|
sql_up(file) {
|
|
441
480
|
let content = import_fs.default.readFileSync(file).toString();
|
|
442
|
-
|
|
481
|
+
if (!this.isDialectSpecific(file)) {
|
|
482
|
+
content = this.read_strategy(content);
|
|
483
|
+
}
|
|
443
484
|
return content.trim();
|
|
444
485
|
}
|
|
445
486
|
sql_down(file) {
|
|
446
487
|
let content = import_fs.default.readFileSync(file).toString();
|
|
447
|
-
|
|
488
|
+
if (!this.isDialectSpecific(file)) {
|
|
489
|
+
content = this.read_strategy(content);
|
|
490
|
+
}
|
|
448
491
|
return content.trim();
|
|
449
492
|
}
|
|
450
493
|
};
|
|
@@ -561,6 +604,9 @@ var BaseSQLRunner = class {
|
|
|
561
604
|
});
|
|
562
605
|
}
|
|
563
606
|
};
|
|
607
|
+
function isPromiseLike(value) {
|
|
608
|
+
return !!value && typeof value.then === "function";
|
|
609
|
+
}
|
|
564
610
|
var SQLRunner = class extends BaseSQLRunner {
|
|
565
611
|
constructor(connection) {
|
|
566
612
|
super();
|
|
@@ -590,14 +636,85 @@ var SQLiteRunner = class extends BaseSQLRunner {
|
|
|
590
636
|
super();
|
|
591
637
|
this.connection = connection;
|
|
592
638
|
}
|
|
639
|
+
prepareStatement(sql) {
|
|
640
|
+
return __async(this, null, function* () {
|
|
641
|
+
if (typeof this.connection.prepare !== "function") {
|
|
642
|
+
throw new Error("SQLite connection does not support prepare()");
|
|
643
|
+
}
|
|
644
|
+
const stmt = this.connection.prepare(sql);
|
|
645
|
+
return isPromiseLike(stmt) ? yield stmt : stmt;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
finalizeStatement(stmt) {
|
|
649
|
+
return __async(this, null, function* () {
|
|
650
|
+
if (!stmt || typeof stmt.finalize !== "function") return;
|
|
651
|
+
const result = stmt.finalize();
|
|
652
|
+
if (isPromiseLike(result)) {
|
|
653
|
+
yield result;
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
statementAll(stmt, params) {
|
|
658
|
+
return __async(this, null, function* () {
|
|
659
|
+
if (typeof stmt.all !== "function") {
|
|
660
|
+
throw new Error("SQLite statement does not support all()");
|
|
661
|
+
}
|
|
662
|
+
if (stmt.all.length >= 2) {
|
|
663
|
+
return yield new Promise((resolve, reject) => {
|
|
664
|
+
const callback = (err, rows) => {
|
|
665
|
+
if (err) return reject(err);
|
|
666
|
+
resolve(rows || []);
|
|
667
|
+
};
|
|
668
|
+
try {
|
|
669
|
+
if (params.length > 0) {
|
|
670
|
+
stmt.all(params, callback);
|
|
671
|
+
} else {
|
|
672
|
+
stmt.all(callback);
|
|
673
|
+
}
|
|
674
|
+
} catch (error) {
|
|
675
|
+
reject(error);
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
const result = stmt.all(...params);
|
|
680
|
+
return isPromiseLike(result) ? yield result : result;
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
statementRun(stmt, params) {
|
|
684
|
+
return __async(this, null, function* () {
|
|
685
|
+
if (typeof stmt.run !== "function") {
|
|
686
|
+
throw new Error("SQLite statement does not support run()");
|
|
687
|
+
}
|
|
688
|
+
if (stmt.run.length >= 2) {
|
|
689
|
+
return yield new Promise((resolve, reject) => {
|
|
690
|
+
const callback = function(err) {
|
|
691
|
+
var _a;
|
|
692
|
+
if (err) return reject(err);
|
|
693
|
+
resolve({ changes: (_a = this == null ? void 0 : this.changes) != null ? _a : 0, lastID: this == null ? void 0 : this.lastID });
|
|
694
|
+
};
|
|
695
|
+
try {
|
|
696
|
+
if (params.length > 0) {
|
|
697
|
+
stmt.run(params, callback);
|
|
698
|
+
} else {
|
|
699
|
+
stmt.run(callback);
|
|
700
|
+
}
|
|
701
|
+
} catch (error) {
|
|
702
|
+
reject(error);
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
const result = stmt.run(...params);
|
|
707
|
+
return isPromiseLike(result) ? yield result : result;
|
|
708
|
+
});
|
|
709
|
+
}
|
|
593
710
|
_query(_0) {
|
|
594
711
|
return __async(this, arguments, function* (sql, params = []) {
|
|
595
|
-
const stmt = yield this.
|
|
712
|
+
const stmt = yield this.prepareStatement(sql);
|
|
596
713
|
try {
|
|
597
|
-
const rows = yield
|
|
714
|
+
const rows = yield this.statementAll(stmt, params);
|
|
598
715
|
return rows;
|
|
599
716
|
} finally {
|
|
600
|
-
yield
|
|
717
|
+
yield this.finalizeStatement(stmt);
|
|
601
718
|
}
|
|
602
719
|
});
|
|
603
720
|
}
|
|
@@ -611,12 +728,12 @@ ${sql}
|
|
|
611
728
|
throw err;
|
|
612
729
|
});
|
|
613
730
|
}
|
|
614
|
-
const stmt = yield this.
|
|
731
|
+
const stmt = yield this.prepareStatement(sql);
|
|
615
732
|
try {
|
|
616
|
-
const info = yield
|
|
733
|
+
const info = yield this.statementRun(stmt, params);
|
|
617
734
|
return info;
|
|
618
735
|
} finally {
|
|
619
|
-
yield
|
|
736
|
+
yield this.finalizeStatement(stmt);
|
|
620
737
|
}
|
|
621
738
|
});
|
|
622
739
|
}
|
|
@@ -632,13 +749,13 @@ ${sql}
|
|
|
632
749
|
).filter((s) => s.trim() !== "");
|
|
633
750
|
const infos = yield statements.reduce((prev, statement) => __async(this, null, function* () {
|
|
634
751
|
const infos2 = yield prev;
|
|
635
|
-
const stmt = yield this.
|
|
752
|
+
const stmt = yield this.prepareStatement(`${statement};`);
|
|
636
753
|
try {
|
|
637
|
-
const info = yield
|
|
754
|
+
const info = yield this.statementRun(stmt, params);
|
|
638
755
|
infos2.push(info);
|
|
639
756
|
return infos2;
|
|
640
757
|
} finally {
|
|
641
|
-
yield
|
|
758
|
+
yield this.finalizeStatement(stmt);
|
|
642
759
|
}
|
|
643
760
|
}), Promise.resolve([null])).then((infos2) => {
|
|
644
761
|
return infos2.filter((info) => info !== null);
|
|
@@ -672,6 +789,9 @@ function toError(error) {
|
|
|
672
789
|
return new Error(String(error));
|
|
673
790
|
}
|
|
674
791
|
var MigrationRunnerFactory = class _MigrationRunnerFactory {
|
|
792
|
+
static isSQLRunner(conn) {
|
|
793
|
+
return !!conn && typeof conn.query === "function" && typeof conn.execute === "function" && typeof conn.end === "function";
|
|
794
|
+
}
|
|
675
795
|
static create(configFile, conn) {
|
|
676
796
|
return __async(this, null, function* () {
|
|
677
797
|
const configReader = new FileMigrationConfigReader(configFile);
|
|
@@ -727,21 +847,27 @@ var MigrationRunnerFactory = class _MigrationRunnerFactory {
|
|
|
727
847
|
create(config, conn) {
|
|
728
848
|
return __async(this, null, function* () {
|
|
729
849
|
let sqlrunner;
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
850
|
+
let driverConnection = conn;
|
|
851
|
+
if (_MigrationRunnerFactory.isSQLRunner(conn)) {
|
|
852
|
+
sqlrunner = conn;
|
|
853
|
+
driverConnection = null;
|
|
854
|
+
} else {
|
|
855
|
+
switch (config.database) {
|
|
856
|
+
case "sql":
|
|
857
|
+
sqlrunner = new SQLRunner(conn);
|
|
858
|
+
break;
|
|
859
|
+
case "sqlite":
|
|
860
|
+
sqlrunner = new SQLiteRunner(conn);
|
|
861
|
+
break;
|
|
862
|
+
default:
|
|
863
|
+
throw ConfigurationError.unknownDatabaseType(config.database);
|
|
864
|
+
}
|
|
739
865
|
}
|
|
740
866
|
const setup = new MigrationSetup(sqlrunner, config);
|
|
741
867
|
const read_strategy = this.getReadStategy(config);
|
|
742
|
-
const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner);
|
|
868
|
+
const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner, config.database);
|
|
743
869
|
yield setup.setup();
|
|
744
|
-
return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner,
|
|
870
|
+
return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, driverConnection);
|
|
745
871
|
});
|
|
746
872
|
}
|
|
747
873
|
createEmpty(config) {
|
|
@@ -760,7 +886,7 @@ var MigrationRunnerFactory = class _MigrationRunnerFactory {
|
|
|
760
886
|
}
|
|
761
887
|
const setup = new MigrationSetup(sqlrunner, config);
|
|
762
888
|
const read_strategy = this.getReadStategy(config);
|
|
763
|
-
const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner);
|
|
889
|
+
const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner, config.database);
|
|
764
890
|
return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, conn);
|
|
765
891
|
});
|
|
766
892
|
}
|
|
@@ -905,6 +1031,11 @@ var MySQLMigrationRunner = class {
|
|
|
905
1031
|
}
|
|
906
1032
|
});
|
|
907
1033
|
}
|
|
1034
|
+
query(sql, params) {
|
|
1035
|
+
return __async(this, null, function* () {
|
|
1036
|
+
return yield this.sqlrunner.query(sql, params);
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
908
1039
|
init(config_file2) {
|
|
909
1040
|
return __async(this, null, function* () {
|
|
910
1041
|
try {
|
|
@@ -1001,6 +1132,224 @@ var MigrationCreator = class {
|
|
|
1001
1132
|
}
|
|
1002
1133
|
};
|
|
1003
1134
|
|
|
1135
|
+
// framework/SeedRunner.ts
|
|
1136
|
+
var import_fs4 = __toESM(require("fs"));
|
|
1137
|
+
var import_path2 = __toESM(require("path"));
|
|
1138
|
+
var import_ajv = __toESM(require("ajv"));
|
|
1139
|
+
var import_ajv_formats = __toESM(require("ajv-formats"));
|
|
1140
|
+
function resolveAlias(name, aliasMap) {
|
|
1141
|
+
var _a;
|
|
1142
|
+
if (!aliasMap) return name;
|
|
1143
|
+
return (_a = aliasMap[name]) != null ? _a : name;
|
|
1144
|
+
}
|
|
1145
|
+
function walkForFile(rootDir, fileName) {
|
|
1146
|
+
if (!import_fs4.default.existsSync(rootDir)) return null;
|
|
1147
|
+
const entries = import_fs4.default.readdirSync(rootDir, { withFileTypes: true });
|
|
1148
|
+
for (const entry of entries) {
|
|
1149
|
+
const full = import_path2.default.join(rootDir, entry.name);
|
|
1150
|
+
if (entry.isDirectory()) {
|
|
1151
|
+
const found = walkForFile(full, fileName);
|
|
1152
|
+
if (found) return found;
|
|
1153
|
+
} else if (entry.isFile() && entry.name === fileName) {
|
|
1154
|
+
return full;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
return null;
|
|
1158
|
+
}
|
|
1159
|
+
function resolveMigrationsDir(migrationConfig, options) {
|
|
1160
|
+
var _a;
|
|
1161
|
+
const fromOptions = options.migrationsDir;
|
|
1162
|
+
const fromConfig = (_a = migrationConfig.seeds) == null ? void 0 : _a.migrationsDir;
|
|
1163
|
+
const dir = fromOptions != null ? fromOptions : fromConfig;
|
|
1164
|
+
if (!dir) {
|
|
1165
|
+
throw new Error("Seed migrationsDir not configured. Set seeds.migrationsDir in proper.json or pass it explicitly.");
|
|
1166
|
+
}
|
|
1167
|
+
return dir;
|
|
1168
|
+
}
|
|
1169
|
+
function mergeSeedConfig(migrationConfig, options) {
|
|
1170
|
+
var _a, _b, _c, _d;
|
|
1171
|
+
const names = options.names && options.names.length ? options.names : ((_a = migrationConfig.seeds) == null ? void 0 : _a.list) && migrationConfig.seeds.list.length ? migrationConfig.seeds.list : [];
|
|
1172
|
+
if (!names.length) {
|
|
1173
|
+
throw new Error("No seed names provided and no seeds.list defined in proper config");
|
|
1174
|
+
}
|
|
1175
|
+
const migrationsDir = resolveMigrationsDir(migrationConfig, options);
|
|
1176
|
+
const dataDir = (_c = options.dataDir) != null ? _c : (_b = migrationConfig.seeds) == null ? void 0 : _b.dataDir;
|
|
1177
|
+
const validate = options.validate !== void 0 ? options.validate : true;
|
|
1178
|
+
const transactional = (_d = options.transactional) != null ? _d : "none";
|
|
1179
|
+
const finalOptions = __spreadProps(__spreadValues({}, options), {
|
|
1180
|
+
migrationsDir,
|
|
1181
|
+
dataDir,
|
|
1182
|
+
validate,
|
|
1183
|
+
transactional
|
|
1184
|
+
});
|
|
1185
|
+
return { names, finalOptions };
|
|
1186
|
+
}
|
|
1187
|
+
function resolveSqlPair(name, migrationsDir) {
|
|
1188
|
+
const up = walkForFile(migrationsDir, `${name}.up.sql`);
|
|
1189
|
+
const down = walkForFile(migrationsDir, `${name}.down.sql`);
|
|
1190
|
+
if (up && down) {
|
|
1191
|
+
return { upPath: up, downPath: down };
|
|
1192
|
+
}
|
|
1193
|
+
return null;
|
|
1194
|
+
}
|
|
1195
|
+
function resolveModule(name, migrationsDir) {
|
|
1196
|
+
const ts = walkForFile(migrationsDir, `${name}.ts`);
|
|
1197
|
+
if (ts) return { kind: "ts", modulePath: ts };
|
|
1198
|
+
const js = walkForFile(migrationsDir, `${name}.js`);
|
|
1199
|
+
if (js) return { kind: "js", modulePath: js };
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
function resolveSeed(name, migrationConfig, options) {
|
|
1203
|
+
return __async(this, null, function* () {
|
|
1204
|
+
var _a, _b;
|
|
1205
|
+
const migrationsDir = resolveMigrationsDir(migrationConfig, options);
|
|
1206
|
+
const alias = resolveAlias(name, options.aliasMap);
|
|
1207
|
+
const sqlPair = resolveSqlPair(name, migrationsDir);
|
|
1208
|
+
if (sqlPair) {
|
|
1209
|
+
return {
|
|
1210
|
+
kind: "sql",
|
|
1211
|
+
name,
|
|
1212
|
+
alias,
|
|
1213
|
+
upPath: sqlPair.upPath,
|
|
1214
|
+
downPath: sqlPair.downPath,
|
|
1215
|
+
dataPath: null,
|
|
1216
|
+
schemaPath: null
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
const module2 = resolveModule(name, migrationsDir);
|
|
1220
|
+
if (!module2) {
|
|
1221
|
+
throw new Error(`Seed implementation not found for "${name}" under ${migrationsDir}`);
|
|
1222
|
+
}
|
|
1223
|
+
const dataDir = (_b = options.dataDir) != null ? _b : (_a = migrationConfig.seeds) == null ? void 0 : _a.dataDir;
|
|
1224
|
+
let dataPath = null;
|
|
1225
|
+
let schemaPath = null;
|
|
1226
|
+
if (dataDir) {
|
|
1227
|
+
dataPath = walkForFile(dataDir, `${alias}.json`);
|
|
1228
|
+
schemaPath = walkForFile(dataDir, `${alias}.schema.json`);
|
|
1229
|
+
}
|
|
1230
|
+
return {
|
|
1231
|
+
kind: module2.kind,
|
|
1232
|
+
name,
|
|
1233
|
+
alias,
|
|
1234
|
+
upPath: module2.modulePath,
|
|
1235
|
+
downPath: module2.modulePath,
|
|
1236
|
+
dataPath,
|
|
1237
|
+
schemaPath
|
|
1238
|
+
};
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
function loadJson(filePath) {
|
|
1242
|
+
return __async(this, null, function* () {
|
|
1243
|
+
const content = yield import_fs4.default.promises.readFile(filePath, "utf8");
|
|
1244
|
+
return JSON.parse(content);
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
function createValidator() {
|
|
1248
|
+
const ajv = new import_ajv.default({ allErrors: true, strict: false });
|
|
1249
|
+
(0, import_ajv_formats.default)(ajv);
|
|
1250
|
+
return ajv;
|
|
1251
|
+
}
|
|
1252
|
+
function validateData(schemaPath, data, validate, log) {
|
|
1253
|
+
return __async(this, null, function* () {
|
|
1254
|
+
if (!validate || !schemaPath) return;
|
|
1255
|
+
const content = yield import_fs4.default.promises.readFile(schemaPath, "utf8");
|
|
1256
|
+
const schema = JSON.parse(content);
|
|
1257
|
+
const ajv = createValidator();
|
|
1258
|
+
const validateFn = ajv.compile(schema);
|
|
1259
|
+
const ok = validateFn(data);
|
|
1260
|
+
if (!ok) {
|
|
1261
|
+
log == null ? void 0 : log(`Validation failed for seed data (${schemaPath})`);
|
|
1262
|
+
throw new Error(`Seed data validation failed: ${ajv.errorsText(validateFn.errors || [])}`);
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
function runSqlSeed(runner, resolved, direction) {
|
|
1267
|
+
return __async(this, null, function* () {
|
|
1268
|
+
const sqlPath = direction === "up" ? resolved.upPath : resolved.downPath;
|
|
1269
|
+
const sql = yield import_fs4.default.promises.readFile(sqlPath, "utf8");
|
|
1270
|
+
yield runner.query(sql);
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
function runModuleSeed(runner, resolved, migrationConfig, options, direction) {
|
|
1274
|
+
return __async(this, null, function* () {
|
|
1275
|
+
const { log } = options;
|
|
1276
|
+
const module2 = yield import(import_path2.default.resolve(resolved.upPath));
|
|
1277
|
+
const handler = module2[direction];
|
|
1278
|
+
if (typeof handler !== "function") {
|
|
1279
|
+
throw new Error(`Seed module "${resolved.name}" does not export ${direction}()`);
|
|
1280
|
+
}
|
|
1281
|
+
let data = null;
|
|
1282
|
+
if (options.preloadedData && Object.prototype.hasOwnProperty.call(options.preloadedData, resolved.name)) {
|
|
1283
|
+
data = options.preloadedData[resolved.name];
|
|
1284
|
+
} else if (resolved.dataPath) {
|
|
1285
|
+
data = yield loadJson(resolved.dataPath);
|
|
1286
|
+
}
|
|
1287
|
+
yield validateData(resolved.schemaPath, data, options.validate, log);
|
|
1288
|
+
const ctx = {
|
|
1289
|
+
data,
|
|
1290
|
+
log,
|
|
1291
|
+
dialect: migrationConfig.database || "sql"
|
|
1292
|
+
};
|
|
1293
|
+
yield handler(runner, ctx);
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
function runSingleSeed(runner, migrationConfig, name, options, direction) {
|
|
1297
|
+
return __async(this, null, function* () {
|
|
1298
|
+
const resolved = yield resolveSeed(name, migrationConfig, options);
|
|
1299
|
+
if (resolved.kind === "sql") {
|
|
1300
|
+
yield runSqlSeed(runner, resolved, direction);
|
|
1301
|
+
} else {
|
|
1302
|
+
yield runModuleSeed(runner, resolved, migrationConfig, options, direction);
|
|
1303
|
+
}
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
function withTransactionalMode(runner, migrationConfig, names, options, direction) {
|
|
1307
|
+
return __async(this, null, function* () {
|
|
1308
|
+
const mode = options.transactional;
|
|
1309
|
+
if (mode === "runner") {
|
|
1310
|
+
yield runner.query("BEGIN");
|
|
1311
|
+
try {
|
|
1312
|
+
for (const name of names) {
|
|
1313
|
+
yield runSingleSeed(runner, migrationConfig, name, options, direction);
|
|
1314
|
+
}
|
|
1315
|
+
yield runner.query("COMMIT");
|
|
1316
|
+
} catch (err) {
|
|
1317
|
+
try {
|
|
1318
|
+
yield runner.query("ROLLBACK");
|
|
1319
|
+
} catch (e) {
|
|
1320
|
+
}
|
|
1321
|
+
throw err;
|
|
1322
|
+
}
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if (mode === "seed") {
|
|
1326
|
+
for (const name of names) {
|
|
1327
|
+
yield runner.query("BEGIN");
|
|
1328
|
+
try {
|
|
1329
|
+
yield runSingleSeed(runner, migrationConfig, name, options, direction);
|
|
1330
|
+
yield runner.query("COMMIT");
|
|
1331
|
+
} catch (err) {
|
|
1332
|
+
try {
|
|
1333
|
+
yield runner.query("ROLLBACK");
|
|
1334
|
+
} catch (e) {
|
|
1335
|
+
}
|
|
1336
|
+
throw err;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
for (const name of names) {
|
|
1342
|
+
yield runSingleSeed(runner, migrationConfig, name, options, direction);
|
|
1343
|
+
}
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
function runSeedsWithRunner(runner, migrationConfig, direction, options) {
|
|
1347
|
+
return __async(this, null, function* () {
|
|
1348
|
+
const { names, finalOptions } = mergeSeedConfig(migrationConfig, options);
|
|
1349
|
+
yield withTransactionalMode(runner, migrationConfig, names, finalOptions, direction);
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1004
1353
|
// cli.ts
|
|
1005
1354
|
var args = MigrationCLIFactory.setup(process.argv);
|
|
1006
1355
|
if (!args.commands || args.commands.length === 0) {
|
|
@@ -1047,8 +1396,9 @@ pending_runner.then((runner) => __async(null, null, function* () {
|
|
|
1047
1396
|
const migrations_rollback = yield runner.getMigrations();
|
|
1048
1397
|
let downgraded = yield migration_filter(migrations_rollback, true);
|
|
1049
1398
|
downgraded = downgraded.reverse();
|
|
1050
|
-
if (args.flags.
|
|
1051
|
-
|
|
1399
|
+
if (args.flags.all) {
|
|
1400
|
+
} else {
|
|
1401
|
+
const increment = parseInt(args.flags.increment || "1");
|
|
1052
1402
|
downgraded = downgraded.slice(0, increment);
|
|
1053
1403
|
}
|
|
1054
1404
|
console.log(`Rolling back ${downgraded.length} migration(s)`);
|
|
@@ -1120,7 +1470,7 @@ pending_runner.then((runner) => __async(null, null, function* () {
|
|
|
1120
1470
|
throw new CLIError("Invalid format. Use --format table or --format json");
|
|
1121
1471
|
}
|
|
1122
1472
|
try {
|
|
1123
|
-
const [results] = yield runner.
|
|
1473
|
+
const [results] = yield runner.query(sql_query);
|
|
1124
1474
|
if (Array.isArray(results) && results.length > 0) {
|
|
1125
1475
|
if (format === "json") {
|
|
1126
1476
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -1140,6 +1490,40 @@ Returned ${results.length} row(s)`);
|
|
|
1140
1490
|
}
|
|
1141
1491
|
yield runner.close();
|
|
1142
1492
|
break;
|
|
1493
|
+
case "seed": {
|
|
1494
|
+
const subCommands = commands.slice(1);
|
|
1495
|
+
const actionFlag = (args.flags.action || "").toString().toLowerCase();
|
|
1496
|
+
const firstSub = (subCommands[0] || "").toString().toLowerCase();
|
|
1497
|
+
const action = actionFlag === "down" || firstSub === "down" ? "down" : "up";
|
|
1498
|
+
const positionalNames = actionFlag ? subCommands : firstSub === "up" || firstSub === "down" ? subCommands.slice(1) : subCommands;
|
|
1499
|
+
const aliasFlag = args.flags.alias;
|
|
1500
|
+
const aliasMap = {};
|
|
1501
|
+
if (aliasFlag) {
|
|
1502
|
+
const aliases = Array.isArray(aliasFlag) ? aliasFlag : [aliasFlag];
|
|
1503
|
+
for (const entry of aliases) {
|
|
1504
|
+
const eq = entry.indexOf("=");
|
|
1505
|
+
if (eq > 0) {
|
|
1506
|
+
const key = entry.slice(0, eq);
|
|
1507
|
+
const value = entry.slice(eq + 1);
|
|
1508
|
+
if (key) aliasMap[key] = value;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
const seedOptions = {
|
|
1513
|
+
migrationsDir: args.flags.migrationsDir || args.flags["migrations-dir"],
|
|
1514
|
+
dataDir: args.flags.dataDir || args.flags["data-dir"],
|
|
1515
|
+
validate: args.flags.validate === void 0 ? true : String(args.flags.validate).toLowerCase() !== "false",
|
|
1516
|
+
transactional: args.flags.transactional,
|
|
1517
|
+
aliasMap: Object.keys(aliasMap).length ? aliasMap : void 0,
|
|
1518
|
+
names: positionalNames.length ? positionalNames : void 0,
|
|
1519
|
+
log: (msg) => console.log(msg)
|
|
1520
|
+
};
|
|
1521
|
+
const reader = new FileMigrationConfigReader(config_file);
|
|
1522
|
+
const migrationConfig = reader.loadFile();
|
|
1523
|
+
yield runSeedsWithRunner(runner, migrationConfig, action, seedOptions);
|
|
1524
|
+
yield runner.close();
|
|
1525
|
+
break;
|
|
1526
|
+
}
|
|
1143
1527
|
default:
|
|
1144
1528
|
throw CLIError.unknownCommand(command);
|
|
1145
1529
|
}
|
|
@@ -1171,12 +1555,15 @@ Commands:
|
|
|
1171
1555
|
Options:
|
|
1172
1556
|
-c, --config Specify the config file (default: proper.json)
|
|
1173
1557
|
--increment <n> Limit the number of migrations to apply or roll back
|
|
1558
|
+
--all Roll back all completed migrations (down command only)
|
|
1174
1559
|
--format <fmt> Output format for query command: 'table' (default) or 'json'
|
|
1175
1560
|
|
|
1176
1561
|
Examples:
|
|
1177
1562
|
proper up Apply all pending migrations
|
|
1178
1563
|
proper up --increment 1 Apply only the next pending migration
|
|
1179
|
-
proper down Roll back the last applied migration
|
|
1564
|
+
proper down Roll back the last applied migration (default: 1)
|
|
1565
|
+
proper down --increment 3 Roll back the last 3 applied migrations
|
|
1566
|
+
proper down --all Roll back all completed migrations
|
|
1180
1567
|
proper create my_migration Create a new migration named "my_migration"
|
|
1181
1568
|
proper init Create a new config file
|
|
1182
1569
|
proper status Show the status of all migrations
|