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

findHasMany should be called instead of findMany if a has-many relationship is undefined #2162

Open
tomdale opened this Issue Aug 5, 2014 · 12 comments

Comments

Projects
None yet
9 participants
@tomdale
Copy link
Member

tomdale commented Aug 5, 2014

Given a payload for a particular record, Ember Data currently resolves has-many relationships through the adapter using the following heuristic:

  1. If the relationship is defined in the top-level links object, the store will call the adapter's findHasMany hook.
  2. If the relationship is not defined in the top-level links object, the store will call the adapter's findMany hook, passing it the array of IDs provided in the payload after removing the IDs of any records that are already loaded.

This behavior works well when the relationship is provided as a URL in the links object, or when the relationship is provided as an array of IDs.

However, there is a third, very common case, where the relationship should be populated by fetching a URL, but the URL is derived from information contained in the record, rather than being provided in the payload, hypermedia-style.

For example, imagine the following model:

// models/post.js
var attr = DS.attr,
    hasMany = DS.hasMany;
export default DS.Model.extend({
  title: attr(),
  body: attr(),
  comments: hasMany()
});

In this example, materializing the comments relationship by calling post.get('comments') should result in the client retrieving /post/123/comments. Thus, the server sends the following payload for the post with ID 123:

{
  "id": 123,
  "title": "Rails is Omakase",
  "body": "Trololol"
  // Note lack of comments relationship
}

This case is extraordinarily common (I ran into it when writing an app that uses the Portland public transit API, and Django's REST framework uses this approach), but currently getting this to work requires synthesizing a fake links entry in the serializer's normalizePayload hook and filling it with garbage data, which is a huge PITA.

@wycats and I think that it may be appropriate to add a third hook, which generates a URL for the relationship, and if that returns a value, the store will call findHasMany with the result. The current links behavior can be explained and implemented in terms of this new hook.

@tomdale tomdale added the improvement label Aug 5, 2014

@recipher

This comment has been minimized.

Copy link

recipher commented Aug 5, 2014

+1—
Johnny H
07971 880871

On Tue, Aug 5, 2014 at 10:04 PM, Tom Dale notifications@github.com
wrote:

Given a payload for a particular record, Ember Data currently resolves has-many relationships through the adapter using the following heuristic:

  1. If the relationship is defined in the top-level links object, the store will call the adapter's findHasMany hook.
  2. If the relationship is not defined in the top-level links object, the store will call the adapter's findMany hook, passing it the array of IDs provided in the payload after removing the IDs of any records that are already loaded.
    This behavior works well when the relationship is provided as a URL in the links object, or when the relationship is provided as an array of IDs.
    However, there is a third, very common case, where the relationship should be populated by fetching a URL, but the URL is derived from information contained in the record, rather than being provided in the payload, hypermedia-style.
    For example, imagine the following model:
// models/post.js
var attr = DS.attr,
    hasMany = DS.hasMany;
export default DS.Model.extend({
  title: attr(),
  body: attr(),
  comments: hasMany()
});

In this example, materializing the comments relationship by calling post.get('comments') should result in the client retrieving /post/123/comments. Thus, the server sends the following payload for the post with ID 123:

{
  "title": "Rails is Omakase",
  "body": "Trololol"
  // Note lack of comments relationship
}

This case is extraordinarily common (I ran into it when writing an app that uses the Portland public transit API, and Django's REST framework uses this approach), but currently getting this to work requires synthesizing a fake links entry in the serializer's normalizePayload hook and filling it with garbage data, which is a huge PITA.

@wycats and I think that it may be appropriate to add a third hook, which generates a URL for the relationship, and if that returns a value, the store will call findHasMany with the result. The current links behavior can be explained and implemented in terms of this new hook.

Reply to this email directly or view it on GitHub:
#2162

@tomdale

This comment has been minimized.

Copy link
Member

tomdale commented Aug 5, 2014

It may also be possible to eliminate the findMany hook, by calling the URL-generator hook with the IDs and having it create the appropriate URL that is passed to findHasMany.

@stefanpenner

This comment has been minimized.

Copy link
Member

stefanpenner commented Aug 5, 2014

@tomdale those ID's get rather length especially if using guids. Which means we either need to treat them as POST's over GETS or have ember-data chunk the requests (lots of backends/api's may not support this easily). The last option seems to prefer findMany still existing, and having it call the url building multiple times for multiple discrete URL's

@tomdale

This comment has been minimized.

Copy link
Member

tomdale commented Aug 5, 2014

@stefanpenner The recent "bucketing" feature by @igorT resolves this. Perhaps the URL-generator hook could support returning an array of URLs, which could be batched.

@stefanpenner

This comment has been minimized.

Copy link
Member

stefanpenner commented Aug 5, 2014

@tomdale interesting, ya that makes sense.

@igorT

This comment has been minimized.

Copy link
Member

igorT commented Aug 5, 2014

In fact #2159

@thomasdashney

This comment has been minimized.

Copy link

thomasdashney commented Aug 13, 2014

+1

@igorT

This comment has been minimized.

Copy link
Member

igorT commented Oct 28, 2014

I am happy to help if someone has time to create a PR.

@psteininger

This comment has been minimized.

Copy link

psteininger commented Mar 17, 2016

@tomdale @igorT has this been resolved in 2.0+ ? I have a use case where the nested route produces aggregate level data, from a large dataset.
Let's say I have widgets, and each widget has thousands of scores, but they are only exposed as aggregates, w/o id property. A URL looks like so:

/widgets/:id/scores_by_month 
@amiel

This comment has been minimized.

Copy link
Contributor

amiel commented Apr 19, 2017

Having this would be super helpful for https://github.com/amiel/ember-data-url-templates, particularly to support the case @psteininger is talking about.

Is anyone else working on this? and is it still desired by others?

I'd be happy to give it a shot...

@amiel

This comment has been minimized.

Copy link
Contributor

amiel commented Oct 31, 2017

I have submitted an RFC for this: emberjs/rfcs#266

@runspired

This comment has been minimized.

Copy link
Contributor

runspired commented Apr 6, 2018

With the refactor in #5410 it would be fairly trivial to call findHasMany instead of findMany in this particular case.

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