async-graphql-parser 1.16.11

GraphQL query parser for async-graphql
Documentation
use crate::pos::Positioned;
use crate::value::Value;
use std::collections::HashMap;
use std::fmt;

#[derive(Debug, PartialEq, Clone)]
pub enum Type {
    Named(String),
    List(Box<Type>),
    NonNull(Box<Type>),
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Type::Named(name) => write!(f, "{}", name),
            Type::List(ty) => write!(f, "[{}]", ty),
            Type::NonNull(ty) => write!(f, "{}!", ty),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Directive {
    pub name: Positioned<String>,
    pub arguments: Vec<(Positioned<String>, Positioned<Value>)>,
}

impl Directive {
    pub fn get_argument(&self, name: &str) -> Option<&Positioned<Value>> {
        self.arguments
            .iter()
            .find(|item| item.0.node == name)
            .map(|item| &item.1)
    }
}

pub type FragmentsMap = HashMap<String, Positioned<FragmentDefinition>>;

/// Query operation type
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum OperationType {
    Query,
    Mutation,
    Subscription,
}

#[derive(Debug, Clone)]
pub struct CurrentOperation {
    pub ty: OperationType,
    pub variable_definitions: Vec<Positioned<VariableDefinition>>,
    pub selection_set: Positioned<SelectionSet>,
}

#[derive(Debug, Clone)]
pub struct Document {
    pub(crate) definitions: Vec<Positioned<Definition>>,
    pub(crate) fragments: FragmentsMap,
    pub(crate) current_operation: Option<CurrentOperation>,
}

impl Document {
    #[inline]
    pub fn definitions(&self) -> &[Positioned<Definition>] {
        &self.definitions
    }

    #[inline]
    pub fn fragments(&self) -> &FragmentsMap {
        &self.fragments
    }

    #[inline]
    pub fn current_operation(&self) -> &CurrentOperation {
        self.current_operation
            .as_ref()
            .expect("Must first call retain_operation")
    }

    pub fn retain_operation(&mut self, operation_name: Option<&str>) -> bool {
        let mut fragments = HashMap::new();

        for definition in self.definitions.drain(..) {
            match definition.node {
                Definition::Operation(operation_definition) if self.current_operation.is_none() => {
                    match operation_definition.node {
                        OperationDefinition::SelectionSet(s) => {
                            self.current_operation = Some(CurrentOperation {
                                ty: OperationType::Query,
                                variable_definitions: Vec::new(),
                                selection_set: s,
                            });
                        }
                        OperationDefinition::Query(query)
                            if query.name.is_none()
                                || operation_name.is_none()
                                || query.name.as_ref().map(|name| name.node.as_str())
                                    == operation_name.as_deref() =>
                        {
                            self.current_operation = Some(CurrentOperation {
                                ty: OperationType::Query,
                                variable_definitions: query.node.variable_definitions,
                                selection_set: query.node.selection_set,
                            });
                        }
                        OperationDefinition::Mutation(mutation)
                            if mutation.name.is_none()
                                || operation_name.is_none()
                                || mutation.name.as_ref().map(|name| name.node.as_str())
                                    == operation_name =>
                        {
                            self.current_operation = Some(CurrentOperation {
                                ty: OperationType::Mutation,
                                variable_definitions: mutation.node.variable_definitions,
                                selection_set: mutation.node.selection_set,
                            });
                        }
                        OperationDefinition::Subscription(subscription)
                            if subscription.name.is_none()
                                || operation_name.is_none()
                                || subscription.name.as_ref().map(|name| name.node.as_str())
                                    == operation_name =>
                        {
                            self.current_operation = Some(CurrentOperation {
                                ty: OperationType::Subscription,
                                variable_definitions: subscription.node.variable_definitions,
                                selection_set: subscription.node.selection_set,
                            });
                        }
                        _ => {}
                    }
                }
                Definition::Operation(_) => {}
                Definition::Fragment(fragment) => {
                    fragments.insert(fragment.name.clone_inner(), fragment);
                }
            }
        }
        self.fragments = fragments;
        self.current_operation.is_some()
    }
}

#[derive(Debug, Clone)]
pub enum Definition {
    Operation(Positioned<OperationDefinition>),
    Fragment(Positioned<FragmentDefinition>),
}

#[derive(Debug, Clone)]
pub enum TypeCondition {
    On(Positioned<String>),
}

#[derive(Debug, Clone)]
pub struct FragmentDefinition {
    pub name: Positioned<String>,
    pub type_condition: Positioned<TypeCondition>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}

#[derive(Debug, Clone)]
pub enum OperationDefinition {
    SelectionSet(Positioned<SelectionSet>),
    Query(Positioned<Query>),
    Mutation(Positioned<Mutation>),
    Subscription(Positioned<Subscription>),
}

#[derive(Debug, Clone)]
pub struct Query {
    pub name: Option<Positioned<String>>,
    pub variable_definitions: Vec<Positioned<VariableDefinition>>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}

#[derive(Debug, Clone)]
pub struct Mutation {
    pub name: Option<Positioned<String>>,
    pub variable_definitions: Vec<Positioned<VariableDefinition>>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}

#[derive(Debug, Clone)]
pub struct Subscription {
    pub name: Option<Positioned<String>>,
    pub variable_definitions: Vec<Positioned<VariableDefinition>>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}

#[derive(Debug, Default, Clone)]
pub struct SelectionSet {
    pub items: Vec<Positioned<Selection>>,
}

#[derive(Debug, Clone)]
pub struct VariableDefinition {
    pub name: Positioned<String>,
    pub var_type: Positioned<Type>,
    pub default_value: Option<Positioned<Value>>,
}

#[derive(Debug, Clone)]
pub enum Selection {
    Field(Positioned<Field>),
    FragmentSpread(Positioned<FragmentSpread>),
    InlineFragment(Positioned<InlineFragment>),
}

#[derive(Debug, Clone)]
pub struct Field {
    pub alias: Option<Positioned<String>>,
    pub name: Positioned<String>,
    pub arguments: Vec<(Positioned<String>, Positioned<Value>)>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}

impl Field {
    pub fn get_argument(&self, name: &str) -> Option<&Positioned<Value>> {
        self.arguments
            .iter()
            .find(|item| item.0.node == name)
            .map(|item| &item.1)
    }
}

#[derive(Debug, Clone)]
pub struct FragmentSpread {
    pub fragment_name: Positioned<String>,
    pub directives: Vec<Positioned<Directive>>,
}

#[derive(Debug, Clone)]
pub struct InlineFragment {
    pub type_condition: Option<Positioned<TypeCondition>>,
    pub directives: Vec<Positioned<Directive>>,
    pub selection_set: Positioned<SelectionSet>,
}