in compiler/crates/schema/src/in_memory/mod.rs [972:1301]
fn add_definition(
&mut self,
definition: &TypeSystemDefinition,
location_key: &SourceLocationKey,
is_extension: bool,
) -> DiagnosticsResult<()> {
match definition {
TypeSystemDefinition::SchemaDefinition(SchemaDefinition {
operation_types,
directives: _directives,
}) => {
for OperationTypeDefinition { operation, type_ } in &operation_types.items {
let operation_id = self.build_object_id(type_.value)?;
match operation {
OperationType::Query => {
if let Some(prev_query_type) = self.query_type {
return Err(vec![Diagnostic::error(
SchemaError::DuplicateOperationDefinition(
*operation,
type_.value,
expect_object_type_name(&self.type_map, prev_query_type),
),
Location::new(*location_key, type_.span),
)]);
} else {
self.query_type = Some(operation_id);
}
}
OperationType::Mutation => {
if let Some(prev_mutation_type) = self.mutation_type {
return Err(vec![Diagnostic::error(
SchemaError::DuplicateOperationDefinition(
*operation,
type_.value,
expect_object_type_name(&self.type_map, prev_mutation_type),
),
Location::new(*location_key, type_.span),
)]);
} else {
self.mutation_type = Some(operation_id);
}
}
OperationType::Subscription => {
if let Some(prev_subscription_type) = self.subscription_type {
return Err(vec![Diagnostic::error(
SchemaError::DuplicateOperationDefinition(
*operation,
type_.value,
expect_object_type_name(
&self.type_map,
prev_subscription_type,
),
),
Location::new(*location_key, type_.span),
)]);
} else {
self.subscription_type = Some(operation_id);
}
}
}
}
}
TypeSystemDefinition::DirectiveDefinition(DirectiveDefinition {
name,
arguments,
repeatable,
locations,
description,
}) => {
if self.directives.contains_key(&name.value) {
let str_name = name.value.lookup();
if str_name != "skip" && str_name != "include" {
// TODO(T63941319) @skip and @include directives are duplicated in our schema
return Err(vec![Diagnostic::error(
SchemaError::DuplicateDirectiveDefinition(name.value),
Location::new(*location_key, name.span),
)]);
}
}
let arguments = self.build_arguments(arguments)?;
self.directives.insert(
name.value,
Directive {
name: name.value,
arguments,
locations: locations.clone(),
repeatable: *repeatable,
is_extension,
description: description.as_ref().map(|node| node.value),
},
);
}
TypeSystemDefinition::ObjectTypeDefinition(ObjectTypeDefinition {
name,
interfaces,
fields,
directives,
}) => {
let parent_id = Type::Object(ObjectID(self.objects.len() as u32));
let fields = if is_extension {
self.build_extend_fields(
fields,
&mut HashMap::with_capacity(len_of_option_list(fields)),
*location_key,
Some(parent_id),
)?
} else {
self.build_fields(fields, *location_key, Some(parent_id))?
};
let interfaces = interfaces
.iter()
.map(|name| self.build_interface_id(name, location_key))
.collect::<DiagnosticsResult<Vec<_>>>()?;
let directives = self.build_directive_values(directives);
self.objects.push(Object {
name: WithLocation::new(Location::new(*location_key, name.span), name.value),
fields,
is_extension,
interfaces,
directives,
description: None,
});
}
TypeSystemDefinition::InterfaceTypeDefinition(InterfaceTypeDefinition {
name,
interfaces,
directives,
fields,
}) => {
let parent_id = Type::Interface(InterfaceID(self.interfaces.len() as u32));
let fields = if is_extension {
self.build_extend_fields(
fields,
&mut HashMap::with_capacity(len_of_option_list(fields)),
*location_key,
Some(parent_id),
)?
} else {
self.build_fields(fields, *location_key, Some(parent_id))?
};
let interfaces = interfaces
.iter()
.map(|name| self.build_interface_id(name, location_key))
.collect::<DiagnosticsResult<Vec<_>>>()?;
let directives = self.build_directive_values(directives);
self.interfaces.push(Interface {
name: name.value,
implementing_objects: vec![],
is_extension,
fields,
directives,
interfaces,
description: None,
});
}
TypeSystemDefinition::UnionTypeDefinition(UnionTypeDefinition {
name,
directives,
members,
}) => {
let members = members
.iter()
.map(|name| self.build_object_id(name.value))
.collect::<DiagnosticsResult<Vec<_>>>()?;
let directives = self.build_directive_values(directives);
self.unions.push(Union {
name: name.value,
is_extension,
members,
directives,
description: None,
});
}
TypeSystemDefinition::InputObjectTypeDefinition(InputObjectTypeDefinition {
name,
fields,
directives,
}) => {
let fields = self.build_arguments(fields)?;
let directives = self.build_directive_values(directives);
self.input_objects.push(InputObject {
name: name.value,
fields,
directives,
description: None,
});
}
TypeSystemDefinition::EnumTypeDefinition(EnumTypeDefinition {
name,
directives,
values,
}) => {
let directives = self.build_directive_values(directives);
let values = if let Some(values) = values {
values
.items
.iter()
.map(|enum_def| EnumValue {
value: enum_def.name.value,
directives: self.build_directive_values(&enum_def.directives),
})
.collect()
} else {
Vec::new()
};
self.enums.push(Enum {
name: name.value,
is_extension,
values,
directives,
description: None,
});
}
TypeSystemDefinition::ScalarTypeDefinition(ScalarTypeDefinition {
name,
directives,
}) => {
let directives = self.build_directive_values(directives);
self.scalars.push(Scalar {
name: name.value,
is_extension,
directives,
description: None,
})
}
TypeSystemDefinition::ObjectTypeExtension(ObjectTypeExtension {
name,
interfaces,
fields,
directives,
}) => match self.type_map.get(&name.value).cloned() {
Some(Type::Object(id)) => {
let index = id.as_usize();
let obj = self.objects.get(index).ok_or_else(|| {
vec![Diagnostic::error(
SchemaError::ExtendUndefinedType(name.value),
Location::new(*location_key, name.span),
)]
})?;
let field_ids = &obj.fields;
let mut existing_fields =
HashMap::with_capacity(field_ids.len() + len_of_option_list(fields));
for field_id in field_ids {
let field_name = self.fields[field_id.as_usize()].name;
existing_fields.insert(field_name.item, field_name.location);
}
let client_fields = self.build_extend_fields(
fields,
&mut existing_fields,
*location_key,
Some(Type::Object(id)),
)?;
self.objects[index].fields.extend(client_fields);
let built_interfaces = interfaces
.iter()
.map(|name| self.build_interface_id(name, location_key))
.collect::<DiagnosticsResult<Vec<_>>>()?;
extend_without_duplicates(
&mut self.objects[index].interfaces,
built_interfaces,
);
let built_directives = self.build_directive_values(directives);
extend_without_duplicates(
&mut self.objects[index].directives,
built_directives,
);
}
_ => {
return Err(vec![Diagnostic::error(
SchemaError::ExtendUndefinedType(name.value),
Location::new(*location_key, name.span),
)]);
}
},
TypeSystemDefinition::InterfaceTypeExtension(InterfaceTypeExtension {
name,
fields,
directives,
..
}) => match self.type_map.get(&name.value).cloned() {
Some(Type::Interface(id)) => {
let index = id.as_usize();
let interface = self.interfaces.get(index).ok_or_else(|| {
vec![Diagnostic::error(
SchemaError::ExtendUndefinedType(name.value),
Location::new(*location_key, name.span),
)]
})?;
let field_ids = &interface.fields;
let mut existing_fields =
HashMap::with_capacity(field_ids.len() + len_of_option_list(fields));
for field_id in field_ids {
let field_name = self.fields[field_id.as_usize()].name;
existing_fields.insert(field_name.item, field_name.location);
}
let client_fields = self.build_extend_fields(
fields,
&mut existing_fields,
*location_key,
Some(Type::Interface(id)),
)?;
self.interfaces[index].fields.extend(client_fields);
let built_directives = self.build_directive_values(directives);
extend_without_duplicates(
&mut self.interfaces[index].directives,
built_directives,
);
}
_ => {
return Err(vec![Diagnostic::error(
SchemaError::ExtendUndefinedType(name.value),
Location::new(*location_key, name.span),
)]);
}
},
TypeSystemDefinition::SchemaExtension { .. } => todo!("SchemaExtension"),
TypeSystemDefinition::EnumTypeExtension { .. } => todo!("EnumTypeExtension"),
TypeSystemDefinition::UnionTypeExtension { .. } => todo!("UnionTypeExtension"),
TypeSystemDefinition::InputObjectTypeExtension { .. } => {
todo!("InputObjectTypeExtension")
}
TypeSystemDefinition::ScalarTypeExtension { .. } => todo!("ScalarTypeExtension"),
}
Ok(())
}