@warlock.js/cascade 4.9.0 → 4.9.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/CHANGELOG.md +13 -0
- package/cjs/index.cjs +56 -17
- package/cjs/index.cjs.map +1 -1
- package/esm/database-dirty-tracker.d.mts +11 -2
- package/esm/database-dirty-tracker.d.mts.map +1 -1
- package/esm/database-dirty-tracker.mjs +12 -3
- package/esm/database-dirty-tracker.mjs.map +1 -1
- package/esm/migration/migration-order.mjs +35 -0
- package/esm/migration/migration-order.mjs.map +1 -0
- package/esm/migration/migration-runner.d.mts +12 -1
- package/esm/migration/migration-runner.d.mts.map +1 -1
- package/esm/migration/migration-runner.mjs +15 -15
- package/esm/migration/migration-runner.mjs.map +1 -1
- package/llms-full.txt +18 -0
- package/package.json +4 -4
- package/skills/track-changes/SKILL.md +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `@warlock.js/cascade` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 4.9.2
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `migrate:rollback` and `migrate:rollback --all` ran `down()` migrations in **apply order** instead of reverse. `getMigrationsToRollback` reversed the executed list and then re-sorted it ascending, which put it straight back into forward order and made the reverse dead code — so a rollback would drop a table before dropping the column added to it, failing with `relation "…" does not exist`. Any batch containing more than one migration was affected; single-migration batches hid it because one item has no order to get wrong
|
|
12
|
+
- migration ordering now lives in `migration-order.ts` with an explicit `sortMigrationsForRollback`. The descending sort is required, not cosmetic: the executed list is read back ordered by `batch, name`, so it is alphabetical rather than chronological and simply *not* re-sorting after the reverse would have produced reverse-alphabetical order — a different wrong answer
|
|
13
|
+
|
|
14
|
+
## 4.9.1
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- `save({ merge })` silently dropped a `Date` written over a column that already held a `Date` — the dirty tracker's merge treated anything `typeof "object"` as mergeable and recursed into the `Date`, which has no own enumerable properties, so nothing was copied and the old value survived. The column never went dirty and `save()` returned `{ success: true, modifiedCount: 0 }` without issuing an `UPDATE`. Only plain objects deep-merge now; `Date`, `Map`, `Set`, `RegExp` and every other class instance replace, matching what `model.data` already did. Writing into an empty column always worked, so only overwrites were affected
|
|
19
|
+
|
|
7
20
|
## 4.9.0 - 2026-08-06
|
|
8
21
|
|
|
9
22
|
### Fixed
|
package/cjs/index.cjs
CHANGED
|
@@ -691,8 +691,17 @@ var DatabaseDirtyTracker = class {
|
|
|
691
691
|
/**
|
|
692
692
|
* Recursively merges source object into target object, performing a deep merge.
|
|
693
693
|
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
694
|
+
* Only **plain** objects are merged recursively. Everything else — arrays,
|
|
695
|
+
* primitives, and class instances such as `Date` / `Map` / `Set` / `RegExp` —
|
|
696
|
+
* replaces the target value. All values are cloned to prevent reference sharing.
|
|
697
|
+
*
|
|
698
|
+
* The plain-object guard is load-bearing, not tidiness. A bare
|
|
699
|
+
* `typeof value === "object"` also matches a `Date`, and `Object.entries(date)`
|
|
700
|
+
* is `[]` — so merging a `Date` over a column that already held a `Date`
|
|
701
|
+
* recursed into it, copied nothing, and left the old value in the snapshot.
|
|
702
|
+
* The column then never went dirty and `save()` returned
|
|
703
|
+
* `{ success: true, modifiedCount: 0 }` without issuing an `UPDATE`. This is
|
|
704
|
+
* the same lesson `canBeFlatten` above already encodes.
|
|
696
705
|
*
|
|
697
706
|
* @param target - The object to merge into
|
|
698
707
|
* @param source - The object to merge from
|
|
@@ -700,7 +709,7 @@ var DatabaseDirtyTracker = class {
|
|
|
700
709
|
*/
|
|
701
710
|
mergeIntoRaw(target, source) {
|
|
702
711
|
for (const [key, value] of Object.entries(source)) {
|
|
703
|
-
if (
|
|
712
|
+
if ((0, _mongez_supportive_is.isPlainObject)(value) && (0, _mongez_supportive_is.isPlainObject)(target[key])) {
|
|
704
713
|
this.mergeIntoRaw(target[key], value);
|
|
705
714
|
continue;
|
|
706
715
|
}
|
|
@@ -21630,6 +21639,37 @@ function compareCreatedAt(a, b) {
|
|
|
21630
21639
|
if (dateB) return 1;
|
|
21631
21640
|
}
|
|
21632
21641
|
|
|
21642
|
+
//#endregion
|
|
21643
|
+
//#region ../cascade/src/migration/migration-order.ts
|
|
21644
|
+
/**
|
|
21645
|
+
* Comparator for applying migrations — oldest first.
|
|
21646
|
+
*
|
|
21647
|
+
* Priority:
|
|
21648
|
+
* 1. `createdAt` timestamp (older = earlier)
|
|
21649
|
+
* 2. Alphabetical by migration name (last resort)
|
|
21650
|
+
*/
|
|
21651
|
+
function sortMigrations(a, b) {
|
|
21652
|
+
const byCreatedAt = compareCreatedAt(a.createdAt, b.createdAt);
|
|
21653
|
+
if (byCreatedAt !== void 0) return byCreatedAt;
|
|
21654
|
+
return a.migrationName.localeCompare(b.migrationName);
|
|
21655
|
+
}
|
|
21656
|
+
/**
|
|
21657
|
+
* Comparator for rolling migrations back — newest first, the exact inverse of
|
|
21658
|
+
* {@link sortMigrations}.
|
|
21659
|
+
*
|
|
21660
|
+
* A rollback has to undo migrations in the reverse of the order they were
|
|
21661
|
+
* applied, or a `down()` will hit schema its predecessor already removed —
|
|
21662
|
+
* dropping a table before dropping the column that was added to it.
|
|
21663
|
+
*
|
|
21664
|
+
* This must be an explicit descending sort rather than a `.reverse()` of the
|
|
21665
|
+
* executed list: that list is read back ordered by `batch, name`, so it is
|
|
21666
|
+
* alphabetical rather than chronological, and reversing it merely produces
|
|
21667
|
+
* reverse-alphabetical order.
|
|
21668
|
+
*/
|
|
21669
|
+
function sortMigrationsForRollback(a, b) {
|
|
21670
|
+
return sortMigrations(b, a);
|
|
21671
|
+
}
|
|
21672
|
+
|
|
21633
21673
|
//#endregion
|
|
21634
21674
|
//#region ../cascade/src/migration/sql-grammar.ts
|
|
21635
21675
|
/**
|
|
@@ -21754,18 +21794,6 @@ var SQLGrammar = class {
|
|
|
21754
21794
|
//#endregion
|
|
21755
21795
|
//#region ../cascade/src/migration/migration-runner.ts
|
|
21756
21796
|
/**
|
|
21757
|
-
* Comparator for sorting migration classes.
|
|
21758
|
-
*
|
|
21759
|
-
* Priority:
|
|
21760
|
-
* 1. `createdAt` timestamp (older = earlier)
|
|
21761
|
-
* 2. Alphabetical by migration name (last resort)
|
|
21762
|
-
*/
|
|
21763
|
-
function sortMigrations(a, b) {
|
|
21764
|
-
const byCreatedAt = compareCreatedAt(a.createdAt, b.createdAt);
|
|
21765
|
-
if (byCreatedAt !== void 0) return byCreatedAt;
|
|
21766
|
-
return a.migrationName.localeCompare(b.migrationName);
|
|
21767
|
-
}
|
|
21768
|
-
/**
|
|
21769
21797
|
* Migration runner that executes migrations.
|
|
21770
21798
|
*
|
|
21771
21799
|
* This is a pure executor - it doesn't discover migrations.
|
|
@@ -22339,13 +22367,24 @@ var MigrationRunner = class {
|
|
|
22339
22367
|
return this.migrations.filter((m) => !executedNames.has(m.migrationName)).sort(sortMigrations);
|
|
22340
22368
|
}
|
|
22341
22369
|
/**
|
|
22342
|
-
* Get migrations to rollback.
|
|
22370
|
+
* Get migrations to rollback, newest-first.
|
|
22371
|
+
*
|
|
22372
|
+
* A rollback must undo migrations in the exact inverse of the order `up`
|
|
22373
|
+
* applied them, or a `down()` will hit schema its predecessor already
|
|
22374
|
+
* removed — dropping a table before dropping the column added to it, say.
|
|
22375
|
+
*
|
|
22376
|
+
* The sort has to be explicitly **descending**. Reversing the executed list
|
|
22377
|
+
* is not enough: `getExecutedMigrations` orders by `batch, name`, so the
|
|
22378
|
+
* input is alphabetical rather than chronological, and reversing it only
|
|
22379
|
+
* yields reverse-alphabetical order. (Sorting *ascending* here — which is
|
|
22380
|
+
* what this method used to do after a `.reverse()` — silently restored the
|
|
22381
|
+
* forward `up` order and made the reverse dead code.)
|
|
22343
22382
|
*/
|
|
22344
22383
|
async getMigrationsToRollback(batches) {
|
|
22345
22384
|
const executed = await this.getExecutedMigrations();
|
|
22346
22385
|
if (executed.length === 0) return [];
|
|
22347
22386
|
const batchNumbers = [...new Set(executed.map((r) => r.batch))].sort((a, b) => b - a).slice(0, batches);
|
|
22348
|
-
return executed.filter((r) => batchNumbers.includes(r.batch)).
|
|
22387
|
+
return executed.filter((r) => batchNumbers.includes(r.batch)).map((r) => this.migrations.find((m) => m.migrationName === r.name)).filter((m) => !!m).sort(sortMigrationsForRollback);
|
|
22349
22388
|
}
|
|
22350
22389
|
/**
|
|
22351
22390
|
* Get executed migration records.
|