@noego/proper 0.2.0 → 0.2.2

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
@@ -108,6 +108,16 @@ var DatabaseConnectionError = class _DatabaseConnectionError extends MigrationEr
108
108
  return new _DatabaseConnectionError(`Authentication failed for ${dbType} database`);
109
109
  }
110
110
  };
111
+ var MigrationStampError = class _MigrationStampError extends MigrationError {
112
+ constructor(migrationKey) {
113
+ super(
114
+ `Migration '${migrationKey}' cannot be migrated: its timestamp ends in "000", so it does not look like it was generated by 'proper create'. Recreate it with 'proper create <name>' and move the SQL into the generated files.`
115
+ );
116
+ this.migrationKey = migrationKey;
117
+ this.name = "MigrationStampError";
118
+ Object.setPrototypeOf(this, _MigrationStampError.prototype);
119
+ }
120
+ };
111
121
  var MigrationExecutionError = class _MigrationExecutionError extends MigrationError {
112
122
  constructor(message, migrationName, sql, originalError) {
113
123
  let fullMessage = `Migration Execution Error${migrationName ? ` in '${migrationName}'` : ""}: ${message}`;
@@ -370,8 +380,19 @@ var SqlMigrationBuilder = class {
370
380
  // framework/MigrationManifest.ts
371
381
  import fs from "fs";
372
382
  import path from "path";
383
+ var MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
384
+ function isMigrationFile(fileName) {
385
+ return MIGRATION_FILE_REGEX.test(fileName);
386
+ }
373
387
  function canonicalMigrationKey(value) {
374
- return value.replace(/(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i, "").toLowerCase();
388
+ return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
389
+ }
390
+ function mintMigrationStamp(now = Date.now()) {
391
+ return now % 10 === 0 ? now + 1 : now;
392
+ }
393
+ function isHandStampedKey(key) {
394
+ const stamp = key.split("_")[0];
395
+ return /^\d+$/.test(stamp) && /000$/.test(stamp);
375
396
  }
376
397
  function resolveMigrationFile(directory, baseName, direction, dialect) {
377
398
  const dialectExt = dialect === "sql" ? "mysql" : dialect;
@@ -384,7 +405,7 @@ function resolveMigrationFile(directory, baseName, direction, dialect) {
384
405
  function loadMigrationManifest(directory, dialect) {
385
406
  const manifest = /* @__PURE__ */ new Map();
386
407
  if (!fs.existsSync(directory)) return manifest;
387
- const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name);
408
+ const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
388
409
  const uniqueKeys = /* @__PURE__ */ new Set();
389
410
  files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
390
411
  uniqueKeys.forEach((key) => {
@@ -421,7 +442,7 @@ var MigrationDirectoryReader = class {
421
442
  }
422
443
  loadMigrations(table, connection) {
423
444
  fs2.existsSync(this.directory) || fs2.mkdirSync(this.directory);
424
- const dir_content = fs2.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name);
445
+ const dir_content = fs2.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name).filter(isMigrationFile);
425
446
  const uniqueKeys = /* @__PURE__ */ new Set();
426
447
  dir_content.forEach((file) => {
427
448
  const key = canonicalMigrationKey(file);
@@ -1284,7 +1305,7 @@ var PatchCreator = class _PatchCreator {
1284
1305
  if (!fs5.existsSync(this.patchFolder)) {
1285
1306
  fs5.mkdirSync(this.patchFolder, { recursive: true });
1286
1307
  }
1287
- let stamp = Date.now();
1308
+ let stamp = mintMigrationStamp();
1288
1309
  for (let attempt = 0; attempt < 1e3; attempt++) {
1289
1310
  const filePath = path4.join(this.patchFolder, `${stamp}_${normalized}.yaml`);
1290
1311
  try {
@@ -1292,7 +1313,7 @@ var PatchCreator = class _PatchCreator {
1292
1313
  return filePath;
1293
1314
  } catch (error) {
1294
1315
  if (error && error.code === "EEXIST") {
1295
- stamp += 1;
1316
+ stamp = mintMigrationStamp(stamp + 1);
1296
1317
  continue;
1297
1318
  }
1298
1319
  throw error;
@@ -1887,6 +1908,14 @@ var MySQLMigrationRunner = class {
1887
1908
  migrate(migrationNodes, forward) {
1888
1909
  return __async(this, null, function* () {
1889
1910
  yield this.setup();
1911
+ if (forward) {
1912
+ for (const node of migrationNodes) {
1913
+ const key = node.get_key();
1914
+ if (isHandStampedKey(key) && !(yield node.status()).completed) {
1915
+ throw new MigrationStampError(key);
1916
+ }
1917
+ }
1918
+ }
1890
1919
  for (let node of migrationNodes) {
1891
1920
  try {
1892
1921
  if (forward) {
@@ -2024,7 +2053,7 @@ var MigrationCreator = class {
2024
2053
  if (!fs6.existsSync(this.config.migration_folder)) {
2025
2054
  fs6.mkdirSync(this.config.migration_folder, { recursive: true });
2026
2055
  }
2027
- const now_timestamp = Date.now();
2056
+ const now_timestamp = mintMigrationStamp();
2028
2057
  const filename_up = `${now_timestamp}_${name}.up.sql`;
2029
2058
  const filename_down = `${now_timestamp}_${name}.down.sql`;
2030
2059
  fs6.writeFileSync(`${this.config.migration_folder}/${filename_up}`, `