@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.mjs CHANGED
@@ -1,8 +1,24 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
2
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
6
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
4
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
8
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __spreadValues = (a, b) => {
11
+ for (var prop in b || (b = {}))
12
+ if (__hasOwnProp.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ if (__getOwnPropSymbols)
15
+ for (var prop of __getOwnPropSymbols(b)) {
16
+ if (__propIsEnum.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ }
19
+ return a;
20
+ };
21
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6
22
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
23
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
24
  }) : x)(function(x) {
@@ -404,26 +420,50 @@ var init_MigrationDirectoryReader = __esm({
404
420
  "framework/MigrationDirectoryReader.ts"() {
405
421
  init_SqlMigrationBuilder();
406
422
  MigrationDirectoryReader = class {
407
- constructor(directory, read_strategy, sqlrunner) {
423
+ constructor(directory, read_strategy, sqlrunner, dialect = "sql") {
408
424
  this.directory = directory;
409
425
  this.read_strategy = read_strategy;
410
426
  this.sqlrunner = sqlrunner;
427
+ this.dialect = dialect;
428
+ }
429
+ /**
430
+ * Resolves the appropriate file for a migration based on dialect.
431
+ * Priority: dialect-specific file > generic file
432
+ */
433
+ resolveFile(baseName, direction) {
434
+ const dialectExt = this.dialect === "sql" ? "mysql" : "sqlite";
435
+ const dialectFile = path.join(this.directory, `${baseName}.${dialectExt}.${direction}.sql`);
436
+ if (fs.existsSync(dialectFile)) return dialectFile;
437
+ const genericFile = path.join(this.directory, `${baseName}.${direction}.sql`);
438
+ if (fs.existsSync(genericFile)) return genericFile;
439
+ return null;
440
+ }
441
+ /**
442
+ * Checks if a file path is dialect-specific (contains .mysql. or .sqlite. in the name)
443
+ */
444
+ isDialectSpecific(filePath) {
445
+ return /\.(mysql|sqlite)\.(up|down)\.sql$/i.test(filePath);
411
446
  }
412
447
  loadMigrations(table, connection) {
413
448
  fs.existsSync(this.directory) || fs.mkdirSync(this.directory);
414
449
  const dir_content = fs.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name);
415
- let migration_files = dir_content.map((file) => {
416
- return {
417
- migration_key: file.replace(/\.(up|down)\.(sql|js)/i, "").toLowerCase(),
418
- directory: this.directory,
419
- relative_path: path.join(this.directory, file),
420
- file
421
- };
422
- }).sort();
450
+ const uniqueKeys = /* @__PURE__ */ new Set();
451
+ dir_content.forEach((file) => {
452
+ const key = file.replace(/(?:\.(mysql|sqlite))?\.(up|down)\.(sql|js)/i, "").toLowerCase();
453
+ uniqueKeys.add(key);
454
+ });
423
455
  const migration_sorter = {};
424
- migration_files.forEach((migration) => {
425
- const builder = migration_sorter[migration.migration_key] = migration_sorter[migration.migration_key] || new SqlMigrationBuilder(migration.migration_key);
426
- this.loadMigration(builder, migration.relative_path);
456
+ uniqueKeys.forEach((migration_key) => {
457
+ const builder = new SqlMigrationBuilder(migration_key);
458
+ const upFile = this.resolveFile(migration_key, "up");
459
+ const downFile = this.resolveFile(migration_key, "down");
460
+ if (upFile) {
461
+ this.loadMigration(builder, upFile);
462
+ }
463
+ if (downFile) {
464
+ this.loadMigration(builder, downFile);
465
+ }
466
+ migration_sorter[migration_key] = builder;
427
467
  });
428
468
  const keys = Object.keys(migration_sorter);
429
469
  keys.sort();
@@ -450,12 +490,16 @@ var init_MigrationDirectoryReader = __esm({
450
490
  }
451
491
  sql_up(file) {
452
492
  let content = fs.readFileSync(file).toString();
453
- content = this.read_strategy(content);
493
+ if (!this.isDialectSpecific(file)) {
494
+ content = this.read_strategy(content);
495
+ }
454
496
  return content.trim();
455
497
  }
456
498
  sql_down(file) {
457
499
  let content = fs.readFileSync(file).toString();
458
- content = this.read_strategy(content);
500
+ if (!this.isDialectSpecific(file)) {
501
+ content = this.read_strategy(content);
502
+ }
459
503
  return content.trim();
460
504
  }
461
505
  };
@@ -559,6 +603,9 @@ var init_MigrationDialectParser = __esm({
559
603
  });
560
604
 
561
605
  // framework/SQLRunner.ts
606
+ function isPromiseLike(value) {
607
+ return !!value && typeof value.then === "function";
608
+ }
562
609
  var BaseSQLRunner, SQLRunner, SQLiteRunner;
563
610
  var init_SQLRunner = __esm({
564
611
  "framework/SQLRunner.ts"() {
@@ -615,14 +662,85 @@ var init_SQLRunner = __esm({
615
662
  super();
616
663
  this.connection = connection;
617
664
  }
665
+ prepareStatement(sql) {
666
+ return __async(this, null, function* () {
667
+ if (typeof this.connection.prepare !== "function") {
668
+ throw new Error("SQLite connection does not support prepare()");
669
+ }
670
+ const stmt = this.connection.prepare(sql);
671
+ return isPromiseLike(stmt) ? yield stmt : stmt;
672
+ });
673
+ }
674
+ finalizeStatement(stmt) {
675
+ return __async(this, null, function* () {
676
+ if (!stmt || typeof stmt.finalize !== "function") return;
677
+ const result = stmt.finalize();
678
+ if (isPromiseLike(result)) {
679
+ yield result;
680
+ }
681
+ });
682
+ }
683
+ statementAll(stmt, params) {
684
+ return __async(this, null, function* () {
685
+ if (typeof stmt.all !== "function") {
686
+ throw new Error("SQLite statement does not support all()");
687
+ }
688
+ if (stmt.all.length >= 2) {
689
+ return yield new Promise((resolve, reject) => {
690
+ const callback = (err, rows) => {
691
+ if (err) return reject(err);
692
+ resolve(rows || []);
693
+ };
694
+ try {
695
+ if (params.length > 0) {
696
+ stmt.all(params, callback);
697
+ } else {
698
+ stmt.all(callback);
699
+ }
700
+ } catch (error) {
701
+ reject(error);
702
+ }
703
+ });
704
+ }
705
+ const result = stmt.all(...params);
706
+ return isPromiseLike(result) ? yield result : result;
707
+ });
708
+ }
709
+ statementRun(stmt, params) {
710
+ return __async(this, null, function* () {
711
+ if (typeof stmt.run !== "function") {
712
+ throw new Error("SQLite statement does not support run()");
713
+ }
714
+ if (stmt.run.length >= 2) {
715
+ return yield new Promise((resolve, reject) => {
716
+ const callback = function(err) {
717
+ var _a;
718
+ if (err) return reject(err);
719
+ resolve({ changes: (_a = this == null ? void 0 : this.changes) != null ? _a : 0, lastID: this == null ? void 0 : this.lastID });
720
+ };
721
+ try {
722
+ if (params.length > 0) {
723
+ stmt.run(params, callback);
724
+ } else {
725
+ stmt.run(callback);
726
+ }
727
+ } catch (error) {
728
+ reject(error);
729
+ }
730
+ });
731
+ }
732
+ const result = stmt.run(...params);
733
+ return isPromiseLike(result) ? yield result : result;
734
+ });
735
+ }
618
736
  _query(_0) {
619
737
  return __async(this, arguments, function* (sql, params = []) {
620
- const stmt = yield this.connection.prepare(sql);
738
+ const stmt = yield this.prepareStatement(sql);
621
739
  try {
622
- const rows = yield stmt.all(...params);
740
+ const rows = yield this.statementAll(stmt, params);
623
741
  return rows;
624
742
  } finally {
625
- yield stmt.finalize();
743
+ yield this.finalizeStatement(stmt);
626
744
  }
627
745
  });
628
746
  }
@@ -636,12 +754,12 @@ ${sql}
636
754
  throw err;
637
755
  });
638
756
  }
639
- const stmt = yield this.connection.prepare(sql);
757
+ const stmt = yield this.prepareStatement(sql);
640
758
  try {
641
- const info = yield stmt.run(...params);
759
+ const info = yield this.statementRun(stmt, params);
642
760
  return info;
643
761
  } finally {
644
- yield stmt.finalize();
762
+ yield this.finalizeStatement(stmt);
645
763
  }
646
764
  });
647
765
  }
@@ -657,13 +775,13 @@ ${sql}
657
775
  ).filter((s) => s.trim() !== "");
658
776
  const infos = yield statements.reduce((prev, statement) => __async(this, null, function* () {
659
777
  const infos2 = yield prev;
660
- const stmt = yield this.connection.prepare(`${statement};`);
778
+ const stmt = yield this.prepareStatement(`${statement};`);
661
779
  try {
662
- const info = yield stmt.run(...params);
780
+ const info = yield this.statementRun(stmt, params);
663
781
  infos2.push(info);
664
782
  return infos2;
665
783
  } finally {
666
- yield stmt.finalize();
784
+ yield this.finalizeStatement(stmt);
667
785
  }
668
786
  }), Promise.resolve([null])).then((infos2) => {
669
787
  return infos2.filter((info) => info !== null);
@@ -712,6 +830,9 @@ var init_MigrationRunner = __esm({
712
830
  init_SQLRunner();
713
831
  init_errors();
714
832
  MigrationRunnerFactory = class _MigrationRunnerFactory {
833
+ static isSQLRunner(conn) {
834
+ return !!conn && typeof conn.query === "function" && typeof conn.execute === "function" && typeof conn.end === "function";
835
+ }
715
836
  static create(configFile, conn) {
716
837
  return __async(this, null, function* () {
717
838
  const configReader = new FileMigrationConfigReader(configFile);
@@ -767,21 +888,27 @@ var init_MigrationRunner = __esm({
767
888
  create(config, conn) {
768
889
  return __async(this, null, function* () {
769
890
  let sqlrunner;
770
- switch (config.database) {
771
- case "sql":
772
- sqlrunner = new SQLRunner(conn);
773
- break;
774
- case "sqlite":
775
- sqlrunner = new SQLiteRunner(conn);
776
- break;
777
- default:
778
- throw ConfigurationError.unknownDatabaseType(config.database);
891
+ let driverConnection = conn;
892
+ if (_MigrationRunnerFactory.isSQLRunner(conn)) {
893
+ sqlrunner = conn;
894
+ driverConnection = null;
895
+ } else {
896
+ switch (config.database) {
897
+ case "sql":
898
+ sqlrunner = new SQLRunner(conn);
899
+ break;
900
+ case "sqlite":
901
+ sqlrunner = new SQLiteRunner(conn);
902
+ break;
903
+ default:
904
+ throw ConfigurationError.unknownDatabaseType(config.database);
905
+ }
779
906
  }
780
907
  const setup = new MigrationSetup(sqlrunner, config);
781
908
  const read_strategy = this.getReadStategy(config);
782
- const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner);
909
+ const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner, config.database);
783
910
  yield setup.setup();
784
- return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, conn);
911
+ return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, driverConnection);
785
912
  });
786
913
  }
787
914
  createEmpty(config) {
@@ -800,7 +927,7 @@ var init_MigrationRunner = __esm({
800
927
  }
801
928
  const setup = new MigrationSetup(sqlrunner, config);
802
929
  const read_strategy = this.getReadStategy(config);
803
- const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner);
930
+ const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner, config.database);
804
931
  return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, conn);
805
932
  });
806
933
  }
@@ -945,6 +1072,11 @@ var init_MigrationRunner = __esm({
945
1072
  }
946
1073
  });
947
1074
  }
1075
+ query(sql, params) {
1076
+ return __async(this, null, function* () {
1077
+ return yield this.sqlrunner.query(sql, params);
1078
+ });
1079
+ }
948
1080
  init(config_file) {
949
1081
  return __async(this, null, function* () {
950
1082
  try {
@@ -1043,6 +1175,229 @@ var init_MigrationRunner = __esm({
1043
1175
  }
1044
1176
  });
1045
1177
 
1178
+ // framework/SeedRunner.ts
1179
+ import fs4 from "fs";
1180
+ import path2 from "path";
1181
+ import Ajv from "ajv";
1182
+ import addFormats from "ajv-formats";
1183
+ function resolveAlias(name, aliasMap) {
1184
+ var _a;
1185
+ if (!aliasMap) return name;
1186
+ return (_a = aliasMap[name]) != null ? _a : name;
1187
+ }
1188
+ function walkForFile(rootDir, fileName) {
1189
+ if (!fs4.existsSync(rootDir)) return null;
1190
+ const entries = fs4.readdirSync(rootDir, { withFileTypes: true });
1191
+ for (const entry of entries) {
1192
+ const full = path2.join(rootDir, entry.name);
1193
+ if (entry.isDirectory()) {
1194
+ const found = walkForFile(full, fileName);
1195
+ if (found) return found;
1196
+ } else if (entry.isFile() && entry.name === fileName) {
1197
+ return full;
1198
+ }
1199
+ }
1200
+ return null;
1201
+ }
1202
+ function resolveMigrationsDir(migrationConfig, options) {
1203
+ var _a;
1204
+ const fromOptions = options.migrationsDir;
1205
+ const fromConfig = (_a = migrationConfig.seeds) == null ? void 0 : _a.migrationsDir;
1206
+ const dir = fromOptions != null ? fromOptions : fromConfig;
1207
+ if (!dir) {
1208
+ throw new Error("Seed migrationsDir not configured. Set seeds.migrationsDir in proper.json or pass it explicitly.");
1209
+ }
1210
+ return dir;
1211
+ }
1212
+ function mergeSeedConfig(migrationConfig, options) {
1213
+ var _a, _b, _c, _d;
1214
+ const names = options.names && options.names.length ? options.names : ((_a = migrationConfig.seeds) == null ? void 0 : _a.list) && migrationConfig.seeds.list.length ? migrationConfig.seeds.list : [];
1215
+ if (!names.length) {
1216
+ throw new Error("No seed names provided and no seeds.list defined in proper config");
1217
+ }
1218
+ const migrationsDir = resolveMigrationsDir(migrationConfig, options);
1219
+ const dataDir = (_c = options.dataDir) != null ? _c : (_b = migrationConfig.seeds) == null ? void 0 : _b.dataDir;
1220
+ const validate = options.validate !== void 0 ? options.validate : true;
1221
+ const transactional = (_d = options.transactional) != null ? _d : "none";
1222
+ const finalOptions = __spreadProps(__spreadValues({}, options), {
1223
+ migrationsDir,
1224
+ dataDir,
1225
+ validate,
1226
+ transactional
1227
+ });
1228
+ return { names, finalOptions };
1229
+ }
1230
+ function resolveSqlPair(name, migrationsDir) {
1231
+ const up = walkForFile(migrationsDir, `${name}.up.sql`);
1232
+ const down = walkForFile(migrationsDir, `${name}.down.sql`);
1233
+ if (up && down) {
1234
+ return { upPath: up, downPath: down };
1235
+ }
1236
+ return null;
1237
+ }
1238
+ function resolveModule(name, migrationsDir) {
1239
+ const ts = walkForFile(migrationsDir, `${name}.ts`);
1240
+ if (ts) return { kind: "ts", modulePath: ts };
1241
+ const js = walkForFile(migrationsDir, `${name}.js`);
1242
+ if (js) return { kind: "js", modulePath: js };
1243
+ return null;
1244
+ }
1245
+ function resolveSeed(name, migrationConfig, options) {
1246
+ return __async(this, null, function* () {
1247
+ var _a, _b;
1248
+ const migrationsDir = resolveMigrationsDir(migrationConfig, options);
1249
+ const alias = resolveAlias(name, options.aliasMap);
1250
+ const sqlPair = resolveSqlPair(name, migrationsDir);
1251
+ if (sqlPair) {
1252
+ return {
1253
+ kind: "sql",
1254
+ name,
1255
+ alias,
1256
+ upPath: sqlPair.upPath,
1257
+ downPath: sqlPair.downPath,
1258
+ dataPath: null,
1259
+ schemaPath: null
1260
+ };
1261
+ }
1262
+ const module = resolveModule(name, migrationsDir);
1263
+ if (!module) {
1264
+ throw new Error(`Seed implementation not found for "${name}" under ${migrationsDir}`);
1265
+ }
1266
+ const dataDir = (_b = options.dataDir) != null ? _b : (_a = migrationConfig.seeds) == null ? void 0 : _a.dataDir;
1267
+ let dataPath = null;
1268
+ let schemaPath = null;
1269
+ if (dataDir) {
1270
+ dataPath = walkForFile(dataDir, `${alias}.json`);
1271
+ schemaPath = walkForFile(dataDir, `${alias}.schema.json`);
1272
+ }
1273
+ return {
1274
+ kind: module.kind,
1275
+ name,
1276
+ alias,
1277
+ upPath: module.modulePath,
1278
+ downPath: module.modulePath,
1279
+ dataPath,
1280
+ schemaPath
1281
+ };
1282
+ });
1283
+ }
1284
+ function loadJson(filePath) {
1285
+ return __async(this, null, function* () {
1286
+ const content = yield fs4.promises.readFile(filePath, "utf8");
1287
+ return JSON.parse(content);
1288
+ });
1289
+ }
1290
+ function createValidator() {
1291
+ const ajv = new Ajv({ allErrors: true, strict: false });
1292
+ addFormats(ajv);
1293
+ return ajv;
1294
+ }
1295
+ function validateData(schemaPath, data, validate, log) {
1296
+ return __async(this, null, function* () {
1297
+ if (!validate || !schemaPath) return;
1298
+ const content = yield fs4.promises.readFile(schemaPath, "utf8");
1299
+ const schema = JSON.parse(content);
1300
+ const ajv = createValidator();
1301
+ const validateFn = ajv.compile(schema);
1302
+ const ok = validateFn(data);
1303
+ if (!ok) {
1304
+ log == null ? void 0 : log(`Validation failed for seed data (${schemaPath})`);
1305
+ throw new Error(`Seed data validation failed: ${ajv.errorsText(validateFn.errors || [])}`);
1306
+ }
1307
+ });
1308
+ }
1309
+ function runSqlSeed(runner, resolved, direction) {
1310
+ return __async(this, null, function* () {
1311
+ const sqlPath = direction === "up" ? resolved.upPath : resolved.downPath;
1312
+ const sql = yield fs4.promises.readFile(sqlPath, "utf8");
1313
+ yield runner.query(sql);
1314
+ });
1315
+ }
1316
+ function runModuleSeed(runner, resolved, migrationConfig, options, direction) {
1317
+ return __async(this, null, function* () {
1318
+ const { log } = options;
1319
+ const module = yield import(path2.resolve(resolved.upPath));
1320
+ const handler = module[direction];
1321
+ if (typeof handler !== "function") {
1322
+ throw new Error(`Seed module "${resolved.name}" does not export ${direction}()`);
1323
+ }
1324
+ let data = null;
1325
+ if (options.preloadedData && Object.prototype.hasOwnProperty.call(options.preloadedData, resolved.name)) {
1326
+ data = options.preloadedData[resolved.name];
1327
+ } else if (resolved.dataPath) {
1328
+ data = yield loadJson(resolved.dataPath);
1329
+ }
1330
+ yield validateData(resolved.schemaPath, data, options.validate, log);
1331
+ const ctx = {
1332
+ data,
1333
+ log,
1334
+ dialect: migrationConfig.database || "sql"
1335
+ };
1336
+ yield handler(runner, ctx);
1337
+ });
1338
+ }
1339
+ function runSingleSeed(runner, migrationConfig, name, options, direction) {
1340
+ return __async(this, null, function* () {
1341
+ const resolved = yield resolveSeed(name, migrationConfig, options);
1342
+ if (resolved.kind === "sql") {
1343
+ yield runSqlSeed(runner, resolved, direction);
1344
+ } else {
1345
+ yield runModuleSeed(runner, resolved, migrationConfig, options, direction);
1346
+ }
1347
+ });
1348
+ }
1349
+ function withTransactionalMode(runner, migrationConfig, names, options, direction) {
1350
+ return __async(this, null, function* () {
1351
+ const mode = options.transactional;
1352
+ if (mode === "runner") {
1353
+ yield runner.query("BEGIN");
1354
+ try {
1355
+ for (const name of names) {
1356
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1357
+ }
1358
+ yield runner.query("COMMIT");
1359
+ } catch (err) {
1360
+ try {
1361
+ yield runner.query("ROLLBACK");
1362
+ } catch (e) {
1363
+ }
1364
+ throw err;
1365
+ }
1366
+ return;
1367
+ }
1368
+ if (mode === "seed") {
1369
+ for (const name of names) {
1370
+ yield runner.query("BEGIN");
1371
+ try {
1372
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1373
+ yield runner.query("COMMIT");
1374
+ } catch (err) {
1375
+ try {
1376
+ yield runner.query("ROLLBACK");
1377
+ } catch (e) {
1378
+ }
1379
+ throw err;
1380
+ }
1381
+ }
1382
+ return;
1383
+ }
1384
+ for (const name of names) {
1385
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1386
+ }
1387
+ });
1388
+ }
1389
+ function runSeedsWithRunner(runner, migrationConfig, direction, options) {
1390
+ return __async(this, null, function* () {
1391
+ const { names, finalOptions } = mergeSeedConfig(migrationConfig, options);
1392
+ yield withTransactionalMode(runner, migrationConfig, names, finalOptions, direction);
1393
+ });
1394
+ }
1395
+ var init_SeedRunner = __esm({
1396
+ "framework/SeedRunner.ts"() {
1397
+ init_MigrationRunner();
1398
+ }
1399
+ });
1400
+
1046
1401
  // cli.ts
1047
1402
  import "source-map-support/register";
1048
1403
  var require_cli = __commonJS({
@@ -1051,6 +1406,7 @@ var require_cli = __commonJS({
1051
1406
  init_MigrationFilter();
1052
1407
  init_MigrationRunner();
1053
1408
  init_errors();
1409
+ init_SeedRunner();
1054
1410
  var args = MigrationCLIFactory.setup(process.argv);
1055
1411
  if (!args.commands || args.commands.length === 0) {
1056
1412
  console.error("Error: No command specified");
@@ -1096,8 +1452,9 @@ var require_cli = __commonJS({
1096
1452
  const migrations_rollback = yield runner.getMigrations();
1097
1453
  let downgraded = yield migration_filter(migrations_rollback, true);
1098
1454
  downgraded = downgraded.reverse();
1099
- if (args.flags.increment) {
1100
- const increment = parseInt(args.flags.increment);
1455
+ if (args.flags.all) {
1456
+ } else {
1457
+ const increment = parseInt(args.flags.increment || "1");
1101
1458
  downgraded = downgraded.slice(0, increment);
1102
1459
  }
1103
1460
  console.log(`Rolling back ${downgraded.length} migration(s)`);
@@ -1169,7 +1526,7 @@ var require_cli = __commonJS({
1169
1526
  throw new CLIError("Invalid format. Use --format table or --format json");
1170
1527
  }
1171
1528
  try {
1172
- const [results] = yield runner.sqlrunner.query(sql_query);
1529
+ const [results] = yield runner.query(sql_query);
1173
1530
  if (Array.isArray(results) && results.length > 0) {
1174
1531
  if (format === "json") {
1175
1532
  console.log(JSON.stringify(results, null, 2));
@@ -1189,6 +1546,40 @@ Returned ${results.length} row(s)`);
1189
1546
  }
1190
1547
  yield runner.close();
1191
1548
  break;
1549
+ case "seed": {
1550
+ const subCommands = commands.slice(1);
1551
+ const actionFlag = (args.flags.action || "").toString().toLowerCase();
1552
+ const firstSub = (subCommands[0] || "").toString().toLowerCase();
1553
+ const action = actionFlag === "down" || firstSub === "down" ? "down" : "up";
1554
+ const positionalNames = actionFlag ? subCommands : firstSub === "up" || firstSub === "down" ? subCommands.slice(1) : subCommands;
1555
+ const aliasFlag = args.flags.alias;
1556
+ const aliasMap = {};
1557
+ if (aliasFlag) {
1558
+ const aliases = Array.isArray(aliasFlag) ? aliasFlag : [aliasFlag];
1559
+ for (const entry of aliases) {
1560
+ const eq = entry.indexOf("=");
1561
+ if (eq > 0) {
1562
+ const key = entry.slice(0, eq);
1563
+ const value = entry.slice(eq + 1);
1564
+ if (key) aliasMap[key] = value;
1565
+ }
1566
+ }
1567
+ }
1568
+ const seedOptions = {
1569
+ migrationsDir: args.flags.migrationsDir || args.flags["migrations-dir"],
1570
+ dataDir: args.flags.dataDir || args.flags["data-dir"],
1571
+ validate: args.flags.validate === void 0 ? true : String(args.flags.validate).toLowerCase() !== "false",
1572
+ transactional: args.flags.transactional,
1573
+ aliasMap: Object.keys(aliasMap).length ? aliasMap : void 0,
1574
+ names: positionalNames.length ? positionalNames : void 0,
1575
+ log: (msg) => console.log(msg)
1576
+ };
1577
+ const reader = new FileMigrationConfigReader(config_file);
1578
+ const migrationConfig = reader.loadFile();
1579
+ yield runSeedsWithRunner(runner, migrationConfig, action, seedOptions);
1580
+ yield runner.close();
1581
+ break;
1582
+ }
1192
1583
  default:
1193
1584
  throw CLIError.unknownCommand(command);
1194
1585
  }
@@ -1220,12 +1611,15 @@ Commands:
1220
1611
  Options:
1221
1612
  -c, --config Specify the config file (default: proper.json)
1222
1613
  --increment <n> Limit the number of migrations to apply or roll back
1614
+ --all Roll back all completed migrations (down command only)
1223
1615
  --format <fmt> Output format for query command: 'table' (default) or 'json'
1224
1616
 
1225
1617
  Examples:
1226
1618
  proper up Apply all pending migrations
1227
1619
  proper up --increment 1 Apply only the next pending migration
1228
- proper down Roll back the last applied migration
1620
+ proper down Roll back the last applied migration (default: 1)
1621
+ proper down --increment 3 Roll back the last 3 applied migrations
1622
+ proper down --all Roll back all completed migrations
1229
1623
  proper create my_migration Create a new migration named "my_migration"
1230
1624
  proper init Create a new config file
1231
1625
  proper status Show the status of all migrations