fix: preserve absent vs explicit-null distinction in argument coercion#57
Open
toiroakr wants to merge 1 commit into
Open
fix: preserve absent vs explicit-null distinction in argument coercion#57toiroakr wants to merge 1 commit into
toiroakr wants to merge 1 commit into
Conversation
Variables declared in an operation but not supplied by the caller used to arrive at resolvers as explicit nil, making it impossible to tell "field omitted" from "field explicitly null". Restore the three-state semantics required by the spec (CoerceArgumentValues / CoerceVariableValues) while keeping the existing behavior of preserving explicit nulls. - getVariableValues: only insert a coerced value when the caller supplied the variable or when the definition declares a default value. - getArgumentValues: treat an argument that resolves to an unprovided variable reference as absent, but still surface explicit nulls. - valueFromAST (InputObject): fields whose values come from unprovided variables stay absent in the resulting map. - Add argument_coercion_test.go covering the three states for scalars, input objects, and input-object literals.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
nil, making it impossible to distinguish "field omitted" from "field explicitly null". This breaks downstream patterns that rely onarg != nil/arg !== undefinedto mean "the caller actually sent this field".Background
The current behavior was introduced by #17, which added handling so that explicit
nullvariables would survive intop.Args(previously they were dropped, matching upstream graphql-go but conflicting with this fork's needs). That change achieved its goal for explicit nulls but, as a side effect, also marked omitted variables as present-with-nil — collapsing the spec's three states (absent / null / value) into two on the resolver side.This PR keeps the intent of #17 (explicit nulls remain visible) and only fixes the omitted-variable case.
Changes
getVariableValues: insert a coerced value into the result map only when the caller actually supplied the variable, or when the definition declares a default value. Omitted variables stay omitted instead of being recorded asnil.getArgumentValues: treat an argument that resolves to a reference to an unprovided variable as absent. Explicit nulls still surface asnil.valueFromAST(*InputObjectcase): nested fields whose values come from unprovided variables stay absent in the resulting map, instead of being included asnil.argument_coercion_test.gocovering the three states (absent / explicit null / value) for both scalar arguments and input-object fields, plus input-object literals with omitted fields.Behavior comparison
Each row is for the operation
query Q($x: Int) { f(x: $x) }(or the input-object equivalent,query Q($y: Int) { f(input: {x: $y}) }). "Resolver sees" describes the state ofp.Args(or the nested input map) on the resolver side.{}nullto mean "clear this field"{"x": null}{"x": 1}111{}{"y": null}The two highlighted rows are the whole point of this fork's divergence from upstream: clients use explicit
nullto express "clear this field" in partial-update operations, and that signal must reach resolvers. Upstream collapses it with omission; the fork has always preserved it (since #17) and continues to do so after this PR. What changes is only that omission now stays omission instead of being relabeled asnull.Notes
./...continue to pass.nullliteral in query documents, so the new tests exercise that case via variables only.Related