@warlock.js/cascade 4.9.0 → 4.9.1

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 CHANGED
@@ -4,6 +4,12 @@ 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.1
8
+
9
+ ### Fixed
10
+
11
+ - `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
12
+
7
13
  ## 4.9.0 - 2026-08-06
8
14
 
9
15
  ### 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
- * For nested objects, the merge is recursive. For arrays and primitives, the source
695
- * value replaces the target value. All values are cloned to prevent reference sharing.
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 (value && typeof value === "object" && !Array.isArray(value) && target[key] && typeof target[key] === "object" && !Array.isArray(target[key])) {
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
  }