@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/cli.mjs CHANGED
@@ -121,7 +121,7 @@ var init_MigrationFilter = __esm({
121
121
  });
122
122
 
123
123
  // framework/errors.ts
124
- var MigrationError, ConfigurationError, DatabaseConnectionError, MigrationExecutionError, PatchError, PatchValidationError, PatchIntegrityError, PatchConflictError, PatchExecutionError, CLIError;
124
+ var MigrationError, ConfigurationError, DatabaseConnectionError, MigrationStampError, MigrationExecutionError, PatchError, PatchValidationError, PatchIntegrityError, PatchConflictError, PatchExecutionError, CLIError;
125
125
  var init_errors = __esm({
126
126
  "framework/errors.ts"() {
127
127
  MigrationError = class _MigrationError extends Error {
@@ -187,6 +187,16 @@ var init_errors = __esm({
187
187
  return new _DatabaseConnectionError(`Authentication failed for ${dbType} database`);
188
188
  }
189
189
  };
190
+ MigrationStampError = class _MigrationStampError extends MigrationError {
191
+ constructor(migrationKey) {
192
+ super(
193
+ `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.`
194
+ );
195
+ this.migrationKey = migrationKey;
196
+ this.name = "MigrationStampError";
197
+ Object.setPrototypeOf(this, _MigrationStampError.prototype);
198
+ }
199
+ };
190
200
  MigrationExecutionError = class _MigrationExecutionError extends MigrationError {
191
201
  constructor(message, migrationName, sql, originalError) {
192
202
  let fullMessage = `Migration Execution Error${migrationName ? ` in '${migrationName}'` : ""}: ${message}`;
@@ -463,8 +473,18 @@ var init_SqlMigrationBuilder = __esm({
463
473
  // framework/MigrationManifest.ts
464
474
  import fs from "fs";
465
475
  import path from "path";
476
+ function isMigrationFile(fileName) {
477
+ return MIGRATION_FILE_REGEX.test(fileName);
478
+ }
466
479
  function canonicalMigrationKey(value) {
467
- return value.replace(/(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i, "").toLowerCase();
480
+ return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
481
+ }
482
+ function mintMigrationStamp(now = Date.now()) {
483
+ return now % 10 === 0 ? now + 1 : now;
484
+ }
485
+ function isHandStampedKey(key) {
486
+ const stamp = key.split("_")[0];
487
+ return /^\d+$/.test(stamp) && /000$/.test(stamp);
468
488
  }
469
489
  function resolveMigrationFile(directory, baseName, direction, dialect) {
470
490
  const dialectExt = dialect === "sql" ? "mysql" : dialect;
@@ -477,7 +497,7 @@ function resolveMigrationFile(directory, baseName, direction, dialect) {
477
497
  function loadMigrationManifest(directory, dialect) {
478
498
  const manifest = /* @__PURE__ */ new Map();
479
499
  if (!fs.existsSync(directory)) return manifest;
480
- const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name);
500
+ const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
481
501
  const uniqueKeys = /* @__PURE__ */ new Set();
482
502
  files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
483
503
  uniqueKeys.forEach((key) => {
@@ -489,8 +509,10 @@ function loadMigrationManifest(directory, dialect) {
489
509
  });
490
510
  return manifest;
491
511
  }
512
+ var MIGRATION_FILE_REGEX;
492
513
  var init_MigrationManifest = __esm({
493
514
  "framework/MigrationManifest.ts"() {
515
+ MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
494
516
  }
495
517
  });
496
518
 
@@ -524,7 +546,7 @@ var init_MigrationDirectoryReader = __esm({
524
546
  }
525
547
  loadMigrations(table, connection) {
526
548
  fs2.existsSync(this.directory) || fs2.mkdirSync(this.directory);
527
- const dir_content = fs2.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name);
549
+ const dir_content = fs2.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name).filter(isMigrationFile);
528
550
  const uniqueKeys = /* @__PURE__ */ new Set();
529
551
  dir_content.forEach((file) => {
530
552
  const key = canonicalMigrationKey(file);
@@ -1370,6 +1392,7 @@ var MAX_NAME_LENGTH, SCAFFOLD, PatchCreator;
1370
1392
  var init_PatchCreator = __esm({
1371
1393
  "framework/PatchCreator.ts"() {
1372
1394
  init_errors();
1395
+ init_MigrationManifest();
1373
1396
  MAX_NAME_LENGTH = 120;
1374
1397
  SCAFFOLD = `version: 1
1375
1398
  description: TODO
@@ -1416,7 +1439,7 @@ operations: []
1416
1439
  if (!fs5.existsSync(this.patchFolder)) {
1417
1440
  fs5.mkdirSync(this.patchFolder, { recursive: true });
1418
1441
  }
1419
- let stamp = Date.now();
1442
+ let stamp = mintMigrationStamp();
1420
1443
  for (let attempt = 0; attempt < 1e3; attempt++) {
1421
1444
  const filePath = path4.join(this.patchFolder, `${stamp}_${normalized}.yaml`);
1422
1445
  try {
@@ -1424,7 +1447,7 @@ operations: []
1424
1447
  return filePath;
1425
1448
  } catch (error) {
1426
1449
  if (error && error.code === "EEXIST") {
1427
- stamp += 1;
1450
+ stamp = mintMigrationStamp(stamp + 1);
1428
1451
  continue;
1429
1452
  }
1430
1453
  throw error;
@@ -1782,6 +1805,8 @@ var init_MigrationRunner = __esm({
1782
1805
  init_PatchRunner();
1783
1806
  init_PatchCreator();
1784
1807
  init_PatchTypes();
1808
+ init_MigrationManifest();
1809
+ init_errors();
1785
1810
  init_SQLRunner();
1786
1811
  init_errors();
1787
1812
  MigrationRunnerFactory = class _MigrationRunnerFactory {
@@ -2035,6 +2060,14 @@ var init_MigrationRunner = __esm({
2035
2060
  migrate(migrationNodes, forward) {
2036
2061
  return __async(this, null, function* () {
2037
2062
  yield this.setup();
2063
+ if (forward) {
2064
+ for (const node of migrationNodes) {
2065
+ const key = node.get_key();
2066
+ if (isHandStampedKey(key) && !(yield node.status()).completed) {
2067
+ throw new MigrationStampError(key);
2068
+ }
2069
+ }
2070
+ }
2038
2071
  for (let node of migrationNodes) {
2039
2072
  try {
2040
2073
  if (forward) {
@@ -2172,7 +2205,7 @@ var init_MigrationRunner = __esm({
2172
2205
  if (!fs6.existsSync(this.config.migration_folder)) {
2173
2206
  fs6.mkdirSync(this.config.migration_folder, { recursive: true });
2174
2207
  }
2175
- const now_timestamp = Date.now();
2208
+ const now_timestamp = mintMigrationStamp();
2176
2209
  const filename_up = `${now_timestamp}_${name}.up.sql`;
2177
2210
  const filename_down = `${now_timestamp}_${name}.down.sql`;
2178
2211
  fs6.writeFileSync(`${this.config.migration_folder}/${filename_up}`, `