use std::collections::HashMap;
use crate::{
diagnostics::{UniqueDefinition, UniqueField},
hir::{InputObjectTypeDefinition, InputValueDefinition},
ApolloDiagnostic, ValidationDatabase,
};
pub fn check(db: &dyn ValidationDatabase) -> Vec<ApolloDiagnostic> {
let mut diagnostics = Vec::new();
let mut seen: HashMap<&str, &InputObjectTypeDefinition> = HashMap::new();
for input_object in db.input_objects().iter() {
let name = input_object.name();
if let Some(prev_def) = seen.get(name) {
let prev_offset: usize = prev_def.ast_node(db.upcast()).text_range().start().into();
let prev_node_len: usize = prev_def.ast_node(db.upcast()).text_range().len().into();
let current_offset: usize = input_object
.ast_node(db.upcast())
.text_range()
.start()
.into();
let current_node_len: usize =
input_object.ast_node(db.upcast()).text_range().len().into();
diagnostics.push(ApolloDiagnostic::UniqueDefinition(UniqueDefinition {
ty: "input object".into(),
name: name.into(),
src: db.input(),
original_definition: (prev_offset, prev_node_len).into(),
redefined_definition: (current_offset, current_node_len).into(),
help: Some(format!(
"`{name}` must only be defined once in this document."
)),
}));
} else {
seen.insert(name, input_object);
}
}
for input_objects in db.input_objects().iter() {
let mut seen: HashMap<&str, &InputValueDefinition> = HashMap::new();
let input_fields = input_objects.input_fields_definition();
for field in input_fields {
let field_name = field.name();
if let Some(prev_field) = seen.get(&field_name) {
if prev_field.ast_node(db.upcast()).is_some()
&& field.ast_node(db.upcast()).is_some()
{
let prev_offset: usize = prev_field
.ast_node(db.upcast())
.unwrap()
.text_range()
.start()
.into();
let prev_node_len: usize = prev_field
.ast_node(db.upcast())
.unwrap()
.text_range()
.len()
.into();
let current_offset: usize = field
.ast_node(db.upcast())
.unwrap()
.text_range()
.start()
.into();
let current_node_len: usize = field
.ast_node(db.upcast())
.unwrap()
.text_range()
.len()
.into();
diagnostics.push(ApolloDiagnostic::UniqueField(UniqueField {
field: field_name.into(),
src: db.input(),
original_field: (prev_offset, prev_node_len).into(),
redefined_field: (current_offset, current_node_len).into(),
help: Some(format!(
"{field_name} field must only be defined once in this input object definition."
)),
}));
}
} else {
seen.insert(field_name, field);
}
}
}
diagnostics
}