emberjs/data — pull request #672 by mmpestorich (2013-01-28 18:30:08+00:00)
Title: Resolve hasMany Relationships On-Demand

This allows one to implement a `findHasMany` hook on a custom adapter to resolve hasMany relationships on demand (IOW, not needing a list of related ids upfront).

Currently, the expectation is that there is a list of related ids for any unresolved hasMany relationships. Then, when the relationship is needed, that list of ids will be used to resolve the related records by passing them along to the store's `findMany`. The workflow is essentially:

DS.Model.get('aHasManyRelationship') -> DS.hasMany -> DS.Store.findMany -> DS.Adapter.findMany -> ... request to server ... -> DS.Adapter.didFindMany -> DS.Serializer.extractMany -> DS.Store.loadMany

There has been a lot of discussion online about trying to do this without the need to provide any related ids upfront. Given a record and name of a hasMany relationship, one would presume to have everything they would need to resolve that relationship server-side without needing any ids. The DS.Adapter could, for example, introspect the record to obtain its type and id. Then pass a record type, unique id and relationship name to the server. With that information a server could then grab the record for the given type and id and then ask for the realted records using the name of the hasMany relationship.

I notice in reading through some of ember-data's more recent revisions that the initial plumbing seems to be in place for this. The store implements a `loadHasMany` and contains code in `findMany` to fire off a call to the adapter's `findHasMany` hook if the expected array of related ids is undefined and call `didFindHasMany` in a success callback when the server returns the requested payload.

So, I teaked things in a couple places. This pull request assumes that if a hasMany relationship is undefined on an existing record, it should be resolved with a request to the server. The workflow becomes:

DS.Model.get('aHasManyRelationship') -> DS.hasMany -> DS.Store.findMany -> DS.Adapter.findHasMany -> ... request to server ... -> DS.Adapter.didFindHasMany -> DS.Serializer.extractMany -> DS.Store.loadHasMany

All one needs to do is implement a `Adapter.findHasMany(store, record, relationship)` and call `adapter.didFindHasMany(store, type, payload, record, key)` in a success callback.

I have been using this for that last few days without issue. I also believe that these changes are non-breaking to existing symantics but haven't had the time to extensively test that.