fix: preserve nested arrays in cloneDataFromOriginalDoc#17492
Open
Nahid-NHB wants to merge 1 commit into
Open
Conversation
cloneDataFromOriginalDoc shallow-clones each row of an array value
with `{...row}`. When a row is itself an array (e.g. json field data
shaped as an array of coordinate tuples), the spread turns it into an
index-keyed object (`{"0": 1, "1": 2}`), silently corrupting the data
whenever the field is omitted from a partial update and its fallback
value is cloned from the original document.
Check `Array.isArray(row)` before falling back to the object-spread
branch so array rows are cloned as arrays.
Fixes payloadcms#17475
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
cloneDataFromOriginalDocmangles ajsonfield's array-of-arrays value (e.g.[[1, 2], [3, 4]]) into an array of index-keyed objects ([{"0": 1, "1": 2}, {"0": 3, "1": 4}]) whenever the field is omitted from a partialupdate/PATCHand its value is carried forward from the original document.Why?
cloneDataFromOriginalDocshallow-clones each row of an array value with{...row}.typeof row === 'object'is alsotruefor arrays, so when a row is itself an array (nested arrays, as opposed to the usual array/blocks-field row objects), the object-spread branch runs instead and turns it into an index-keyed object. On a publish operation this trips fieldvalidateand is caught, but draft saves skip validation, so the corrupted shape silently persists to the database. Downstream consumers that iterate the tuples then crash withTypeError: object is not iterable.How?
Check
Array.isArray(row)before the generic object check, and clone array rows with[...row]instead of{...row}, preserving their shape. This keeps the same one-level-deep shallow-clone semantics the function already uses for object rows — only the branching changes.Testing performed
cloneDataFromOriginalDoc.spec.ts) covering nested-array cloning, non-mutation of the original, and the existing object/primitive clone behavior. Verified it fails without the fix and passes with it.test/fields/int.spec.tsreproducing the exact reported flow: create a doc with ajsonfield holding an array-of-arrays, then partially update the doc without touching that field, and assert the stored value is unchanged. Verified it fails without the fix (reproducing the reported corruption exactly) and passes with it.test/fieldsandtest/fields-relationshipintegration suites (sqlite) — all passing, no regressions.tsc --noEmitonpackages/payload— no errors.prettier --checkandeslinton all changed files — clean.Fixes #17475