Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object::set_property_value does not sync embedded objects correctly with CreatePolicy::UpdateAll #4740

Closed
sync-by-unito bot opened this issue Jun 4, 2021 · 1 comment · Fixed by #4741
Assignees

Comments

@sync-by-unito
Copy link

sync-by-unito bot commented Jun 4, 2021

If an embedded object with an array gets updated via an SDK, like this:

realmQuery.update({
  ...,
  update: {
    foo: {
      bar: {
        bizz: [ 1, 2 ]
      }
    }
  }
});

The object at bar will be replaced with a new embedded object with a new array, and the sync instructions will reflect that. However, there's nothing in the sync instructions to clear the object that was there previously. This leads to uploading corrupted changesets to the sync server with prior_sizes that look as though the embedded object was set to null and then re-created, even though there are no instructions to do that. If you select a CreatePolicy of CreatePolicy::UpdateModified, then the object bar will be diffed and the array values will get updated instead of inserted.

@sync-by-unito
Copy link
Author

sync-by-unito bot commented Jul 8, 2021

➤ Tyler Kaye commented:

Wrote up a description of the problem while looking at a HELP ticket so adding it here for visibility / to link to if another HELP opens up that can be fixed with this change.

Here is the description:

Translator initializes object (or client, doesn't matter)

{ subObj: { arrField: [1, 2] } }
CreateObject{ "table": table1, id: "object1" }
Update{ "table": table1, id: "object1", field: "subObj: ObjectValue{} }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.0: 1, priorSize: 0 }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.1: 2, priorSize: 1 }

Then, if a client comes along and reset the embedded object, it would do so without setting the embedded object to null, so it would emit these instructions to create the object :

{ subObj: { arrField: [3, 4] } }
Update{ "table": table1, id: "object1", field: "subObj: ObjectValue{} }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.0: 3, priorSize: 0 }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.1: 4, priorSize: 1 }

So these instructions are theoretically invalid because the state of the object currently is really that the priorSize should be set to 2 and 3 for these since the instructions being emitted dont actually reset the object since the Update to ObjectValue{} does not clear the object (it only creates one if it does not exist).

Therefore, in server history we now have committed an invalid sequence of instructions that any bootstrapping client would crash on receiving:

CreateObject{ "table": table1, id: "object1" }
Update{ "table": table1, id: "object1", field: "subObj: ObjectValue{} }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.0: 1, priorSize: 0 }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.1: 2, priorSize: 1 }

Update{ "table": table1, id: "object1", field: "subObj: ObjectValue{} }

// This will cause an error, because in downloading these instructions, the client will currently have an array of size 2
// but the prior_size field here says that it should be 0
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.0: 3, priorSize: 0 }
ArrayInsert{ "table": table1, id: "object1", field: "subObj.arrField.1: 4, priorSize: 1 }

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant