@noego/proper 0.2.1 → 0.3.0
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.js +90 -40
- package/bin/cli.js.map +1 -1
- package/bin/cli.mjs +103 -43
- package/bin/cli.mjs.map +1 -1
- package/bin/index.d.mts +5 -0
- package/bin/index.d.ts +5 -0
- package/bin/index.js +90 -40
- package/bin/index.js.map +1 -1
- package/bin/index.mjs +90 -40
- package/bin/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +12 -0
package/bin/cli.js
CHANGED
|
@@ -125,9 +125,6 @@ function migration_filter(_0) {
|
|
|
125
125
|
// framework/MigrationRunner.ts
|
|
126
126
|
var import_fs6 = __toESM(require("fs"));
|
|
127
127
|
|
|
128
|
-
// framework/MigrationDirectoryReader.ts
|
|
129
|
-
var import_fs2 = __toESM(require("fs"));
|
|
130
|
-
|
|
131
128
|
// framework/errors.ts
|
|
132
129
|
var MigrationError = class _MigrationError extends Error {
|
|
133
130
|
constructor(message) {
|
|
@@ -192,6 +189,16 @@ var DatabaseConnectionError = class _DatabaseConnectionError extends MigrationEr
|
|
|
192
189
|
return new _DatabaseConnectionError(`Authentication failed for ${dbType} database`);
|
|
193
190
|
}
|
|
194
191
|
};
|
|
192
|
+
var MigrationStampError = class _MigrationStampError extends MigrationError {
|
|
193
|
+
constructor(migrationKey) {
|
|
194
|
+
super(
|
|
195
|
+
`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.`
|
|
196
|
+
);
|
|
197
|
+
this.migrationKey = migrationKey;
|
|
198
|
+
this.name = "MigrationStampError";
|
|
199
|
+
Object.setPrototypeOf(this, _MigrationStampError.prototype);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
195
202
|
var MigrationExecutionError = class _MigrationExecutionError extends MigrationError {
|
|
196
203
|
constructor(message, migrationName, sql, originalError) {
|
|
197
204
|
let fullMessage = `Migration Execution Error${migrationName ? ` in '${migrationName}'` : ""}: ${message}`;
|
|
@@ -320,6 +327,71 @@ var CLIError = class _CLIError extends MigrationError {
|
|
|
320
327
|
}
|
|
321
328
|
};
|
|
322
329
|
|
|
330
|
+
// framework/MigrationManifest.ts
|
|
331
|
+
var import_fs = __toESM(require("fs"));
|
|
332
|
+
var import_path = __toESM(require("path"));
|
|
333
|
+
var MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
334
|
+
function isMigrationFile(fileName) {
|
|
335
|
+
return MIGRATION_FILE_REGEX.test(fileName);
|
|
336
|
+
}
|
|
337
|
+
function canonicalMigrationKey(value) {
|
|
338
|
+
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
339
|
+
}
|
|
340
|
+
function mintMigrationStamp(now = Date.now()) {
|
|
341
|
+
return now % 10 === 0 ? now + 1 : now;
|
|
342
|
+
}
|
|
343
|
+
function isHandStampedKey(key) {
|
|
344
|
+
const stamp = key.split("_")[0];
|
|
345
|
+
return /^\d+$/.test(stamp) && /000$/.test(stamp);
|
|
346
|
+
}
|
|
347
|
+
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
348
|
+
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
349
|
+
const dialectFile = import_path.default.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
350
|
+
if (import_fs.default.existsSync(dialectFile)) return dialectFile;
|
|
351
|
+
const genericFile = import_path.default.join(directory, `${baseName}.${direction}.sql`);
|
|
352
|
+
if (import_fs.default.existsSync(genericFile)) return genericFile;
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
function loadMigrationManifest(directory, dialect) {
|
|
356
|
+
const manifest = /* @__PURE__ */ new Map();
|
|
357
|
+
if (!import_fs.default.existsSync(directory)) return manifest;
|
|
358
|
+
const files = import_fs.default.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
359
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
360
|
+
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
361
|
+
uniqueKeys.forEach((key) => {
|
|
362
|
+
manifest.set(key, {
|
|
363
|
+
key,
|
|
364
|
+
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
365
|
+
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
return manifest;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// framework/MigrationConfig.ts
|
|
372
|
+
function validateLegacyMigrationKeys(value) {
|
|
373
|
+
if (value === void 0) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (!Array.isArray(value) || value.some((key) => !isExactCanonicalMigrationKey(key))) {
|
|
377
|
+
throw new ConfigurationError(
|
|
378
|
+
"legacy_migration_keys must be an array of nonempty exact canonical migration keys; filenames, paths, wildcards, and nonstrings are not allowed"
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function isExactCanonicalMigrationKey(value) {
|
|
383
|
+
if (typeof value !== "string" || value.length === 0 || value !== value.trim()) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
if (value.includes("/") || value.includes("\\") || ["*", "?", "[", "]", "{", "}"].some((token) => value.includes(token))) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
return !isMigrationFile(value) && canonicalMigrationKey(value) === value;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// framework/MigrationDirectoryReader.ts
|
|
393
|
+
var import_fs2 = __toESM(require("fs"));
|
|
394
|
+
|
|
323
395
|
// framework/MigrationNode.ts
|
|
324
396
|
var MigrationNode = class {
|
|
325
397
|
constructor(name) {
|
|
@@ -451,40 +523,6 @@ var SqlMigrationBuilder = class {
|
|
|
451
523
|
}
|
|
452
524
|
};
|
|
453
525
|
|
|
454
|
-
// framework/MigrationManifest.ts
|
|
455
|
-
var import_fs = __toESM(require("fs"));
|
|
456
|
-
var import_path = __toESM(require("path"));
|
|
457
|
-
var MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
458
|
-
function isMigrationFile(fileName) {
|
|
459
|
-
return MIGRATION_FILE_REGEX.test(fileName);
|
|
460
|
-
}
|
|
461
|
-
function canonicalMigrationKey(value) {
|
|
462
|
-
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
463
|
-
}
|
|
464
|
-
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
465
|
-
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
466
|
-
const dialectFile = import_path.default.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
467
|
-
if (import_fs.default.existsSync(dialectFile)) return dialectFile;
|
|
468
|
-
const genericFile = import_path.default.join(directory, `${baseName}.${direction}.sql`);
|
|
469
|
-
if (import_fs.default.existsSync(genericFile)) return genericFile;
|
|
470
|
-
return null;
|
|
471
|
-
}
|
|
472
|
-
function loadMigrationManifest(directory, dialect) {
|
|
473
|
-
const manifest = /* @__PURE__ */ new Map();
|
|
474
|
-
if (!import_fs.default.existsSync(directory)) return manifest;
|
|
475
|
-
const files = import_fs.default.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
476
|
-
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
477
|
-
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
478
|
-
uniqueKeys.forEach((key) => {
|
|
479
|
-
manifest.set(key, {
|
|
480
|
-
key,
|
|
481
|
-
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
482
|
-
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
483
|
-
});
|
|
484
|
-
});
|
|
485
|
-
return manifest;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
526
|
// framework/MigrationDirectoryReader.ts
|
|
489
527
|
var MigrationDirectoryReader = class {
|
|
490
528
|
constructor(directory, read_strategy, sqlrunner, dialect = "sql") {
|
|
@@ -1357,7 +1395,7 @@ var PatchCreator = class _PatchCreator {
|
|
|
1357
1395
|
if (!import_fs5.default.existsSync(this.patchFolder)) {
|
|
1358
1396
|
import_fs5.default.mkdirSync(this.patchFolder, { recursive: true });
|
|
1359
1397
|
}
|
|
1360
|
-
let stamp =
|
|
1398
|
+
let stamp = mintMigrationStamp();
|
|
1361
1399
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
1362
1400
|
const filePath = import_path4.default.join(this.patchFolder, `${stamp}_${normalized}.yaml`);
|
|
1363
1401
|
try {
|
|
@@ -1365,7 +1403,7 @@ var PatchCreator = class _PatchCreator {
|
|
|
1365
1403
|
return filePath;
|
|
1366
1404
|
} catch (error) {
|
|
1367
1405
|
if (error && error.code === "EEXIST") {
|
|
1368
|
-
stamp
|
|
1406
|
+
stamp = mintMigrationStamp(stamp + 1);
|
|
1369
1407
|
continue;
|
|
1370
1408
|
}
|
|
1371
1409
|
throw error;
|
|
@@ -1850,6 +1888,7 @@ var MySQLMigrationRunner = class {
|
|
|
1850
1888
|
*/
|
|
1851
1889
|
this.preflightPromise = null;
|
|
1852
1890
|
this.lastPatchResults = [];
|
|
1891
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
1853
1892
|
}
|
|
1854
1893
|
setup() {
|
|
1855
1894
|
return __async(this, null, function* () {
|
|
@@ -1955,7 +1994,17 @@ var MySQLMigrationRunner = class {
|
|
|
1955
1994
|
}
|
|
1956
1995
|
migrate(migrationNodes, forward) {
|
|
1957
1996
|
return __async(this, null, function* () {
|
|
1997
|
+
var _a;
|
|
1958
1998
|
yield this.setup();
|
|
1999
|
+
if (forward) {
|
|
2000
|
+
const legacyMigrationKeys = new Set((_a = this.config.legacy_migration_keys) != null ? _a : []);
|
|
2001
|
+
for (const node of migrationNodes) {
|
|
2002
|
+
const key = node.get_key();
|
|
2003
|
+
if (isHandStampedKey(key) && !legacyMigrationKeys.has(key) && !(yield node.status()).completed) {
|
|
2004
|
+
throw new MigrationStampError(key);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
1959
2008
|
for (let node of migrationNodes) {
|
|
1960
2009
|
try {
|
|
1961
2010
|
if (forward) {
|
|
@@ -2051,6 +2100,7 @@ var FileMigrationConfigReader = class {
|
|
|
2051
2100
|
try {
|
|
2052
2101
|
const fileContent = import_fs6.default.readFileSync(this.configFile);
|
|
2053
2102
|
const config = JSON.parse(fileContent.toString());
|
|
2103
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
2054
2104
|
if (!config.migration_folder) {
|
|
2055
2105
|
throw ConfigurationError.missingRequiredProperty("migration_folder");
|
|
2056
2106
|
}
|
|
@@ -2093,7 +2143,7 @@ var MigrationCreator = class {
|
|
|
2093
2143
|
if (!import_fs6.default.existsSync(this.config.migration_folder)) {
|
|
2094
2144
|
import_fs6.default.mkdirSync(this.config.migration_folder, { recursive: true });
|
|
2095
2145
|
}
|
|
2096
|
-
const now_timestamp =
|
|
2146
|
+
const now_timestamp = mintMigrationStamp();
|
|
2097
2147
|
const filename_up = `${now_timestamp}_${name}.up.sql`;
|
|
2098
2148
|
const filename_down = `${now_timestamp}_${name}.down.sql`;
|
|
2099
2149
|
import_fs6.default.writeFileSync(`${this.config.migration_folder}/${filename_up}`, `
|