Skip to content

Instantly share code, notes, and snippets.

@tomdale
Created May 23, 2013 20:49
Show Gist options
  • Save tomdale/5639320 to your computer and use it in GitHub Desktop.
Save tomdale/5639320 to your computer and use it in GitHub Desktop.
Ember Data Merge Handling

Ember Data Merge Handling

Internally, Ember Data models use a state machine to represent their lifecycle. One of the limitations of the current implementation is that records cannot be modified:

  • By the client application if the record is in-flight, or
  • By the server (via an out-of-band load()) if the record has pending changes on the client.

One solution to both of these limitations is to implement merging logic if there a conflict between client and server truth is detected. The default could be as simple as last-write-wins or as sophisticated as a three-way merge (à la Git's default), with the application developer given the option of overriding the default merge strategy.

App.Person = DS.Model.extend({
  firstName: DS.attr('string'),
  lastName: DS.attr('string'),

  addresses: DS.hasMany('App.Address'),

  merge: function(original, local, remote) {
    //... resolve conflict here
    return resolved;
  }
});

Outstanding Issues

Dirtiness

After a merge is resolved, how do you indicate whether the record is still dirty? For example, imagine that after a merge all of the changes made locally have been subsumed by the new truth that arrived from the adapter. At this point, the record should be considered clean.

Perhaps the best thing to do here is to simply diff the returned hash against the new remote hash, and mark the record as clean if they are the same.

Merge Hook Location

The most natural place for the merge hook to be implemented seems to be on the DS.Model class, but:

  • Is this actually a model concern? May people want adapter-specific merge semantics?
  • The above proposed API makes merge a reserved attribute and relationship name. Are we okay with this?

Arguments to Merge Hook

We obviously need to provide original, local and remote copies of the data. But should those arguments be raw data hashes, or DS.Model instances? I think it would break people's mental model if they weren't models. For example, imagine you have a computed property on your DS.Model and you want to use that to compare the two. The fact that this wouldn't work if we passed raw hashes would be confusing.

If we do pass DS.Model instances, we may need to do some work to make sure that people don't somehow hang on to references, because they will essentially be inert. This may take some infrastructure work.

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