diff --git a/benches/bench.rs b/benches/bench.rs index a5ea5840..5d707527 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -3,9 +3,7 @@ extern crate juniper; use bencher::Bencher; -use std::collections::{HashMap}; - -use juniper::{execute, RootNode, EmptyMutation}; +use juniper::{execute, RootNode, EmptyMutation, Variables}; use juniper::tests::model::Database; fn query_type_name(b: &mut Bencher) { @@ -21,7 +19,7 @@ fn query_type_name(b: &mut Bencher) { } }"#; - b.iter(|| execute(doc, None, &schema, &HashMap::new(), &database)); + b.iter(|| execute(doc, None, &schema, &Variables::new(), &database)); } fn introspection_query(b: &mut Bencher) { @@ -122,7 +120,7 @@ fn introspection_query(b: &mut Bencher) { } "#; - b.iter(|| execute(doc, None, &schema, &HashMap::new(), &database)); + b.iter(|| execute(doc, None, &schema, &Variables::new(), &database)); } benchmark_group!(queries, query_type_name, introspection_query); diff --git a/src/ast.rs b/src/ast.rs index 31023d3c..64ee69ad 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -4,6 +4,7 @@ use std::hash::Hash; use std::vec; use std::slice; +use executor::Variables; use parser::Spanning; /// A type literal in the syntax tree @@ -265,7 +266,7 @@ impl InputValue { } /// Resolve all variables to their values. - pub fn into_const(self, vars: &HashMap) -> InputValue { + pub fn into_const(self, vars: &Variables) -> InputValue { match self { InputValue::Variable(v) => vars.get(&v) .map_or_else(InputValue::null, Clone::clone), diff --git a/src/executor.rs b/src/executor.rs index 6e4b2734..1f36b7ba 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -36,7 +36,7 @@ pub enum FieldPath<'a> { /// of the current field stack, context, variables, and errors. pub struct Executor<'a, CtxT> where CtxT: 'a { fragments: &'a HashMap<&'a str, &'a Fragment<'a>>, - variables: &'a HashMap, + variables: &'a Variables, current_selection_set: Option<&'a [Selection<'a>]>, schema: &'a SchemaType<'a>, context: &'a CtxT, @@ -61,6 +61,9 @@ pub type FieldResult = Result; /// The result of resolving an unspecified field pub type ExecutionResult = Result; +/// The map of variables used for substitution during query execution +pub type Variables = HashMap; + #[doc(hidden)] pub trait IntoResolvable<'a, T: GraphQLType, C>: Sized { #[doc(hidden)] @@ -221,7 +224,7 @@ impl<'a, CtxT> Executor<'a, CtxT> { } #[doc(hidden)] - pub fn variables(&self) -> &'a HashMap { + pub fn variables(&self) -> &'a Variables { self.variables } @@ -294,7 +297,7 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>( document: Document, operation_name: Option<&str>, root_node: &RootNode, - variables: &HashMap, + variables: &Variables, context: &CtxT ) -> Result<(Value, Vec), GraphQLError<'a>> diff --git a/src/executor_tests/directives.rs b/src/executor_tests/directives.rs index b681dd01..fbe384b5 100644 --- a/src/executor_tests/directives.rs +++ b/src/executor_tests/directives.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use value::Value; use ast::InputValue; +use executor::Variables; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -17,7 +18,7 @@ graphql_object!(TestType: () |&self| { } }); -fn run_variable_query(query: &str, vars: HashMap, f: F) +fn run_variable_query(query: &str, vars: Variables, f: F) where F: Fn(&HashMap) -> () { let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); @@ -37,7 +38,7 @@ fn run_variable_query(query: &str, vars: HashMap, f: F) fn run_query(query: &str, f: F) where F: Fn(&HashMap) -> () { - run_variable_query(query, HashMap::new(), f); + run_variable_query(query, Variables::new(), f); } #[test] diff --git a/src/executor_tests/enums.rs b/src/executor_tests/enums.rs index bfec7ba2..f6984490 100644 --- a/src/executor_tests/enums.rs +++ b/src/executor_tests/enums.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use value::Value; use ast::InputValue; +use executor::Variables; use schema::model::RootNode; use ::GraphQLError::ValidationError; use validation::RuleError; @@ -28,7 +29,7 @@ graphql_object!(TestType: () |&self| { } }); -fn run_variable_query(query: &str, vars: HashMap, f: F) +fn run_variable_query(query: &str, vars: Variables, f: F) where F: Fn(&HashMap) -> () { let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); @@ -48,7 +49,7 @@ fn run_variable_query(query: &str, vars: HashMap, f: F) fn run_query(query: &str, f: F) where F: Fn(&HashMap) -> () { - run_variable_query(query, HashMap::new(), f); + run_variable_query(query, Variables::new(), f); } #[test] diff --git a/src/executor_tests/introspection.rs b/src/executor_tests/introspection.rs index 03b725e3..a6235e1a 100644 --- a/src/executor_tests/introspection.rs +++ b/src/executor_tests/introspection.rs @@ -1,5 +1,4 @@ -use std::collections::HashMap; - +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -70,7 +69,7 @@ fn test_execution() { "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); @@ -107,7 +106,7 @@ fn enum_introspection() { "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); @@ -185,7 +184,7 @@ fn interface_introspection() { "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); @@ -286,7 +285,7 @@ fn object_introspection() { "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); @@ -398,7 +397,7 @@ fn scalar_introspection() { "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); diff --git a/src/executor_tests/variables.rs b/src/executor_tests/variables.rs index 0d2c78a7..2ba53b10 100644 --- a/src/executor_tests/variables.rs +++ b/src/executor_tests/variables.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use value::Value; use ast::InputValue; +use executor::Variables; use schema::model::RootNode; use ::GraphQLError::ValidationError; use validation::RuleError; @@ -86,7 +87,7 @@ graphql_object!(TestType: () |&self| { } }); -fn run_variable_query(query: &str, vars: HashMap, f: F) +fn run_variable_query(query: &str, vars: Variables, f: F) where F: Fn(&HashMap) -> () { let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); @@ -106,7 +107,7 @@ fn run_variable_query(query: &str, vars: HashMap, f: F) fn run_query(query: &str, f: F) where F: Fn(&HashMap) -> () { - run_variable_query(query, HashMap::new(), f); + run_variable_query(query, Variables::new(), f); } #[test] diff --git a/src/integrations/iron_handlers.rs b/src/integrations/iron_handlers.rs index efbc2311..c5657e8d 100644 --- a/src/integrations/iron_handlers.rs +++ b/src/integrations/iron_handlers.rs @@ -6,11 +6,11 @@ use iron::mime::Mime; use iron::status; use iron::method; -use std::collections::{HashMap, BTreeMap}; +use std::collections::BTreeMap; use rustc_serialize::json::{ToJson, Json}; -use ::{InputValue, GraphQLType, RootNode, execute}; +use ::{InputValue, GraphQLType, RootNode, Variables, execute}; /// Handler that executes GraphQL queries in the given schema /// @@ -62,7 +62,7 @@ impl<'a, CtxFactory, Query, Mutation, CtxT> let url = req.url.clone().into_generic_url(); let mut query = None; - let variables = HashMap::new(); + let variables = Variables::new(); for (k, v) in url.query_pairs() { if k == "query" { @@ -84,17 +84,16 @@ impl<'a, CtxFactory, Query, Mutation, CtxT> }; let mut query = None; - let mut variables = HashMap::new(); + let mut variables = Variables::new(); for (k, v) in json_obj.into_iter() { if k == "query" { query = v.as_string().map(|s| s.to_owned()); } else if k == "variables" { - variables = match InputValue::from_json(v).to_object_value() { - Some(o) => o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect(), - _ => HashMap::new(), - }; + variables = InputValue::from_json(v).to_object_value() + .map(|o| o.into_iter().map(|(k, v)| (k.to_owned(), v.clone())).collect()) + .unwrap_or_default(); } } @@ -103,7 +102,7 @@ impl<'a, CtxFactory, Query, Mutation, CtxT> self.execute(req, &query, &variables) } - fn execute(&self, req: &mut Request, query: &str, variables: &HashMap) -> IronResult { + fn execute(&self, req: &mut Request, query: &str, variables: &Variables) -> IronResult { let context = (self.context_factory)(req); let result = execute(query, None, &self.root_node, variables, &context); diff --git a/src/lib.rs b/src/lib.rs index eb23bcb7..fb94eaac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,8 +209,6 @@ mod integrations; #[cfg(test)] mod executor_tests; -use std::collections::HashMap; - use parser::{parse_document_source, ParseError, Spanning}; use validation::{ValidatorContext, visit_all_rules, validate_input_values}; use executor::execute_validated_query; @@ -219,8 +217,9 @@ pub use ast::{ToInputValue, FromInputValue, InputValue, Type, Selection}; pub use value::Value; pub use types::base::{Arguments, GraphQLType, TypeKind}; pub use executor::{ - Context, FromContext, - Executor, Registry, ExecutionResult, ExecutionError, FieldResult, IntoResolvable, + Executor, ExecutionError, Registry, + Context, FromContext, IntoResolvable, + FieldResult, ExecutionResult, Variables, }; pub use validation::RuleError; pub use types::scalars::{EmptyMutation, ID}; @@ -247,7 +246,7 @@ pub fn execute<'a, CtxT, QueryT, MutationT>( document_source: &'a str, operation_name: Option<&str>, root_node: &RootNode, - variables: &HashMap, + variables: &Variables, context: &CtxT, ) -> Result<(Value, Vec), GraphQLError<'a>> diff --git a/src/macros/tests/args.rs b/src/macros/tests/args.rs index 37d16eec..07901cff 100644 --- a/src/macros/tests/args.rs +++ b/src/macros/tests/args.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -90,7 +91,7 @@ fn run_args_info_query(field_name: &str, f: F) "#; let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); diff --git a/src/macros/tests/enums.rs b/src/macros/tests/enums.rs index db2bc686..a29df66d 100644 --- a/src/macros/tests/enums.rs +++ b/src/macros/tests/enums.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -70,7 +71,7 @@ graphql_object!(Root: () |&self| { fn run_type_info_query(doc: &str, f: F) where F: Fn((&HashMap, &Vec)) -> () { let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); diff --git a/src/macros/tests/input_object.rs b/src/macros/tests/input_object.rs index f196ded7..30ee606f 100644 --- a/src/macros/tests/input_object.rs +++ b/src/macros/tests/input_object.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use ast::{InputValue, FromInputValue}; +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -97,7 +98,7 @@ graphql_object!(Root: () |&self| { fn run_type_info_query(doc: &str, f: F) where F: Fn(&HashMap, &Vec) -> () { let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); diff --git a/src/macros/tests/scalar.rs b/src/macros/tests/scalar.rs index c8744a22..ba77083f 100644 --- a/src/macros/tests/scalar.rs +++ b/src/macros/tests/scalar.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -72,7 +73,7 @@ graphql_object!(Root: () |&self| { fn run_type_info_query(doc: &str, f: F) where F: Fn(&HashMap) -> () { let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); - let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &()) + let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &()) .expect("Execution failed"); assert_eq!(errs, []); diff --git a/src/tests/introspection_tests.rs b/src/tests/introspection_tests.rs index 97d7c587..6e9cceab 100644 --- a/src/tests/introspection_tests.rs +++ b/src/tests/introspection_tests.rs @@ -1,5 +1,6 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; +use executor::Variables; use value::Value; use schema::model::RootNode; use tests::model::Database; @@ -19,7 +20,7 @@ fn test_query_type_name() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("__schema", Value::object(vec![ ("queryType", Value::object(vec![ @@ -42,7 +43,7 @@ fn test_specific_type_name() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("__type", Value::object(vec![ ("name", Value::string("Droid")), @@ -65,7 +66,7 @@ fn test_specific_object_type_name_and_kind() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("__type", Value::object(vec![ ("name", Value::string("Droid")), @@ -89,7 +90,7 @@ fn test_specific_interface_type_name_and_kind() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("__type", Value::object(vec![ ("name", Value::string("Character")), @@ -113,7 +114,7 @@ fn test_documentation() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok(( Value::object(vec![ ("__type", Value::object(vec![ @@ -138,7 +139,7 @@ fn test_possible_types() { let database = Database::new(); let schema = RootNode::new(&database, EmptyMutation::::new()); - let result = ::execute(doc, None, &schema, &HashMap::new(), &database); + let result = ::execute(doc, None, &schema, &Variables::new(), &database); println!("Result: {:#?}", result); diff --git a/src/tests/query_tests.rs b/src/tests/query_tests.rs index c9325efd..2837c7b0 100644 --- a/src/tests/query_tests.rs +++ b/src/tests/query_tests.rs @@ -1,6 +1,5 @@ -use std::collections::HashMap; - use ast::InputValue; +use executor::Variables; use value::Value; use schema::model::RootNode; use types::scalars::EmptyMutation; @@ -18,7 +17,7 @@ fn test_hero_name() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("hero", Value::object(vec![ ("name", Value::string("R2-D2")), @@ -43,7 +42,7 @@ fn test_hero_name_and_friends() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("hero", Value::object(vec![ ("id", Value::string("2001")), @@ -84,7 +83,7 @@ fn test_hero_name_and_friends_and_friends_of_friends() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("hero", Value::object(vec![ ("id", Value::string("2001")), @@ -166,7 +165,7 @@ fn test_query_name() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("human", Value::object(vec![ ("name", Value::string("Luke Skywalker")), @@ -182,7 +181,7 @@ fn test_query_alias_single() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("luke", Value::object(vec![ ("name", Value::string("Luke Skywalker")), @@ -202,7 +201,7 @@ fn test_query_alias_multiple() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("luke", Value::object(vec![ ("name", Value::string("Luke Skywalker")), @@ -230,7 +229,7 @@ fn test_query_alias_multiple_with_fragment() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("luke", Value::object(vec![ ("name", Value::string("Luke Skywalker")), @@ -289,7 +288,7 @@ fn test_query_friends_names() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("human", Value::object(vec![ ("friends", Value::list(vec![ @@ -329,7 +328,7 @@ fn test_query_inline_fragments_droid() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("hero", Value::object(vec![ ("__typename", Value::string("Droid")), @@ -354,7 +353,7 @@ fn test_query_inline_fragments_human() { let schema = RootNode::new(&database, EmptyMutation::::new()); assert_eq!( - ::execute(doc, None, &schema, &HashMap::new(), &database), + ::execute(doc, None, &schema, &Variables::new(), &database), Ok((Value::object(vec![ ("hero", Value::object(vec![ ("__typename", Value::string("Human")), diff --git a/src/types/base.rs b/src/types/base.rs index eadab4a3..1b6623f6 100644 --- a/src/types/base.rs +++ b/src/types/base.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; use ast::{InputValue, Selection, Directive, FromInputValue}; +use executor::Variables; use value::Value; use schema::meta::{Argument, MetaType}; @@ -390,7 +391,7 @@ fn resolve_selection_set_into( } } -fn is_excluded(directives: &Option>>, vars: &HashMap) -> bool { +fn is_excluded(directives: &Option>>, vars: &Variables) -> bool { if let Some(ref directives) = *directives { for &Spanning { item: ref directive, .. } in directives { let condition: bool = directive.arguments.iter() diff --git a/src/validation/input_value.rs b/src/validation/input_value.rs index 97130620..aec372fd 100644 --- a/src/validation/input_value.rs +++ b/src/validation/input_value.rs @@ -1,8 +1,9 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::fmt; use parser::SourcePosition; use ast::{InputValue, Document, Definition, VariableDefinitions}; +use executor::Variables; use validation::RuleError; use schema::model::{SchemaType, TypeType}; use schema::meta::{MetaType, ScalarMeta, InputObjectMeta, EnumMeta}; @@ -15,7 +16,7 @@ enum Path<'a> { } pub fn validate_input_values( - values: &HashMap, + values: &Variables, document: &Document, schema: &SchemaType, ) @@ -36,7 +37,7 @@ pub fn validate_input_values( } fn validate_var_defs( - values: &HashMap, + values: &Variables, var_defs: &VariableDefinitions, schema: &SchemaType, errors: &mut Vec,