@noego/proper 0.0.3 → 0.0.4

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/index.mjs CHANGED
@@ -1,3 +1,22 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1
20
  var __async = (__this, __arguments, generator) => {
2
21
  return new Promise((resolve, reject) => {
3
22
  var fulfilled = (value) => {
@@ -489,6 +508,9 @@ var BaseSQLRunner = class {
489
508
  });
490
509
  }
491
510
  };
511
+ function isPromiseLike(value) {
512
+ return !!value && typeof value.then === "function";
513
+ }
492
514
  var SQLRunner = class extends BaseSQLRunner {
493
515
  constructor(connection) {
494
516
  super();
@@ -518,14 +540,85 @@ var SQLiteRunner = class extends BaseSQLRunner {
518
540
  super();
519
541
  this.connection = connection;
520
542
  }
543
+ prepareStatement(sql) {
544
+ return __async(this, null, function* () {
545
+ if (typeof this.connection.prepare !== "function") {
546
+ throw new Error("SQLite connection does not support prepare()");
547
+ }
548
+ const stmt = this.connection.prepare(sql);
549
+ return isPromiseLike(stmt) ? yield stmt : stmt;
550
+ });
551
+ }
552
+ finalizeStatement(stmt) {
553
+ return __async(this, null, function* () {
554
+ if (!stmt || typeof stmt.finalize !== "function") return;
555
+ const result = stmt.finalize();
556
+ if (isPromiseLike(result)) {
557
+ yield result;
558
+ }
559
+ });
560
+ }
561
+ statementAll(stmt, params) {
562
+ return __async(this, null, function* () {
563
+ if (typeof stmt.all !== "function") {
564
+ throw new Error("SQLite statement does not support all()");
565
+ }
566
+ if (stmt.all.length >= 2) {
567
+ return yield new Promise((resolve, reject) => {
568
+ const callback = (err, rows) => {
569
+ if (err) return reject(err);
570
+ resolve(rows || []);
571
+ };
572
+ try {
573
+ if (params.length > 0) {
574
+ stmt.all(params, callback);
575
+ } else {
576
+ stmt.all(callback);
577
+ }
578
+ } catch (error) {
579
+ reject(error);
580
+ }
581
+ });
582
+ }
583
+ const result = stmt.all(...params);
584
+ return isPromiseLike(result) ? yield result : result;
585
+ });
586
+ }
587
+ statementRun(stmt, params) {
588
+ return __async(this, null, function* () {
589
+ if (typeof stmt.run !== "function") {
590
+ throw new Error("SQLite statement does not support run()");
591
+ }
592
+ if (stmt.run.length >= 2) {
593
+ return yield new Promise((resolve, reject) => {
594
+ const callback = function(err) {
595
+ var _a;
596
+ if (err) return reject(err);
597
+ resolve({ changes: (_a = this == null ? void 0 : this.changes) != null ? _a : 0, lastID: this == null ? void 0 : this.lastID });
598
+ };
599
+ try {
600
+ if (params.length > 0) {
601
+ stmt.run(params, callback);
602
+ } else {
603
+ stmt.run(callback);
604
+ }
605
+ } catch (error) {
606
+ reject(error);
607
+ }
608
+ });
609
+ }
610
+ const result = stmt.run(...params);
611
+ return isPromiseLike(result) ? yield result : result;
612
+ });
613
+ }
521
614
  _query(_0) {
522
615
  return __async(this, arguments, function* (sql, params = []) {
523
- const stmt = yield this.connection.prepare(sql);
616
+ const stmt = yield this.prepareStatement(sql);
524
617
  try {
525
- const rows = yield stmt.all(...params);
618
+ const rows = yield this.statementAll(stmt, params);
526
619
  return rows;
527
620
  } finally {
528
- yield stmt.finalize();
621
+ yield this.finalizeStatement(stmt);
529
622
  }
530
623
  });
531
624
  }
@@ -539,12 +632,12 @@ ${sql}
539
632
  throw err;
540
633
  });
541
634
  }
