diff --git a/crates/apollo-compiler/src/executable/validation.rs b/crates/apollo-compiler/src/executable/validation.rs index 409307a72..f4df78bfb 100644 --- a/crates/apollo-compiler/src/executable/validation.rs +++ b/crates/apollo-compiler/src/executable/validation.rs @@ -57,9 +57,6 @@ pub(crate) fn validate_field_set( document, Some((schema, &field_set.selection_set.ty)), &field_set.selection_set, - crate::validation::operation::OperationValidationConfig { - schema: Some(schema), - variables: &[], - }, + &crate::validation::operation::OperationValidationConfig::new(Some(schema), &[]), ) } diff --git a/crates/apollo-compiler/src/validation/field.rs b/crates/apollo-compiler/src/validation/field.rs index c1a3e883d..64c07b2e2 100644 --- a/crates/apollo-compiler/src/validation/field.rs +++ b/crates/apollo-compiler/src/validation/field.rs @@ -14,7 +14,7 @@ pub(crate) fn validate_field( // May be None if a parent selection was invalid against_type: Option<(&crate::Schema, &ast::NamedType)>, field: &Node, - context: OperationValidationConfig<'_>, + context: &OperationValidationConfig<'_>, ) { // First do all the validation that we can without knowing the type of the field. diff --git a/crates/apollo-compiler/src/validation/fragment.rs b/crates/apollo-compiler/src/validation/fragment.rs index 093566f47..f5c0aa8a5 100644 --- a/crates/apollo-compiler/src/validation/fragment.rs +++ b/crates/apollo-compiler/src/validation/fragment.rs @@ -52,6 +52,7 @@ fn validate_fragment_spread_type( against_type: &NamedType, type_condition: &NamedType, selection: &executable::Selection, + context: &OperationValidationConfig<'_>, ) { // Another diagnostic will be raised if the type condition was wrong. // We reduce noise by silencing other issues with the fragment. @@ -64,7 +65,7 @@ fn validate_fragment_spread_type( return; }; - let implementers_map = schema.implementers_map(); + let implementers_map = context.implementers_map(); let concrete_parent_types = get_possible_types(against_type_definition, &implementers_map); let concrete_condition_types = get_possible_types(type_condition_definition, &implementers_map); @@ -107,7 +108,7 @@ pub(crate) fn validate_inline_fragment( document: &ExecutableDocument, against_type: Option<(&crate::Schema, &ast::NamedType)>, inline: &Node, - context: OperationValidationConfig<'_>, + context: &OperationValidationConfig<'_>, ) { super::directive::validate_directives( diagnostics, @@ -138,6 +139,7 @@ pub(crate) fn validate_inline_fragment( against_type, type_condition, &executable::Selection::InlineFragment(inline.clone()), + &context, ); } super::selection::validate_selection_set( @@ -159,7 +161,7 @@ pub(crate) fn validate_fragment_spread( document: &ExecutableDocument, against_type: Option<(&crate::Schema, &NamedType)>, spread: &Node, - context: OperationValidationConfig<'_>, + context: &OperationValidationConfig<'_>, ) { super::directive::validate_directives( diagnostics, @@ -179,6 +181,7 @@ pub(crate) fn validate_fragment_spread( against_type, def.type_condition(), &executable::Selection::FragmentSpread(spread.clone()), + context, ); } validate_fragment_definition(diagnostics, document, def, context); @@ -198,7 +201,7 @@ pub(crate) fn validate_fragment_definition( diagnostics: &mut DiagnosticList, document: &ExecutableDocument, fragment: &Node, - context: OperationValidationConfig<'_>, + context: &OperationValidationConfig<'_>, ) { super::directive::validate_directives( diagnostics, diff --git a/crates/apollo-compiler/src/validation/operation.rs b/crates/apollo-compiler/src/validation/operation.rs index a5f9c5975..484369441 100644 --- a/crates/apollo-compiler/src/validation/operation.rs +++ b/crates/apollo-compiler/src/validation/operation.rs @@ -1,12 +1,41 @@ +use std::collections::HashMap; +use std::sync::OnceLock; + +use crate::ast; +use crate::ast::Name; +use crate::executable; +use crate::schema::Implementers; use crate::validation::DiagnosticList; -use crate::{ast, executable, ExecutableDocument, Node, Schema}; +use crate::ExecutableDocument; +use crate::Node; +use crate::Schema; -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct OperationValidationConfig<'a> { /// When None, rules that require a schema to validate are disabled. - pub schema: Option<&'a crate::Schema>, + pub schema: Option<&'a Schema>, /// The variables defined for this operation. pub variables: &'a [Node], + implementers_map: OnceLock>, +} + +impl<'a> OperationValidationConfig<'a> { + pub fn new(schema: Option<&'a Schema>, variables: &'a [Node]) -> Self { + Self { + schema, + variables, + implementers_map: Default::default(), + } + } + + /// Returns a cached reference to the implementers map. + pub fn implementers_map(&self) -> &HashMap { + self.implementers_map.get_or_init(|| { + self.schema + .map(|schema| schema.implementers_map()) + .unwrap_or_default() + }) + } } pub(crate) fn validate_subscription( @@ -60,10 +89,7 @@ pub(crate) fn validate_operation( document: &ExecutableDocument, operation: &executable::Operation, ) { - let config = OperationValidationConfig { - schema, - variables: &operation.variables, - }; + let config = OperationValidationConfig::new(schema, &operation.variables); let against_type = if let Some(schema) = schema { schema @@ -92,7 +118,7 @@ pub(crate) fn validate_operation( document, against_type, &operation.selection_set, - config, + &config, ); } diff --git a/crates/apollo-compiler/src/validation/selection.rs b/crates/apollo-compiler/src/validation/selection.rs index 514e9c616..8741b02d5 100644 --- a/crates/apollo-compiler/src/validation/selection.rs +++ b/crates/apollo-compiler/src/validation/selection.rs @@ -545,24 +545,20 @@ pub(crate) fn validate_selection_set( document: &ExecutableDocument, against_type: Option<(&crate::Schema, &NamedType)>, selection_set: &SelectionSet, - context: OperationValidationConfig<'_>, + context: &OperationValidationConfig<'_>, ) { for selection in &selection_set.selections { match selection { - executable::Selection::Field(field) => super::field::validate_field( - diagnostics, - document, - against_type, - field, - context.clone(), - ), + executable::Selection::Field(field) => { + super::field::validate_field(diagnostics, document, against_type, field, context) + } executable::Selection::FragmentSpread(fragment) => { super::fragment::validate_fragment_spread( diagnostics, document, against_type, fragment, - context.clone(), + context, ) } executable::Selection::InlineFragment(inline) => { @@ -571,7 +567,7 @@ pub(crate) fn validate_selection_set( document, against_type, inline, - context.clone(), + context, ) } }