def test_merged_input_object_type_has_name_of_original_type(self): self._assert_merge( [ GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLInt), }), GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLInt), }), ], has_properties(name="Object"), )
def test_field_type_is_common_supertype_of_field_types(self): self._assert_merge( [ GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLNonNull(GraphQLInt)), }), GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLInt), }), ], is_input_object_type(fields=has_entries({ "id": is_input_field(type=is_int), })), )
def test_types_within_list_types_are_merged(self): self._assert_merge( [ GraphQLList(GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLInt), })), GraphQLList(GraphQLInputObjectType("Object", fields={ "name": GraphQLInputObjectField(type=GraphQLString), })), ], is_list_type(is_input_object_type(fields=has_entries({ "id": is_input_field(type=is_int), "name": is_input_field(type=is_string), }))), )
def test_input_object_types_are_merged_to_input_object_type_with_union_of_fields(self): self._assert_merge( [ GraphQLInputObjectType("Object", fields={ "id": GraphQLInputObjectField(type=GraphQLInt), }), GraphQLInputObjectType("Object", fields={ "name": GraphQLInputObjectField(type=GraphQLString), }), ], is_input_object_type(fields=has_entries({ "id": is_input_field(type=is_int), "name": is_input_field(type=is_string), })), )
def from_input_object(self, object_type: type) -> GraphQLInputObjectType: type_definition = object_type._type_definition # type: ignore # Don't reevaluate known types if type_definition.name in self.type_map: graphql_object_type = self.type_map[ type_definition.name].implementation assert isinstance(graphql_object_type, GraphQLInputObjectType) # For mypy return graphql_object_type def get_graphql_fields() -> Dict[str, GraphQLInputField]: graphql_fields = {} for field in type_definition.fields: field_name = field.get_graphql_name( self.config.auto_camel_case) graphql_fields[field_name] = self.from_input_field(field) return graphql_fields graphql_object_type = GraphQLInputObjectType( name=type_definition.name, fields=get_graphql_fields, description=type_definition.description, ) self.type_map[type_definition.name] = ConcreteType( definition=type_definition, implementation=graphql_object_type) return graphql_object_type
def _make_generic_input_type(self, base, ops): name = f'Filter{base.name}' self._gql_inobjtypes[name] = GraphQLInputObjectType( name=name, fields={op: GraphQLInputObjectField(base) for op in ops}, )
def _make_generic_nested_insert_type(self, edb_base): typename = edb_base.get_name(self.edb_schema) name = f'NestedInsert{typename}' nitype = GraphQLInputObjectType( name=self.get_input_name('NestedInsert', self.get_gql_name(typename)), fields={ 'data': GraphQLInputObjectField( self._gql_inobjtypes[f'Insert{typename}']), 'filter': GraphQLInputObjectField(self._gql_inobjtypes[typename]), 'order': GraphQLInputObjectField(self._gql_ordertypes[typename]), 'first': GraphQLInputObjectField(GraphQLInt), 'last': GraphQLInputObjectField(GraphQLInt), # before and after are supposed to be opaque values # serialized to string 'before': GraphQLInputObjectField(GraphQLString), 'after': GraphQLInputObjectField(GraphQLString), }, ) self._gql_inobjtypes[name] = nitype return nitype
def _make_generic_nested_insert_type(self, edb_base): typename = edb_base.get_name(self.edb_schema) name = f'NestedInsert{typename}' fields = { 'filter': GraphQLInputObjectField(self._gql_inobjtypes[typename]), 'order': GraphQLInputObjectField(self._gql_ordertypes[typename]), 'first': GraphQLInputObjectField(GraphQLInt), 'last': GraphQLInputObjectField(GraphQLInt), # before and after are supposed to be opaque values # serialized to string 'before': GraphQLInputObjectField(GraphQLString), 'after': GraphQLInputObjectField(GraphQLString), } # The data can only be a specific non-interface type, if no # such type exists, skip it as we cannot accept unambiguous # data input. It's still possible to just select some existing # data. data_t = self._gql_inobjtypes.get(f'Insert{typename}') if data_t: fields['data'] = GraphQLInputObjectField(data_t) nitype = GraphQLInputObjectType( name=self.get_input_name('NestedInsert', self.get_gql_name(typename)), fields=fields, ) self._gql_inobjtypes[name] = nitype return nitype
def map_input(self, cls: Type) -> GraphQLInputObjectType: return GraphQLInputObjectType( name=cls.__name__, description=cls.__doc__, fields=lambda: self.map_input_fields(cls), container_type=lambda data: cls(**data) # type: ignore )
def define_generic_order_types(self): self._gql_ordertypes['directionEnum'] = GraphQLEnumType( 'directionEnum', values=OrderedDict( ASC=GraphQLEnumValue(), DESC=GraphQLEnumValue() ) ) self._gql_ordertypes['nullsOrderingEnum'] = GraphQLEnumType( 'nullsOrderingEnum', values=OrderedDict( SMALLEST=GraphQLEnumValue(), BIGGEST=GraphQLEnumValue(), ) ) self._gql_ordertypes['Ordering'] = GraphQLInputObjectType( 'Ordering', fields=OrderedDict( dir=GraphQLInputObjectField( GraphQLNonNull(self._gql_ordertypes['directionEnum']), ), nulls=GraphQLInputObjectField( self._gql_ordertypes['nullsOrderingEnum'], default_value='SMALLEST', ), ) )
def get_type_comparison_fields(graphql_type: Union[GraphQLScalarType, GraphQLList], inputs: Inputs, type_name: str) -> GraphQLInputObjectType: if type_name in inputs: return inputs[type_name] fields = { "_eq": GraphQLInputField(graphql_type), "_neq": GraphQLInputField(graphql_type), "_in": GraphQLInputField(GraphQLList(GraphQLNonNull(graphql_type))), "_nin": GraphQLInputField(GraphQLList(GraphQLNonNull(graphql_type))), "_lt": GraphQLInputField(graphql_type), "_gt": GraphQLInputField(graphql_type), "_gte": GraphQLInputField(graphql_type), "_lte": GraphQLInputField(graphql_type), "_is_null": GraphQLInputField(GraphQLBoolean), } fields_string = { "_like": GraphQLInputField(GraphQLString), "_nlike": GraphQLInputField(GraphQLString), } if graphql_type == GraphQLString: fields.update(fields_string) inputs[type_name] = GraphQLInputObjectType(type_name, fields) return inputs[type_name]
def __new__(meta, name, bases, attrs): cls = super(InputObjectTypeMeta, meta).__new__(meta, name, bases, attrs) if attrs.get("__abstract__"): return cls field_definitions, fields = _declare_fields(cls) fields = lazy(fields) cls.__fields__ = staticmethod(lambda: list(field_definitions)) cls.__graphql__ = GraphQLInputObjectType( name=cls.__name__, fields=lambda: collections.OrderedDict( (key, field.to_graphql_input_field()) for key, field in six.iteritems(fields())), ) def __init__(self, **kwargs): self.raw_ = kwargs.pop("raw_", undefined) for field in fields().values(): default = getattr(field, "default", undefined) setattr(self, field.attr_name, kwargs.pop(field.attr_name, default)) for key in kwargs: raise TypeError( "__init__() got an unexpected keyword argument '{}'". format(key)) cls.__init__ = __init__ def __repr__(self): fields_repr = ", ".join("{}={}".format( field.attr_name, repr(getattr(self, field.attr_name))) for field in fields().values()) return "{}({})".format(cls.__name__, fields_repr) cls.__repr__ = __repr__ @staticmethod def read_arg_value(value): if value is None: return None else: def get_value(field_definition): field = field_definition.__get__(None, cls) field_value = value[field.field_name] return _read_input_value(field_definition.type, field_value) return cls(raw_=value, **dict((field_definition.attr_name, get_value(field_definition)) for field_definition in field_definitions if field_definition.field_name in value)) cls.__read__ = read_arg_value return cls
def get_where_input_type(model: DeclarativeMeta, inputs: Inputs) -> GraphQLInputObjectType: type_name = get_model_where_input_name(model) if type_name in inputs: return inputs[type_name] def get_fields() -> GraphQLInputFieldMap: fields = { "_and": GraphQLInputField(GraphQLList(inputs[type_name])), "_or": GraphQLInputField(GraphQLList(inputs[type_name])), "_not": GraphQLInputField(inputs[type_name]), } for column in get_table(model).columns: fields[column.name] = GraphQLInputField( get_comparison_input_type(column, inputs)) for name, relationship in get_relationships(model): fields[name] = GraphQLInputField(inputs[get_model_where_input_name( relationship.mapper.entity)]) return fields inputs[type_name] = GraphQLInputObjectType(type_name, get_fields) return inputs[type_name]
def _common_supertype(left, right): if left == right: return left elif isinstance(left, GraphQLNonNull) and isinstance( right, GraphQLNonNull): return GraphQLNonNull(_common_supertype(left.of_type, right.of_type)) elif isinstance(left, GraphQLNonNull): return _common_supertype(left.of_type, right) elif isinstance(right, GraphQLNonNull): return _common_supertype(left, right.of_type) elif isinstance(left, GraphQLList) and isinstance(right, GraphQLList): return GraphQLList(_common_supertype(left.of_type, right.of_type)) elif isinstance(left, GraphQLInputObjectType) and isinstance( right, GraphQLInputObjectType): fields = dict((field_name, _common_superfield(left.fields.get(field_name), right.fields.get(field_name))) for field_name in set(left.fields.keys()) | set(right.fields.keys())) return GraphQLInputObjectType( name=left.name, fields=fields, ) else: raise ValueError("Cannot find common supertype")
def create_type(): return GraphQLInputObjectType( name='TodoUserInput', fields=lambda: { 'name': GraphQLInputObjectField(type=req(GraphQLString)), }, )
def make_model_fields_input_type(model: DeclarativeMeta, type_name: str) -> GraphQLInputObjectType: fields = {} for column in get_table(model).columns: fields[column.name] = GraphQLInputField( get_graphql_type_from_column(column.type)) return GraphQLInputObjectType(type_name, fields)
def compile_input_object(self, obj: InputObject) -> GraphQLInputObjectType: assert isinstance(obj, InputObject) # Create map between fields used internally and by the client. # Convert all names to camelCase, as that's the convention # normally used with GraphQL / Javascript. # NOTE: see note about name conversion in compile_field() FIELD_NAMES_PYTHON_TO_GQL = { py_name: _name_to_graphql(py_name) for py_name in obj.fields.keys() } FIELD_NAMES_GQL_TO_PYTHON = { gql_name: py_name for py_name, gql_name in FIELD_NAMES_PYTHON_TO_GQL.items() } # Create an instance of the object that will be passed as argument # to the resolver. # We need to convert names to their original form (usually # snake_case). def create_container(arg): return obj.container_type( **{ FIELD_NAMES_GQL_TO_PYTHON[name]: value for name, value in arg.items() }) compiled_type = GraphQLInputObjectType( name=obj.name, fields={}, # placeholder description=obj.description, out_type=create_container, ) self.add_to_cache(obj, compiled_type) compiled_type.fields = { FIELD_NAMES_PYTHON_TO_GQL[name]: self.compile_input_field(field) for name, field in obj.fields.items() } return compiled_type
def create_type(): return GraphQLInputObjectType( name='WorksheetEntryInput', fields=lambda: { 'line': GraphQLInputObjectField(type=req(GraphQLString)), 'column': GraphQLInputObjectField(type=req(GraphQLString)), 'value': GraphQLInputObjectField(type=req(GraphQLString)), }, )
def get_pk_columns_input(model: DeclarativeMeta) -> GraphQLInputObjectType: type_name = get_model_pk_columns_input_type_name(model) primary_key = get_table(model).primary_key fields = {} for column in primary_key.columns: fields[column.name] = GraphQLInputField( GraphQLNonNull(get_graphql_type_from_column(column.type))) return GraphQLInputObjectType(type_name, fields)
def get_filter_fields(self, typename, nested=False): selftype = self._gql_inobjtypes[typename] fields = OrderedDict() if not nested: fields['and'] = GraphQLInputObjectField( GraphQLList(GraphQLNonNull(selftype))) fields['or'] = GraphQLInputObjectField( GraphQLList(GraphQLNonNull(selftype))) fields['not'] = GraphQLInputObjectField(selftype) edb_type = self.edb_schema.get(typename) pointers = edb_type.get_pointers(self.edb_schema) names = sorted(pointers.keys(self.edb_schema)) for name in names: if name == '__type__': continue if name in fields: raise g_errors.GraphQLCoreError( f"{name!r} of {typename} clashes with special " "reserved fields required for GraphQL conversion" ) ptr = edb_type.getptr(self.edb_schema, name) edb_target = ptr.get_target(self.edb_schema) if edb_target.is_object_type(): t_name = edb_target.get_name(self.edb_schema) gql_name = self.get_input_name( 'NestedFilter', self.get_gql_name(t_name)) intype = self._gql_inobjtypes.get(gql_name) if intype is None: # construct a nested insert type intype = GraphQLInputObjectType( name=gql_name, fields=partial(self.get_filter_fields, t_name, True), ) self._gql_inobjtypes[gql_name] = intype elif not edb_target.is_scalar(): continue else: target = self._convert_edb_type(edb_target) if target is None: # don't expose this continue intype = self._gql_inobjtypes.get(f'Filter{target.name}') if intype: fields[name] = GraphQLInputObjectField(intype) return fields
def convert(self, type_map: t.Dict[str, GraphQLType]) -> GraphQLInputObjectType: if self.name in type_map: return t.cast(GraphQLInputObjectType, type_map[self.name]) type_map[self.name] = GraphQLInputObjectType(self.name, {}, self.description) for field_name, field in self.fields.items(): t.cast(GraphQLInputObjectType, type_map[self.name]).fields[ field_name ] = field.convert(type_map) return t.cast(GraphQLInputObjectType, type_map[self.name])
def create_type(): return GraphQLInputObjectType( name='CreateWorksheetInstanceInput', fields=lambda: { 'reportRecordNumber': GraphQLInputObjectField(type=req(GraphQLInt)), 'worksheetCode': GraphQLInputObjectField(type=req(GraphQLString)), 'worksheetEntries': GraphQLInputObjectField(type=req( list_of(req(GraphQLWorksheetEntryInput.type())))), }, )
def get_conflict_type(model: DeclarativeMeta, inputs: Inputs) -> GraphQLInputObjectType: type_name = get_field_name(model, "on_conflict") if type_name in inputs: return inputs[type_name] fields = { "constraint": GraphQLInputField(GraphQLNonNull(get_constraint_enum(model))), "update_columns": GraphQLInputField(GraphQLNonNull(GraphQLList(GraphQLNonNull(get_update_column_enums(model))))), "where": GraphQLInputField(get_input_type(model, inputs, "where")), } input_type = GraphQLInputObjectType(type_name, fields) inputs[type_name] = input_type return input_type
def get_inc_input_type(model: DeclarativeMeta, inputs: Inputs) -> GraphQLInputObjectType: type_name = get_model_inc_input_type_name(model) if type_name in inputs: return inputs[type_name] fields = {} for column in get_table(model).columns: if isinstance(column.type, (Integer, Float)): fields[column.name] = GraphQLInputField( get_graphql_type_from_column(column.type)) inputs[type_name] = GraphQLInputObjectType(type_name, fields) return inputs[type_name]
def get_comparison_input_type(column: Column, inputs: Inputs) -> GraphQLInputObjectType: graphql_type = get_graphql_type_from_column(column.type) type_name = get_graphql_type_comparison_name(graphql_type) if type_name in inputs: return inputs[type_name] fields = get_base_comparison_fields(graphql_type) if graphql_type == GraphQLString: fields.update(get_string_comparison_fields()) inputs[type_name] = GraphQLInputObjectType(type_name, fields) return inputs[type_name]
def define_generic_order_types(self): self._gql_ordertypes['directionEnum'] = \ self._gql_enums['directionEnum'] self._gql_ordertypes['nullsOrderingEnum'] = \ self._gql_enums['nullsOrderingEnum'] self._gql_ordertypes['Ordering'] = GraphQLInputObjectType( 'Ordering', fields=OrderedDict( dir=GraphQLInputObjectField( GraphQLNonNull(self._gql_enums['directionEnum']), ), nulls=GraphQLInputObjectField( self._gql_enums['nullsOrderingEnum'], default_value='SMALLEST', ), ))
def __new__(meta, name, bases, attrs): cls = super(InputObjectTypeMeta, meta).__new__(meta, name, bases, attrs) if attrs.get("__abstract__"): return cls field_definitions, fields = _declare_fields(cls) fields = lazy(fields) cls.__fields__ = staticmethod(lambda: list(field_definitions)) cls.__graphql__ = GraphQLInputObjectType( name=cls.__name__, fields=lambda: dict((key, field.to_graphql_input_field()) for key, field in six.iteritems(fields())), ) def __init__(self, **kwargs): attr.attrs( these=dict( raw_=attr.attrib(default=undefined), **dict((field.attr_name, attr.attrib( default=getattr(field, "default", undefined))) for field in fields().values())), cmp=False, slots=True, frozen=True, )(cls) return cls.__init__(self, **kwargs) cls.__init__ = __init__ @staticmethod def read_arg_value(value): def get_value(field_definition): field = field_definition.__get__(None, cls) field_value = value[field.field_name] return _read_input_value(field_definition.type, field_value) return cls(raw_=value, **dict((field_definition.attr_name, get_value(field_definition)) for field_definition in field_definitions if field_definition.field_name in value)) cls.__read__ = read_arg_value return cls
def mutation(name, input_fields, output_fields, mutate_and_get_payload, description=None): # https://github.com/graphql/graphql-relay-js/blob/master/src/mutation/mutation.js augmented_input_fields = { **input_fields, 'clientMutationId': GraphQLInputObjectField(type=GraphQLBoolean), } augmented_output_fields = { **output_fields, 'clientMutationId': GraphQLField(type=GraphQLBoolean), } output_type = GraphQLObjectType(name=name + 'Payload', fields=augmented_output_fields) input_type = GraphQLInputObjectType(name=name + 'Input', fields=augmented_input_fields) def sync_resolve(parent, info, *, input): logger.info('sync_resolver(%r, %r, %r)', parent, info, input) assert isinstance(input, dict) cmi = input.get('clientMutationId') result = mutate_and_get_payload(info, **input) result.clientMutationId = cmi return result async def async_resolve(parent, info, *, input): logger.info('async_resolver(%r, %r, %r)', parent, info, input) assert isinstance(input, dict) cmi = input.get('clientMutationId') result = await mutate_and_get_payload(info, **input) result.clientMutationId = cmi return result if asyncio.iscoroutinefunction(mutate_and_get_payload): resolve = async_resolve else: resolve = sync_resolve return GraphQLField( description=description, type=output_type, args={ 'input': GraphQLArgument(type=GraphQLNonNull(type=input_type)), }, resolver=resolve)
def _make_generic_update_op_type(self, ptr, fname, edb_base, target): typename = edb_base.get_name(self.edb_schema) name = f'UpdateOp{typename}__{fname}' edb_target = ptr.get_target(self.edb_schema) fields = { 'set': GraphQLInputObjectField(target) } # get additional commands based on the pointer type if not ptr.get_required(self.edb_schema): fields['clear'] = GraphQLInputObjectField(GraphQLBoolean) if edb_target.is_scalar(): base_target = edb_target.get_topmost_concrete_base(self.edb_schema) bt_name = base_target.get_name(self.edb_schema) else: bt_name = None # first check for this being a multi-link if not ptr.singular(self.edb_schema): fields['add'] = GraphQLInputObjectField(target) fields['remove'] = GraphQLInputObjectField(target) elif target in {GraphQLInt, GraphQLInt64, GraphQLBigint, GraphQLFloat, GraphQLDecimal}: # anything that maps onto the numeric types is a fair game fields['increment'] = GraphQLInputObjectField(target) fields['decrement'] = GraphQLInputObjectField(target) elif bt_name == 'std::str' or edb_target.is_array(): # only actual strings and arrays have append, prepend and # slice ops fields['prepend'] = GraphQLInputObjectField(target) fields['append'] = GraphQLInputObjectField(target) # slice [from, to] fields['slice'] = GraphQLInputObjectField( GraphQLList(GraphQLNonNull(GraphQLInt)) ) nitype = GraphQLInputObjectType( name=self.get_input_name( f'UpdateOp_{fname}_', self.get_gql_name(typename)), fields=fields, ) self._gql_inobjtypes[name] = nitype return nitype
def create_type(): return GraphQLInputObjectType( name='ProviderCsvRow', fields=lambda: { 'provider': GraphQLInputObjectField(type=req(GraphQLString)), 'fyb': GraphQLInputObjectField(type=req(GraphQLString)), 'fye': GraphQLInputObjectField(type=req(GraphQLString)), 'status': GraphQLInputObjectField(type=req(GraphQLString)), 'ctrl_type': GraphQLInputObjectField(type=req(GraphQLString)), 'hosp_name': GraphQLInputObjectField(type=req(GraphQLString)), 'street_addr': GraphQLInputObjectField(type=GraphQLString), 'po_box': GraphQLInputObjectField(type=GraphQLString), 'city': GraphQLInputObjectField(type=req(GraphQLString)), 'state': GraphQLInputObjectField(type=req(GraphQLString)), 'zip_code': GraphQLInputObjectField(type=req(GraphQLString)), 'county': GraphQLInputObjectField(type=GraphQLString), }, )