use graphql_tools::parser::query::{
Definition, Field, Mutation, OperationDefinition, Query, Selection, SelectionSet, Subscription,
};
use crate::query_planner::ast::normalization::context::NormalizationContext;
use crate::query_planner::ast::normalization::error::NormalizationError;
use crate::query_planner::utils::ast::equal_directives_arr;
#[inline]
pub fn merge_fields(ctx: &mut NormalizationContext) -> Result<(), NormalizationError> {
for definition in &mut ctx.document.definitions {
match definition {
Definition::Operation(op_def) => match op_def {
OperationDefinition::SelectionSet(selection_set) => {
handle_selection_set(selection_set)?;
}
OperationDefinition::Query(Query { selection_set, .. }) => {
handle_selection_set(selection_set)?;
}
OperationDefinition::Mutation(Mutation { selection_set, .. }) => {
handle_selection_set(selection_set)?;
}
OperationDefinition::Subscription(Subscription { selection_set, .. }) => {
handle_selection_set(selection_set)?;
}
},
Definition::Fragment(_) => {
}
}
}
Ok(())
}
#[inline]
fn fields_equal<'a>(a: &Field<'a, String>, b: &Field<'a, String>) -> bool {
if a.alias != b.alias {
return false;
}
if a.name != b.name {
return false;
}
if a.arguments != b.arguments {
return false;
}
if !equal_directives_arr(&a.directives, &b.directives) {
return false;
}
true
}
#[inline]
fn handle_selection_set<'a>(
selection_set: &mut SelectionSet<'a, String>,
) -> Result<(), NormalizationError> {
let old_items = std::mem::take(&mut selection_set.items);
let mut new_items: Vec<Selection<'a, String>> = Vec::new();
for selection in old_items {
match selection {
Selection::Field(mut current_field) => {
handle_selection_set(&mut current_field.selection_set)?;
let mut merged_into_existing = false;
for new_item_selection in new_items.iter_mut() {
if let Selection::Field(ref mut existing_field) = new_item_selection {
if fields_equal(¤t_field, existing_field) {
existing_field
.selection_set
.items
.append(&mut current_field.selection_set.items);
handle_selection_set(&mut existing_field.selection_set)?;
merged_into_existing = true;
break;
}
}
}
if !merged_into_existing {
new_items.push(Selection::Field(current_field));
}
}
Selection::InlineFragment(mut inline_fragment) => {
handle_selection_set(&mut inline_fragment.selection_set)?;
new_items.push(Selection::InlineFragment(inline_fragment));
}
Selection::FragmentSpread(_) => {
}
}
}
selection_set.items = new_items;
Ok(())
}