The assignments field should contain all the assignments between the patient and the doctor, and these assignments are obtained by a dedicated resolver, i.e.:
field :assignments,
:user_assignments,
meta: [
trace: true
] do
resolve &AssignmentsResolver.resolve_assignments/3
end
My problem is that the resolve_assignments function can get the patientId through the parent attribute passed to the resolver, but how can I get the doctorId?
Is there a way to access to āgrandparentā data?
Ok, for anyone who has the same issue, I have found a āworkaroundā to achieve what I want.
In the particular case I described, i made the method which resolves the patient entity to include, in the map returned to the resolver, a parent_id field which contains the id of the doctor.
In this way, in the resolve_assignments method, in the first (āparentā) attribute I have both the patient_id (parent) and the doctor_id (the āgrandparentā).
Furthermore, if the parent_id does not have a corresponding graphql field in the patient entity, it wonāt be exposed in the graphql schema but it will be included in the first attribute passed to the resolve_assignments method.
@francesco.pessina Hey did you end up keeping that solution or was there something better.
From your experience, would you like to see A feature implemented into absinthe itself, such as A parent object in A resolver function (or a list of ancestors for example)?
@dylan-chong No, I didnāt find anything better. According to my needs, this was a good solution.
Yes, if this feature would be available in absinthe would be great
Interesting idea @maartenvanvliet! Iām not sure if that will work, as context is a global field and would be tricky to assemble with a simple and a tree structure like this
Itās conceivable to do this in Absinthe, although one issue is that it adds a performance penalty for every field traversal even if it is never used, since Absinthe has to do book keeping to track the object stack, and to persist it in the case of suspended resolution.
In general, this is a bit of a fragile feature. If you add a new field to the graph and return that object, the resolver which depends on the grandparent will have a new kind of grand parent potentially.
A better solution IMHO is to use Dataloader to explicitly try to load the value you are asking for. Then, in certain fields if you expect to always need a value, you could explicitly set the value in dataloader so that it is basically pre-cached.
Itās conceivable to do this in Absinthe, although one issue is that it adds a performance penalty for every field traversal even if it is never used, since Absinthe has to do book keeping to track the object stack, and to persist it in the case of suspended resolution.
A better solution IMHO is to use Dataloader to explicitly try to load the value you are asking for. Then, in certain fields if you expect to always need a value, you could explicitly set the value in dataloader so that it is basically pre-cached.
I wonder if this would be tricky in the generic case because you dont know what the root is. E.g. if c needs to access a, with a->b->c, but you could have d->a->b->c, or e->d->a->b->c
i have a temporary solution at the moment which is to store, on b, a reference to a.field by adding a virtual b.parent_field to itās Ecto Schema, then manually populating it in all of aās resolver functions
Iām not clear how this is an issue for my implementation, but it is definitely an issue for your proposed one. If you do:
value = parent.grand_parent
What is the type of grand_parent? You have no way of knowing. Instead of relying on what happens to be the GraphQL ancestor you should explicitly try to load some value for a given parent object.
hmm iāll have a play with dataloader at some point to get a better understanding of the library.
Iām not clear how this is an issue for my implementation, but it is definitely an issue for your proposed one. If you do:
if you are at c and you want to get the grandparent, you would look up the 2nd ancestor. this would always work as long as b can only be a child of a (in our case this is true)
Right, but to be part of Absinthe it has to work in the general case. In the general case, b can be the child of basically any object. If, in your case, b can only be a child of a via a specific field then the āpass the GP down as a value to the parentā pattern works great and is definitely the route I would recommend.