542
- const stmt = yield this.connection.prepare(sql);
635
+ const stmt = yield this.prepareStatement(sql);
543
636
  try {
544
- const info = yield stmt.run(...params);
637
+ const info = yield this.statementRun(stmt, params);
545
638
  return info;
546
639
  } finally {
547
- yield stmt.finalize();
640
+ yield this.finalizeStatement(stmt);
548
641
  }
549
642
  });
550
643
  }
@@ -560,13 +653,13 @@ ${sql}
560
653
  ).filter((s) => s.trim() !== "");
561
654
  const infos = yield statements.reduce((prev, statement) => __async(this, null, function* () {
562
655
  const infos2 = yield prev;
563
- const stmt = yield this.connection.prepare(`${statement};`);
656
+ const stmt = yield this.prepareStatement(`${statement};`);
564
657
  try {
565
- const info = yield stmt.run(...params);
658
+ const info = yield this.statementRun(stmt, params);
566
659
  infos2.push(info);
567
660
  return infos2;
568
661
  } finally {
569
- yield stmt.finalize();
662
+ yield this.finalizeStatement(stmt);
570
663
  }
571
664
  }), Promise.resolve([null])).then((infos2) => {
572
665
  return infos2.filter((info) => info !== null);
@@ -599,7 +692,14 @@ function toError(error) {
599
692
  if (error instanceof Error) return error;
600
693
  return new Error(String(error));
601
694
  }
695
+ function loadMigrationConfig(configFile) {
696
+ const reader = new FileMigrationConfigReader(configFile);
697
+ return reader.loadFile();
698
+ }
602
699
  var MigrationRunnerFactory = class _MigrationRunnerFactory {
700
+ static isSQLRunner(conn) {
701
+ return !!conn && typeof conn.query === "function" && typeof conn.execute === "function" && typeof conn.end === "function";
702
+ }
603
703
  static create(configFile, conn) {
604
704
  return __async(this, null, function* () {
605
705
  const configReader = new FileMigrationConfigReader(configFile);
@@ -655,21 +755,27 @@ var MigrationRunnerFactory = class _MigrationRunnerFactory {
655
755
  create(config, conn) {
656
756
  return __async(this, null, function* () {
657
757
  let sqlrunner;
658
- switch (config.database) {
659
- case "sql":
660
- sqlrunner = new SQLRunner(conn);
661
- break;
662
- case "sqlite":
663
- sqlrunner = new SQLiteRunner(conn);
664
- break;
665
- default:
666
- throw ConfigurationError.unknownDatabaseType(config.database);
758
+ let driverConnection = conn;
759
+ if (_MigrationRunnerFactory.isSQLRunner(conn)) {
760
+ sqlrunner = conn;
761
+ driverConnection = null;
762
+ } else {
763
+ switch (config.database) {
764
+ case "sql":
765
+ sqlrunner = new SQLRunner(conn);
766
+ break;
767
+ case "sqlite":
768
+ sqlrunner = new SQLiteRunner(conn);
769
+ break;
770
+ default:
771
+ throw ConfigurationError.unknownDatabaseType(config.database);
772
+ }
667
773
  }
668
774
  const setup = new MigrationSetup(sqlrunner, config);
669
775
  const read_strategy = this.getReadStategy(config);
670
776
  const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner);
671
777
  yield setup.setup();
672
- return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, conn);
778
+ return new MySQLMigrationRunner(config, migration_files, setup, sqlrunner, driverConnection);
673
779
  });
674
780
  }
675
781
  createEmpty(config) {
@@ -833,6 +939,11 @@ var MySQLMigrationRunner = class {
833
939
  }
834
940
  });
835
941
  }
942
+ query(sql, params) {
943
+ return __async(this, null, function* () {
944
+ return yield this.sqlrunner.query(sql, params);
945
+ });
946
+ }
836
947
  init(config_file) {
837
948
  return __async(this, null, function* () {
838
949
  try {
@@ -928,8 +1039,261 @@ var MigrationCreator = class {
928
1039
  }
929
1040
  }
930
1041
  };
1042
+
1043
+ // framework/SeedRunner.ts
1044
+ import fs4 from "fs";
1045
+ import path2 from "path";
1046
+ import Ajv from "ajv";
1047
+ import addFormats from "ajv-formats";
1048
+ function resolveAlias(name, aliasMap) {
1049
+ var _a;
1050
+ if (!aliasMap) return name;
1051
+ return (_a = aliasMap[name]) != null ? _a : name;
1052
+ }
1053
+ function walkForFile(rootDir, fileName) {
1054
+ if (!fs4.existsSync(rootDir)) return null;
1055
+ const entries = fs4.readdirSync(rootDir, { withFileTypes: true });
1056
+ for (const entry of entries) {
1057
+ const full = path2.join(rootDir, entry.name);
1058
+ if (entry.isDirectory()) {
1059
+ const found = walkForFile(full, fileName);
1060
+ if (found) return found;
1061
+ } else if (entry.isFile() && entry.name === fileName) {
1062
+ return full;
1063
+ }
1064
+ }
1065
+ return null;
1066
+ }
1067
+ function resolveMigrationsDir(migrationConfig, options) {
1068
+ var _a;
1069
+ const fromOptions = options.migrationsDir;
1070
+ const fromConfig = (_a = migrationConfig.seeds) == null ? void 0 : _a.migrationsDir;
1071
+ const dir = fromOptions != null ? fromOptions : fromConfig;
1072
+ if (!dir) {
1073
+ throw new Error("Seed migrationsDir not configured. Set seeds.migrationsDir in proper.json or pass it explicitly.");
1074
+ }
1075
+ return dir;
1076
+ }
1077
+ function mergeSeedConfig(migrationConfig, options) {
1078
+ var _a, _b, _c, _d;
1079
+ const names = options.names && options.names.length ? options.names : ((_a = migrationConfig.seeds) == null ? void 0 : _a.list) && migrationConfig.seeds.list.length ? migrationConfig.seeds.list : [];
1080
+ if (!names.length) {
1081
+ throw new Error("No seed names provided and no seeds.list defined in proper config");
1082
+ }
1083
+ const migrationsDir = resolveMigrationsDir(migrationConfig, options);
1084
+ const dataDir = (_c = options.dataDir) != null ? _c : (_b = migrationConfig.seeds) == null ? void 0 : _b.dataDir;
1085
+ const validate = options.validate !== void 0 ? options.validate : true;
1086
+ const transactional = (_d = options.transactional) != null ? _d : "none";
1087
+ const finalOptions = __spreadProps(__spreadValues({}, options), {
1088
+ migrationsDir,
1089
+ dataDir,
1090
+ validate,
1091
+ transactional
1092
+ });
1093
+ return { names, finalOptions };
1094
+ }
1095
+ function resolveSqlPair(name, migrationsDir) {
1096
+ const up = walkForFile(migrationsDir, `${name}.up.sql`);
1097
+ const down = walkForFile(migrationsDir, `${name}.down.sql`);
1098
+ if (up && down) {
1099
+ return { upPath: up, downPath: down };
1100
+ }
1101
+ return null;
1102
+ }
1103
+ function resolveModule(name, migrationsDir) {
1104
+ const ts = walkForFile(migrationsDir, `${name}.ts`);
1105
+ if (ts) return { kind: "ts", modulePath: ts };
1106
+ const js = walkForFile(migrationsDir, `${name}.js`);
1107
+ if (js) return { kind: "js", modulePath: js };
1108
+ return null;
1109
+ }
1110
+ function resolveSeed(name, migrationConfig, options) {
1111
+ return __async(this, null, function* () {
1112
+ var _a, _b;
1113
+ const migrationsDir = resolveMigrationsDir(migrationConfig, options);
1114
+ const alias = resolveAlias(name, options.aliasMap);
1115
+ const sqlPair = resolveSqlPair(name, migrationsDir);
1116
+ if (sqlPair) {
1117
+ return {
1118
+ kind: "sql",
1119
+ name,
1120
+ alias,
1121
+ upPath: sqlPair.upPath,
1122
+ downPath: sqlPair.downPath,
1123
+ dataPath: null,
1124
+ schemaPath: null
1125
+ };
1126
+ }
1127
+ const module = resolveModule(name, migrationsDir);
1128
+ if (!module) {
1129
+ throw new Error(`Seed implementation not found for "${name}" under ${migrationsDir}`);
1130
+ }
1131
+ const dataDir = (_b = options.dataDir) != null ? _b : (_a = migrationConfig.seeds) == null ? void 0 : _a.dataDir;
1132
+ let dataPath = null;
1133
+ let schemaPath = null;
1134
+ if (dataDir) {
1135
+ dataPath = walkForFile(dataDir, `${alias}.json`);
1136
+ schemaPath = walkForFile(dataDir, `${alias}.schema.json`);
1137
+ }
1138
+ return {
1139
+ kind: module.kind,
1140
+ name,
1141
+ alias,
1142
+ upPath: module.modulePath,
1143
+ downPath: module.modulePath,
1144
+ dataPath,
1145
+ schemaPath
1146
+ };
1147
+ });
1148
+ }
1149
+ function loadJson(filePath) {
1150
+ return __async(this, null, function* () {
1151
+ const content = yield fs4.promises.readFile(filePath, "utf8");
1152
+ return JSON.parse(content);
1153
+ });
1154
+ }
1155
+ function createValidator() {
1156
+ const ajv = new Ajv({ allErrors: true, strict: false });
1157
+ addFormats(ajv);
1158
+ return ajv;
1159
+ }
1160
+ function validateData(schemaPath, data, validate, log) {
1161
+ return __async(this, null, function* () {
1162
+ if (!validate || !schemaPath) return;
1163
+ const content = yield fs4.promises.readFile(schemaPath, "utf8");
1164
+ const schema = JSON.parse(content);
1165
+ const ajv = createValidator();
1166
+ const validateFn = ajv.compile(schema);
1167
+ const ok = validateFn(data);
1168
+ if (!ok) {
1169
+ log == null ? void 0 : log(`Validation failed for seed data (${schemaPath})`);
1170
+ throw new Error(`Seed data validation failed: ${ajv.errorsText(validateFn.errors || [])}`);
1171
+ }
1172
+ });
1173
+ }
1174
+ function runSqlSeed(runner, resolved, direction) {
1175
+ return __async(this, null, function* () {
1176
+ const sqlPath = direction === "up" ? resolved.upPath : resolved.downPath;
1177
+ const sql = yield fs4.promises.readFile(sqlPath, "utf8");
1178
+ yield runner.query(sql);
1179
+ });
1180
+ }
1181
+ function runModuleSeed(runner, resolved, migrationConfig, options, direction) {
1182
+ return __async(this, null, function* () {
1183
+ const { log } = options;
1184
+ const module = yield import(path2.resolve(resolved.upPath));
1185
+ const handler = module[direction];
1186
+ if (typeof handler !== "function") {
1187
+ throw new Error(`Seed module "${resolved.name}" does not export ${direction}()`);
1188
+ }
1189
+ let data = null;
1190
+ if (options.preloadedData && Object.prototype.hasOwnProperty.call(options.preloadedData, resolved.name)) {
1191
+ data = options.preloadedData[resolved.name];
1192
+ } else if (resolved.dataPath) {
1193
+ data = yield loadJson(resolved.dataPath);
1194
+ }
1195
+ yield validateData(resolved.schemaPath, data, options.validate, log);
1196
+ const ctx = {
1197
+ data,
1198
+ log,
1199
+ dialect: migrationConfig.database || "sql"
1200
+ };
1201
+ yield handler(runner, ctx);
1202
+ });
1203
+ }
1204
+ function runSingleSeed(runner, migrationConfig, name, options, direction) {
1205
+ return __async(this, null, function* () {
1206
+ const resolved = yield resolveSeed(name, migrationConfig, options);
1207
+ if (resolved.kind === "sql") {
1208
+ yield runSqlSeed(runner, resolved, direction);
1209
+ } else {
1210
+ yield runModuleSeed(runner, resolved, migrationConfig, options, direction);
1211
+ }
1212
+ });
1213
+ }
1214
+ function withTransactionalMode(runner, migrationConfig, names, options, direction) {
1215
+ return __async(this, null, function* () {
1216
+ const mode = options.transactional;
1217
+ if (mode === "runner") {
1218
+ yield runner.query("BEGIN");
1219
+ try {
1220
+ for (const name of names) {
1221
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1222
+ }
1223
+ yield runner.query("COMMIT");
1224
+ } catch (err) {
1225
+ try {
1226
+ yield runner.query("ROLLBACK");
1227
+ } catch (e) {
1228
+ }
1229
+ throw err;
1230
+ }
1231
+ return;
1232
+ }
1233
+ if (mode === "seed") {
1234
+ for (const name of names) {
1235
+ yield runner.query("BEGIN");
1236
+ try {
1237
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1238
+ yield runner.query("COMMIT");
1239
+ } catch (err) {
1240
+ try {
1241
+ yield runner.query("ROLLBACK");
1242
+ } catch (e) {
1243
+ }
1244
+ throw err;
1245
+ }
1246
+ }
1247
+ return;
1248
+ }
1249
+ for (const name of names) {
1250
+ yield runSingleSeed(runner, migrationConfig, name, options, direction);
1251
+ }
1252
+ });
1253
+ }
1254
+ function runSeedsWithRunner(runner, migrationConfig, direction, options) {
1255
+ return __async(this, null, function* () {
1256
+ const { names, finalOptions } = mergeSeedConfig(migrationConfig, options);
1257
+ yield withTransactionalMode(runner, migrationConfig, names, finalOptions, direction);
1258
+ });
1259
+ }
1260
+ function createSeedFactory(options) {
1261
+ var _a;
1262
+ const configFile = (_a = options.configFile) != null ? _a : "proper.json";
1263
+ return {
1264
+ up(names) {
1265
+ return __async(this, null, function* () {
1266
+ const runner = yield MigrationRunnerFactory.create(configFile);
1267
+ const migrationConfig = loadMigrationConfig(configFile);
1268
+ try {
1269
+ yield runSeedsWithRunner(runner, migrationConfig, "up", __spreadProps(__spreadValues({}, options), {
1270
+ names: names && names.length ? names : options.names
1271
+ }));
1272
+ } finally {
1273
+ yield runner.close();
1274
+ }
1275
+ });
1276
+ },
1277
+ down(names) {
1278
+ return __async(this, null, function* () {
1279
+ const runner = yield MigrationRunnerFactory.create(configFile);
1280
+ const migrationConfig = loadMigrationConfig(configFile);
1281
+ try {
1282
+ yield runSeedsWithRunner(runner, migrationConfig, "down", __spreadProps(__spreadValues({}, options), {
1283
+ names: names && names.length ? names : options.names
1284
+ }));
1285
+ } finally {
1286
+ yield runner.close();
1287
+ }
1288
+ });
1289
+ }
1290
+ };
1291
+ }
931
1292
  export {
932
1293
  MySQLMigrationRunner as MigrationRunner,
933
- MigrationRunnerFactory
1294
+ MigrationRunnerFactory,
1295
+ createSeedFactory,
1296
+ loadMigrationConfig,
1297
+ runSeedsWithRunner
934
1298
  };
935
1299
  //# sourceMappingURL=index.mjs.map