11from inspect import isawaitable
2+ from typing import Any , Callable , Dict
23
4+ from graphql .error import GraphQLError
5+ from graphql .pyutils import AwaitableOrValue , inspect
36from graphql .type import (
47 GraphQLArgument ,
8+ GraphQLField ,
9+ GraphQLFieldMap ,
510 GraphQLInputField ,
11+ GraphQLInputFieldMap ,
612 GraphQLInputObjectType ,
713 GraphQLNonNull ,
814 GraphQLObjectType ,
15+ GraphQLResolveInfo ,
916 GraphQLString ,
10- GraphQLField ,
17+ Thunk
1118)
12- from graphql .error import GraphQLError
13- from graphql .pyutils import inspect
1419
15- from ..utils import resolve_maybe_thunk
20+ MutationFn = Callable [[Dict [str , Any ], GraphQLResolveInfo ], AwaitableOrValue [Any ]]
21+
22+
23+ def resolve_maybe_thunk (thing_or_thunk : Thunk ) -> Any :
24+ return thing_or_thunk () if callable (thing_or_thunk ) else thing_or_thunk
1625
1726
1827def mutation_with_client_mutation_id (
19- name , input_fields , output_fields , mutate_and_get_payload ):
20- augmented_input_fields = dict (
21- resolve_maybe_thunk (input_fields ),
22- clientMutationId = GraphQLInputField (
23- GraphQLNonNull (GraphQLString )))
24- augmented_output_fields = dict (
25- resolve_maybe_thunk (output_fields ),
26- clientMutationId = GraphQLField (
27- GraphQLNonNull (GraphQLString )))
28- input_type = GraphQLInputObjectType (
29- name + 'Input' ,
30- fields = augmented_input_fields )
28+ name : str ,
29+ input_fields : Thunk [GraphQLInputFieldMap ],
30+ output_fields : Thunk [GraphQLFieldMap ],
31+ mutate_and_get_payload : MutationFn ,
32+ description : str = None ,
33+ deprecation_reason : str = None ) -> GraphQLField :
34+ """
35+ Returns a GraphQLFieldConfig for the specified mutation.
36+
37+ The input_fields and output_fields should not include `clientMutationId`,
38+ as this will be provided automatically.
39+
40+ An input object will be created containing the input fields, and an
41+ object will be created containing the output fields.
42+
43+ mutate_and_get_payload will receive a dict with a key for each input field,
44+ and it should return an object (or a dict) with an attribute (or a key)
45+ for each output field. It may return synchronously or asynchronously.
46+ """
47+ def augmented_input_fields () -> GraphQLInputFieldMap :
48+ return dict (
49+ resolve_maybe_thunk (input_fields ),
50+ clientMutationId = GraphQLInputField (
51+ GraphQLNonNull (GraphQLString )))
52+
53+ def augmented_output_fields () -> GraphQLFieldMap :
54+ return dict (
55+ resolve_maybe_thunk (output_fields ),
56+ clientMutationId = GraphQLField (
57+ GraphQLNonNull (GraphQLString )))
58+
3159 output_type = GraphQLObjectType (
3260 name + 'Payload' ,
3361 fields = augmented_output_fields )
3462
35- async def resolve (_root , info , ** args ):
36- input_ = args .get ('input' ) or {}
37- payload = mutate_and_get_payload (info , ** input_ )
63+ input_type = GraphQLInputObjectType (
64+ name + 'Input' ,
65+ fields = augmented_input_fields )
66+
67+ # noinspection PyShadowingBuiltins
68+ async def resolve (_root , info , input ):
69+ payload = mutate_and_get_payload (input , info )
3870 if isawaitable (payload ):
3971 payload = await payload
4072 try :
41- payload .clientMutationId = input_ ['clientMutationId' ]
73+ payload .clientMutationId = input ['clientMutationId' ]
4274 except KeyError :
4375 raise GraphQLError (
4476 'Cannot set clientMutationId'
@@ -47,5 +79,7 @@ async def resolve(_root, info, **args):
4779
4880 return GraphQLField (
4981 output_type ,
82+ description = description ,
83+ deprecation_reason = deprecation_reason ,
5084 args = {'input' : GraphQLArgument (GraphQLNonNull (input_type ))},
5185 resolve = resolve )
0 commit comments