bluejay-parser 0.3.1

A GraphQL parser
Documentation
use crate::ast::definition::{
    ArgumentsDefinition, Context, CustomScalarTypeDefinition, DefaultContext, Directive,
    DirectiveDefinition, Directives, EnumTypeDefinition, EnumValueDefinition, EnumValueDefinitions,
    FieldDefinition, FieldsDefinition, InputFieldsDefinition, InputObjectTypeDefinition, InputType,
    InputValueDefinition, InterfaceImplementation, InterfaceImplementations,
    InterfaceTypeDefinition, ObjectTypeDefinition, OutputType, TypeDefinition, UnionMemberType,
    UnionMemberTypes, UnionTypeDefinition,
};
use crate::lexical_token::StringValue;
use bluejay_core::definition::{
    HasDirectives, InterfaceImplementation as CoreInterfaceImplementation,
    ObjectTypeDefinition as CoreObjectTypeDefinition, SchemaDefinition as CoreSchemaDefinition,
    TypeDefinition as CoreTypeDefinition, TypeDefinitionReference,
};
use bluejay_core::AsIter;
use std::collections::{btree_map::Values, BTreeMap, HashMap};

#[derive(Debug)]
pub struct SchemaDefinition<'a, C: Context = DefaultContext> {
    type_definitions: BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
    directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, C>>,
    description: Option<&'a StringValue<'a>>,
    query: &'a ObjectTypeDefinition<'a, C>,
    mutation: Option<&'a ObjectTypeDefinition<'a, C>>,
    subscription: Option<&'a ObjectTypeDefinition<'a, C>>,
    directives: Option<&'a Directives<'a, C>>,
    interface_implementors: HashMap<&'a str, Vec<&'a ObjectTypeDefinition<'a, C>>>,
}

impl<'a, C: Context> SchemaDefinition<'a, C> {
    pub(crate) fn new(
        type_definitions: BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
        directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, C>>,
        description: Option<&'a StringValue>,
        query: &'a ObjectTypeDefinition<'a, C>,
        mutation: Option<&'a ObjectTypeDefinition<'a, C>>,
        subscription: Option<&'a ObjectTypeDefinition<'a, C>>,
        directives: Option<&'a Directives<'a, C>>,
    ) -> Self {
        let interface_implementors = Self::interface_implementors(&type_definitions);
        Self {
            type_definitions,
            directive_definitions,
            description,
            query,
            mutation,
            subscription,
            directives,
            interface_implementors,
        }
    }

    fn interface_implementors(
        type_definitions: &BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
    ) -> HashMap<&'a str, Vec<&'a ObjectTypeDefinition<'a, C>>> {
        type_definitions.values().fold(
            HashMap::new(),
            |mut interface_implementors, &type_definition| {
                if let TypeDefinition::Object(otd) = type_definition {
                    if let Some(interface_implementations) = otd.interface_implementations() {
                        interface_implementations
                            .iter()
                            .for_each(|interface_implementation| {
                                let itd_name = interface_implementation.name();
                                interface_implementors
                                    .entry(itd_name)
                                    .or_default()
                                    .push(otd);
                            });
                    }
                }

                interface_implementors
            },
        )
    }
}

impl<'a, C: Context> CoreSchemaDefinition for SchemaDefinition<'a, C> {
    type Directive = Directive<'a, C>;
    type Directives = Directives<'a, C>;
    type InputValueDefinition = InputValueDefinition<'a, C>;
    type InputFieldsDefinition = InputFieldsDefinition<'a, C>;
    type ArgumentsDefinition = ArgumentsDefinition<'a, C>;
    type EnumValueDefinition = EnumValueDefinition<'a, C>;
    type EnumValueDefinitions = EnumValueDefinitions<'a, C>;
    type FieldDefinition = FieldDefinition<'a, C>;
    type FieldsDefinition = FieldsDefinition<'a, C>;
    type InterfaceImplementation = InterfaceImplementation<'a, C>;
    type InterfaceImplementations = InterfaceImplementations<'a, C>;
    type UnionMemberType = UnionMemberType<'a, C>;
    type UnionMemberTypes = UnionMemberTypes<'a, C>;
    type InputType = InputType<'a, C>;
    type OutputType = OutputType<'a, C>;
    type CustomScalarTypeDefinition = CustomScalarTypeDefinition<'a, C>;
    type ObjectTypeDefinition = ObjectTypeDefinition<'a, C>;
    type InterfaceTypeDefinition = InterfaceTypeDefinition<'a, C>;
    type UnionTypeDefinition = UnionTypeDefinition<'a, C>;
    type InputObjectTypeDefinition = InputObjectTypeDefinition<'a, C>;
    type EnumTypeDefinition = EnumTypeDefinition<'a, C>;
    type TypeDefinition = TypeDefinition<'a, C>;
    type DirectiveDefinition = DirectiveDefinition<'a, C>;
    type TypeDefinitions<'b>
        = std::iter::Map<
        Values<'b, &'b str, &'b TypeDefinition<'a, C>>,
        fn(&&'b TypeDefinition<'a, C>) -> TypeDefinitionReference<'b, TypeDefinition<'a, C>>,
    >
    where
        'a: 'b;
    type DirectiveDefinitions<'b>
        = std::iter::Copied<Values<'b, &'b str, &'b DirectiveDefinition<'a, C>>>
    where
        'a: 'b;
    type InterfaceImplementors<'b>
        = std::iter::Flatten<
        std::option::IntoIter<
            std::iter::Copied<std::slice::Iter<'b, &'b ObjectTypeDefinition<'a, C>>>,
        >,
    >
    where
        'a: 'b;

    fn description(&self) -> Option<&str> {
        self.description.as_ref().map(AsRef::as_ref)
    }

    fn query(&self) -> &Self::ObjectTypeDefinition {
        self.query
    }

    fn mutation(&self) -> Option<&Self::ObjectTypeDefinition> {
        self.mutation
    }

    fn subscription(&self) -> Option<&Self::ObjectTypeDefinition> {
        self.subscription
    }

    fn get_type_definition(
        &self,
        name: &str,
    ) -> Option<TypeDefinitionReference<'_, Self::TypeDefinition>> {
        self.type_definitions.get(name).map(|td| td.as_ref())
    }

    fn type_definitions(&self) -> Self::TypeDefinitions<'_> {
        self.type_definitions.values().map(
            |td: &&TypeDefinition<C>| -> TypeDefinitionReference<'_, TypeDefinition<'a, C>> {
                td.as_ref()
            },
        )
    }

    fn get_directive_definition(&self, name: &str) -> Option<&Self::DirectiveDefinition> {
        self.directive_definitions.get(name).copied()
    }

    fn directive_definitions(&self) -> Self::DirectiveDefinitions<'_> {
        self.directive_definitions.values().copied()
    }

    fn get_interface_implementors(
        &self,
        itd: &Self::InterfaceTypeDefinition,
    ) -> Self::InterfaceImplementors<'_> {
        self.interface_implementors
            .get(itd.name().as_ref())
            .map(|implementors| implementors.iter().copied())
            .into_iter()
            .flatten()
    }
}

impl<'a, C: Context> HasDirectives for SchemaDefinition<'a, C> {
    type Directives = Directives<'a, C>;

    fn directives(&self) -> Option<&Self::Directives> {
        self.directives
    }
}