diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 47e85cb..4cf02c0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,7 +18,15 @@ jobs: uses: Swatinem/rust-cache@v1 - name: Test Rust - run: cargo test + run: | + # features=graphql_parser_fork + cargo test --features graphql_parser_fork --no-default-features + # features=graphql_parser + cargo test - name: Build Rust - run: cargo build --release \ No newline at end of file + run: | + # features=graphql_parser_fork + cargo build --release --features graphql_parser_fork --no-default-features + # features=graphql_parser + cargo build --release diff --git a/Cargo.lock b/Cargo.lock index b3eb7e9..3929b12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,9 +37,15 @@ checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" @@ -89,6 +95,16 @@ dependencies = [ "unreachable", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -176,9 +192,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "fnv" @@ -192,7 +208,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ebc8013b4426d5b81a4364c419a95ed0b404af2b82e2457de52d9348f0e474" dependencies = [ - "combine", + "combine 3.8.1", + "thiserror", +] + +[[package]] +name = "graphql-parser-hive-fork" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0137d5de726e9c6ddb3e6abcddc4fc3fd1c1cfcf23667388b6ccec9fa6433f" +dependencies = [ + "combine 4.6.7", "thiserror", ] @@ -201,6 +227,7 @@ name = "graphql-tools" version = "0.2.5" dependencies = [ "graphql-parser", + "graphql-parser-hive-fork", "lazy_static", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 95fbba1..205193d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,14 @@ documentation = "https://github.com/dotansimha/graphql-tools-rs" authors = ["Dotan Simha "] [dependencies] -graphql-parser = "^0.4.0" +graphql-parser = { version = "^0.4.0", optional = true } +graphql-parser-hive-fork = { version = "^0.5.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_with = "2.2.0" -[dev-dependencies] -graphql-parser = "0.4.0" +[features] +default = ["graphql_parser"] +graphql_parser_fork = ["dep:graphql-parser-hive-fork"] +graphql_parser = ["dep:graphql-parser"] diff --git a/README.md b/README.md index 3b9073a..84fdb9a 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [Documentation](https://docs.rs/graphql-tools) | [Crate](https://crates.io/crates/graphql-tools) | [GitHub](https://github.com/dotansimha/graphql-tools-rs) -> **Note: this crate is still under development (see roadmap below)** - The [`graphql_tools` crate](https://crates.io/crates/graphql-tools) implements tooling around GraphQL for Rust libraries. Most of the tools are based on `trait`s and `struct`s implemented in [`graphql_parser` crate](https://crates.io/crates/graphql-parser). The goal of this library is to create a common layer of tools that has similar/improved APIs to [`graphql-js` reference implementation](https://github.com/graphql/graphql-js) and [`graphql-tools` from the JS/TS ecosystem](https://github.com/ardatan/graphql-tools). @@ -25,23 +23,16 @@ Or, if you are using [`cargo-edit`](https://github.com/killercup/cargo-edit): cargo add graphql-tools ``` -### Roadmap and progress - -- [ ] Better documentation -- [x] AST Visitor for GraphQL schema (`graphql_parser::schema::Document`) -- [x] AST Visitor for GraphQL operations (`graphql_parser::operation::Document`) -- [x] AST Visitor with TypeInfo -- [x] AST tools (ongoing) -- [x] `struct` extensions -- [x] GraphQL Validation engine -- [x] Validation rules -- [x] GraphQL operations transformer +By default, this crate is using the [`graphql-parser`](https://github.com/graphql-rust/graphql-parser) library for parsing. If you wish to use an alternative implementation such as [`graphql-hive/graphql-parser-hive-fork`](https://github.com/graphql-hive/graphql-parser-hive-fork), use the following `features` setup: -> If you have an idea / missing feature, feel free to open an issue / start a GitHub discussion! +```toml +[dependencies] +graphql-tools = { version = "...", features = "graphql_parser_fork", default-features = false } +``` #### Validation Rules -> This comparison is based on `graphql-js` refernece implementation. +> This comparison is based on `graphql-js` refernece implementation. - [x] ExecutableDefinitions (not actually needed) - [x] UniqueOperationNames @@ -68,4 +59,4 @@ cargo add graphql-tools - [x] ProvidedRequiredArguments - [x] VariablesInAllowedPosition - [x] OverlappingFieldsCanBeMerged -- [ ] UniqueInputFieldNames (blocked by https://github.com/graphql-rust/graphql-parser/issues/59) \ No newline at end of file +- [ ] UniqueInputFieldNames (blocked by https://github.com/graphql-rust/graphql-parser/issues/59) diff --git a/src/ast/collect_fields.rs b/src/ast/collect_fields.rs index c03de3a..edb0da2 100644 --- a/src/ast/collect_fields.rs +++ b/src/ast/collect_fields.rs @@ -47,7 +47,7 @@ fn does_fragment_condition_match<'a>( return interface_type.is_implemented_by(current_selection_set_type) } TypeDefinition::Union(union_type) => { - return union_type.has_sub_type(¤t_selection_set_type.name()) + return union_type.has_sub_type(current_selection_set_type.name()) } _ => return false, } @@ -70,14 +70,14 @@ fn collect_fields_inner<'a>( ) { selection_set.items.iter().for_each(|item| match item { Selection::Field(f) => { - let existing = result_arr.entry(f.name.clone()).or_insert(vec![]); + let existing = result_arr.entry(f.name.clone()).or_default(); existing.push(f.clone()); } Selection::InlineFragment(f) => { if does_fragment_condition_match(&f.type_condition, parent_type, context) { collect_fields_inner( &f.selection_set, - &parent_type, + parent_type, known_fragments, context, result_arr, @@ -86,22 +86,21 @@ fn collect_fields_inner<'a>( } } Selection::FragmentSpread(f) => { - if visited_fragments_names + if !visited_fragments_names .iter() - .find(|name| f.fragment_name.eq(*name)) - .is_none() + .any(|name| f.fragment_name.eq(name)) { visited_fragments_names.push(f.fragment_name.clone()); if let Some(fragment) = known_fragments.get(f.fragment_name.as_str()) { if does_fragment_condition_match( &Some(fragment.type_condition.clone()), - &parent_type, + parent_type, context, ) { collect_fields_inner( &fragment.selection_set, - &parent_type, + parent_type, known_fragments, context, result_arr, diff --git a/src/ast/ext.rs b/src/ast/ext.rs index b2fb4b5..140c974 100644 --- a/src/ast/ext.rs +++ b/src/ast/ext.rs @@ -57,7 +57,7 @@ impl OperationDefinitionExtension for OperationDefinition { fn selection_set(&self) -> &SelectionSet { match self { OperationDefinition::Query(query) => &query.selection_set, - OperationDefinition::SelectionSet(selection_set) => &selection_set, + OperationDefinition::SelectionSet(selection_set) => selection_set, OperationDefinition::Mutation(mutation) => &mutation.selection_set, OperationDefinition::Subscription(subscription) => &subscription.selection_set, } @@ -156,7 +156,7 @@ impl SchemaDocumentExtension for schema::Document { self.schema_definition() .subscription .as_ref() - .and_then(|name| self.object_type_by_name(&name)) + .and_then(|name| self.object_type_by_name(name)) } fn object_type_by_name(&self, name: &str) -> Option<&ObjectType> { @@ -185,7 +185,7 @@ impl SchemaDocumentExtension for schema::Document { self.type_by_name(sub_type_name), self.type_by_name(super_type_name), ) { - super_type.is_abstract_type() && self.is_possible_type(&super_type, &sub_type) + super_type.is_abstract_type() && self.is_possible_type(super_type, sub_type) } else { false } @@ -206,7 +206,7 @@ impl SchemaDocumentExtension for schema::Document { TypeDefinition::Interface(interface_typedef) => { let implementes_interfaces = possible_type.interfaces(); - return implementes_interfaces.contains(&interface_typedef.name); + implementes_interfaces.contains(&interface_typedef.name) } _ => false, } @@ -248,12 +248,12 @@ impl SchemaDocumentExtension for schema::Document { // If superType type is an abstract type, check if it is super type of maybeSubType. // Otherwise, the child type is not a valid subtype of the parent type. if let (Some(sub_type), Some(super_type)) = ( - self.type_by_name(&sub_type.inner_type()), - self.type_by_name(&super_type.inner_type()), + self.type_by_name(sub_type.inner_type()), + self.type_by_name(super_type.inner_type()), ) { return super_type.is_abstract_type() && (sub_type.is_interface_type() || sub_type.is_object_type()) - && self.is_possible_type(&super_type, &sub_type); + && self.is_possible_type(super_type, sub_type); } false @@ -350,7 +350,7 @@ pub trait InputValueHelpers { impl InputValueHelpers for InputValue { fn is_required(&self) -> bool { if let Type::NonNullType(_inner_type) = &self.value_type { - if let None = &self.default_value { + if self.default_value.is_none() { return true; } } @@ -394,22 +394,20 @@ impl ImplementingInterfaceExtension for TypeDefinition { fn has_sub_type(&self, other_type: &TypeDefinition) -> bool { match self { TypeDefinition::Interface(interface_type) => { - return interface_type.is_implemented_by(other_type) + interface_type.is_implemented_by(other_type) } TypeDefinition::Union(union_type) => return union_type.has_sub_type(other_type.name()), - _ => return false, + _ => false, } } fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool { match self { TypeDefinition::Interface(interface_type) => { - return interface_type.is_implemented_by(concrete_type) - } - TypeDefinition::Union(union_type) => { - return union_type.has_sub_type(&concrete_type.name) + interface_type.is_implemented_by(concrete_type) } - _ => return false, + TypeDefinition::Union(union_type) => union_type.has_sub_type(&concrete_type.name), + _ => false, } } } @@ -487,17 +485,13 @@ pub trait SubTypeExtension { impl SubTypeExtension for UnionType { fn has_sub_type(&self, other_type_name: &str) -> bool { - self.types.iter().find(|v| other_type_name.eq(*v)).is_some() + self.types.iter().any(|v| other_type_name.eq(v)) } } impl AbstractTypeDefinitionExtension for InterfaceType { fn is_implemented_by(&self, other_type: &dyn ImplementingInterfaceExtension) -> bool { - other_type - .interfaces() - .iter() - .find(|v| self.name.eq(*v)) - .is_some() + other_type.interfaces().iter().any(|v| self.name.eq(v)) } } @@ -627,31 +621,19 @@ impl TypeDefinitionExtension for schema::TypeDefinition { } fn is_object_type(&self) -> bool { - match self { - schema::TypeDefinition::Object(_o) => true, - _ => false, - } + matches!(self, schema::TypeDefinition::Object(_o)) } fn is_union_type(&self) -> bool { - match self { - schema::TypeDefinition::Union(_o) => true, - _ => false, - } + matches!(self, schema::TypeDefinition::Union(_o)) } fn is_enum_type(&self) -> bool { - match self { - schema::TypeDefinition::Enum(_o) => true, - _ => false, - } + matches!(self, schema::TypeDefinition::Enum(_o)) } fn is_scalar_type(&self) -> bool { - match self { - schema::TypeDefinition::Scalar(_o) => true, - _ => false, - } + matches!(self, schema::TypeDefinition::Scalar(_o)) } } diff --git a/src/ast/operation_transformer.rs b/src/ast/operation_transformer.rs index 62232b5..2cf52dd 100644 --- a/src/ast/operation_transformer.rs +++ b/src/ast/operation_transformer.rs @@ -1,4 +1,4 @@ -use graphql_parser::query::*; +use crate::parser::query::*; #[derive(Clone, Debug)] pub enum Transformed { @@ -31,9 +31,9 @@ impl TransformedValue { } } -impl Into> for TransformedValue { - fn into(self) -> Transformed { - match self { +impl From> for Transformed { + fn from(val: TransformedValue) -> Self { + match val { TransformedValue::Keep => Transformed::Keep, TransformedValue::Replace(replacement) => Transformed::Replace(replacement), } @@ -370,7 +370,7 @@ pub trait OperationTransformer<'a, T: Text<'a> + Clone> { fn transform_directives( &mut self, - directives: &Vec>, + directives: &[Directive<'a, T>], ) -> TransformedValue>> { self.transform_list(directives, Self::transform_directive) } @@ -417,7 +417,7 @@ pub trait OperationTransformer<'a, T: Text<'a> + Clone> { ) -> Transformed<(T::Value, Value<'a, T>)> { let (name, value) = argument; - match self.transform_value(&value) { + match self.transform_value(value) { TransformedValue::Keep => Transformed::Keep, TransformedValue::Replace(replacement) => { Transformed::Replace((name.clone(), replacement)) @@ -452,7 +452,7 @@ pub trait OperationTransformer<'a, T: Text<'a> + Clone> { fn default_transform_variable_definitions( &mut self, - variable_definitions: &Vec>, + variable_definitions: &[VariableDefinition<'a, T>], ) -> TransformedValue>> { self.transform_list( variable_definitions, @@ -486,7 +486,7 @@ pub trait OperationTransformer<'a, T: Text<'a> + Clone> { } } - return TransformedValue::Keep; + TransformedValue::Keep } fn transform_list(&mut self, list: &[I], f: F) -> TransformedValue> @@ -582,8 +582,8 @@ mod tests { fn transform_field( &mut self, - field: &graphql_parser::query::Field<'a, T>, - ) -> Transformed> { + field: &crate::parser::query::Field<'a, T>, + ) -> Transformed> { let selection_set = self.transform_selection_set(&field.selection_set); let arguments = self.transform_arguments(&field.arguments); let directives = self.transform_directives(&field.directives); diff --git a/src/ast/operation_visitor.rs b/src/ast/operation_visitor.rs index 278321f..044e245 100644 --- a/src/ast/operation_visitor.rs +++ b/src/ast/operation_visitor.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, HashMap}; -use graphql_parser::query::TypeCondition; +use crate::parser::query::TypeCondition; use crate::static_graphql::{ query::{self, *}, @@ -55,11 +55,11 @@ impl<'a> OperationVisitorContext<'a> { pub fn with_type(&mut self, t: Option<&Type>, func: Func) where - Func: FnOnce(&mut OperationVisitorContext<'a>) -> (), + Func: FnOnce(&mut OperationVisitorContext<'a>), { if let Some(t) = t { self.type_stack - .push(self.schema.type_by_name(&t.inner_type())); + .push(self.schema.type_by_name(t.inner_type())); } else { self.type_stack.push(None); } @@ -72,17 +72,17 @@ impl<'a> OperationVisitorContext<'a> { pub fn with_parent_type(&mut self, func: Func) where - Func: FnOnce(&mut OperationVisitorContext<'a>) -> (), + Func: FnOnce(&mut OperationVisitorContext<'a>), { self.parent_type_stack - .push(self.type_stack.last().unwrap_or(&None).clone()); + .push(*self.type_stack.last().unwrap_or(&None)); func(self); self.parent_type_stack.pop(); } pub fn with_field<'f, Func>(&mut self, f: Option<&'f schema::Field>, func: Func) where - Func: FnOnce(&mut OperationVisitorContext<'a>) -> (), + Func: FnOnce(&mut OperationVisitorContext<'a>), 'f: 'a, { if let Some(f) = f { @@ -97,11 +97,11 @@ impl<'a> OperationVisitorContext<'a> { pub fn with_input_type(&mut self, t: Option<&'a Type>, func: Func) where - Func: FnOnce(&mut OperationVisitorContext<'a>) -> (), + Func: FnOnce(&mut OperationVisitorContext<'a>), { - if let Some(ref t) = t { + if let Some(t) = t { self.input_type_stack - .push(self.schema.type_by_name(&t.inner_type())); + .push(self.schema.type_by_name(t.inner_type())); } else { self.input_type_stack.push(None); } @@ -277,9 +277,9 @@ fn visit_input_value<'a, Visitor, UserContext>( for (sub_key, sub_value) in v.iter() { let input_type = context .current_input_type_literal() - .and_then(|v| context.schema.type_by_name(&v.inner_type())) - .and_then(|v| v.input_field_by_name(&sub_key)) - .and_then(|v| Some(&v.value_type)); + .and_then(|v| context.schema.type_by_name(v.inner_type())) + .and_then(|v| v.input_field_by_name(sub_key)) + .map(|v| &v.value_type); context.with_input_type(input_type, |context| { let param = &(sub_key.clone(), sub_value.clone()); @@ -311,7 +311,7 @@ fn visit_variable_definitions<'a, Visitor, UserContext>( visitor.enter_variable_definition(context, user_context, variable); if let Some(default_value) = &variable.default_value { - visit_input_value(visitor, &default_value, context, user_context); + visit_input_value(visitor, default_value, context, user_context); } // DOTAN: We should visit the directives as well here, but it's extracted in graphql_parser. @@ -335,7 +335,7 @@ fn visit_selection<'a, Visitor, UserContext>( .current_parent_type() .and_then(|t| t.field_by_name(&field.name)); - let field_type = parent_type_def.clone().map(|f| &f.field_type); + let field_type = parent_type_def.map(|f| &f.field_type); let field_args = parent_type_def.map(|f| &f.arguments); context.with_type(field_type, |context| { diff --git a/src/ast/schema_visitor.rs b/src/ast/schema_visitor.rs index 73f4fa3..8f75fd9 100644 --- a/src/ast/schema_visitor.rs +++ b/src/ast/schema_visitor.rs @@ -174,7 +174,7 @@ pub trait SchemaVisitor { #[test] fn visit_schema() { - use graphql_parser::schema::parse_schema; + use crate::parser::schema::parse_schema; let schema_ast = parse_schema( r#" scalar Date diff --git a/src/lib.rs b/src/lib.rs index c472c23..103cbc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ pub mod static_graphql { macro_rules! static_graphql { ($m:ident, $m2:ident, {$($n:ident,)*}) => { pub mod $m { - use graphql_parser::$m2 as $m; + use crate::parser::$m2 as $m; pub use $m::*; $( pub type $n = $m::$n<'static, String>; @@ -35,3 +35,8 @@ pub mod static_graphql { pub mod introspection; pub mod validation; + +#[cfg(feature = "graphql_parser")] +pub extern crate graphql_parser as parser; +#[cfg(feature = "graphql_parser_fork")] +pub extern crate graphql_parser_hive_fork as parser; diff --git a/src/validation/rules/fields_on_correct_type.rs b/src/validation/rules/fields_on_correct_type.rs index abf05f8..89fe9b4 100644 --- a/src/validation/rules/fields_on_correct_type.rs +++ b/src/validation/rules/fields_on_correct_type.rs @@ -13,6 +13,12 @@ use super::ValidationRule; /// See https://spec.graphql.org/draft/#sec-Field-Selections pub struct FieldsOnCorrectType; +impl Default for FieldsOnCorrectType { + fn default() -> Self { + Self::new() + } +} + impl FieldsOnCorrectType { pub fn new() -> Self { FieldsOnCorrectType @@ -56,7 +62,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for FieldsOnCorrectType { return; } - if let None = parent_type.field_by_name(field_name) { + if parent_type.field_by_name(field_name).is_none() { user_context.report_error(ValidationError { error_code: self.error_code(), locations: vec![field.position], @@ -75,14 +81,14 @@ impl ValidationRule for FieldsOnCorrectType { "FieldsOnCorrectType" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut FieldsOnCorrectType::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -124,7 +130,7 @@ fn object_field_selection() { __typename name }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -141,7 +147,7 @@ fn aliased_object_field_selection() { tn : __typename otherName : name }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -158,7 +164,7 @@ fn interface_field_selection() { __typename name }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -174,7 +180,7 @@ fn aliased_interface_field_selection() { "fragment interfaceFieldSelection on Pet { otherName : name }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -190,7 +196,7 @@ fn lying_alias_selection() { "fragment lyingAliasSelection on Dog { name : nickname }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -206,7 +212,7 @@ fn ignores_fields_on_unknown_type() { "fragment unknownSelection on UnknownType { unknownField }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -226,7 +232,7 @@ fn reports_errors_when_type_is_known_again() { } } }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -250,7 +256,7 @@ fn field_not_defined_on_fragment() { "fragment fieldNotDefined on Dog { meowVolume }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -273,7 +279,7 @@ fn ignores_deeply_unknown_field() { deeper_unknown_field } }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -296,7 +302,7 @@ fn sub_field_not_defined() { unknown_field } }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -319,7 +325,7 @@ fn field_not_defined_on_inline_fragment() { meowVolume } }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -340,7 +346,7 @@ fn aliased_field_target_not_defined() { "fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -361,7 +367,7 @@ fn aliased_lying_field_target_not_defined() { "fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -382,7 +388,7 @@ fn not_defined_on_interface() { "fragment notDefinedOnInterface on Pet { tailLength }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -403,7 +409,7 @@ fn defined_on_implementors_but_not_on_interface() { "fragment definedOnImplementorsButNotInterface on Pet { nickname }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -424,7 +430,7 @@ fn direct_field_selection_on_union() { "fragment directFieldSelectionOnUnion on CatOrDog { directField }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -445,7 +451,7 @@ fn defined_on_implementors_queried_on_union() { "fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -466,7 +472,7 @@ fn meta_field_selection_on_union() { "fragment directFieldSelectionOnUnion on CatOrDog { __typename }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -488,7 +494,7 @@ fn valid_field_in_inline_fragment() { name } }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); @@ -505,7 +511,7 @@ fn forbidden_typename_on_subscription_type() { "subscription { __typename }", - &FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, + FIELDS_ON_CORRECT_TYPE_TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/fragments_on_composite_types.rs b/src/validation/rules/fragments_on_composite_types.rs index c9c6097..1782683 100644 --- a/src/validation/rules/fragments_on_composite_types.rs +++ b/src/validation/rules/fragments_on_composite_types.rs @@ -15,6 +15,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// https://spec.graphql.org/draft/#sec-Fragments-On-Composite-Types pub struct FragmentsOnCompositeTypes; +impl Default for FragmentsOnCompositeTypes { + fn default() -> Self { + Self::new() + } +} + impl FragmentsOnCompositeTypes { pub fn new() -> Self { FragmentsOnCompositeTypes @@ -72,14 +78,14 @@ impl ValidationRule for FragmentsOnCompositeTypes { "FragmentsOnCompositeTypes" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut FragmentsOnCompositeTypes::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/known_argument_names.rs b/src/validation/rules/known_argument_names.rs index 37130ca..a1b58fd 100644 --- a/src/validation/rules/known_argument_names.rs +++ b/src/validation/rules/known_argument_names.rs @@ -24,6 +24,12 @@ enum ArgumentParent<'a> { Directive(&'a str), } +impl<'a> Default for KnownArgumentNames<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> KnownArgumentNames<'a> { pub fn new() -> Self { KnownArgumentNames { @@ -97,7 +103,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownArgumentNames<'a> match arg_position { ArgumentParent::Field(field_name, type_name) => { user_context.report_error(ValidationError { - error_code: self.error_code(), + error_code: self.error_code(), message: format!( "Unknown argument \"{}\" on field \"{}.{}\".", argument_name, @@ -109,7 +115,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownArgumentNames<'a> } ArgumentParent::Directive(directive_name) => { user_context.report_error(ValidationError { - error_code: self.error_code(), + error_code: self.error_code(), message: format!( "Unknown argument \"{}\" on directive \"@{}\".", argument_name, directive_name @@ -128,14 +134,14 @@ impl<'k> ValidationRule for KnownArgumentNames<'k> { "KnownArgumentNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut KnownArgumentNames::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -151,7 +157,7 @@ fn single_arg_is_known() { "fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -167,7 +173,7 @@ fn multple_args_are_known() { "fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -183,7 +189,7 @@ fn ignores_args_of_unknown_fields() { "fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -199,7 +205,7 @@ fn multiple_args_in_reverse_order_are_known() { "fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -215,7 +221,7 @@ fn no_args_on_optional_arg() { "fragment noArgOnOptionalArg on Dog { isHouseTrained }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -240,7 +246,7 @@ fn args_are_known_deeply() { } } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -256,7 +262,7 @@ fn directive_args_are_known() { "{ dog @skip(if: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -272,7 +278,7 @@ fn field_args_are_invalid() { "{ dog @skip(unless: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -293,7 +299,7 @@ fn directive_without_args_is_valid() { " { dog @onField }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -310,7 +316,7 @@ fn arg_passed_to_directive_without_arg_is_reported() { " { dog @onField(if: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -332,7 +338,7 @@ fn misspelled_directive_args_are_reported() { "{ dog @skip(iff: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -353,7 +359,7 @@ fn invalid_arg_name() { "fragment invalidArgName on Dog { doesKnowCommand(unknown: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -375,7 +381,7 @@ fn misspelled_arg_name_is_reported() { "fragment invalidArgName on Dog { doesKnowCommand(DogCommand: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -396,7 +402,7 @@ fn unknown_args_amongst_known_args() { "fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -429,7 +435,7 @@ fn unknown_args_deeply() { } } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/known_directives.rs b/src/validation/rules/known_directives.rs index b74f721..a9acf35 100644 --- a/src/validation/rules/known_directives.rs +++ b/src/validation/rules/known_directives.rs @@ -16,6 +16,12 @@ pub struct KnownDirectives { recent_location: Option, } +impl Default for KnownDirectives { + fn default() -> Self { + Self::new() + } +} + impl KnownDirectives { pub fn new() -> Self { KnownDirectives { @@ -133,7 +139,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownDirectives { .iter() .any(|l| l == current_location) { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![directive.position], message: format!( "Directive \"@{}\" may not be used on {}", @@ -144,7 +151,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownDirectives { } } } else { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![directive.position], message: format!("Unknown directive \"@{}\".", directive.name), }); @@ -157,14 +165,14 @@ impl ValidationRule for KnownDirectives { "KnownDirectives" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut KnownDirectives::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/known_fragment_names.rs b/src/validation/rules/known_fragment_names.rs index 3e55a31..e0c90b6 100644 --- a/src/validation/rules/known_fragment_names.rs +++ b/src/validation/rules/known_fragment_names.rs @@ -11,6 +11,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined pub struct KnownFragmentNames; +impl Default for KnownFragmentNames { + fn default() -> Self { + Self::new() + } +} + impl KnownFragmentNames { pub fn new() -> Self { KnownFragmentNames @@ -24,15 +30,15 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownFragmentNames { user_context: &mut ValidationErrorContext, fragment_spread: &FragmentSpread, ) { - match visitor_context + if !visitor_context .known_fragments - .get(fragment_spread.fragment_name.as_str()) + .contains_key(fragment_spread.fragment_name.as_str()) { - None => user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![fragment_spread.position], message: format!("Unknown fragment \"{}\".", fragment_spread.fragment_name), - }), - _ => {} + }) } } } @@ -42,14 +48,14 @@ impl ValidationRule for KnownFragmentNames { "KnownFragmentNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut KnownFragmentNames::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/known_type_names.rs b/src/validation/rules/known_type_names.rs index ea045bd..c945afd 100644 --- a/src/validation/rules/known_type_names.rs +++ b/src/validation/rules/known_type_names.rs @@ -14,6 +14,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence pub struct KnownTypeNames; +impl Default for KnownTypeNames { + fn default() -> Self { + Self::new() + } +} + impl KnownTypeNames { pub fn new() -> Self { KnownTypeNames @@ -29,13 +35,12 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownTypeNames { ) { let TypeCondition::On(fragment_type_name) = &fragment_definition.type_condition; - if let None = visitor_context.schema.type_by_name(fragment_type_name) { - if !fragment_type_name.starts_with("__") { - user_context.report_error(ValidationError {error_code: self.error_code(), - locations: vec![fragment_definition.position], - message: format!("Unknown type \"{}\".", fragment_type_name), - }); - } + if visitor_context.schema.type_by_name(fragment_type_name).is_none() && !fragment_type_name.starts_with("__") { + user_context.report_error(ValidationError { + error_code: self.error_code(), + locations: vec![fragment_definition.position], + message: format!("Unknown type \"{}\".", fragment_type_name), + }); } } @@ -46,13 +51,12 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownTypeNames { inline_fragment: &crate::static_graphql::query::InlineFragment, ) { if let Some(TypeCondition::On(fragment_type_name)) = &inline_fragment.type_condition { - if let None = visitor_context.schema.type_by_name(fragment_type_name) { - if !fragment_type_name.starts_with("__") { - user_context.report_error(ValidationError {error_code: self.error_code(), - locations: vec![inline_fragment.position], - message: format!("Unknown type \"{}\".", fragment_type_name), - }); - } + if visitor_context.schema.type_by_name(fragment_type_name).is_none() && !fragment_type_name.starts_with("__") { + user_context.report_error(ValidationError { + error_code: self.error_code(), + locations: vec![inline_fragment.position], + message: format!("Unknown type \"{}\".", fragment_type_name), + }); } } } @@ -65,13 +69,12 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownTypeNames { ) { let base_type = variable_definition.var_type.inner_type(); - if let None = visitor_context.schema.type_by_name(&base_type) { - if !base_type.starts_with("__") { - user_context.report_error(ValidationError {error_code: self.error_code(), - locations: vec![variable_definition.position], - message: format!("Unknown type \"{}\".", base_type), - }); - } + if visitor_context.schema.type_by_name(base_type).is_none() && !base_type.starts_with("__") { + user_context.report_error(ValidationError { + error_code: self.error_code(), + locations: vec![variable_definition.position], + message: format!("Unknown type \"{}\".", base_type), + }); } } } @@ -81,14 +84,14 @@ impl ValidationRule for KnownTypeNames { "KnownTypeNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut KnownTypeNames::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -114,7 +117,7 @@ fn known_type_names_are_valid() { fragment PetFields on Pet { name }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -138,7 +141,7 @@ fn unknown_type_names_are_invalid() { fragment PetFields on Peat { name }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/leaf_field_selections.rs b/src/validation/rules/leaf_field_selections.rs index cf7675d..142cf39 100644 --- a/src/validation/rules/leaf_field_selections.rs +++ b/src/validation/rules/leaf_field_selections.rs @@ -11,6 +11,12 @@ use crate::{ /// https://spec.graphql.org/draft/#sec-Leaf-Field-Selections pub struct LeafFieldSelections; +impl Default for LeafFieldSelections { + fn default() -> Self { + Self::new() + } +} + impl LeafFieldSelections { pub fn new() -> Self { LeafFieldSelections @@ -32,7 +38,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for LeafFieldSelections { if field_type.is_leaf_type() { if field_selection_count > 0 { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![field.position], message: format!( "Field \"{}\" must not have a selection since type \"{}\" has no subfields.", @@ -41,19 +48,17 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for LeafFieldSelections { ), }); } - } else { - if field_selection_count == 0 { - user_context.report_error(ValidationError {error_code: self.error_code(), - locations: vec![field.position], - message: format!( - "Field \"{}\" of type \"{}\" must have a selection of subfields. Did you mean \"{} {{ ... }}\"?", - field.name, - field_type_literal, - field.name - ), - }); - } - } + } else if field_selection_count == 0 { + user_context.report_error(ValidationError {error_code: self.error_code(), + locations: vec![field.position], + message: format!( + "Field \"{}\" of type \"{}\" must have a selection of subfields. Did you mean \"{} {{ ... }}\"?", + field.name, + field_type_literal, + field.name + ), + }); + } } } } @@ -63,14 +68,14 @@ impl ValidationRule for LeafFieldSelections { "LeafFieldSelections" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut LeafFieldSelections::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/lone_anonymous_operation.rs b/src/validation/rules/lone_anonymous_operation.rs index 33df726..42a6f39 100644 --- a/src/validation/rules/lone_anonymous_operation.rs +++ b/src/validation/rules/lone_anonymous_operation.rs @@ -11,6 +11,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// https://spec.graphql.org/draft/#sec-Lone-Anonymous-Operation pub struct LoneAnonymousOperation; +impl Default for LoneAnonymousOperation { + fn default() -> Self { + Self::new() + } +} + impl LoneAnonymousOperation { pub fn new() -> Self { LoneAnonymousOperation @@ -40,7 +46,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for LoneAnonymousOperation match definition { Definition::Operation(OperationDefinition::SelectionSet(_)) => { if operations_count > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: "This anonymous operation must be the only defined operation." .to_string(), locations: vec![], @@ -48,29 +55,32 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for LoneAnonymousOperation } } Definition::Operation(OperationDefinition::Query(query)) => { - if query.name == None && operations_count > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + if query.name.is_none() && operations_count > 1 { + user_context.report_error(ValidationError { + error_code: self.error_code(), message: "This anonymous operation must be the only defined operation." .to_string(), - locations: vec![query.position.clone()], + locations: vec![query.position], }) } } Definition::Operation(OperationDefinition::Mutation(mutation)) => { - if mutation.name == None && operations_count > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + if mutation.name.is_none() && operations_count > 1 { + user_context.report_error(ValidationError { + error_code: self.error_code(), message: "This anonymous operation must be the only defined operation." .to_string(), - locations: vec![mutation.position.clone()], + locations: vec![mutation.position], }) } } Definition::Operation(OperationDefinition::Subscription(subscription)) => { - if subscription.name == None && operations_count > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + if subscription.name.is_none() && operations_count > 1 { + user_context.report_error(ValidationError { + error_code: self.error_code(), message: "This anonymous operation must be the only defined operation." .to_string(), - locations: vec![subscription.position.clone()], + locations: vec![subscription.position], }) } } @@ -85,14 +95,14 @@ impl ValidationRule for LoneAnonymousOperation { "LoneAnonymousOperation" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut LoneAnonymousOperation::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/no_fragments_cycle.rs b/src/validation/rules/no_fragments_cycle.rs index d091470..90e5b3f 100644 --- a/src/validation/rules/no_fragments_cycle.rs +++ b/src/validation/rules/no_fragments_cycle.rs @@ -15,6 +15,12 @@ pub struct NoFragmentsCycle { visited_fragments: HashSet, } +impl Default for NoFragmentsCycle { + fn default() -> Self { + Self::new() + } +} + impl NoFragmentsCycle { pub fn new() -> Self { Self { @@ -41,7 +47,7 @@ impl NoFragmentsCycle { let spread_nodes = fragment.selection_set.get_recursive_fragment_spreads(); - if spread_nodes.len() == 0 { + if spread_nodes.is_empty() { return; } @@ -64,7 +70,7 @@ impl NoFragmentsCycle { } } Some(cycle_index) => { - let cycle_path = &spread_paths[cycle_index.clone()..]; + let cycle_path = &spread_paths[*cycle_index..]; let via_path = match cycle_path.len() { 0 => vec![], _ => cycle_path[0..cycle_path.len() - 1] @@ -73,8 +79,9 @@ impl NoFragmentsCycle { .collect::>(), }; - error_context.report_error(ValidationError {error_code: self.error_code(), - locations: cycle_path.iter().map(|f| f.position.clone()).collect(), + error_context.report_error(ValidationError { + error_code: self.error_code(), + locations: cycle_path.iter().map(|f| f.position).collect(), message: match via_path.len() { 0 => { format!("Cannot spread fragment \"{}\" within itself.", spread_name) @@ -121,14 +128,14 @@ impl ValidationRule for NoFragmentsCycle { "NoFragmentsCycle" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut NoFragmentsCycle::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/no_undefined_variables.rs b/src/validation/rules/no_undefined_variables.rs index 50ba5ab..1a2c30e 100644 --- a/src/validation/rules/no_undefined_variables.rs +++ b/src/validation/rules/no_undefined_variables.rs @@ -13,10 +13,16 @@ use std::collections::{HashMap, HashSet}; /// /// See https://spec.graphql.org/draft/#sec-All-Variable-Uses-Defined pub struct NoUndefinedVariables<'a> { - current_scope: Option>, + current_scope: Option>, defined_variables: HashMap, HashSet<&'a str>>, - used_variables: HashMap, Vec<&'a str>>, - spreads: HashMap, Vec<&'a str>>, + used_variables: HashMap, Vec<&'a str>>, + spreads: HashMap, Vec<&'a str>>, +} + +impl<'a> Default for NoUndefinedVariables<'a> { + fn default() -> Self { + Self::new() + } } impl<'a> NoUndefinedVariables<'a> { @@ -33,10 +39,10 @@ impl<'a> NoUndefinedVariables<'a> { impl<'a> NoUndefinedVariables<'a> { fn find_undefined_vars( &self, - from: &Scope<'a>, + from: &NoUndefinedVariablesScope<'a>, defined: &HashSet<&str>, unused: &mut HashSet<&'a str>, - visited: &mut HashSet>, + visited: &mut HashSet>, ) { if visited.contains(from) { return; @@ -54,14 +60,19 @@ impl<'a> NoUndefinedVariables<'a> { if let Some(spreads) = self.spreads.get(from) { for spread in spreads { - self.find_undefined_vars(&Scope::Fragment(spread), defined, unused, visited); + self.find_undefined_vars( + &NoUndefinedVariablesScope::Fragment(spread), + defined, + unused, + visited, + ); } } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Scope<'a> { +pub enum NoUndefinedVariablesScope<'a> { Operation(Option<&'a str>), Fragment(&'a str), } @@ -74,7 +85,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' operation_definition: &'a OperationDefinition, ) { let op_name = operation_definition.node_name(); - self.current_scope = Some(Scope::Operation(op_name)); + self.current_scope = Some(NoUndefinedVariablesScope::Operation(op_name)); self.defined_variables.insert(op_name, HashSet::new()); } @@ -84,7 +95,9 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' _: &mut ValidationErrorContext, fragment_definition: &'a query::FragmentDefinition, ) { - self.current_scope = Some(Scope::Fragment(&fragment_definition.name)); + self.current_scope = Some(NoUndefinedVariablesScope::Fragment( + &fragment_definition.name, + )); } fn enter_fragment_spread( @@ -96,7 +109,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' if let Some(scope) = &self.current_scope { self.spreads .entry(scope.clone()) - .or_insert_with(Vec::new) + .or_default() .push(&fragment_spread.fragment_name); } } @@ -107,7 +120,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' _: &mut ValidationErrorContext, variable_definition: &'a query::VariableDefinition, ) { - if let Some(Scope::Operation(ref name)) = self.current_scope { + if let Some(NoUndefinedVariablesScope::Operation(ref name)) = self.current_scope { if let Some(vars) = self.defined_variables.get_mut(name) { vars.insert(&variable_definition.name); } @@ -123,7 +136,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' if let Some(ref scope) = self.current_scope { self.used_variables .entry(scope.clone()) - .or_insert_with(Vec::new) + .or_default() .append(&mut arg_value.variables_in_use()); } } @@ -139,15 +152,16 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUndefinedVariables<' let mut visited = HashSet::new(); self.find_undefined_vars( - &Scope::Operation(op_name.clone()), + &NoUndefinedVariablesScope::Operation(*op_name), def_vars, &mut unused, &mut visited, ); unused.iter().for_each(|var| { - user_context.report_error(ValidationError {error_code: self.error_code(), - message: error_message(&var, op_name), + user_context.report_error(ValidationError { + error_code: self.error_code(), + message: error_message(var, op_name), locations: vec![], }) }) @@ -171,14 +185,14 @@ impl<'n> ValidationRule for NoUndefinedVariables<'n> { "NoUndefinedVariables" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut NoUndefinedVariables::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/no_unused_fragments.rs b/src/validation/rules/no_unused_fragments.rs index 02ba9da..b23c085 100644 --- a/src/validation/rules/no_unused_fragments.rs +++ b/src/validation/rules/no_unused_fragments.rs @@ -34,14 +34,15 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedFragments<'a> .known_fragments .iter() .filter_map(|(fragment_name, _fragment)| { - if !self.fragments_in_use.contains(&fragment_name) { - Some(fragment_name.clone()) + if !self.fragments_in_use.contains(fragment_name) { + Some(fragment_name) } else { None } }) .for_each(|unused_fragment_name| { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![], message: format!("Fragment \"{}\" is never used.", unused_fragment_name), }); @@ -49,6 +50,12 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedFragments<'a> } } +impl<'a> Default for NoUnusedFragments<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> NoUnusedFragments<'a> { pub fn new() -> Self { NoUnusedFragments { @@ -62,14 +69,14 @@ impl<'n> ValidationRule for NoUnusedFragments<'n> { "NoUnusedFragments" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut NoUnusedFragments::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/no_unused_variables.rs b/src/validation/rules/no_unused_variables.rs index cfc5886..a4c5589 100644 --- a/src/validation/rules/no_unused_variables.rs +++ b/src/validation/rules/no_unused_variables.rs @@ -14,10 +14,16 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// /// See https://spec.graphql.org/draft/#sec-All-Variables-Used pub struct NoUnusedVariables<'a> { - current_scope: Option>, + current_scope: Option>, defined_variables: HashMap, HashSet<&'a str>>, - used_variables: HashMap, Vec<&'a str>>, - spreads: HashMap, Vec<&'a str>>, + used_variables: HashMap, Vec<&'a str>>, + spreads: HashMap, Vec<&'a str>>, +} + +impl<'a> Default for NoUnusedVariables<'a> { + fn default() -> Self { + Self::new() + } } impl<'a> NoUnusedVariables<'a> { @@ -34,10 +40,10 @@ impl<'a> NoUnusedVariables<'a> { impl<'a> NoUnusedVariables<'a> { fn find_used_vars( &self, - from: &Scope<'a>, + from: &NoUnusedVariablesScope<'a>, defined: &HashSet<&str>, used: &mut HashSet<&'a str>, - visited: &mut HashSet>, + visited: &mut HashSet>, ) { if visited.contains(from) { return; @@ -55,14 +61,19 @@ impl<'a> NoUnusedVariables<'a> { if let Some(spreads) = self.spreads.get(from) { for spread in spreads { - self.find_used_vars(&Scope::Fragment(spread), defined, used, visited); + self.find_used_vars( + &NoUnusedVariablesScope::Fragment(spread), + defined, + used, + visited, + ); } } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Scope<'a> { +pub enum NoUnusedVariablesScope<'a> { Operation(Option<&'a str>), Fragment(&'a str), } @@ -75,7 +86,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> operation_definition: &'a OperationDefinition, ) { let op_name = operation_definition.node_name(); - self.current_scope = Some(Scope::Operation(op_name)); + self.current_scope = Some(NoUnusedVariablesScope::Operation(op_name)); self.defined_variables.insert(op_name, HashSet::new()); } @@ -85,7 +96,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> _: &mut ValidationErrorContext, fragment_definition: &'a query::FragmentDefinition, ) { - self.current_scope = Some(Scope::Fragment(&fragment_definition.name)); + self.current_scope = Some(NoUnusedVariablesScope::Fragment(&fragment_definition.name)); } fn enter_fragment_spread( @@ -97,7 +108,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> if let Some(scope) = &self.current_scope { self.spreads .entry(scope.clone()) - .or_insert_with(Vec::new) + .or_default() .push(&fragment_spread.fragment_name); } } @@ -108,7 +119,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> _: &mut ValidationErrorContext, variable_definition: &'a query::VariableDefinition, ) { - if let Some(Scope::Operation(ref name)) = self.current_scope { + if let Some(NoUnusedVariablesScope::Operation(ref name)) = self.current_scope { if let Some(vars) = self.defined_variables.get_mut(name) { vars.insert(&variable_definition.name); } @@ -124,7 +135,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> if let Some(ref scope) = self.current_scope { self.used_variables .entry(scope.clone()) - .or_insert_with(Vec::new) + .or_default() .append(&mut arg_value.variables_in_use()); } } @@ -140,8 +151,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> let mut visited = HashSet::new(); self.find_used_vars( - &Scope::Operation(op_name.clone()), - &def_vars, + &NoUnusedVariablesScope::Operation(*op_name), + def_vars, &mut used, &mut visited, ); @@ -150,7 +161,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for NoUnusedVariables<'a> .iter() .filter(|var| !used.contains(*var)) .for_each(|var| { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: error_message(var, op_name), locations: vec![], }) @@ -175,14 +187,14 @@ impl<'n> ValidationRule for NoUnusedVariables<'n> { "NoUnusedVariables" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut NoUnusedVariables::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/overlapping_fields_can_be_merged.rs b/src/validation/rules/overlapping_fields_can_be_merged.rs index 6d9827c..0b9c1dd 100644 --- a/src/validation/rules/overlapping_fields_can_be_merged.rs +++ b/src/validation/rules/overlapping_fields_can_be_merged.rs @@ -1,5 +1,5 @@ -use graphql_parser::query::{Definition, TypeCondition}; -use graphql_parser::Pos; +use crate::parser::query::{Definition, TypeCondition}; +use crate::parser::Pos; use super::ValidationRule; use crate::ast::ext::TypeDefinitionExtension; @@ -194,15 +194,15 @@ impl<'a> PairSet<'a> { } pub fn insert(&mut self, a: &'a str, b: &'a str, mutex: bool) { - self.data - .entry(a) - .or_insert_with(HashMap::new) - .insert(b, mutex); - - self.data - .entry(b) - .or_insert_with(HashMap::new) - .insert(a, mutex); + self.data.entry(a).or_default().insert(b, mutex); + + self.data.entry(b).or_default().insert(a, mutex); + } +} + +impl<'a> Default for OverlappingFieldsCanBeMerged<'a> { + fn default() -> Self { + Self::new() } } @@ -297,18 +297,14 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { } } - fn is_same_arguments( - &self, - f1_args: &Vec<(String, Value)>, - f2_args: &Vec<(String, Value)>, - ) -> bool { + fn is_same_arguments(&self, f1_args: &[(String, Value)], f2_args: &[(String, Value)]) -> bool { if f1_args.len() != f2_args.len() { return false; } - f1_args.iter().all(|&(ref n1, ref v1)| { - if let Some(&(_, ref v2)) = f2_args.iter().find(|&&(ref n2, _)| n1.eq(n2)) { - v1.compare(&v2) + f1_args.iter().all(|(n1, v1)| { + if let Some((_, v2)) = f2_args.iter().find(|&(n2, _)| n1.eq(n2)) { + v1.compare(v2) } else { false } @@ -318,10 +314,10 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { // Two types conflict if both types could not apply to a value simultaneously. // Composite types are ignored as their individual field types will be compared // later recursively. However List and Non-Null types must match. - fn is_type_conflict(&self, schema: &SchemaDocument, t1: &Type, t2: &Type) -> bool { + fn is_type_conflict(schema: &SchemaDocument, t1: &Type, t2: &Type) -> bool { if let Type::ListType(t1) = t1 { if let Type::ListType(t2) = t2 { - return self.is_type_conflict(schema, t1, t2); + return Self::is_type_conflict(schema, t1, t2); } else { return true; } @@ -333,7 +329,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { if let Type::NonNullType(t1) = t1 { if let Type::NonNullType(t2) = t2 { - return self.is_type_conflict(schema, t1, t2); + return Self::is_type_conflict(schema, t1, t2); } else { return true; } @@ -343,15 +339,15 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { return true; } - let schema_type1 = schema.type_by_name(&t1.inner_type()); - let schema_type2 = schema.type_by_name(&t2.inner_type()); + let schema_type1 = schema.type_by_name(t1.inner_type()); + let schema_type2 = schema.type_by_name(t2.inner_type()); if schema_type1.map(|t| t.is_leaf_type()).unwrap_or(false) || schema_type2.map(|t| t.is_leaf_type()).unwrap_or(false) { - return t1 != t2; + t1 != t2 } else { - return false; + false } } @@ -416,7 +412,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { let t2 = field2_def.as_ref().map(|def| &def.field_type); if let (Some(t1), Some(t2)) = (t1, t2) { - if self.is_type_conflict(schema, t1, t2) { + if Self::is_type_conflict(schema, t1, t2) { return Some(Conflict( ConflictReason( out_field_name.to_owned(), @@ -434,7 +430,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { // Collect and compare sub-fields. Use the same "visited fragment names" list // for both collections so fields in a fragment reference are never // compared to themselves. - if field1.selection_set.items.len() > 0 && field2.selection_set.items.len() > 0 { + if !field1.selection_set.items.is_empty() && !field2.selection_set.items.is_empty() { let conflicts = self.find_conflicts_between_sub_selection_sets( schema, mutually_exclusive, @@ -458,7 +454,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { fn subfield_conflicts( &self, - conflicts: &Vec, + conflicts: &[Conflict], out_field_name: &str, f1_pos: Pos, f2_pos: Pos, @@ -486,6 +482,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { // Find all conflicts found between two selection sets, including those found // via spreading in fragments. Called when determining if conflicts exist // between the sub-fields of two overlapping fields. + #[allow(clippy::too_many_arguments)] fn find_conflicts_between_sub_selection_sets( &mut self, schema: &'a SchemaDocument, @@ -497,8 +494,8 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { visited_fragments: &mut Vec<&'a str>, ) -> Vec { let mut conflicts = Vec::::new(); - let parent_type1 = parent_type_name1.and_then(|t| schema.type_by_name(&t)); - let parent_type2 = parent_type_name2.and_then(|t| schema.type_by_name(&t)); + let parent_type1 = parent_type_name1.and_then(|t| schema.type_by_name(t)); + let parent_type2 = parent_type_name2.and_then(|t| schema.type_by_name(t)); let (field_map1, fragment_names1) = self.get_fields_and_fragment_names(schema, parent_type1, selection_set1); @@ -752,7 +749,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { let mut ast_and_defs = OrderedMap::new(); let mut fragment_names = Vec::new(); - self.collect_fields_and_fragment_names( + Self::collect_fields_and_fragment_names( schema, parent_type, selection_set, @@ -764,7 +761,6 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { } fn collect_fields_and_fragment_names( - &self, schema: &'a SchemaDocument, parent_type: Option<&'a TypeDefinition>, selection_set: &'a SelectionSet, @@ -779,7 +775,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { let out_field_name = field.alias.as_ref().unwrap_or(field_name).as_str(); if !ast_and_defs.contains_key(out_field_name) { - ast_and_defs.insert(out_field_name.clone(), Vec::new()); + ast_and_defs.insert(out_field_name, Vec::new()); } ast_and_defs @@ -788,9 +784,9 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { .push(AstAndDef(parent_type, field, field_def)); } Selection::FragmentSpread(fragment_spread) => { - if let None = fragment_names + if !fragment_names .iter() - .find(|n| (*n).eq(&fragment_spread.fragment_name)) + .any(|n| (*n).eq(&fragment_spread.fragment_name)) { fragment_names.push(&fragment_spread.fragment_name); } @@ -806,7 +802,7 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> { }) .or(parent_type); - self.collect_fields_and_fragment_names( + Self::collect_fields_and_fragment_names( schema, fragment_type, &inline_fragment.selection_set, @@ -828,7 +824,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for OverlappingFieldsCanBe ) { for definition in &document.definitions { if let Definition::Fragment(fragment) = definition { - self.named_fragments.insert(&fragment.name, &fragment); + self.named_fragments.insert(&fragment.name, fragment); } } } @@ -843,7 +839,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for OverlappingFieldsCanBe let schema = visitor_context.schema; let mut visited_fragments = Vec::new(); let found_conflicts = self.find_conflicts_within_selection_set( - &schema, + schema, parent_type, selection_set, &mut visited_fragments, @@ -852,7 +848,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for OverlappingFieldsCanBe for Conflict(ConflictReason(reason_name, reason_msg), mut p1, p2) in found_conflicts { p1.extend(p2); - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: error_message(&reason_name, &reason_msg), locations: p1, }); @@ -876,7 +873,7 @@ fn format_reason(reason: &ConflictReasonMessage) -> String { ConflictReasonMessage::Message(ref name) => name.clone(), ConflictReasonMessage::Nested(ref nested) => nested .iter() - .map(|&ConflictReason(ref name, ref subreason)| { + .map(|ConflictReason(name, subreason)| { format!( r#"subfields "{}" conflict because {}"#, name, @@ -893,14 +890,14 @@ impl<'o> ValidationRule for OverlappingFieldsCanBeMerged<'o> { "OverlappingFieldsCanBeMerged" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut OverlappingFieldsCanBeMerged::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/possible_fragment_spreads.rs b/src/validation/rules/possible_fragment_spreads.rs index 393ec73..85e9a19 100644 --- a/src/validation/rules/possible_fragment_spreads.rs +++ b/src/validation/rules/possible_fragment_spreads.rs @@ -17,6 +17,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// https://spec.graphql.org/draft/#sec-Fragment-spread-is-possible pub struct PossibleFragmentSpreads; +impl Default for PossibleFragmentSpreads { + fn default() -> Self { + Self::new() + } +} + impl PossibleFragmentSpreads { pub fn new() -> Self { Self {} @@ -73,7 +79,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for PossibleFragmentSpread if let Some(parent_type) = visitor_context.current_parent_type() { if frag_schema_type.is_composite_type() && parent_type.is_composite_type() - && !do_types_overlap(&visitor_context.schema, frag_schema_type, &parent_type) + && !do_types_overlap(visitor_context.schema, frag_schema_type, parent_type) { user_context.report_error(ValidationError {error_code: self.error_code(), locations: vec![], @@ -100,7 +106,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for PossibleFragmentSpread if let Some(parent_type) = visitor_context.current_parent_type() { if fragment_type.is_composite_type() && parent_type.is_composite_type() - && !do_types_overlap(&visitor_context.schema, &fragment_type, &parent_type) + && !do_types_overlap(visitor_context.schema, fragment_type, parent_type) { user_context.report_error(ValidationError {error_code: self.error_code(), locations: vec![], @@ -118,14 +124,14 @@ impl ValidationRule for PossibleFragmentSpreads { "PossibleFragmentSpreads" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut PossibleFragmentSpreads::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/provided_required_arguments.rs b/src/validation/rules/provided_required_arguments.rs index d737d52..274069f 100644 --- a/src/validation/rules/provided_required_arguments.rs +++ b/src/validation/rules/provided_required_arguments.rs @@ -15,6 +15,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// See https://spec.graphql.org/draft/#sec-Required-Arguments pub struct ProvidedRequiredArguments; +impl Default for ProvidedRequiredArguments { + fn default() -> Self { + Self::new() + } +} + impl ProvidedRequiredArguments { pub fn new() -> Self { ProvidedRequiredArguments @@ -67,18 +73,17 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for ProvidedRequiredArgume } } -fn validate_arguments<'a>( - arguments_used: &Vec<(String, Value)>, - arguments_defined: &Vec, +fn validate_arguments( + arguments_used: &[(String, Value)], + arguments_defined: &[InputValue], ) -> Vec { arguments_defined - .into_iter() + .iter() .filter_map(|field_arg_def| { if field_arg_def.is_required() - && arguments_used + && !arguments_used .iter() - .find(|(name, _value)| name.eq(&field_arg_def.name)) - .is_none() + .any(|(name, _value)| name.eq(&field_arg_def.name)) { Some(field_arg_def.clone()) } else { @@ -93,14 +98,14 @@ impl ValidationRule for ProvidedRequiredArguments { "ProvidedRequiredArguments" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut ProvidedRequiredArguments::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -118,7 +123,7 @@ fn ignores_unknown_arguments() { isHouseTrained(unknownArgument: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -136,7 +141,7 @@ fn arg_on_optional_arg() { isHouseTrained(atOtherHomes: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -154,7 +159,7 @@ fn no_arg_on_optional_arg() { isHouseTrained } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -172,7 +177,7 @@ fn multiple_args() { multipleReqs(req1: 1, req2: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -190,7 +195,7 @@ fn multiple_args_reverse_order() { multipleReqs(req2: 2, req1: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -208,7 +213,7 @@ fn no_args_on_multiple_optional() { multipleOpts } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -226,7 +231,7 @@ fn one_arg_on_multiple_optional() { multipleOpts(opt1: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -244,7 +249,7 @@ fn second_arg_on_multiple_optional() { multipleOpts(opt2: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -262,7 +267,7 @@ fn multiple_required_args_on_mixed_list() { multipleOptAndReq(req1: 3, req2: 4) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -280,7 +285,7 @@ fn multiple_required_and_one_optional_arg_on_mixedlist() { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -298,7 +303,7 @@ fn all_required_and_optional_args_on_mixedlist() { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -316,7 +321,7 @@ fn missing_one_non_nullable_argument() { multipleReqs(req2: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -338,7 +343,7 @@ fn missing_multiple_non_nullable_arguments() { multipleReqs } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -361,7 +366,7 @@ fn incorrect_value_and_missing_argument() { multipleReqs(req1: \"one\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -381,7 +386,7 @@ fn ignores_unknown_directives() { "{ dog @unknown }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -403,7 +408,7 @@ fn with_directives_of_valid_types() { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -422,7 +427,7 @@ fn with_directive_with_missing_types() { name @skip } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/rule.rs b/src/validation/rules/rule.rs index c8d2040..093cb00 100644 --- a/src/validation/rules/rule.rs +++ b/src/validation/rules/rule.rs @@ -1,11 +1,11 @@ use crate::{ast::OperationVisitorContext, validation::utils::ValidationErrorContext}; pub trait ValidationRule: Send + Sync { - fn validate<'a>( + fn validate( &self, - _ctx: &mut OperationVisitorContext<'a>, + _ctx: &mut OperationVisitorContext<'_>, _error_collector: &mut ValidationErrorContext, - ) -> (); + ); fn error_code<'a>(&self) -> &'a str; } diff --git a/src/validation/rules/single_field_subscriptions.rs b/src/validation/rules/single_field_subscriptions.rs index a0ab223..f415028 100644 --- a/src/validation/rules/single_field_subscriptions.rs +++ b/src/validation/rules/single_field_subscriptions.rs @@ -14,6 +14,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness pub struct SingleFieldSubscriptions; +impl Default for SingleFieldSubscriptions { + fn default() -> Self { + Self::new() + } +} + impl SingleFieldSubscriptions { pub fn new() -> Self { Self @@ -27,61 +33,59 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for SingleFieldSubscriptio user_context: &mut ValidationErrorContext, operation: &OperationDefinition, ) { - match operation { - OperationDefinition::Subscription(subscription) => { - if let Some(subscription_type) = visitor_context.schema.subscription_type() { - let operation_name = subscription.name.as_ref(); - - let selection_set_fields = collect_fields( - &subscription.selection_set, - &TypeDefinition::Object(subscription_type.clone()), - &visitor_context.known_fragments, - visitor_context, - ); - - if selection_set_fields.len() > 1 { - let error_message = match operation_name { - Some(operation_name) => format!( - "Subscription \"{}\" must select only one top level field.", - operation_name - ), - None => "Anonymous Subscription must select only one top level field." - .to_owned(), - }; - - user_context.report_error(ValidationError {error_code: self.error_code(), - locations: vec![subscription.position], - message: error_message, - }); - } - - selection_set_fields - .into_iter() - .filter_map(|(field_name, fields_records)| { - if field_name.starts_with("__") { - return Some((field_name, fields_records)); - } - - None - }) - .for_each(|(_field_name, _fields_records)| { - let error_message = match operation_name { - Some(operation_name) => format!( - "Subscription \"{}\" must not select an introspection top level field.", - operation_name - ), - None => "Anonymous Subscription must not select an introspection top level field." - .to_owned(), - }; - - user_context.report_error(ValidationError {error_code: self.error_code(), + if let OperationDefinition::Subscription(subscription) = operation { + if let Some(subscription_type) = visitor_context.schema.subscription_type() { + let operation_name = subscription.name.as_ref(); + + let selection_set_fields = collect_fields( + &subscription.selection_set, + &TypeDefinition::Object(subscription_type.clone()), + &visitor_context.known_fragments, + visitor_context, + ); + + if selection_set_fields.len() > 1 { + let error_message = match operation_name { + Some(operation_name) => format!( + "Subscription \"{}\" must select only one top level field.", + operation_name + ), + None => "Anonymous Subscription must select only one top level field." + .to_owned(), + }; + + user_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![subscription.position], message: error_message, }); - }) } + + selection_set_fields + .into_iter() + .filter_map(|(field_name, fields_records)| { + if field_name.starts_with("__") { + return Some((field_name, fields_records)); + } + + None + }) + .for_each(|(_field_name, _fields_records)| { + let error_message = match operation_name { + Some(operation_name) => format!( + "Subscription \"{}\" must not select an introspection top level field.", + operation_name + ), + None => "Anonymous Subscription must not select an introspection top level field." + .to_owned(), + }; + + user_context.report_error(ValidationError {error_code: self.error_code(), + locations: vec![subscription.position], + message: error_message, + }); + }) } - _ => {} } } } @@ -91,14 +95,14 @@ impl ValidationRule for SingleFieldSubscriptions { "SingleFieldSubscriptions" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut SingleFieldSubscriptions::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/unique_argument_names.rs b/src/validation/rules/unique_argument_names.rs index ec2d57b..6fd4e02 100644 --- a/src/validation/rules/unique_argument_names.rs +++ b/src/validation/rules/unique_argument_names.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use graphql_parser::Pos; +use crate::parser::Pos; use super::ValidationRule; use crate::ast::{visit_document, OperationVisitor, OperationVisitorContext}; @@ -15,6 +15,12 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// See https://spec.graphql.org/draft/#sec-Argument-Names pub struct UniqueArgumentNames; +impl Default for UniqueArgumentNames { + fn default() -> Self { + Self::new() + } +} + impl UniqueArgumentNames { pub fn new() -> Self { UniqueArgumentNames @@ -32,7 +38,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for UniqueArgumentNames { found_args.iter().for_each(|(arg_name, positions)| { if positions.len() > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!("There can be only one argument named \"{}\".", arg_name), locations: positions.clone(), }) @@ -50,7 +57,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for UniqueArgumentNames { found_args.iter().for_each(|(arg_name, positions)| { if positions.len() > 1 { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!("There can be only one argument named \"{}\".", arg_name), locations: positions.clone(), }) @@ -68,7 +76,7 @@ fn collect_from_arguments( for (arg_name, _arg_value) in arguments { found_args .entry(arg_name.clone()) - .or_insert(vec![]) + .or_default() .push(reported_position); } @@ -80,14 +88,14 @@ impl ValidationRule for UniqueArgumentNames { "UniqueArgumentNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut UniqueArgumentNames::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/unique_directives_per_location.rs b/src/validation/rules/unique_directives_per_location.rs index e984556..fd62adc 100644 --- a/src/validation/rules/unique_directives_per_location.rs +++ b/src/validation/rules/unique_directives_per_location.rs @@ -18,6 +18,12 @@ use crate::{ /// See https://spec.graphql.org/draft/#sec-Directives-Are-Unique-Per-Location pub struct UniqueDirectivesPerLocation {} +impl Default for UniqueDirectivesPerLocation { + fn default() -> Self { + Self::new() + } +} + impl UniqueDirectivesPerLocation { pub fn new() -> Self { UniqueDirectivesPerLocation {} @@ -35,7 +41,8 @@ impl UniqueDirectivesPerLocation { if let Some(meta_directive) = ctx.directives.get(&directive.name) { if !meta_directive.repeatable { if exists.contains(&directive.name) { - err_context.report_error(ValidationError {error_code: self.error_code(), + err_context.report_error(ValidationError { + error_code: self.error_code(), locations: vec![directive.position], message: format!("Duplicate directive \"{}\"", &directive.name), }); @@ -102,14 +109,14 @@ impl ValidationRule for UniqueDirectivesPerLocation { "UniqueDirectivesPerLocation" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut UniqueDirectivesPerLocation::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -125,7 +132,7 @@ fn no_directives() { "fragment Test on Type { field }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -141,7 +148,7 @@ fn unique_directives_in_different_locations() { "fragment Test on Type @directiveA { field @directiveB }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -157,7 +164,7 @@ fn unique_directives_in_same_location() { "fragment Test on Type @directiveA @directiveB { field @directiveA @directiveB }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -173,7 +180,7 @@ fn same_directives_in_different_locations() { "fragment Test on Type @directiveA { field @directiveA }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -190,7 +197,7 @@ fn same_directives_in_similar_locations() { field @directive field @directive }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -206,7 +213,7 @@ fn repeatable_directives_in_same_location() { "fragment Test on Type @repeatable @repeatable { field @repeatable @repeatable }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -222,7 +229,7 @@ fn unknown_directives_must_be_ignored() { "fragment Test on Type @repeatable @repeatable { field @repeatable @repeatable }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -238,7 +245,7 @@ fn duplicate_directives_in_one_location() { "fragment Test on Type { field @onField @onField }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); let messages = get_messages(&errors); @@ -255,7 +262,7 @@ fn many_duplicate_directives_in_one_location() { "fragment Test on Type { field @onField @onField @onField }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); let messages = get_messages(&errors); @@ -278,7 +285,7 @@ fn different_duplicate_directives_in_one_location() { "fragment Test on Type { field @onField @testDirective @onField @testDirective }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); let messages = get_messages(&errors); @@ -301,7 +308,7 @@ fn duplicate_directives_in_many_location() { "fragment Test on Type @onFragmentDefinition @onFragmentDefinition { field @onField @onField }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); let messages = get_messages(&errors); diff --git a/src/validation/rules/unique_fragment_names.rs b/src/validation/rules/unique_fragment_names.rs index b0d7f98..a677297 100644 --- a/src/validation/rules/unique_fragment_names.rs +++ b/src/validation/rules/unique_fragment_names.rs @@ -22,11 +22,17 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for UniqueFragmentNames<'a fragment: &'a FragmentDefinition, ) { if let Some(name) = fragment.node_name() { - self.store_finding(&name); + self.store_finding(name); } } } +impl<'a> Default for UniqueFragmentNames<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> UniqueFragmentNames<'a> { pub fn new() -> Self { Self { @@ -36,7 +42,7 @@ impl<'a> UniqueFragmentNames<'a> { fn store_finding(&mut self, name: &'a str) { let value = *self.findings_counter.entry(name).or_insert(0); - self.findings_counter.insert(name.clone(), value + 1); + self.findings_counter.insert(name, value + 1); } } @@ -45,20 +51,21 @@ impl<'u> ValidationRule for UniqueFragmentNames<'u> { "UniqueFragmentNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { let mut rule = UniqueFragmentNames::new(); - visit_document(&mut rule, &ctx.operation, ctx, error_collector); + visit_document(&mut rule, ctx.operation, ctx, error_collector); rule.findings_counter .into_iter() .filter(|(_key, value)| *value > 1) .for_each(|(key, _value)| { - error_collector.report_error(ValidationError {error_code: self.error_code(), + error_collector.report_error(ValidationError { + error_code: self.error_code(), message: format!("There can be only one fragment named \"{}\".", key), locations: vec![], }) diff --git a/src/validation/rules/unique_operation_names.rs b/src/validation/rules/unique_operation_names.rs index c7281bc..e3b146e 100644 --- a/src/validation/rules/unique_operation_names.rs +++ b/src/validation/rules/unique_operation_names.rs @@ -27,6 +27,12 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for UniqueOperationNames<' } } +impl<'a> Default for UniqueOperationNames<'a> { + fn default() -> Self { + Self::new() + } +} + impl<'a> UniqueOperationNames<'a> { pub fn new() -> Self { Self { @@ -35,8 +41,8 @@ impl<'a> UniqueOperationNames<'a> { } fn store_finding(&mut self, name: &'a str) { - let value = *self.findings_counter.entry(name.clone()).or_insert(0); - self.findings_counter.insert(name.clone(), value + 1); + let value = *self.findings_counter.entry(name).or_insert(0); + self.findings_counter.insert(name, value + 1); } } @@ -45,20 +51,21 @@ impl<'u> ValidationRule for UniqueOperationNames<'u> { "UniqueOperationNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { let mut rule = UniqueOperationNames::new(); - visit_document(&mut rule, &ctx.operation, ctx, error_collector); + visit_document(&mut rule, ctx.operation, ctx, error_collector); rule.findings_counter .into_iter() .filter(|(_key, value)| *value > 1) .for_each(|(key, _value)| { - error_collector.report_error(ValidationError {error_code: self.error_code(), + error_collector.report_error(ValidationError { + error_code: self.error_code(), message: format!("There can be only one operation named \"{}\".", key), locations: vec![], }) diff --git a/src/validation/rules/unique_variable_names.rs b/src/validation/rules/unique_variable_names.rs index 591ba89..7745a29 100644 --- a/src/validation/rules/unique_variable_names.rs +++ b/src/validation/rules/unique_variable_names.rs @@ -1,7 +1,7 @@ use std::collections::hash_map::Entry; use std::collections::HashMap; -use graphql_parser::Pos; +use crate::parser::Pos; use super::ValidationRule; use crate::ast::{visit_document, OperationVisitor, OperationVisitorContext}; @@ -13,6 +13,7 @@ use crate::validation::utils::{ValidationError, ValidationErrorContext}; /// A GraphQL operation is only valid if all its variables are uniquely named. /// /// See https://spec.graphql.org/draft/#sec-Variable-Uniqueness +#[derive(Default)] pub struct UniqueVariableNames<'a> { found_records: HashMap<&'a str, Pos>, } @@ -41,10 +42,10 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for UniqueVariableNames<'a user_context: &mut ValidationErrorContext, variable_definition: &'a VariableDefinition, ) { - let error_code = self.error_code(); + let error_code = self.error_code(); match self.found_records.entry(&variable_definition.name) { Entry::Occupied(entry) => user_context.report_error(ValidationError { - error_code, + error_code, locations: vec![*entry.get(), variable_definition.position], message: format!( "There can only be one variable named \"${}\".", @@ -63,14 +64,14 @@ impl<'v> ValidationRule for UniqueVariableNames<'v> { "UniqueVariableNames" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut UniqueVariableNames::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); diff --git a/src/validation/rules/values_of_correct_type.rs b/src/validation/rules/values_of_correct_type.rs index 724f32a..419a48a 100644 --- a/src/validation/rules/values_of_correct_type.rs +++ b/src/validation/rules/values_of_correct_type.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use graphql_parser::schema::TypeDefinition; +use crate::parser::schema::TypeDefinition; use crate::ast::{ InputValueHelpers, SchemaDocumentExtension, TypeDefinitionExtension, TypeExtension, @@ -16,16 +16,19 @@ use super::ValidationRule; pub struct ValuesOfCorrectType {} +impl Default for ValuesOfCorrectType { + fn default() -> Self { + Self::new() + } +} + impl ValuesOfCorrectType { pub fn new() -> Self { Self {} } pub fn is_custom_scalar(&self, type_name: &str) -> bool { - match type_name { - "String" | "Int" | "Float" | "Boolean" | "ID" => false, - _ => true, - } + !matches!(type_name, "String" | "Int" | "Float" | "Boolean" | "ID") } pub fn validate_value( @@ -37,9 +40,10 @@ impl ValuesOfCorrectType { if let Some(input_type) = visitor_context.current_input_type_literal() { let named_type = input_type.inner_type(); - if let Some(type_def) = visitor_context.schema.type_by_name(&named_type) { + if let Some(type_def) = visitor_context.schema.type_by_name(named_type) { if !type_def.is_leaf_type() { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Expected value of type \"{}\", found {}.", named_type, raw_value @@ -62,7 +66,8 @@ impl ValuesOfCorrectType { return; } - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Expected value of type \"{}\", found {}.", expected, value @@ -76,13 +81,9 @@ impl ValuesOfCorrectType { if let TypeDefinition::Enum(enum_type_def) = &type_def { match raw_value { Value::Enum(enum_value) => { - if enum_type_def - .values - .iter() - .find(|v| v.name.eq(enum_value)) - .is_none() - { - user_context.report_error(ValidationError {error_code: self.error_code(), + if !enum_type_def.values.iter().any(|v| v.name.eq(enum_value)) { + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Value \"{}\" does not exist in \"{}\" enum.", enum_value, enum_type_def.name @@ -91,7 +92,8 @@ impl ValuesOfCorrectType { }) } } - value => user_context.report_error(ValidationError {error_code: self.error_code(), + value => user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Enum \"{}\" cannot represent non-enum value: {}", enum_type_def.name, value @@ -114,7 +116,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for ValuesOfCorrectType { ) { if let Some(input_type) = visitor_context.current_input_type_literal() { if input_type.is_non_null() { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!("Expected value of type \"{}\", found null", input_type), locations: vec![], }) @@ -133,7 +136,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for ValuesOfCorrectType { { input_object_def.fields.iter().for_each(|field| { if field.is_required() && !object_value.contains_key(&field.name) { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Field \"{}.{}\" of required type \"{}\" was not provided.", input_object_def.name, field.name, field.value_type @@ -144,13 +148,13 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for ValuesOfCorrectType { }); object_value.keys().for_each(|field_name| { - if (input_object_def + if !input_object_def .fields .iter() - .find(|f| f.name.eq(field_name))) - .is_none() + .any(|f| f.name.eq(field_name)) { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Field \"{}\" is not defined by type \"{}\".", field_name, input_object_def.name @@ -186,14 +190,14 @@ impl ValidationRule for ValuesOfCorrectType { "ValuesOfCorrectType" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut ValuesOfCorrectType::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -212,7 +216,7 @@ fn valid_int_value() { intArgField(intArg: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -232,7 +236,7 @@ fn valid_negative_int_value() { intArgField(intArg: -2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -252,7 +256,7 @@ fn valid_boolean_value() { booleanArgField(booleanArg: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -272,7 +276,7 @@ fn valid_string_value() { stringArgField(stringArg: \"foo\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -292,7 +296,7 @@ fn valid_float_value() { floatArgField(floatArg: 1.1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -312,7 +316,7 @@ fn valid_negative_float_value() { floatArgField(floatArg: -1.1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -332,7 +336,7 @@ fn valid_int_into_float_value() { floatArgField(floatArg: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -352,7 +356,7 @@ fn valid_int_into_id_value() { idArgField(idArg: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -372,7 +376,7 @@ fn valid_string_into_id_value() { idArgField(idArg: \"someIdString\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -392,7 +396,7 @@ fn valid_enum_value() { doesKnowCommand(dogCommand: SIT) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -412,7 +416,7 @@ fn enum_undefined_value() { enumArgField(enumArg: UNKNOWN) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -432,7 +436,7 @@ fn enum_null_value() { enumArgField(enumArg: NO_FUR) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -452,7 +456,7 @@ fn valid_null_into_nullable() { intArgField(intArg: null) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -466,7 +470,7 @@ fn valid_null_into_nullable() { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -486,7 +490,7 @@ fn invalid_int_into_string() { stringArgField(stringArg: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -510,7 +514,7 @@ fn invalid_float_into_string() { stringArgField(stringArg: 1.0) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -534,7 +538,7 @@ fn invalid_bool_into_string() { stringArgField(stringArg: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -558,7 +562,7 @@ fn unquoted_string_to_string() { stringArgField(stringArg: BAR) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -582,7 +586,7 @@ fn invalid_string_into_int() { intArgField(intArg: \"3\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -607,7 +611,7 @@ fn bigint_into_int() { intArgField(intArg: 829384293849283498239482938) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -631,7 +635,7 @@ fn unquoted_string_into_int() { intArgField(intArg: FOO) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -652,7 +656,7 @@ fn simple_float_into_int() { intArgField(intArg: 3.0) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -673,7 +677,7 @@ fn float_into_int() { intArgField(intArg: 3.333) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -697,7 +701,7 @@ fn string_into_float() { floatArgField(floatArg: \"3.333\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -721,7 +725,7 @@ fn boolean_into_float() { floatArgField(floatArg: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -745,7 +749,7 @@ fn unquoted_into_float() { floatArgField(floatArg: FOO) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -769,7 +773,7 @@ fn int_into_boolean() { booleanArgField(booleanArg: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -793,7 +797,7 @@ fn float_into_boolean() { booleanArgField(booleanArg: 2.0) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -817,7 +821,7 @@ fn string_into_boolean() { booleanArgField(booleanArg: \"true\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -841,7 +845,7 @@ fn unquoted_into_boolean() { booleanArgField(booleanArg: TRUE) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -865,7 +869,7 @@ fn float_into_id() { idArgField(idArg: 1.0) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -886,7 +890,7 @@ fn bool_into_id() { idArgField(idArg: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -907,7 +911,7 @@ fn unquoted_into_id() { idArgField(idArg: SOMETHING) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -931,7 +935,7 @@ fn int_into_enum() { doesKnowCommand(dogCommand: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -955,7 +959,7 @@ fn float_into_enum() { doesKnowCommand(dogCommand: 1.0) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -979,7 +983,7 @@ fn string_into_enum() { doesKnowCommand(dogCommand: \"SIT\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1003,7 +1007,7 @@ fn boolean_into_enum() { doesKnowCommand(dogCommand: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1027,7 +1031,7 @@ fn unknown_enum_value_into_enum() { doesKnowCommand(dogCommand: JUGGLE) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1051,7 +1055,7 @@ fn different_case_enum_value_into_enum() { doesKnowCommand(dogCommand: sit) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1075,7 +1079,7 @@ fn valid_list_value() { stringListArgField(stringListArg: [\"one\", null, \"two\"]) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1095,7 +1099,7 @@ fn valid_empty_list_value() { stringListArgField(stringListArg: []) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1115,7 +1119,7 @@ fn valid_null_list_value() { stringListArgField(stringListArg: null) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1135,7 +1139,7 @@ fn valid_single_value_into_list_value() { stringListArgField(stringListArg: \"one\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1155,7 +1159,7 @@ fn incorrect_item_type() { stringListArgField(stringListArg: [\"one\", 2]) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1179,7 +1183,7 @@ fn single_value_of_incorrect_type() { stringListArgField(stringListArg: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1203,7 +1207,7 @@ fn arg_on_optional_arg() { isHouseTrained(atOtherHomes: true) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1223,7 +1227,7 @@ fn no_arg_on_optional_arg() { isHouseTrained } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1243,7 +1247,7 @@ fn multiple_valid_args() { multipleReqs(req1: 1, req2: 2) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1263,7 +1267,7 @@ fn multiple_valid_args_reverse_oreder() { multipleReqs(req2: 2, req1: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1283,7 +1287,7 @@ fn no_args_multiple_optional() { multipleOpts } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1303,7 +1307,7 @@ fn one_arg_multiple_optinals() { multipleOpts(opt1: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1323,7 +1327,7 @@ fn second_arg_multiple_optinals() { multipleOpts(opt2: 1) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1343,7 +1347,7 @@ fn multiple_required_args_on_mixed_list() { multipleOptAndReq(req1: 3, req2: 4) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1363,7 +1367,7 @@ fn multiple_required_args_and_one_optional_on_mixed_list() { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1383,7 +1387,7 @@ fn all_required_and_one_optional() { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1403,7 +1407,7 @@ fn incorrect_value_type() { multipleReqs(req2: \"two\", req1: \"one\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1430,7 +1434,7 @@ fn incorrect_value_and_missing_argument() { multipleReqs(req1: \"one\") } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1454,7 +1458,7 @@ fn null_value() { multipleReqs(req1: null) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1478,7 +1482,7 @@ fn optional_arg_despite_required_field_in_type() { complexArgField } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1498,7 +1502,7 @@ fn partial_object_only_required() { complexArgField(complexArg: { requiredField: true }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1518,7 +1522,7 @@ fn partial_object_required_field_can_be_falsy() { complexArgField(complexArg: { requiredField: false }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1538,7 +1542,7 @@ fn partial_object_including_required() { complexArgField(complexArg: { requiredField: true, intField: 4 }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1564,7 +1568,7 @@ fn full_object() { }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1590,7 +1594,7 @@ fn full_object_with_fields_in_different_order() { }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1610,7 +1614,7 @@ fn partial_object_missing_required() { complexArgField(complexArg: { intField: 4 }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1639,7 +1643,7 @@ fn partial_object_invalid_field_type() { }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1666,7 +1670,7 @@ fn partial_object_null_to_non_null_field() { }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1693,7 +1697,7 @@ fn partial_object_unknown_field_arg() { }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1747,7 +1751,7 @@ fn with_directives_of_valid_types() { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1767,7 +1771,7 @@ fn with_directives_of_invalid_types() { name @skip(if: ENUM) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1797,7 +1801,7 @@ fn variables_with_valid_default_values() { ) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1819,7 +1823,7 @@ fn variables_with_valid_default_null_values() { ) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1841,7 +1845,7 @@ fn variables_with_invalid_default_null_values() { ) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1871,7 +1875,7 @@ fn variables_with_invalid_default_values() { ) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1899,7 +1903,7 @@ fn variables_with_complex_invalid_default_values() { ) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1924,7 +1928,7 @@ fn complex_variables_missing_required_field() { query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -1948,7 +1952,7 @@ fn list_variables_with_invalid_item() { query InvalidItem($a: [String] = [\"one\", 2]) { dog { name } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/variables_are_input_types.rs b/src/validation/rules/variables_are_input_types.rs index 18f2697..984f533 100644 --- a/src/validation/rules/variables_are_input_types.rs +++ b/src/validation/rules/variables_are_input_types.rs @@ -12,6 +12,7 @@ use crate::validation::utils::ValidationErrorContext; /// input types (scalar, enum, or input object). /// /// See https://spec.graphql.org/draft/#sec-Variables-Are-Input-Types +#[derive(Default)] pub struct VariablesAreInputTypes; impl VariablesAreInputTypes { @@ -29,10 +30,11 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for VariablesAreInputTypes ) { if let Some(var_schema_type) = context .schema - .type_by_name(&variable_definition.var_type.inner_type()) + .type_by_name(variable_definition.var_type.inner_type()) { if !var_schema_type.is_input_type() { - user_context.report_error(ValidationError {error_code: self.error_code(), + user_context.report_error(ValidationError { + error_code: self.error_code(), message: format!( "Variable \"${}\" cannot be non-input type \"{}\".", variable_definition.name, variable_definition.var_type @@ -49,14 +51,14 @@ impl ValidationRule for VariablesAreInputTypes { "VariablesAreInputTypes" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut VariablesAreInputTypes::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -73,7 +75,7 @@ fn unknown_types_are_ignored() { query Foo($a: Unknown, $b: [[Unknown!]]!) { field(a: $a, b: $b) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -91,7 +93,7 @@ fn input_types_are_valid() { query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -109,7 +111,7 @@ fn output_types_are_invalid() { query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/rules/variables_in_allowed_position.rs b/src/validation/rules/variables_in_allowed_position.rs index c964cc3..6235525 100644 --- a/src/validation/rules/variables_in_allowed_position.rs +++ b/src/validation/rules/variables_in_allowed_position.rs @@ -16,6 +16,7 @@ use super::ValidationRule; /// Variable usages must be compatible with the arguments they are passed to. /// /// See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed +#[derive(Default)] pub struct VariablesInAllowedPosition<'a> { spreads: HashMap, HashSet<&'a str>>, variable_usages: HashMap, Vec<(&'a str, &'a Type)>>, @@ -49,8 +50,7 @@ impl<'a> VariablesInAllowedPosition<'a> { if let Some(usages) = self.variable_usages.get(from) { for (var_name, var_type) in usages { - if let Some(ref var_def) = var_defs.iter().find(|var_def| var_def.name == *var_name) - { + if let Some(var_def) = var_defs.iter().find(|var_def| var_def.name == *var_name) { let expected_type = match (&var_def.default_value, &var_def.var_type) { (Some(_), Type::ListType(inner)) => Type::NonNullType(inner.clone()), (Some(default_value), Type::NamedType(_)) => { @@ -143,7 +143,7 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for VariablesInAllowedPosi if let Some(scope) = &self.current_scope { self.spreads .entry(scope.clone()) - .or_insert_with(HashSet::new) + .or_default() .insert(&fragment_spread.fragment_name); } } @@ -157,8 +157,8 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for VariablesInAllowedPosi if let Some(ref scope) = self.current_scope { self.variable_defs .entry(scope.clone()) - .or_insert_with(Vec::new) - .push(&variable_definition); + .or_default() + .push(variable_definition); } } @@ -168,13 +168,13 @@ impl<'a> OperationVisitor<'a, ValidationErrorContext> for VariablesInAllowedPosi _: &mut ValidationErrorContext, variable_name: &'a str, ) { - if let (&Some(ref scope), Some(input_type)) = ( + if let (Some(scope), Some(input_type)) = ( &self.current_scope, visitor_context.current_input_type_literal(), ) { self.variable_usages .entry(scope.clone()) - .or_insert_with(Vec::new) + .or_default() .push((variable_name, input_type)); } } @@ -185,14 +185,14 @@ impl<'v> ValidationRule for VariablesInAllowedPosition<'v> { "VariablesInAllowedPosition" } - fn validate<'a>( + fn validate( &self, - ctx: &'a mut OperationVisitorContext, + ctx: &mut OperationVisitorContext, error_collector: &mut ValidationErrorContext, ) { visit_document( &mut VariablesInAllowedPosition::new(), - &ctx.operation, + ctx.operation, ctx, error_collector, ); @@ -211,7 +211,7 @@ fn boolean_to_boolean() { booleanArgField(booleanArg: $booleanArg) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -233,7 +233,7 @@ fn boolean_to_boolean_within_fragment() { ...booleanArgFrag } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -249,7 +249,7 @@ fn boolean_to_boolean_within_fragment() { fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -268,7 +268,7 @@ fn boolean_nonnull_to_boolean() { booleanArgField(booleanArg: $nonNullBooleanArg) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -287,7 +287,7 @@ fn string_list_to_string_list() { stringListArgField(stringListArg: $stringListVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -306,7 +306,7 @@ fn string_list_nonnull_to_string_list() { stringListArgField(stringListArg: $stringListVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -325,7 +325,7 @@ fn string_to_string_list_in_item_position() { stringListArgField(stringListArg: [$stringVar]) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -344,7 +344,7 @@ fn string_nonnull_to_string_list_in_item_position() { stringListArgField(stringListArg: [$stringVar]) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -363,7 +363,7 @@ fn complexinput_to_complexinput() { complexArgField(complexArg: $complexVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -382,7 +382,7 @@ fn complexinput_to_complexinput_in_field_position() { complexArgField(complexArg: { requiredArg: $boolVar }) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -400,7 +400,7 @@ fn boolean_nonnull_to_boolean_nonnull_in_directive() { { dog @include(if: $boolVar) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -418,7 +418,7 @@ fn int_to_int_nonnull() { nonNullIntArgField(nonNullIntArg: $intArg) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -444,7 +444,7 @@ fn int_to_int_nonnull_within_fragment() { ...nonNullIntArgFieldFrag } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -473,7 +473,7 @@ fn int_to_int_nonnull_within_nested_fragment() { ...outerFrag } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -496,7 +496,7 @@ fn string_over_boolean() { booleanArgField(booleanArg: $stringVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -521,7 +521,7 @@ fn string_over_string_list() { stringListArgField(stringListArg: $stringVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -544,7 +544,7 @@ fn boolean_to_boolean_nonnull_in_directive() { "query Query($boolVar: Boolean) { dog @include(if: $boolVar) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -567,7 +567,7 @@ fn string_to_boolean_nonnull_in_directive() { "query Query($stringVar: String) { dog @include(if: $stringVar) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -593,7 +593,7 @@ fn string_list_to_string_nonnull_list() { stringListNonNullArgField(stringListNonNullArg: $stringListVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -615,7 +615,7 @@ fn int_to_int_non_null_with_null_default_value() { nonNullIntArgField(nonNullIntArg: $intVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -638,7 +638,7 @@ fn int_to_int_non_null_with_default_value() { nonNullIntArgField(nonNullIntArg: $intVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -657,7 +657,7 @@ fn int_to_int_non_null_where_argument_with_default_value() { nonNullFieldWithDefault(nonNullIntArg: $intVar) } }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); @@ -674,7 +674,7 @@ fn boolean_to_boolean_non_null_with_default_value() { "query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) }", - &TEST_SCHEMA, + TEST_SCHEMA, &mut plan, ); diff --git a/src/validation/test_utils.rs b/src/validation/test_utils.rs index 6b473a5..96cbf22 100644 --- a/src/validation/test_utils.rs +++ b/src/validation/test_utils.rs @@ -233,13 +233,11 @@ pub fn create_plan_from_rule(rule: Box) -> ValidationPlan { let mut rules = Vec::new(); rules.push(rule); - let plan = ValidationPlan { rules }; - - plan + ValidationPlan { rules } } #[cfg(test)] -pub fn get_messages(validation_errors: &Vec) -> Vec<&String> { +pub fn get_messages(validation_errors: &[ValidationError]) -> Vec<&String> { validation_errors .iter() .map(|m| &m.message) @@ -251,7 +249,7 @@ pub fn test_operation_without_schema<'a>( operation: &'a str, plan: &'a mut ValidationPlan, ) -> Vec { - let schema_ast = graphql_parser::parse_schema( + let schema_ast = crate::parser::parse_schema( " type Query { dummy: String @@ -260,11 +258,9 @@ type Query { ) .expect("Failed to parse schema"); - let operation_ast = graphql_parser::parse_query(operation) - .unwrap() - .into_static(); + let operation_ast = crate::parser::parse_query(operation).unwrap().into_static(); - validate(&schema_ast, &operation_ast, &plan) + validate(&schema_ast, &operation_ast, plan) } #[cfg(test)] @@ -279,11 +275,9 @@ pub fn test_operation_with_schema<'a>( plan: &'a ValidationPlan, ) -> Vec { let schema_clone = string_to_static_str(schema.to_string() + INTROSPECTION_SCHEMA); - let schema_ast = graphql_parser::parse_schema(&schema_clone).expect("Failed to parse schema"); + let schema_ast = crate::parser::parse_schema(schema_clone).expect("Failed to parse schema"); - let operation_ast = graphql_parser::parse_query(operation) - .unwrap() - .into_static(); + let operation_ast = crate::parser::parse_query(operation).unwrap().into_static(); - validate(&schema_ast, &operation_ast, &plan) + validate(&schema_ast, &operation_ast, plan) } diff --git a/src/validation/utils.rs b/src/validation/utils.rs index ba5cb58..03e9738 100644 --- a/src/validation/utils.rs +++ b/src/validation/utils.rs @@ -1,10 +1,10 @@ -use graphql_parser::Pos; +use crate::parser::Pos; use serde::ser::*; use serde::{Serialize, Serializer}; use serde_with::{serde_as, SerializeAs}; use std::fmt::Debug; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct ValidationErrorContext { pub errors: Vec, } diff --git a/src/validation/validate.rs b/src/validation/validate.rs index 5d02d6a..6efb09f 100644 --- a/src/validation/validate.rs +++ b/src/validation/validate.rs @@ -26,6 +26,12 @@ impl ValidationPlan { } } +impl Default for ValidationPlan { + fn default() -> Self { + Self::new() + } +} + pub fn validate<'a>( schema: &'a schema::Document, operation: &'a query::Document,