Fix for customized remote schema input object types in query variables

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3417
GitOrigin-RevId: a4d3e59f5177f971a64a2b9e62fd1acaa8079a6b
This commit is contained in:
David Overton 2022-01-24 15:45:44 +11:00 committed by hasura-bot
parent dc113cc2b8
commit 8eca322b94
5 changed files with 39 additions and 17 deletions

View File

@ -30,6 +30,7 @@ count (
- server: fix parsing FLOAT64s in scientific notation and non-finite ones in BigQuery
- server: extend support for the `min`/`max` aggregates to all comparable types in BigQuery
- server: fix support for joins in aggregates nodes in BigQuery
- server: fix for passing input objects in query variables to remote schemas with type name customization (#7977)
- console: action/event trigger transforms are now called REST connectors
- console: fix list of tables (and schemas) being unsorted when creating a new trigger event (fix #6391)
- cli: migrate and seed subcommands has an option in prompt to choose and apply operation on all available databases

View File

@ -216,10 +216,12 @@ exact same value as the input (if perhaps represented differently); by discardin
just forwarding the input, we avoid expanding variables if no preset needs be inserted.
-}
-- | Helper, used to track whether an input value was altered during its parsing. At time of
-- writing, the only possible source of alteration is preset values. They might force evaluation of
-- variables, and encapsulation of sub-JSON expressions as new variables. Each parser indicates
-- whether such alteration took place within its part of the tree.
-- | Helper, used to track whether an input value was altered during its parsing.
-- There are two possible sources of alteration:
-- - preset values, and
-- - type name customizations.
-- They might force evaluation of variables, and encapsulation of sub-JSON expressions as new variables.
-- Each parser indicates whether such alteration took place within its part of the tree.
-- See Note [Variable expansion in remote schema input parsers] for more information.
newtype Altered = Altered {getAltered :: Bool}
deriving (Show)
@ -340,10 +342,12 @@ remoteFieldScalarParser customizeTypename (G.ScalarTypeDefinition description na
{ pType = schemaType,
pParser = \case
JSONValue v ->
-- Disallow short-circuit optimisation if the type name has been changed by remote schema customization
pure $ (Altered $ G.getBaseType gType /= name, G.VVariable $ RemoteJSONValue (mkRemoteGType gType) v)
GraphQLValue v -> case v of
G.VVariable var -> do
P.typeCheck False gType var
-- Disallow short-circuit optimisation if the type name has been changed by remote schema customization
pure $ (Altered $ G.getBaseType (vType var) /= name, G.VVariable $ QueryVariable var {vType = mkRemoteGType (vType var)})
_ -> pure (Altered False, QueryVariable <$> v)
}
@ -414,7 +418,10 @@ remoteInputObjectParser schemaDoc defn@(G.InputObjectTypeDefinition desc name _
Right <$> P.memoizeOn 'remoteInputObjectParser defn do
typename <- mkTypename name
argsParser <- argumentsParser valueDefns schemaDoc
-- Disallow short-circuit optimisation if the type name has been changed by remote schema customization
let altered = Altered $ typename /= name
argsParser <- fmap (first (<> altered)) <$> argumentsParser valueDefns schemaDoc
pure $ fmap G.VObject <$> P.object typename desc argsParser
-- | Variable expansion optimization.
@ -433,7 +440,7 @@ shortCircuitIfUnaltered parser =
result <- P.pParser parser value
pure $ case result of
-- The parser did yield a value, and it was unmodified by presets
-- we can short-citcuit by transforming the input value, therefore
-- we can short-circuit by transforming the input value, therefore
-- "unpeeling" variables and avoiding extraneous JSON variables.
Just (Altered False, _) -> Just $
(Altered False,) $ case castWith (P.inputParserInput @k) value of
@ -444,7 +451,7 @@ shortCircuitIfUnaltered parser =
-- all the leaves of said value each be their own distinct value.
JSONValue v -> G.VVariable $ RemoteJSONValue (toGraphQLType $ P.pType parser) v
-- Otherwise either the parser did not yield any value, or a value
-- that has been altered by presets and permissions; we forward it
-- that has been altered by presets, permissions or type name customization; we forward it
-- unoptimized.
_ -> result
}

View File

@ -354,6 +354,9 @@ character_search_results = {
2: Human("Tatooine", r2, Character(7, "Luke Skywalker")),
}
class CharacterInputArgs(graphene.InputObjectType):
episode = graphene.Int(required=True)
class CharacterIFaceQuery(graphene.ObjectType):
hero = graphene.Field(
Character,
@ -366,12 +369,21 @@ class CharacterIFaceQuery(graphene.ObjectType):
required=False
)
hero_by_args = graphene.Field(
Character,
required=False,
arguments=CharacterInputArgs(required=True)
)
def resolve_hero(_, info, episode):
return all_characters.get(episode)
def resolve_heroes(_, info):
return all_characters.values()
def resolve_hero_by_args(_, info, arguments):
return all_characters.get(arguments.episode)
schema = graphene.Schema(query=CharacterIFaceQuery, types=[Human, Droid])
character_interface_schema = graphene.Schema(query=CharacterIFaceQuery, types=[Human, Droid])

View File

@ -94,18 +94,19 @@
url: /v1/graphql
status: 200
query:
operationName: "HeroByArgs"
query: |
query Hero($ep: MyInt!) {
hero(episode: $ep) {
query HeroByArgs($args: FooCharacterInputArgs!) {
heroByArgs(arguments: $args) {
id
name
}
}
variables:
ep: 4
args: { episode: 4 }
response:
data:
hero:
heroByArgs:
id: "1"
name: R2-D2
@ -113,21 +114,22 @@
url: /v1/graphql
status: 200
query:
operationName: "HeroByArgs"
query: |
query Hero($ep: Int!) {
hero(episode: $ep) {
query HeroByArgs($args: CharacterInputArgs!) {
heroByArgs(arguments: $args) {
id
name
}
}
variables:
ep: 4
args: { episode: 4 }
response:
errors:
- extensions:
path: $.selectionSet.hero.args.episode
path: $.selectionSet.heroByArgs.args.arguments
code: validation-failed
message: variable "ep" is declared as Int!, but used where MyInt! is expected
message: variable "args" is declared as CharacterInputArgs!, but used where FooCharacterInputArgs! is expected
- description: query with __type introspection
url: /v1/graphql

View File

@ -785,7 +785,7 @@ class TestValidateRemoteSchemaTypePrefixQuery:
def transact(self, request, hge_ctx):
config = request.config
if not config.getoption('--skip-schema-setup'):
q = mk_add_remote_q('character-foo', 'http://localhost:5000/character-iface-graphql', customization=type_prefix_customization("Foo", {"Int": "MyInt"}))
q = mk_add_remote_q('character-foo', 'http://localhost:5000/character-iface-graphql', customization=type_prefix_customization("Foo"))
st_code, resp = hge_ctx.v1q(q)
assert st_code == 200, resp
yield