mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-20 06:58:39 +03:00
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:
parent
dc113cc2b8
commit
8eca322b94
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user