@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/index.mjs
CHANGED
|
@@ -41,9 +41,6 @@ var __async = (__this, __arguments, generator) => {
|
|
|
41
41
|
// framework/MigrationRunner.ts
|
|
42
42
|
import fs6 from "fs";
|
|
43
43
|
|
|
44
|
-
// framework/MigrationDirectoryReader.ts
|
|
45
|
-
import fs2 from "fs";
|
|
46
|
-
|
|
47
44
|
// framework/errors.ts
|
|
48
45
|
var MigrationError = class _MigrationError extends Error {
|
|
49
46
|
constructor(message) {
|
|
@@ -108,6 +105,16 @@ var DatabaseConnectionError = class _DatabaseConnectionError extends MigrationEr
|
|
|
108
105
|
return new _DatabaseConnectionError(`Authentication failed for ${dbType} database`);
|
|
109
106
|
}
|
|
110
107
|
};
|
|
108
|
+
var MigrationStampError = class _MigrationStampError extends MigrationError {
|
|
109
|
+
constructor(migrationKey) {
|
|
110
|
+
super(
|
|
111
|
+
`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.`
|
|
112
|
+
);
|
|
113
|
+
this.migrationKey = migrationKey;
|
|
114
|
+
this.name = "MigrationStampError";
|
|
115
|
+
Object.setPrototypeOf(this, _MigrationStampError.prototype);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
111
118
|
var MigrationExecutionError = class _MigrationExecutionError extends MigrationError {
|
|
112
119
|
constructor(message, migrationName, sql, originalError) {
|
|
113
120
|
let fullMessage = `Migration Execution Error${migrationName ? ` in '${migrationName}'` : ""}: ${message}`;
|
|
@@ -236,6 +243,71 @@ var CLIError = class _CLIError extends MigrationError {
|
|
|
236
243
|
}
|
|
237
244
|
};
|
|
238
245
|
|
|
246
|
+
// framework/MigrationManifest.ts
|
|
247
|
+
import fs from "fs";
|
|
248
|
+
import path from "path";
|
|
249
|
+
var MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
250
|
+
function isMigrationFile(fileName) {
|
|
251
|
+
return MIGRATION_FILE_REGEX.test(fileName);
|
|
252
|
+
}
|
|
253
|
+
function canonicalMigrationKey(value) {
|
|
254
|
+
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
255
|
+
}
|
|
256
|
+
function mintMigrationStamp(now = Date.now()) {
|
|
257
|
+
return now % 10 === 0 ? now + 1 : now;
|
|
258
|
+
}
|
|
259
|
+
function isHandStampedKey(key) {
|
|
260
|
+
const stamp = key.split("_")[0];
|
|
261
|
+
return /^\d+$/.test(stamp) && /000$/.test(stamp);
|
|
262
|
+
}
|
|
263
|
+
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
264
|
+
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
265
|
+
const dialectFile = path.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
266
|
+
if (fs.existsSync(dialectFile)) return dialectFile;
|
|
267
|
+
const genericFile = path.join(directory, `${baseName}.${direction}.sql`);
|
|
268
|
+
if (fs.existsSync(genericFile)) return genericFile;
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
function loadMigrationManifest(directory, dialect) {
|
|
272
|
+
const manifest = /* @__PURE__ */ new Map();
|
|
273
|
+
if (!fs.existsSync(directory)) return manifest;
|
|
274
|
+
const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
275
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
276
|
+
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
277
|
+
uniqueKeys.forEach((key) => {
|
|
278
|
+
manifest.set(key, {
|
|
279
|
+
key,
|
|
280
|
+
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
281
|
+
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
return manifest;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// framework/MigrationConfig.ts
|
|
288
|
+
function validateLegacyMigrationKeys(value) {
|
|
289
|
+
if (value === void 0) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (!Array.isArray(value) || value.some((key) => !isExactCanonicalMigrationKey(key))) {
|
|
293
|
+
throw new ConfigurationError(
|
|
294
|
+
"legacy_migration_keys must be an array of nonempty exact canonical migration keys; filenames, paths, wildcards, and nonstrings are not allowed"
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function isExactCanonicalMigrationKey(value) {
|
|
299
|
+
if (typeof value !== "string" || value.length === 0 || value !== value.trim()) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
if (value.includes("/") || value.includes("\\") || ["*", "?", "[", "]", "{", "}"].some((token) => value.includes(token))) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
return !isMigrationFile(value) && canonicalMigrationKey(value) === value;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// framework/MigrationDirectoryReader.ts
|
|
309
|
+
import fs2 from "fs";
|
|
310
|
+
|
|
239
311
|
// framework/MigrationNode.ts
|
|
240
312
|
var MigrationNode = class {
|
|
241
313
|
constructor(name) {
|
|
@@ -367,40 +439,6 @@ var SqlMigrationBuilder = class {
|
|
|
367
439
|
}
|
|
368
440
|
};
|
|
369
441
|
|
|
370
|
-
// framework/MigrationManifest.ts
|
|
371
|
-
import fs from "fs";
|
|
372
|
-
import path from "path";
|
|
373
|
-
var MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
374
|
-
function isMigrationFile(fileName) {
|
|
375
|
-
return MIGRATION_FILE_REGEX.test(fileName);
|
|
376
|
-
}
|
|
377
|
-
function canonicalMigrationKey(value) {
|
|
378
|
-
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
379
|
-
}
|
|
380
|
-
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
381
|
-
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
382
|
-
const dialectFile = path.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
383
|
-
if (fs.existsSync(dialectFile)) return dialectFile;
|
|
384
|
-
const genericFile = path.join(directory, `${baseName}.${direction}.sql`);
|
|
385
|
-
if (fs.existsSync(genericFile)) return genericFile;
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
function loadMigrationManifest(directory, dialect) {
|
|
389
|
-
const manifest = /* @__PURE__ */ new Map();
|
|
390
|
-
if (!fs.existsSync(directory)) return manifest;
|
|
391
|
-
const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
392
|
-
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
393
|
-
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
394
|
-
uniqueKeys.forEach((key) => {
|
|
395
|
-
manifest.set(key, {
|
|
396
|
-
key,
|
|
397
|
-
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
398
|
-
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
return manifest;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
442
|
// framework/MigrationDirectoryReader.ts
|
|
405
443
|
var MigrationDirectoryReader = class {
|
|
406
444
|
constructor(directory, read_strategy, sqlrunner, dialect = "sql") {
|
|
@@ -1288,7 +1326,7 @@ var PatchCreator = class _PatchCreator {
|
|
|
1288
1326
|
if (!fs5.existsSync(this.patchFolder)) {
|
|
1289
1327
|
fs5.mkdirSync(this.patchFolder, { recursive: true });
|
|
1290
1328
|
}
|
|
1291
|
-
let stamp =
|
|
1329
|
+
let stamp = mintMigrationStamp();
|
|
1292
1330
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
1293
1331
|
const filePath = path4.join(this.patchFolder, `${stamp}_${normalized}.yaml`);
|
|
1294
1332
|
try {
|
|
@@ -1296,7 +1334,7 @@ var PatchCreator = class _PatchCreator {
|
|
|
1296
1334
|
return filePath;
|
|
1297
1335
|
} catch (error) {
|
|
1298
1336
|
if (error && error.code === "EEXIST") {
|
|
1299
|
-
stamp
|
|
1337
|
+
stamp = mintMigrationStamp(stamp + 1);
|
|
1300
1338
|
continue;
|
|
1301
1339
|
}
|
|
1302
1340
|
throw error;
|
|
@@ -1785,6 +1823,7 @@ var MySQLMigrationRunner = class {
|
|
|
1785
1823
|
*/
|
|
1786
1824
|
this.preflightPromise = null;
|
|
1787
1825
|
this.lastPatchResults = [];
|
|
1826
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
1788
1827
|
}
|
|
1789
1828
|
setup() {
|
|
1790
1829
|
return __async(this, null, function* () {
|
|
@@ -1890,7 +1929,17 @@ var MySQLMigrationRunner = class {
|
|
|
1890
1929
|
}
|
|
1891
1930
|
migrate(migrationNodes, forward) {
|
|
1892
1931
|
return __async(this, null, function* () {
|
|
1932
|
+
var _a;
|
|
1893
1933
|
yield this.setup();
|
|
1934
|
+
if (forward) {
|
|
1935
|
+
const legacyMigrationKeys = new Set((_a = this.config.legacy_migration_keys) != null ? _a : []);
|
|
1936
|
+
for (const node of migrationNodes) {
|
|
1937
|
+
const key = node.get_key();
|
|
1938
|
+
if (isHandStampedKey(key) && !legacyMigrationKeys.has(key) && !(yield node.status()).completed) {
|
|
1939
|
+
throw new MigrationStampError(key);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1894
1943
|
for (let node of migrationNodes) {
|
|
1895
1944
|
try {
|
|
1896
1945
|
if (forward) {
|
|
@@ -1986,6 +2035,7 @@ var FileMigrationConfigReader = class {
|
|
|
1986
2035
|
try {
|
|
1987
2036
|
const fileContent = fs6.readFileSync(this.configFile);
|
|
1988
2037
|
const config = JSON.parse(fileContent.toString());
|
|
2038
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
1989
2039
|
if (!config.migration_folder) {
|
|
1990
2040
|
throw ConfigurationError.missingRequiredProperty("migration_folder");
|
|
1991
2041
|
}
|
|
@@ -2028,7 +2078,7 @@ var MigrationCreator = class {
|
|
|
2028
2078
|
if (!fs6.existsSync(this.config.migration_folder)) {
|
|
2029
2079
|
fs6.mkdirSync(this.config.migration_folder, { recursive: true });
|
|
2030
2080
|
}
|
|
2031
|
-
const now_timestamp =
|
|
2081
|
+
const now_timestamp = mintMigrationStamp();
|
|
2032
2082
|
const filename_up = `${now_timestamp}_${name}.up.sql`;
|
|
2033
2083
|
const filename_down = `${now_timestamp}_${name}.down.sql`;
|
|
2034
2084
|
fs6.writeFileSync(`${this.config.migration_folder}/${filename_up}`, `
|