1from functools import partial 2from typing import Any, Callable, Dict, List, Optional 3 4from tartiflette.coercers.inputs.directives_coercer import ( 5 input_directives_coercer, 6) 7from tartiflette.coercers.inputs.input_object_coercer import ( 8 input_object_coercer as input_input_object_coercer, 9) 10from tartiflette.coercers.literals.directives_coercer import ( 11 literal_directives_coercer, 12) 13from tartiflette.coercers.literals.input_object_coercer import ( 14 input_object_coercer as literal_input_object_coercer, 15) 16from tartiflette.types.helpers.get_directive_instances import ( 17 compute_directive_nodes, 18) 19from tartiflette.types.type import ( 20 GraphQLExtension, 21 GraphQLInputType, 22 GraphQLType, 23) 24from tartiflette.utils.directives import wraps_with_directives 25 26__all__ = ("GraphQLInputObjectType",) 27 28 29class GraphQLInputObjectType(GraphQLInputType, GraphQLType): 30 """ 31 Definition of a GraphQL input object. 32 """ 33 34 # Introspection attributes 35 kind = "INPUT_OBJECT" 36 37 def __init__( 38 self, 39 name: str, 40 fields: Dict[str, "GraphQLInputField"], 41 description: Optional[str] = None, 42 directives: Optional[List["DirectiveNode"]] = None, 43 ) -> None: 44 """ 45 :param name: name of the input object 46 :param fields: map of fields linked to the input object 47 :param description: description of the input object 48 :param directives: list of directives linked to the input object 49 :type name: str 50 :type fields: Dict[str, GraphQLInputField] 51 :type description: Optional[str] 52 :type directives: Optional[List[DirectiveNode]] 53 """ 54 self.name = name 55 self.input_fields = fields or {} 56 self.description = description 57 58 # Directives 59 self.directives = directives 60 self.introspection_directives: Optional[Callable] = None 61 62 # Coercers 63 self.input_coercer: Optional[Callable] = None 64 self.literal_coercer: Optional[Callable] = None 65 66 # Introspection attributes 67 self.inputFields: List[ # pylint: disable=invalid-name 68 "GraphQLInputField" 69 ] = [] 70 71 def __eq__(self, other: Any) -> bool: 72 """ 73 Returns True if `other` instance is identical to `self`. 74 :param other: object instance to compare to `self` 75 :type other: Any 76 :return: whether or not `other` is identical to `self` 77 :rtype: bool 78 """ 79 return self is other or ( 80 isinstance(other, GraphQLInputObjectType) 81 and self.name == other.name 82 and self.input_fields == other.input_fields 83 and self.description == other.description 84 and self.directives == other.directives 85 ) 86 87 def __repr__(self) -> str: 88 """ 89 Returns the representation of a GraphQLInputObjectType instance. 90 :return: the representation of a GraphQLInputObjectType instance 91 :rtype: str 92 """ 93 return ( 94 "GraphQLInputObjectType(name={!r}, fields={!r}, description={!r}, " 95 "directives={!r})".format( 96 self.name, self.input_fields, self.description, self.directives 97 ) 98 ) 99 100 def __str__(self) -> str: 101 """ 102 Returns a human-readable representation of the input object. 103 :return: a human-readable representation of the input object 104 :rtype: str 105 """ 106 return self.name 107 108 def bake(self, schema: "GraphQLSchema") -> None: 109 """ 110 Bakes the GraphQLInputObject and computes all the necessary stuff for execution. 111 :param schema: the GraphQLSchema schema instance linked to the engine 112 :type schema: GraphQLSchema 113 """ 114 # Directives 115 directives_definition = compute_directive_nodes( 116 schema, self.directives 117 ) 118 self.introspection_directives = wraps_with_directives( 119 directives_definition=directives_definition, 120 directive_hook="on_introspection", 121 ) 122 post_input_coercion_directives = wraps_with_directives( 123 directives_definition=directives_definition, 124 directive_hook="on_post_input_coercion", 125 ) 126 127 # Coercers 128 self.input_coercer = partial( 129 input_directives_coercer, 130 coercer=partial( 131 input_input_object_coercer, input_object_type=self 132 ), 133 directives=post_input_coercion_directives, 134 ) 135 self.literal_coercer = partial( 136 literal_directives_coercer, 137 coercer=partial( 138 literal_input_object_coercer, input_object_type=self 139 ), 140 directives=post_input_coercion_directives, 141 ) 142 143 async def bake_input_fields(self, schema: "GraphQLSchema") -> None: 144 """ 145 Bakes input object's input fields. 146 :param schema: the GraphQLSchema instance linked to the engine 147 :type schema: GraphQLSchema 148 """ 149 if self.input_fields: 150 for input_field in self.input_fields.values(): 151 input_field.bake(schema) 152 self.inputFields.append(input_field) 153 154 155class GraphQLInputObjectTypeExtension(GraphQLType, GraphQLExtension): 156 def __init__(self, name, input_fields, directives): 157 self.name = name 158 self.input_fields = input_fields or {} 159 self.directives = directives 160 161 def bake(self, schema): 162 extended = schema.find_type(self.name) 163 extended.input_fields.update(self.input_fields) 164 extended.directives.extend(self.directives) 165 166 def __eq__(self, other: Any) -> bool: 167 """ 168 Returns True if `other` instance is identical to `self`. 169 :param other: object instance to compare to `self` 170 :type other: Any 171 :return: whether or not `other` is identical to `self` 172 :rtype: bool 173 """ 174 return self is other or ( 175 isinstance(other, GraphQLInputObjectTypeExtension) 176 and other.directives == self.directives 177 and other.input_fields == self.input_fields 178 and other.name == self.name 179 ) 180 181 def __repr__(self) -> str: 182 """ 183 Returns the representation of a GraphQLType instance. 184 :return: the representation of a GraphQLType instance 185 :rtype: str 186 """ 187 return ( 188 f"GraphQLInputObjectTypeExtension(name={repr(self.name)}, " 189 f"directives={repr(self.directives)}, " 190 f"input_fields={repr(self.input_fields)})" 191 ) 192