Skip to content

[Sync] Track changed columns on locally created records - #1986

Open
joker-777 wants to merge 1 commit into
Nozbe:masterfrom
kenhub:fix/sync-changed-on-created
Open

joker-777 wants to merge 1 commit into
Nozbe:masterfrom
kenhub:fix/sync-changed-on-created

Conversation

@joker-777

@joker-777 joker-777 commented Nov 2, 2026 •

Copy link
Copy Markdown

Records columns set while creating a record in its _changed field, so a conflict with a pulled record of the same id is resolved per column. Related issue: #1533.

Changes

  • Columns set in a collection.create() builder are now recorded in _changed for records with _status: 'created'. Before, _changed stayed empty until the first update
  • When a pull contains a record with the same id as a locally created, not yet pushed one, the conflict is now resolved per column: locally set columns win and the rest comes from the server. Before, the remote version won entirely
  • A custom conflictResolver gets this per-column result as resolved, and local._changed lists the columns set locally
  • Pushed created records now carry a non-empty _changed. The backend docs already say servers must ignore it. markLocalChangesAsSynced still resets it to ''
  • Not tracked: records created with a _status other than created (for example synced records built in a create builder), and _prepareCreateFromDirtyRaw, which sync uses

Tests

  • New test in synchronize.test.js: creates a task offline, pulls the same id with different values, and checks the push payload and the final synced record. It fails on master, where _changed is ""
  • Model tests updated for the new _changed values, plus tests for values equal to the default and for synced creates

Verification

🤖 Generated with Claude Code

* Track changed columns on locally created records

Records created locally had an empty _changed field, so when a pull brought
a record with the same id, per-column conflict resolution had nothing to
keep and the remote version won entirely. Columns set in the create() builder
are now recorded in _changed (for records with _status 'created'), so locally
set columns win and the rest comes from the server.

Servers ignore _changed. markLocalChangesAsSynced still resets it when the
record is marked as synced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Decide whether to track create columns after the builder runs

A create builder that assigned columns and then set _raw._status to 'synced'
left those columns in _changed, so later pulls would keep the stale local
values. Columns set in the builder are now collected while it runs and only
added to _changed afterwards, if the record's final status is 'created'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@StasDoskalenko

Copy link
Copy Markdown

Hi @joker-777, thank you for this!

I maintain NitromelonDB, a maintained fork of WatermelonDB (New Architecture, Nitro Modules). _changed is still left empty on create there too, so the same conflict happens.

Our fork was rewritten in TypeScript (strict mode) to reduce the chance of bugs like this one slipping through, so I think the community would really benefit if you opened your PRs against it too. The relevant code is in src/Model/index.ts.

If you don't have the time or would rather not, no worries at all, I'm happy to port it myself. Just let me know. Thanks a lot!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants