Closed rpander93 closed 7 years ago
Hi,
You should chaine promise to do that. But it a bit hard to give an example without the schema. Can you please provide the graphql schema? (no need resolver)
I'll make some docs for it btw if I can implement it :)
ok i understand, so you need to use a loader for contacts and a other for locations. Locations on contracts should have a independent resolver that returns also a promise. Locations promise will be complete after completing contacts... Let's say you have this: It's a way hard to explain but this could maybe helps...
Hi,
I did some puzzling and came up with the following. In my resolver I call the DataLoader for contracts. Is this how you would implement this?
One more question. How can I use the field selelection to conditionally include/exclude locations if the field is not queried? How can I pass any data to the DataLoader to indicate that it can skip the locations?
Hi, the best way to that is to add an independent resolver on Contract.locations field that returns the promise of locations (in argument it takes the ids of locations), so it will trigger resolution only if field is selected... no need to attach loaders between them.
Right, that idea also came to me this morning. works like a charm! This does present me with another question though. It necessitates me to fetch the ids of related locations even if the field is not resolved fully thereafter. See gist. So I think it would be useful to provide some context to calls to load() or loadMany() to optimize these situations.
See this issue to get how to retrieve the list of selected fields, you can execute fetcher only on demand...
Hi, thanks for the response. I know of the ResolveInfo object and access to the field selection. Let me try to explain it more carefully.
So, for example, I can see from the field selection that the locations field is not selected. In my ContractLoader
however, I still call findContractLocationsForContract
to fetch the related location ids. I dont want this when the locations field is not required. How do I pass this information from my ContractResolver
to ContractLoader
? I tried wrapping the call to findContractLocationsForContract
in a closure to delay execution but that didn't work out (since I first thought that is what you hinted at with the related issue).
I created a new gist here.
Btw, thanks for your help so far!!
The solution is to not fetch Locations id in your ContractLoader directly but chain it with your promise.
$includeLocations = array_key_exists('locations', $resolveInfo->getFieldSelection());
return $this->contractLoader->loadMany($builder->execute()->fetchAll(\PDO::FETCH_COLUMN))
->then(function ($contracts) use ($includeLocations) {
// here you fetch your locations ids if needed and add them to contracts;
return $contracts;
});
Ah, interesting! Thanks! That was the hint I needed.
Hi,
I'm a bit in the dark on how to implement this in my schema. I'm using the GraphQLBundle. In my schema, I have a query field named "contracts" which returns an array of contract entities. Each contract contains a one-to-many to an entity named "location". How would I implement this?
In my ContractsResolver class, I'd like to return a promise from my ContractLoader which returns an array of contracts. Then, the locations field on each contract should also return a promise resolving to an array of locations. How should I implement this in my resolvers and scheme?