in compiler/crates/schema-validate/src/lib.rs [329:430]
fn validate_type_implements_interface<T: TypeWithFields + Named>(
&self,
type_: &T,
interface: &Interface,
) {
let object_field_map = self.field_map(type_.fields());
let interface_field_map = self.field_map(&interface.fields);
let context = ValidationContextType::TypeNode(type_.name());
// Assert each interface field is implemented.
for (field_name, interface_field) in interface_field_map {
// Assert interface field exists on object.
if !object_field_map.contains_key(&field_name) {
self.report_error(
SchemaValidationError::InterfaceFieldNotProvided(
interface.name,
field_name,
type_.name(),
),
context,
);
continue;
}
let object_field = object_field_map.get(&field_name).unwrap();
// Assert interface field type is satisfied by object field type, by being
// a valid subtype. (covariant)
if !self
.schema
.is_type_subtype_of(&object_field.type_, &interface_field.type_)
{
self.report_error(
SchemaValidationError::NotASubType(
interface.name,
field_name,
self.schema.get_type_name(interface_field.type_.inner()),
type_.name(),
self.schema.get_type_name(object_field.type_.inner()),
),
context,
);
}
// Assert each interface field arg is implemented.
for interface_argument in interface_field.arguments.iter() {
let object_argument = object_field
.arguments
.iter()
.find(|arg| arg.name == interface_argument.name);
// Assert interface field arg exists on object field.
if object_argument.is_none() {
self.report_error(
SchemaValidationError::InterfaceFieldArgumentNotProvided(
interface.name,
field_name,
interface_argument.name,
type_.name(),
),
context,
);
continue;
}
let object_argument = object_argument.unwrap();
// Assert interface field arg type matches object field arg type.
// (invariant)
// TODO: change to contravariant?
if interface_argument.type_ != object_argument.type_ {
self.report_error(
SchemaValidationError::NotEqualType(
interface.name,
field_name,
interface_argument.name,
self.schema.get_type_name(interface_argument.type_.inner()),
type_.name(),
self.schema.get_type_name(object_argument.type_.inner()),
),
context,
);
}
// TODO: validate default values?
}
// Assert additional arguments must not be required.
for object_argument in object_field.arguments.iter() {
if !interface_field.arguments.contains(object_argument.name)
&& object_argument.type_.is_non_null()
{
self.report_error(
SchemaValidationError::MissingRequiredArgument(
type_.name(),
field_name,
object_argument.name,
interface.name,
),
context,
);
}
}
}
}