Null trimming not applied when child field uses an async resolver
I think we have an issue with null trimming specifically with async resolvers, but I'm not sure how to solve it.
If I'm understanding the issue, "null trimming" happens on the resolution of a field by looking at its children to see if any non-null violations have occurred. For a field with children using async resolvers, those children might actually be Resolution structs in state: :suspended, not Result.* structs, when the parent field is deciding whether any trimming needs to occur.
If one of those child fields finally resolved null in a second resolution pass, the error might be added, but I think the nullable parent field won't be revisited, so no trimming will occur?
I'm not super familiar with this chunk of the codebase, so I'm not sure what the right solution is, assuming my hypothesis is even correct.
Maybe we could add another phase to be responsible for null trimming? Not sure if that should happen before or after Absinthe.Phase.Document.Result.
Or maybe the fix is actually quite simple but not obvious to my novice eye.... 🤞
I'll open a PR with some failing tests I added as an example.
Environment
- Elixir version (elixir -v):
Elixir 1.12.1 (compiled with Erlang/OTP 24) - Absinthe version (mix deps | grep absinthe):
master - Client Framework and version (Relay, Apollo, etc): N/A
Expected behavior
A query like this:
{
nullable { nullable { nonNull(makeNull: true) { __typename }}}
}
Should return data that looks something like this:
%{
data: %{"nullable" => %{"nullable" => nil}},
errors: [
%{
locations: [%{column: 25, line: 2}],
message: "Cannot return null for non-nullable field",
path: ["nullable", "nullable", "nonNull"]
}
]
}
Actual behavior
Instead we produce this:
%{
data: %{"nullable" => %{"nullable" => %{"nonNull" => nil}}},
errors: [
%{
locations: [%{column: 25, line: 2}],
message: "Cannot return null for non-nullable field",
path: ["nullable", "nullable", "nonNull"]
}
]
}
Relevant Schema/Middleware Code
Mainly Absinthe.Phase.Document.Execution.Resolution I believe.
Examples in #1095
Possibly the root cause of #912 too?
Ah, that's a doozy! Let me take a look.
I posted a reproduction of this issue in what seems to be a duplicate of this issue: https://github.com/absinthe-graphql/absinthe/issues/1071#issuecomment-1516694735