Performance improvements (#202)

Performance improvements

* Replace the IndexMap in the serialized object with a plain
  `Vec<(String, Value)>` because linear search is faster for few
  elements

* Some general tweaks to skip some allocations
This commit is contained in:
Georg Semmler 2018-08-13 13:47:18 +00:00 committed by Christian Legnitto
parent 56f71e934b
commit 90b89f00ee
22 changed files with 614 additions and 353 deletions

View file

@ -1,9 +1,7 @@
use indexmap::IndexMap;
use executor::Variables; use executor::Variables;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
struct TestType; struct TestType;
@ -19,7 +17,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: Variables, f: F) fn run_variable_query<F>(query: &str, vars: Variables, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
@ -36,7 +34,7 @@ where
fn run_query<F>(query: &str, f: F) fn run_query<F>(query: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
run_variable_query(query, Variables::new(), f); run_variable_query(query, Variables::new(), f);
} }
@ -44,32 +42,32 @@ where
#[test] #[test]
fn scalar_include_true() { fn scalar_include_true() {
run_query("{ a, b @include(if: true) }", |result| { run_query("{ a, b @include(if: true) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn scalar_include_false() { fn scalar_include_false() {
run_query("{ a, b @include(if: false) }", |result| { run_query("{ a, b @include(if: false) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn scalar_skip_false() { fn scalar_skip_false() {
run_query("{ a, b @skip(if: false) }", |result| { run_query("{ a, b @skip(if: false) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn scalar_skip_true() { fn scalar_skip_true() {
run_query("{ a, b @skip(if: true) }", |result| { run_query("{ a, b @skip(if: true) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
@ -78,8 +76,8 @@ fn fragment_spread_include_true() {
run_query( run_query(
"{ a, ...Frag @include(if: true) } fragment Frag on TestType { b }", "{ a, ...Frag @include(if: true) } fragment Frag on TestType { b }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}, },
); );
} }
@ -89,8 +87,8 @@ fn fragment_spread_include_false() {
run_query( run_query(
"{ a, ...Frag @include(if: false) } fragment Frag on TestType { b }", "{ a, ...Frag @include(if: false) } fragment Frag on TestType { b }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}, },
); );
} }
@ -100,8 +98,8 @@ fn fragment_spread_skip_false() {
run_query( run_query(
"{ a, ...Frag @skip(if: false) } fragment Frag on TestType { b }", "{ a, ...Frag @skip(if: false) } fragment Frag on TestType { b }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}, },
); );
} }
@ -111,8 +109,8 @@ fn fragment_spread_skip_true() {
run_query( run_query(
"{ a, ...Frag @skip(if: true) } fragment Frag on TestType { b }", "{ a, ...Frag @skip(if: true) } fragment Frag on TestType { b }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}, },
); );
} }
@ -122,8 +120,8 @@ fn inline_fragment_include_true() {
run_query( run_query(
"{ a, ... on TestType @include(if: true) { b } }", "{ a, ... on TestType @include(if: true) { b } }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}, },
); );
} }
@ -133,8 +131,8 @@ fn inline_fragment_include_false() {
run_query( run_query(
"{ a, ... on TestType @include(if: false) { b } }", "{ a, ... on TestType @include(if: false) { b } }",
|result| { |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}, },
); );
} }
@ -142,79 +140,79 @@ fn inline_fragment_include_false() {
#[test] #[test]
fn inline_fragment_skip_false() { fn inline_fragment_skip_false() {
run_query("{ a, ... on TestType @skip(if: false) { b } }", |result| { run_query("{ a, ... on TestType @skip(if: false) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn inline_fragment_skip_true() { fn inline_fragment_skip_true() {
run_query("{ a, ... on TestType @skip(if: true) { b } }", |result| { run_query("{ a, ... on TestType @skip(if: true) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn anonymous_inline_fragment_include_true() { fn anonymous_inline_fragment_include_true() {
run_query("{ a, ... @include(if: true) { b } }", |result| { run_query("{ a, ... @include(if: true) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn anonymous_inline_fragment_include_false() { fn anonymous_inline_fragment_include_false() {
run_query("{ a, ... @include(if: false) { b } }", |result| { run_query("{ a, ... @include(if: false) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn anonymous_inline_fragment_skip_false() { fn anonymous_inline_fragment_skip_false() {
run_query("{ a, ... @skip(if: false) { b } }", |result| { run_query("{ a, ... @skip(if: false) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn anonymous_inline_fragment_skip_true() { fn anonymous_inline_fragment_skip_true() {
run_query("{ a, ... @skip(if: true) { b } }", |result| { run_query("{ a, ... @skip(if: true) { b } }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn scalar_include_true_skip_true() { fn scalar_include_true_skip_true() {
run_query("{ a, b @include(if: true) @skip(if: true) }", |result| { run_query("{ a, b @include(if: true) @skip(if: true) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn scalar_include_true_skip_false() { fn scalar_include_true_skip_false() {
run_query("{ a, b @include(if: true) @skip(if: false) }", |result| { run_query("{ a, b @include(if: true) @skip(if: false) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), Some(&Value::string("b"))); assert_eq!(result.get_field_value("b"), Some(&Value::string("b")));
}); });
} }
#[test] #[test]
fn scalar_include_false_skip_true() { fn scalar_include_false_skip_true() {
run_query("{ a, b @include(if: false) @skip(if: true) }", |result| { run_query("{ a, b @include(if: false) @skip(if: true) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }
#[test] #[test]
fn scalar_include_false_skip_false() { fn scalar_include_false_skip_false() {
run_query("{ a, b @include(if: false) @skip(if: false) }", |result| { run_query("{ a, b @include(if: false) @skip(if: false) }", |result| {
assert_eq!(result.get("a"), Some(&Value::string("a"))); assert_eq!(result.get_field_value("a"), Some(&Value::string("a")));
assert_eq!(result.get("b"), None); assert_eq!(result.get_field_value("b"), None);
}); });
} }

View file

@ -1,12 +1,10 @@
use indexmap::IndexMap;
use ast::InputValue; use ast::InputValue;
use executor::Variables; use executor::Variables;
use parser::SourcePosition; use parser::SourcePosition;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use validation::RuleError; use validation::RuleError;
use value::Value; use value::{Value, Object};
use GraphQLError::ValidationError; use GraphQLError::ValidationError;
#[derive(GraphQLEnum, Debug)] #[derive(GraphQLEnum, Debug)]
@ -30,7 +28,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: Variables, f: F) fn run_variable_query<F>(query: &str, vars: Variables, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
@ -47,7 +45,7 @@ where
fn run_query<F>(query: &str, f: F) fn run_query<F>(query: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
run_variable_query(query, Variables::new(), f); run_variable_query(query, Variables::new(), f);
} }
@ -55,14 +53,14 @@ where
#[test] #[test]
fn accepts_enum_literal() { fn accepts_enum_literal() {
run_query("{ toString(color: RED) }", |result| { run_query("{ toString(color: RED) }", |result| {
assert_eq!(result.get("toString"), Some(&Value::string("Color::Red"))); assert_eq!(result.get_field_value("toString"), Some(&Value::string("Color::Red")));
}); });
} }
#[test] #[test]
fn serializes_as_output() { fn serializes_as_output() {
run_query("{ aColor }", |result| { run_query("{ aColor }", |result| {
assert_eq!(result.get("aColor"), Some(&Value::string("RED"))); assert_eq!(result.get_field_value("aColor"), Some(&Value::string("RED")));
}); });
} }
@ -92,7 +90,7 @@ fn accepts_strings_in_variables() {
.into_iter() .into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("toString"), Some(&Value::string("Color::Red"))); assert_eq!(result.get_field_value("toString"), Some(&Value::string("Color::Red")));
}, },
); );
} }

View file

@ -1,9 +1,7 @@
use indexmap::IndexMap;
use executor::Variables; use executor::Variables;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
/* /*
@ -76,7 +74,7 @@ graphql_object!(Root: () |&self| {
fn run_type_info_query<F>(doc: &str, f: F) fn run_type_info_query<F>(doc: &str, f: F)
where where
F: Fn((&IndexMap<String, Value>, &Vec<Value>)) -> (), F: Fn((&Object, &Vec<Value>)) -> (),
{ {
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
@ -90,13 +88,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let values = type_info let values = type_info
.get("enumValues") .get_field_value("enumValues")
.expect("enumValues field missing") .expect("enumValues field missing")
.as_list_value() .as_list_value()
.expect("enumValues not a list"); .expect("enumValues not a list");
@ -122,8 +120,8 @@ fn default_name_introspection() {
"#; "#;
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!(type_info.get("name"), Some(&Value::string("DefaultName"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("DefaultName")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
@ -171,8 +169,8 @@ fn named_introspection() {
"#; "#;
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!(type_info.get("name"), Some(&Value::string("ANamedEnum"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("ANamedEnum")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
@ -221,10 +219,10 @@ fn no_trailing_comma_introspection() {
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("NoTrailingComma")) Some(&Value::string("NoTrailingComma"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
@ -273,11 +271,11 @@ fn enum_description_introspection() {
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("EnumDescription")) Some(&Value::string("EnumDescription"))
); );
assert_eq!( assert_eq!(
type_info.get("description"), type_info.get_field_value("description"),
Some(&Value::string("A description of the enum itself")) Some(&Value::string("A description of the enum itself"))
); );
@ -328,10 +326,10 @@ fn enum_value_description_introspection() {
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("EnumValueDescription")) Some(&Value::string("EnumValueDescription"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
@ -380,10 +378,10 @@ fn enum_deprecation_introspection() {
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("EnumDeprecation")) Some(&Value::string("EnumDeprecation"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
@ -438,10 +436,10 @@ fn enum_deprecation_no_values_introspection() {
run_type_info_query(doc, |(type_info, values)| { run_type_info_query(doc, |(type_info, values)| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("EnumDeprecation")) Some(&Value::string("EnumDeprecation"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(values.len(), 0); assert_eq!(values.len(), 0);
}); });

View file

@ -1,10 +1,8 @@
use indexmap::IndexMap;
use ast::{FromInputValue, InputValue}; use ast::{FromInputValue, InputValue};
use executor::Variables; use executor::Variables;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
struct Root; struct Root;
@ -106,7 +104,7 @@ graphql_object!(Root: () |&self| {
fn run_type_info_query<F>(doc: &str, f: F) fn run_type_info_query<F>(doc: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>, &Vec<Value>) -> (), F: Fn(&Object, &Vec<Value>) -> (),
{ {
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
@ -120,13 +118,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("inputFields") .get_field_value("inputFields")
.expect("inputFields field missing") .expect("inputFields field missing")
.as_list_value() .as_list_value()
.expect("inputFields not a list"); .expect("inputFields not a list");
@ -156,8 +154,8 @@ fn default_name_introspection() {
"#; "#;
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!(type_info.get("name"), Some(&Value::string("DefaultName"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("DefaultName")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(fields.len(), 2); assert_eq!(fields.len(), 2);
@ -256,10 +254,10 @@ fn no_trailing_comma_introspection() {
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("NoTrailingComma")) Some(&Value::string("NoTrailingComma"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(fields.len(), 2); assert_eq!(fields.len(), 2);
@ -337,8 +335,8 @@ fn derive_introspection() {
"#; "#;
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!(type_info.get("name"), Some(&Value::string("Derive"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("Derive")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(fields.len(), 1); assert_eq!(fields.len(), 1);
@ -405,10 +403,10 @@ fn named_introspection() {
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("ANamedInputObject")) Some(&Value::string("ANamedInputObject"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(fields.len(), 1); assert_eq!(fields.len(), 1);
@ -461,9 +459,9 @@ fn description_introspection() {
"#; "#;
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!(type_info.get("name"), Some(&Value::string("Description"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("Description")));
assert_eq!( assert_eq!(
type_info.get("description"), type_info.get_field_value("description"),
Some(&Value::string("Description for the input object")) Some(&Value::string("Description for the input object"))
); );
@ -519,10 +517,10 @@ fn field_description_introspection() {
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("FieldDescription")) Some(&Value::string("FieldDescription"))
); );
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
assert_eq!(fields.len(), 2); assert_eq!(fields.len(), 2);
@ -597,7 +595,7 @@ fn field_with_defaults_introspection() {
run_type_info_query(doc, |type_info, fields| { run_type_info_query(doc, |type_info, fields| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("FieldWithDefaults")) Some(&Value::string("FieldWithDefaults"))
); );

View file

@ -126,21 +126,39 @@ fn enum_introspection() {
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
assert_eq!(type_info.get("name"), Some(&Value::string("SampleEnum"))); assert_eq!(
assert_eq!(type_info.get("kind"), Some(&Value::string("ENUM"))); type_info.get_field_value("name"),
assert_eq!(type_info.get("description"), Some(&Value::null())); Some(&Value::string("SampleEnum"))
assert_eq!(type_info.get("interfaces"), Some(&Value::null())); );
assert_eq!(type_info.get("possibleTypes"), Some(&Value::null())); assert_eq!(
assert_eq!(type_info.get("inputFields"), Some(&Value::null())); type_info.get_field_value("kind"),
assert_eq!(type_info.get("ofType"), Some(&Value::null())); Some(&Value::string("ENUM"))
);
assert_eq!(
type_info.get_field_value("description"),
Some(&Value::null())
);
assert_eq!(
type_info.get_field_value("interfaces"),
Some(&Value::null())
);
assert_eq!(
type_info.get_field_value("possibleTypes"),
Some(&Value::null())
);
assert_eq!(
type_info.get_field_value("inputFields"),
Some(&Value::null())
);
assert_eq!(type_info.get_field_value("ofType"), Some(&Value::null()));
let values = type_info let values = type_info
.get("enumValues") .get_field_value("enumValues")
.expect("enumValues field missing") .expect("enumValues field missing")
.as_list_value() .as_list_value()
.expect("enumValues not a list"); .expect("enumValues not a list");
@ -219,27 +237,39 @@ fn interface_introspection() {
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("SampleInterface")) Some(&Value::string("SampleInterface"))
); );
assert_eq!(type_info.get("kind"), Some(&Value::string("INTERFACE")));
assert_eq!( assert_eq!(
type_info.get("description"), type_info.get_field_value("kind"),
Some(&Value::string("INTERFACE"))
);
assert_eq!(
type_info.get_field_value("description"),
Some(&Value::string("A sample interface")) Some(&Value::string("A sample interface"))
); );
assert_eq!(type_info.get("interfaces"), Some(&Value::null())); assert_eq!(
assert_eq!(type_info.get("enumValues"), Some(&Value::null())); type_info.get_field_value("interfaces"),
assert_eq!(type_info.get("inputFields"), Some(&Value::null())); Some(&Value::null())
assert_eq!(type_info.get("ofType"), Some(&Value::null())); );
assert_eq!(
type_info.get_field_value("enumValues"),
Some(&Value::null())
);
assert_eq!(
type_info.get_field_value("inputFields"),
Some(&Value::null())
);
assert_eq!(type_info.get_field_value("ofType"), Some(&Value::null()));
let possible_types = type_info let possible_types = type_info
.get("possibleTypes") .get_field_value("possibleTypes")
.expect("possibleTypes field missing") .expect("possibleTypes field missing")
.as_list_value() .as_list_value()
.expect("possibleTypes not a list"); .expect("possibleTypes not a list");
@ -251,7 +281,7 @@ fn interface_introspection() {
))); )));
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields field not an object value"); .expect("fields field not an object value");
@ -353,32 +383,47 @@ fn object_introspection() {
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
assert_eq!(type_info.get("name"), Some(&Value::string("Root")));
assert_eq!(type_info.get("kind"), Some(&Value::string("OBJECT")));
assert_eq!( assert_eq!(
type_info.get("description"), type_info.get_field_value("name"),
Some(&Value::string("Root"))
);
assert_eq!(
type_info.get_field_value("kind"),
Some(&Value::string("OBJECT"))
);
assert_eq!(
type_info.get_field_value("description"),
Some(&Value::string("The root query object in the schema")) Some(&Value::string("The root query object in the schema"))
); );
assert_eq!( assert_eq!(
type_info.get("interfaces"), type_info.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![("name", Value::string("SampleInterface"))] vec![("name", Value::string("SampleInterface"))]
.into_iter() .into_iter()
.collect(), .collect(),
)])) )]))
); );
assert_eq!(type_info.get("enumValues"), Some(&Value::null())); assert_eq!(
assert_eq!(type_info.get("inputFields"), Some(&Value::null())); type_info.get_field_value("enumValues"),
assert_eq!(type_info.get("ofType"), Some(&Value::null())); Some(&Value::null())
assert_eq!(type_info.get("possibleTypes"), Some(&Value::null())); );
assert_eq!(
type_info.get_field_value("inputFields"),
Some(&Value::null())
);
assert_eq!(type_info.get_field_value("ofType"), Some(&Value::null()));
assert_eq!(
type_info.get_field_value("possibleTypes"),
Some(&Value::null())
);
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields field not an object value"); .expect("fields field not an object value");
@ -538,7 +583,7 @@ fn scalar_introspection() {
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing"); .expect("__type field missing");
assert_eq!( assert_eq!(

View file

@ -1,12 +1,10 @@
use indexmap::IndexMap;
use ast::InputValue; use ast::InputValue;
use executor::Variables; use executor::Variables;
use parser::SourcePosition; use parser::SourcePosition;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use validation::RuleError; use validation::RuleError;
use value::Value; use value::{Value, Object};
use GraphQLError::ValidationError; use GraphQLError::ValidationError;
#[derive(Debug)] #[derive(Debug)]
@ -116,7 +114,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: Variables, f: F) fn run_variable_query<F>(query: &str, vars: Variables, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
let schema = RootNode::new(TestType, EmptyMutation::<()>::new()); let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
@ -133,7 +131,7 @@ where
fn run_query<F>(query: &str, f: F) fn run_query<F>(query: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
run_variable_query(query, Variables::new(), f); run_variable_query(query, Variables::new(), f);
} }
@ -144,7 +142,7 @@ fn inline_complex_input() {
r#"{ fieldWithObjectInput(input: {a: "foo", b: ["bar"], c: "baz"}) }"#, r#"{ fieldWithObjectInput(input: {a: "foo", b: ["bar"], c: "baz"}) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#))); Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
}, },
); );
@ -156,7 +154,7 @@ fn inline_parse_single_value_to_list() {
r#"{ fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"}) }"#, r#"{ fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"}) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#))); Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
}, },
); );
@ -168,7 +166,7 @@ fn inline_runs_from_input_value_on_scalar() {
r#"{ fieldWithObjectInput(input: {c: "baz", d: "SerializedValue"}) }"#, r#"{ fieldWithObjectInput(input: {c: "baz", d: "SerializedValue"}) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#))); Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#)));
}, },
); );
@ -192,7 +190,7 @@ fn variable_complex_input() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#))); Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
}, },
); );
@ -216,7 +214,7 @@ fn variable_parse_single_value_to_list() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#))); Some(&Value::string(r#"Some(TestInputObject { a: Some("foo"), b: Some([Some("bar")]), c: "baz", d: None })"#)));
}, },
); );
@ -239,7 +237,7 @@ fn variable_runs_from_input_value_on_scalar() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithObjectInput"), result.get_field_value("fieldWithObjectInput"),
Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#))); Some(&Value::string(r#"Some(TestInputObject { a: None, b: None, c: "baz", d: Some(TestComplexScalar) })"#)));
}, },
); );
@ -387,7 +385,7 @@ fn variable_error_on_additional_field() {
fn allow_nullable_inputs_to_be_omitted() { fn allow_nullable_inputs_to_be_omitted() {
run_query(r#"{ fieldWithNullableStringInput }"#, |result| { run_query(r#"{ fieldWithNullableStringInput }"#, |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#)) Some(&Value::string(r#"None"#))
); );
}); });
@ -399,7 +397,7 @@ fn allow_nullable_inputs_to_be_omitted_in_variable() {
r#"query q($value: String) { fieldWithNullableStringInput(input: $value) }"#, r#"query q($value: String) { fieldWithNullableStringInput(input: $value) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#)) Some(&Value::string(r#"None"#))
); );
}, },
@ -412,7 +410,7 @@ fn allow_nullable_inputs_to_be_explicitly_null() {
r#"{ fieldWithNullableStringInput(input: null) }"#, r#"{ fieldWithNullableStringInput(input: null) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#)) Some(&Value::string(r#"None"#))
); );
}, },
@ -428,7 +426,7 @@ fn allow_nullable_inputs_to_be_set_to_null_in_variable() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"None"#)) Some(&Value::string(r#"None"#))
); );
}, },
@ -444,7 +442,7 @@ fn allow_nullable_inputs_to_be_set_to_value_in_variable() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"Some("a")"#)) Some(&Value::string(r#"Some("a")"#))
); );
}, },
@ -457,7 +455,7 @@ fn allow_nullable_inputs_to_be_set_to_value_directly() {
r#"{ fieldWithNullableStringInput(input: "a") }"#, r#"{ fieldWithNullableStringInput(input: "a") }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNullableStringInput"), result.get_field_value("fieldWithNullableStringInput"),
Some(&Value::string(r#"Some("a")"#)) Some(&Value::string(r#"Some("a")"#))
); );
}, },
@ -511,7 +509,7 @@ fn allow_non_nullable_inputs_to_be_set_to_value_in_variable() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNonNullableStringInput"), result.get_field_value("fieldWithNonNullableStringInput"),
Some(&Value::string(r#""a""#)) Some(&Value::string(r#""a""#))
); );
}, },
@ -524,7 +522,7 @@ fn allow_non_nullable_inputs_to_be_set_to_value_directly() {
r#"{ fieldWithNonNullableStringInput(input: "a") }"#, r#"{ fieldWithNonNullableStringInput(input: "a") }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithNonNullableStringInput"), result.get_field_value("fieldWithNonNullableStringInput"),
Some(&Value::string(r#""a""#)) Some(&Value::string(r#""a""#))
); );
}, },
@ -539,7 +537,7 @@ fn allow_lists_to_be_null() {
.into_iter() .into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("list"), Some(&Value::string(r#"None"#))); assert_eq!(result.get_field_value("list"), Some(&Value::string(r#"None"#)));
}, },
); );
} }
@ -555,7 +553,7 @@ fn allow_lists_to_contain_values() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("list"), result.get_field_value("list"),
Some(&Value::string(r#"Some([Some("A")])"#)) Some(&Value::string(r#"Some([Some("A")])"#))
); );
}, },
@ -577,7 +575,7 @@ fn allow_lists_to_contain_null() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("list"), result.get_field_value("list"),
Some(&Value::string(r#"Some([Some("A"), None, Some("B")])"#)) Some(&Value::string(r#"Some([Some("A"), None, Some("B")])"#))
); );
}, },
@ -614,7 +612,7 @@ fn allow_non_null_lists_to_contain_values() {
)].into_iter() )].into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("nnList"), Some(&Value::string(r#"[Some("A")]"#))); assert_eq!(result.get_field_value("nnList"), Some(&Value::string(r#"[Some("A")]"#)));
}, },
); );
} }
@ -633,7 +631,7 @@ fn allow_non_null_lists_to_contain_null() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("nnList"), result.get_field_value("nnList"),
Some(&Value::string(r#"[Some("A"), None, Some("B")]"#)) Some(&Value::string(r#"[Some("A"), None, Some("B")]"#))
); );
}, },
@ -648,7 +646,7 @@ fn allow_lists_of_non_null_to_be_null() {
.into_iter() .into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("listNn"), Some(&Value::string(r#"None"#))); assert_eq!(result.get_field_value("listNn"), Some(&Value::string(r#"None"#)));
}, },
); );
} }
@ -663,7 +661,7 @@ fn allow_lists_of_non_null_to_contain_values() {
)].into_iter() )].into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("listNn"), Some(&Value::string(r#"Some(["A"])"#))); assert_eq!(result.get_field_value("listNn"), Some(&Value::string(r#"Some(["A"])"#)));
}, },
); );
} }
@ -748,7 +746,7 @@ fn allow_non_null_lists_of_non_null_to_contain_values() {
)].into_iter() )].into_iter()
.collect(), .collect(),
|result| { |result| {
assert_eq!(result.get("nnListNn"), Some(&Value::string(r#"["A"]"#))); assert_eq!(result.get_field_value("nnListNn"), Some(&Value::string(r#"["A"]"#)));
}, },
); );
} }
@ -799,7 +797,7 @@ fn does_not_allow_unknown_types_to_be_used_as_values() {
fn default_argument_when_not_provided() { fn default_argument_when_not_provided() {
run_query(r#"{ fieldWithDefaultArgumentValue }"#, |result| { run_query(r#"{ fieldWithDefaultArgumentValue }"#, |result| {
assert_eq!( assert_eq!(
result.get("fieldWithDefaultArgumentValue"), result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#)) Some(&Value::string(r#""Hello World""#))
); );
}); });
@ -811,7 +809,7 @@ fn default_argument_when_nullable_variable_not_provided() {
r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#, r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#,
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithDefaultArgumentValue"), result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#)) Some(&Value::string(r#""Hello World""#))
); );
}, },
@ -827,7 +825,7 @@ fn default_argument_when_nullable_variable_set_to_null() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("fieldWithDefaultArgumentValue"), result.get_field_value("fieldWithDefaultArgumentValue"),
Some(&Value::string(r#""Hello World""#)) Some(&Value::string(r#""Hello World""#))
); );
}, },
@ -838,14 +836,14 @@ fn default_argument_when_nullable_variable_set_to_null() {
fn nullable_input_object_arguments_successful_without_variables() { fn nullable_input_object_arguments_successful_without_variables() {
run_query(r#"{ exampleInput(arg: {a: "abc", b: 123}) }"#, |result| { run_query(r#"{ exampleInput(arg: {a: "abc", b: 123}) }"#, |result| {
assert_eq!( assert_eq!(
result.get("exampleInput"), result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: Some("abc"), b: 123"#)) Some(&Value::string(r#"a: Some("abc"), b: 123"#))
); );
}); });
run_query(r#"{ exampleInput(arg: {a: null, b: 1}) }"#, |result| { run_query(r#"{ exampleInput(arg: {a: null, b: 1}) }"#, |result| {
assert_eq!( assert_eq!(
result.get("exampleInput"), result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#)) Some(&Value::string(r#"a: None, b: 1"#))
); );
}); });
@ -860,7 +858,7 @@ fn nullable_input_object_arguments_successful_with_variables() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("exampleInput"), result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 123"#)) Some(&Value::string(r#"a: None, b: 123"#))
); );
}, },
@ -873,7 +871,7 @@ fn nullable_input_object_arguments_successful_with_variables() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("exampleInput"), result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#)) Some(&Value::string(r#"a: None, b: 1"#))
); );
}, },
@ -884,7 +882,7 @@ fn nullable_input_object_arguments_successful_with_variables() {
vec![].into_iter().collect(), vec![].into_iter().collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("exampleInput"), result.get_field_value("exampleInput"),
Some(&Value::string(r#"a: None, b: 1"#)) Some(&Value::string(r#"a: None, b: 1"#))
); );
}, },
@ -969,7 +967,7 @@ fn does_not_allow_null_variable_for_required_field() {
fn input_object_with_default_values() { fn input_object_with_default_values() {
run_query(r#"{ inputWithDefaults(arg: {a: 1}) }"#, |result| { run_query(r#"{ inputWithDefaults(arg: {a: 1}) }"#, |result| {
assert_eq!( assert_eq!(
result.get("inputWithDefaults"), result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#)) Some(&Value::string(r#"a: 1"#))
); );
}); });
@ -981,7 +979,7 @@ fn input_object_with_default_values() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("inputWithDefaults"), result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#)) Some(&Value::string(r#"a: 1"#))
); );
}, },
@ -992,7 +990,7 @@ fn input_object_with_default_values() {
vec![].into_iter().collect(), vec![].into_iter().collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("inputWithDefaults"), result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 1"#)) Some(&Value::string(r#"a: 1"#))
); );
}, },
@ -1005,7 +1003,7 @@ fn input_object_with_default_values() {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("inputWithDefaults"), result.get_field_value("inputWithDefaults"),
Some(&Value::string(r#"a: 2"#)) Some(&Value::string(r#"a: 2"#))
); );
}, },
@ -1024,7 +1022,7 @@ mod integers {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("integerInput"), result.get_field_value("integerInput"),
Some(&Value::string(r#"value: 1"#)) Some(&Value::string(r#"value: 1"#))
); );
}, },
@ -1037,7 +1035,7 @@ mod integers {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("integerInput"), result.get_field_value("integerInput"),
Some(&Value::string(r#"value: -1"#)) Some(&Value::string(r#"value: -1"#))
); );
}, },
@ -1097,7 +1095,7 @@ mod floats {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("floatInput"), result.get_field_value("floatInput"),
Some(&Value::string(r#"value: 10"#)) Some(&Value::string(r#"value: 10"#))
); );
}, },
@ -1113,7 +1111,7 @@ mod floats {
.collect(), .collect(),
|result| { |result| {
assert_eq!( assert_eq!(
result.get("floatInput"), result.get_field_value("floatInput"),
Some(&Value::string(r#"value: -1"#)) Some(&Value::string(r#"value: -1"#))
); );
}, },

View file

@ -8,7 +8,7 @@ use ast::InputValue;
use executor::ExecutionError; use executor::ExecutionError;
use parser::{ParseError, SourcePosition, Spanning}; use parser::{ParseError, SourcePosition, Spanning};
use validation::RuleError; use validation::RuleError;
use {GraphQLError, Value}; use {GraphQLError, Object, Value};
#[derive(Serialize)] #[derive(Serialize)]
struct SerializeHelper { struct SerializeHelper {
@ -250,6 +250,22 @@ impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
} }
} }
impl ser::Serialize for Object {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(self.field_count()))?;
for &(ref f, ref v) in self.iter() {
map.serialize_key(f)?;
map.serialize_value(v)?;
}
map.end()
}
}
impl ser::Serialize for Value { impl ser::Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where

View file

@ -162,7 +162,7 @@ pub use schema::model::RootNode;
pub use types::base::{Arguments, GraphQLType, TypeKind}; pub use types::base::{Arguments, GraphQLType, TypeKind};
pub use types::scalars::{EmptyMutation, ID}; pub use types::scalars::{EmptyMutation, ID};
pub use validation::RuleError; pub use validation::RuleError;
pub use value::Value; pub use value::{Value, Object};
pub use schema::meta; pub use schema::meta;

View file

@ -112,13 +112,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields not a list"); .expect("fields not a list");
@ -128,7 +128,7 @@ where
.filter(|f| { .filter(|f| {
f.as_object_value() f.as_object_value()
.expect("Field not an object") .expect("Field not an object")
.get("name") .get_field_value("name")
.expect("name field missing from field") .expect("name field missing from field")
.as_string_value() .as_string_value()
.expect("name is not a string") == field_name .expect("name is not a string") == field_name
@ -141,7 +141,7 @@ where
println!("Field: {:?}", field); println!("Field: {:?}", field);
let args = field let args = field
.get("args") .get_field_value("args")
.expect("args missing from field") .expect("args missing from field")
.as_list_value() .as_list_value()
.expect("args is not a list"); .expect("args is not a list");

View file

@ -1,10 +1,8 @@
use indexmap::IndexMap;
use ast::InputValue; use ast::InputValue;
use executor::FieldResult; use executor::FieldResult;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Object, Value};
struct Interface; struct Interface;
struct Root; struct Root;
@ -59,7 +57,7 @@ graphql_interface!(Interface: () |&self| {
fn run_field_info_query<F>(type_name: &str, field_name: &str, f: F) fn run_field_info_query<F>(type_name: &str, field_name: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
let doc = r#" let doc = r#"
query ($typeName: String!) { query ($typeName: String!) {
@ -87,13 +85,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields not a list"); .expect("fields not a list");
@ -103,7 +101,7 @@ where
.filter(|f| { .filter(|f| {
f.as_object_value() f.as_object_value()
.expect("Field not an object") .expect("Field not an object")
.get("name") .get_field_value("name")
.expect("name field missing from field") .expect("name field missing from field")
.as_string_value() .as_string_value()
.expect("name is not a string") == field_name .expect("name is not a string") == field_name
@ -121,57 +119,78 @@ where
#[test] #[test]
fn introspect_object_field_simple() { fn introspect_object_field_simple() {
run_field_info_query("Root", "simple", |field| { run_field_info_query("Root", "simple", |field| {
assert_eq!(field.get("name"), Some(&Value::string("simple"))); assert_eq!(
assert_eq!(field.get("description"), Some(&Value::null())); field.get_field_value("name"),
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false))); Some(&Value::string("simple"))
assert_eq!(field.get("deprecationReason"), Some(&Value::null())); );
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
assert_eq!(
field.get_field_value("isDeprecated"),
Some(&Value::boolean(false))
);
assert_eq!(
field.get_field_value("deprecationReason"),
Some(&Value::null())
);
}); });
} }
#[test] #[test]
fn introspect_interface_field_simple() { fn introspect_interface_field_simple() {
run_field_info_query("Interface", "simple", |field| { run_field_info_query("Interface", "simple", |field| {
assert_eq!(field.get("name"), Some(&Value::string("simple"))); assert_eq!(
assert_eq!(field.get("description"), Some(&Value::null())); field.get_field_value("name"),
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false))); Some(&Value::string("simple"))
assert_eq!(field.get("deprecationReason"), Some(&Value::null())); );
assert_eq!(field.get_field_value("description"), Some(&Value::null()));
assert_eq!(
field.get_field_value("isDeprecated"),
Some(&Value::boolean(false))
);
assert_eq!(
field.get_field_value("deprecationReason"),
Some(&Value::null())
);
}); });
} }
#[test] #[test]
fn introspect_object_field_description() { fn introspect_object_field_description() {
run_field_info_query("Root", "description", |field| { run_field_info_query("Root", "description", |field| {
assert_eq!(field.get("name"), Some(&Value::string("description")));
assert_eq!( assert_eq!(
field.get("description"), field.get_field_value("name"),
Some(&Value::string("description"))
);
assert_eq!(
field.get_field_value("description"),
Some(&Value::string("Field description")) Some(&Value::string("Field description"))
); );
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null())); assert_eq!(field.get_field_value("deprecationReason"), Some(&Value::null()));
}); });
} }
#[test] #[test]
fn introspect_interface_field_description() { fn introspect_interface_field_description() {
run_field_info_query("Interface", "description", |field| { run_field_info_query("Interface", "description", |field| {
assert_eq!(field.get("name"), Some(&Value::string("description"))); assert_eq!(field.get_field_value("name"), Some(&Value::string("description")));
assert_eq!( assert_eq!(
field.get("description"), field.get_field_value("description"),
Some(&Value::string("Field description")) Some(&Value::string("Field description"))
); );
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(false))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(false)));
assert_eq!(field.get("deprecationReason"), Some(&Value::null())); assert_eq!(field.get_field_value("deprecationReason"), Some(&Value::null()));
}); });
} }
#[test] #[test]
fn introspect_object_field_deprecated() { fn introspect_object_field_deprecated() {
run_field_info_query("Root", "deprecated", |field| { run_field_info_query("Root", "deprecated", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecated"))); assert_eq!(field.get_field_value("name"), Some(&Value::string("deprecated")));
assert_eq!(field.get("description"), Some(&Value::null())); assert_eq!(field.get_field_value("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!( assert_eq!(
field.get("deprecationReason"), field.get_field_value("deprecationReason"),
Some(&Value::string("Deprecation reason")) Some(&Value::string("Deprecation reason"))
); );
}); });
@ -180,11 +199,11 @@ fn introspect_object_field_deprecated() {
#[test] #[test]
fn introspect_interface_field_deprecated() { fn introspect_interface_field_deprecated() {
run_field_info_query("Interface", "deprecated", |field| { run_field_info_query("Interface", "deprecated", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecated"))); assert_eq!(field.get_field_value("name"), Some(&Value::string("deprecated")));
assert_eq!(field.get("description"), Some(&Value::null())); assert_eq!(field.get_field_value("description"), Some(&Value::null()));
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!( assert_eq!(
field.get("deprecationReason"), field.get_field_value("deprecationReason"),
Some(&Value::string("Deprecation reason")) Some(&Value::string("Deprecation reason"))
); );
}); });
@ -193,14 +212,14 @@ fn introspect_interface_field_deprecated() {
#[test] #[test]
fn introspect_object_field_deprecated_descr() { fn introspect_object_field_deprecated_descr() {
run_field_info_query("Root", "deprecatedDescr", |field| { run_field_info_query("Root", "deprecatedDescr", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecatedDescr"))); assert_eq!(field.get_field_value("name"), Some(&Value::string("deprecatedDescr")));
assert_eq!( assert_eq!(
field.get("description"), field.get_field_value("description"),
Some(&Value::string("Field description")) Some(&Value::string("Field description"))
); );
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!( assert_eq!(
field.get("deprecationReason"), field.get_field_value("deprecationReason"),
Some(&Value::string("Deprecation reason")) Some(&Value::string("Deprecation reason"))
); );
}); });
@ -209,14 +228,14 @@ fn introspect_object_field_deprecated_descr() {
#[test] #[test]
fn introspect_interface_field_deprecated_descr() { fn introspect_interface_field_deprecated_descr() {
run_field_info_query("Interface", "deprecatedDescr", |field| { run_field_info_query("Interface", "deprecatedDescr", |field| {
assert_eq!(field.get("name"), Some(&Value::string("deprecatedDescr"))); assert_eq!(field.get_field_value("name"), Some(&Value::string("deprecatedDescr")));
assert_eq!( assert_eq!(
field.get("description"), field.get_field_value("description"),
Some(&Value::string("Field description")) Some(&Value::string("Field description"))
); );
assert_eq!(field.get("isDeprecated"), Some(&Value::boolean(true))); assert_eq!(field.get_field_value("isDeprecated"), Some(&Value::boolean(true)));
assert_eq!( assert_eq!(
field.get("deprecationReason"), field.get_field_value("deprecationReason"),
Some(&Value::string("Deprecation reason")) Some(&Value::string("Deprecation reason"))
); );
}); });

View file

@ -1,10 +1,9 @@
use indexmap::IndexMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use ast::InputValue; use ast::InputValue;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
/* /*
@ -130,7 +129,7 @@ graphql_object!(<'a> Root: () as "Root" |&self| {
fn run_type_info_query<F>(type_name: &str, f: F) fn run_type_info_query<F>(type_name: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>, &Vec<Value>) -> (), F: Fn(&Object, &Vec<Value>) -> (),
{ {
let doc = r#" let doc = r#"
query ($typeName: String!) { query ($typeName: String!) {
@ -157,13 +156,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields field not a list value"); .expect("fields field not a list value");
@ -175,10 +174,10 @@ where
fn introspect_custom_name() { fn introspect_custom_name() {
run_type_info_query("ACustomNamedInterface", |object, fields| { run_type_info_query("ACustomNamedInterface", |object, fields| {
assert_eq!( assert_eq!(
object.get("name"), object.get_field_value("name"),
Some(&Value::string("ACustomNamedInterface")) Some(&Value::string("ACustomNamedInterface"))
); );
assert_eq!(object.get("description"), Some(&Value::null())); assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
fields.contains(&Value::object( fields.contains(&Value::object(
@ -193,8 +192,8 @@ fn introspect_custom_name() {
#[test] #[test]
fn introspect_with_lifetime() { fn introspect_with_lifetime() {
run_type_info_query("WithLifetime", |object, fields| { run_type_info_query("WithLifetime", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("WithLifetime"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("WithLifetime")));
assert_eq!(object.get("description"), Some(&Value::null())); assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
fields.contains(&Value::object( fields.contains(&Value::object(
@ -209,8 +208,8 @@ fn introspect_with_lifetime() {
#[test] #[test]
fn introspect_with_generics() { fn introspect_with_generics() {
run_type_info_query("WithGenerics", |object, fields| { run_type_info_query("WithGenerics", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("WithGenerics"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("WithGenerics")));
assert_eq!(object.get("description"), Some(&Value::null())); assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
fields.contains(&Value::object( fields.contains(&Value::object(
@ -225,9 +224,9 @@ fn introspect_with_generics() {
#[test] #[test]
fn introspect_description_first() { fn introspect_description_first() {
run_type_info_query("DescriptionFirst", |object, fields| { run_type_info_query("DescriptionFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("DescriptionFirst"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("DescriptionFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -244,9 +243,9 @@ fn introspect_description_first() {
#[test] #[test]
fn introspect_fields_first() { fn introspect_fields_first() {
run_type_info_query("FieldsFirst", |object, fields| { run_type_info_query("FieldsFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("FieldsFirst"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("FieldsFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -263,9 +262,9 @@ fn introspect_fields_first() {
#[test] #[test]
fn introspect_interfaces_first() { fn introspect_interfaces_first() {
run_type_info_query("InterfacesFirst", |object, fields| { run_type_info_query("InterfacesFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("InterfacesFirst"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("InterfacesFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -283,11 +282,11 @@ fn introspect_interfaces_first() {
fn introspect_commas_with_trailing() { fn introspect_commas_with_trailing() {
run_type_info_query("CommasWithTrailing", |object, fields| { run_type_info_query("CommasWithTrailing", |object, fields| {
assert_eq!( assert_eq!(
object.get("name"), object.get_field_value("name"),
Some(&Value::string("CommasWithTrailing")) Some(&Value::string("CommasWithTrailing"))
); );
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -304,9 +303,9 @@ fn introspect_commas_with_trailing() {
#[test] #[test]
fn introspect_commas_on_meta() { fn introspect_commas_on_meta() {
run_type_info_query("CommasOnMeta", |object, fields| { run_type_info_query("CommasOnMeta", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("CommasOnMeta"))); assert_eq!(object.get_field_value("name"), Some(&Value::string("CommasOnMeta")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -324,11 +323,11 @@ fn introspect_commas_on_meta() {
fn introspect_resolvers_with_trailing_comma() { fn introspect_resolvers_with_trailing_comma() {
run_type_info_query("ResolversWithTrailingComma", |object, fields| { run_type_info_query("ResolversWithTrailingComma", |object, fields| {
assert_eq!( assert_eq!(
object.get("name"), object.get_field_value("name"),
Some(&Value::string("ResolversWithTrailingComma")) Some(&Value::string("ResolversWithTrailingComma"))
); );
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );

View file

@ -1,11 +1,10 @@
use indexmap::IndexMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use ast::InputValue; use ast::InputValue;
use executor::{Context, FieldResult}; use executor::{Context, FieldResult};
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Object, Value};
/* /*
@ -144,7 +143,7 @@ graphql_object!(<'a> Root: InnerContext as "Root" |&self| {
fn run_type_info_query<F>(type_name: &str, f: F) fn run_type_info_query<F>(type_name: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>, &Vec<Value>) -> (), F: Fn(&Object, &Vec<Value>) -> (),
{ {
let doc = r#" let doc = r#"
query ($typeName: String!) { query ($typeName: String!) {
@ -184,13 +183,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields field not a list value"); .expect("fields field not a list value");
@ -201,9 +200,15 @@ where
#[test] #[test]
fn introspect_custom_name() { fn introspect_custom_name() {
run_type_info_query("ACustomNamedType", |object, fields| { run_type_info_query("ACustomNamedType", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("ACustomNamedType"))); assert_eq!(
assert_eq!(object.get("description"), Some(&Value::null())); object.get_field_value("name"),
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![]))); Some(&Value::string("ACustomNamedType"))
);
assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![]))
);
assert!(fields.contains(&graphql_value!({ assert!(fields.contains(&graphql_value!({
"name": "simple", "name": "simple",
@ -215,9 +220,15 @@ fn introspect_custom_name() {
#[test] #[test]
fn introspect_with_lifetime() { fn introspect_with_lifetime() {
run_type_info_query("WithLifetime", |object, fields| { run_type_info_query("WithLifetime", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("WithLifetime"))); assert_eq!(
assert_eq!(object.get("description"), Some(&Value::null())); object.get_field_value("name"),
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![]))); Some(&Value::string("WithLifetime"))
);
assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![]))
);
assert!(fields.contains(&graphql_value!({ assert!(fields.contains(&graphql_value!({
"name": "simple", "name": "simple",
@ -229,9 +240,15 @@ fn introspect_with_lifetime() {
#[test] #[test]
fn introspect_with_generics() { fn introspect_with_generics() {
run_type_info_query("WithGenerics", |object, fields| { run_type_info_query("WithGenerics", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("WithGenerics"))); assert_eq!(
assert_eq!(object.get("description"), Some(&Value::null())); object.get_field_value("name"),
assert_eq!(object.get("interfaces"), Some(&Value::list(vec![]))); Some(&Value::string("WithGenerics"))
);
assert_eq!(object.get_field_value("description"), Some(&Value::null()));
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![]))
);
assert!(fields.contains(&graphql_value!({ assert!(fields.contains(&graphql_value!({
"name": "simple", "name": "simple",
@ -243,13 +260,16 @@ fn introspect_with_generics() {
#[test] #[test]
fn introspect_description_first() { fn introspect_description_first() {
run_type_info_query("DescriptionFirst", |object, fields| { run_type_info_query("DescriptionFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("DescriptionFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("name"),
Some(&Value::string("DescriptionFirst"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
assert_eq!( assert_eq!(
object.get("interfaces"), object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![ vec![
("name", Value::string("Interface")), ("name", Value::string("Interface")),
@ -269,13 +289,16 @@ fn introspect_description_first() {
#[test] #[test]
fn introspect_fields_first() { fn introspect_fields_first() {
run_type_info_query("FieldsFirst", |object, fields| { run_type_info_query("FieldsFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("FieldsFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("name"),
Some(&Value::string("FieldsFirst"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
assert_eq!( assert_eq!(
object.get("interfaces"), object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![ vec![
("name", Value::string("Interface")), ("name", Value::string("Interface")),
@ -295,13 +318,16 @@ fn introspect_fields_first() {
#[test] #[test]
fn introspect_interfaces_first() { fn introspect_interfaces_first() {
run_type_info_query("InterfacesFirst", |object, fields| { run_type_info_query("InterfacesFirst", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("InterfacesFirst")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("name"),
Some(&Value::string("InterfacesFirst"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
assert_eq!( assert_eq!(
object.get("interfaces"), object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![ vec![
("name", Value::string("Interface")), ("name", Value::string("Interface")),
@ -322,15 +348,15 @@ fn introspect_interfaces_first() {
fn introspect_commas_with_trailing() { fn introspect_commas_with_trailing() {
run_type_info_query("CommasWithTrailing", |object, fields| { run_type_info_query("CommasWithTrailing", |object, fields| {
assert_eq!( assert_eq!(
object.get("name"), object.get_field_value("name"),
Some(&Value::string("CommasWithTrailing")) Some(&Value::string("CommasWithTrailing"))
); );
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
assert_eq!( assert_eq!(
object.get("interfaces"), object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![ vec![
("name", Value::string("Interface")), ("name", Value::string("Interface")),
@ -350,13 +376,16 @@ fn introspect_commas_with_trailing() {
#[test] #[test]
fn introspect_commas_on_meta() { fn introspect_commas_on_meta() {
run_type_info_query("CommasOnMeta", |object, fields| { run_type_info_query("CommasOnMeta", |object, fields| {
assert_eq!(object.get("name"), Some(&Value::string("CommasOnMeta")));
assert_eq!( assert_eq!(
object.get("description"), object.get_field_value("name"),
Some(&Value::string("CommasOnMeta"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
assert_eq!( assert_eq!(
object.get("interfaces"), object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object( Some(&Value::list(vec![Value::object(
vec![ vec![
("name", Value::string("Interface")), ("name", Value::string("Interface")),

View file

@ -1,9 +1,7 @@
use indexmap::IndexMap;
use executor::Variables; use executor::Variables;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
struct DefaultName(i32); struct DefaultName(i32);
struct OtherOrder(i32); struct OtherOrder(i32);
@ -72,7 +70,7 @@ graphql_object!(Root: () |&self| {
fn run_type_info_query<F>(doc: &str, f: F) fn run_type_info_query<F>(doc: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>) -> (), F: Fn(&Object) -> (),
{ {
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new()); let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
@ -86,7 +84,7 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
@ -106,8 +104,8 @@ fn default_name_introspection() {
"#; "#;
run_type_info_query(doc, |type_info| { run_type_info_query(doc, |type_info| {
assert_eq!(type_info.get("name"), Some(&Value::string("DefaultName"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("DefaultName")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
}); });
} }
@ -123,8 +121,8 @@ fn other_order_introspection() {
"#; "#;
run_type_info_query(doc, |type_info| { run_type_info_query(doc, |type_info| {
assert_eq!(type_info.get("name"), Some(&Value::string("OtherOrder"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("OtherOrder")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
}); });
} }
@ -140,8 +138,8 @@ fn named_introspection() {
"#; "#;
run_type_info_query(doc, |type_info| { run_type_info_query(doc, |type_info| {
assert_eq!(type_info.get("name"), Some(&Value::string("ANamedScalar"))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string("ANamedScalar")));
assert_eq!(type_info.get("description"), Some(&Value::null())); assert_eq!(type_info.get_field_value("description"), Some(&Value::null()));
}); });
} }
@ -158,11 +156,11 @@ fn scalar_description_introspection() {
run_type_info_query(doc, |type_info| { run_type_info_query(doc, |type_info| {
assert_eq!( assert_eq!(
type_info.get("name"), type_info.get_field_value("name"),
Some(&Value::string("ScalarDescription")) Some(&Value::string("ScalarDescription"))
); );
assert_eq!( assert_eq!(
type_info.get("description"), type_info.get_field_value("description"),
Some(&Value::string("A sample scalar, represented as an integer")) Some(&Value::string("A sample scalar, represented as an integer"))
); );
}); });

View file

@ -1,10 +1,9 @@
use indexmap::IndexMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use ast::InputValue; use ast::InputValue;
use schema::model::RootNode; use schema::model::RootNode;
use types::scalars::EmptyMutation; use types::scalars::EmptyMutation;
use value::Value; use value::{Value, Object};
/* /*
@ -111,7 +110,7 @@ graphql_object!(<'a> Root: () as "Root" |&self| {
fn run_type_info_query<F>(type_name: &str, f: F) fn run_type_info_query<F>(type_name: &str, f: F)
where where
F: Fn(&IndexMap<String, Value>, &Vec<Value>) -> (), F: Fn(&Object, &Vec<Value>) -> (),
{ {
let doc = r#" let doc = r#"
query ($typeName: String!) { query ($typeName: String!) {
@ -138,13 +137,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let possible_types = type_info let possible_types = type_info
.get("possibleTypes") .get_field_value("possibleTypes")
.expect("possibleTypes field missing") .expect("possibleTypes field missing")
.as_list_value() .as_list_value()
.expect("possibleTypes field not a list value"); .expect("possibleTypes field not a list value");
@ -155,8 +154,8 @@ where
#[test] #[test]
fn introspect_custom_name() { fn introspect_custom_name() {
run_type_info_query("ACustomNamedUnion", |union, possible_types| { run_type_info_query("ACustomNamedUnion", |union, possible_types| {
assert_eq!(union.get("name"), Some(&Value::string("ACustomNamedUnion"))); assert_eq!(union.get_field_value("name"), Some(&Value::string("ACustomNamedUnion")));
assert_eq!(union.get("description"), Some(&Value::null())); assert_eq!(union.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
possible_types.contains(&Value::object( possible_types.contains(&Value::object(
@ -171,8 +170,8 @@ fn introspect_custom_name() {
#[test] #[test]
fn introspect_with_lifetime() { fn introspect_with_lifetime() {
run_type_info_query("WithLifetime", |union, possible_types| { run_type_info_query("WithLifetime", |union, possible_types| {
assert_eq!(union.get("name"), Some(&Value::string("WithLifetime"))); assert_eq!(union.get_field_value("name"), Some(&Value::string("WithLifetime")));
assert_eq!(union.get("description"), Some(&Value::null())); assert_eq!(union.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
possible_types.contains(&Value::object( possible_types.contains(&Value::object(
@ -187,8 +186,8 @@ fn introspect_with_lifetime() {
#[test] #[test]
fn introspect_with_generics() { fn introspect_with_generics() {
run_type_info_query("WithGenerics", |union, possible_types| { run_type_info_query("WithGenerics", |union, possible_types| {
assert_eq!(union.get("name"), Some(&Value::string("WithGenerics"))); assert_eq!(union.get_field_value("name"), Some(&Value::string("WithGenerics")));
assert_eq!(union.get("description"), Some(&Value::null())); assert_eq!(union.get_field_value("description"), Some(&Value::null()));
assert!( assert!(
possible_types.contains(&Value::object( possible_types.contains(&Value::object(
@ -203,9 +202,9 @@ fn introspect_with_generics() {
#[test] #[test]
fn introspect_description_first() { fn introspect_description_first() {
run_type_info_query("DescriptionFirst", |union, possible_types| { run_type_info_query("DescriptionFirst", |union, possible_types| {
assert_eq!(union.get("name"), Some(&Value::string("DescriptionFirst"))); assert_eq!(union.get_field_value("name"), Some(&Value::string("DescriptionFirst")));
assert_eq!( assert_eq!(
union.get("description"), union.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -222,9 +221,9 @@ fn introspect_description_first() {
#[test] #[test]
fn introspect_resolvers_first() { fn introspect_resolvers_first() {
run_type_info_query("ResolversFirst", |union, possible_types| { run_type_info_query("ResolversFirst", |union, possible_types| {
assert_eq!(union.get("name"), Some(&Value::string("ResolversFirst"))); assert_eq!(union.get_field_value("name"), Some(&Value::string("ResolversFirst")));
assert_eq!( assert_eq!(
union.get("description"), union.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -242,11 +241,11 @@ fn introspect_resolvers_first() {
fn introspect_commas_with_trailing() { fn introspect_commas_with_trailing() {
run_type_info_query("CommasWithTrailing", |union, possible_types| { run_type_info_query("CommasWithTrailing", |union, possible_types| {
assert_eq!( assert_eq!(
union.get("name"), union.get_field_value("name"),
Some(&Value::string("CommasWithTrailing")) Some(&Value::string("CommasWithTrailing"))
); );
assert_eq!( assert_eq!(
union.get("description"), union.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );
@ -264,11 +263,11 @@ fn introspect_commas_with_trailing() {
fn introspect_resolvers_with_trailing_comma() { fn introspect_resolvers_with_trailing_comma() {
run_type_info_query("ResolversWithTrailingComma", |union, possible_types| { run_type_info_query("ResolversWithTrailingComma", |union, possible_types| {
assert_eq!( assert_eq!(
union.get("name"), union.get_field_value("name"),
Some(&Value::string("ResolversWithTrailingComma")) Some(&Value::string("ResolversWithTrailingComma"))
); );
assert_eq!( assert_eq!(
union.get("description"), union.get_field_value("description"),
Some(&Value::string("A description")) Some(&Value::string("A description"))
); );

View file

@ -2,7 +2,7 @@ use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
/// A reference to a line and column in an input source file /// A reference to a line and column in an input source file
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
pub struct SourcePosition { pub struct SourcePosition {
index: usize, index: usize,
line: usize, line: usize,

View file

@ -319,6 +319,7 @@ impl<'a> SchemaType<'a> {
} }
impl<'a> TypeType<'a> { impl<'a> TypeType<'a> {
#[inline]
pub fn to_concrete(&self) -> Option<&'a MetaType> { pub fn to_concrete(&self) -> Option<&'a MetaType> {
match *self { match *self {
TypeType::Concrete(t) => Some(t), TypeType::Concrete(t) => Some(t),
@ -326,6 +327,7 @@ impl<'a> TypeType<'a> {
} }
} }
#[inline]
pub fn innermost_concrete(&self) -> &'a MetaType { pub fn innermost_concrete(&self) -> &'a MetaType {
match *self { match *self {
TypeType::Concrete(t) => t, TypeType::Concrete(t) => t,
@ -333,6 +335,7 @@ impl<'a> TypeType<'a> {
} }
} }
#[inline]
pub fn list_contents(&self) -> Option<&TypeType<'a>> { pub fn list_contents(&self) -> Option<&TypeType<'a>> {
match *self { match *self {
TypeType::List(ref n) => Some(n), TypeType::List(ref n) => Some(n),
@ -341,6 +344,7 @@ impl<'a> TypeType<'a> {
} }
} }
#[inline]
pub fn is_non_null(&self) -> bool { pub fn is_non_null(&self) -> bool {
match *self { match *self {
TypeType::NonNull(_) => true, TypeType::NonNull(_) => true,

View file

@ -1,5 +1,7 @@
use executor::{ExecutionResult, Executor, Registry}; use executor::{ExecutionResult, Executor, Registry};
use types::base::{Arguments, GraphQLType, TypeKind}; use types::base::{Arguments, GraphQLType, TypeKind};
use value::Value;
use ast::Selection;
use schema::meta::{ use schema::meta::{
Argument, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta, MetaType, ObjectMeta, Argument, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta, MetaType, ObjectMeta,
@ -43,6 +45,26 @@ where
_ => self.query_type.resolve_field(info, field, args, executor), _ => self.query_type.resolve_field(info, field, args, executor),
} }
} }
fn resolve(
&self,
info: &Self::TypeInfo,
selection_set: Option<&[Selection]>,
executor: &Executor<Self::Context>,
) -> Value {
use value::Object;
use types::base::resolve_selection_set_into;
if let Some(selection_set) = selection_set {
let mut result = Object::with_capacity(selection_set.len());
if resolve_selection_set_into(self, info, selection_set, executor, &mut result) {
Value::Object(result)
} else {
Value::null()
}
} else {
panic!("resolve() must be implemented by non-object output types");
}
}
} }
graphql_object!(<'a> SchemaType<'a>: SchemaType<'a> as "__Schema" |&self| { graphql_object!(<'a> SchemaType<'a>: SchemaType<'a> as "__Schema" |&self| {

View file

@ -198,11 +198,11 @@ fn test_possible_types() {
let possible_types = result let possible_types = result
.as_object_value() .as_object_value()
.expect("execution result not an object") .expect("execution result not an object")
.get("__type") .get_field_value("__type")
.expect("'__type' not present in result") .expect("'__type' not present in result")
.as_object_value() .as_object_value()
.expect("'__type' not an object") .expect("'__type' not an object")
.get("possibleTypes") .get_field_value("possibleTypes")
.expect("'possibleTypes' not present in '__type'") .expect("'possibleTypes' not present in '__type'")
.as_list_value() .as_list_value()
.expect("'possibleTypes' not a list") .expect("'possibleTypes' not a list")
@ -210,7 +210,7 @@ fn test_possible_types() {
.map(|t| { .map(|t| {
t.as_object_value() t.as_object_value()
.expect("possible type not an object") .expect("possible type not an object")
.get("name") .get_field_value("name")
.expect("'name' not present in type") .expect("'name' not present in type")
.as_string_value() .as_string_value()
.expect("'name' not a string") .expect("'name' not a string")

View file

@ -1,9 +1,8 @@
use indexmap::map::Entry;
use indexmap::IndexMap; use indexmap::IndexMap;
use ast::{Directive, FromInputValue, InputValue, Selection}; use ast::{Directive, FromInputValue, InputValue, Selection};
use executor::Variables; use executor::Variables;
use value::Value; use value::{Object, Value};
use executor::{ExecutionResult, Executor, Registry}; use executor::{ExecutionResult, Executor, Registry};
use parser::Spanning; use parser::Spanning;
@ -310,9 +309,9 @@ pub trait GraphQLType: Sized {
executor: &Executor<Self::Context>, executor: &Executor<Self::Context>,
) -> Value { ) -> Value {
if let Some(selection_set) = selection_set { if let Some(selection_set) = selection_set {
let mut result = IndexMap::new(); let mut result = Object::with_capacity(selection_set.len());
if resolve_selection_set_into(self, info, selection_set, executor, &mut result) { if resolve_selection_set_into(self, info, selection_set, executor, &mut result) {
Value::object(result) Value::Object(result)
} else { } else {
Value::null() Value::null()
} }
@ -322,12 +321,12 @@ pub trait GraphQLType: Sized {
} }
} }
fn resolve_selection_set_into<T, CtxT>( pub(crate) fn resolve_selection_set_into<T, CtxT>(
instance: &T, instance: &T,
info: &T::TypeInfo, info: &T::TypeInfo,
selection_set: &[Selection], selection_set: &[Selection],
executor: &Executor<CtxT>, executor: &Executor<CtxT>,
result: &mut IndexMap<String, Value>, result: &mut Object,
) -> bool ) -> bool
where where
T: GraphQLType<Context = CtxT>, T: GraphQLType<Context = CtxT>,
@ -352,11 +351,11 @@ where
continue; continue;
} }
let response_name = &f.alias.as_ref().unwrap_or(&f.name).item; let response_name = f.alias.as_ref().unwrap_or(&f.name).item;
if f.name.item == "__typename" { if f.name.item == "__typename" {
result.insert( result.add_field(
(*response_name).to_owned(), response_name,
Value::string(instance.concrete_type_name(executor.context(), info)), Value::string(instance.concrete_type_name(executor.context(), info)),
); );
continue; continue;
@ -406,7 +405,7 @@ where
return false; return false;
} }
result.insert((*response_name).to_owned(), Value::null()); result.add_field(response_name, Value::null());
} }
} }
} }
@ -453,8 +452,8 @@ where
&sub_exec, &sub_exec,
); );
if let Ok(Value::Object(mut hash_map)) = sub_result { if let Ok(Value::Object(object)) = sub_result {
for (k, v) in hash_map.drain(..) { for (k, v) in object {
merge_key_into(result, &k, v); merge_key_into(result, &k, v);
} }
} else if let Err(e) = sub_result { } else if let Err(e) = sub_result {
@ -503,15 +502,16 @@ fn is_excluded(directives: &Option<Vec<Spanning<Directive>>>, vars: &Variables)
false false
} }
fn merge_key_into(result: &mut IndexMap<String, Value>, response_name: &str, value: Value) { fn merge_key_into(result: &mut Object, response_name: &str, value: Value) {
match result.entry(response_name.to_owned()) { if let Some(&mut (_, ref mut e)) = result.iter_mut().find(|&&mut (ref key, _)| key == response_name)
Entry::Occupied(mut e) => match e.get_mut() { {
&mut Value::Object(ref mut dest_obj) => { match *e {
Value::Object(ref mut dest_obj) => {
if let Value::Object(src_obj) = value { if let Value::Object(src_obj) = value {
merge_maps(dest_obj, src_obj); merge_maps(dest_obj, src_obj);
} }
} }
&mut Value::List(ref mut dest_list) => { Value::List(ref mut dest_list) => {
if let Value::List(src_list) = value { if let Value::List(src_list) = value {
dest_list dest_list
.iter_mut() .iter_mut()
@ -527,19 +527,18 @@ fn merge_key_into(result: &mut IndexMap<String, Value>, response_name: &str, val
} }
} }
_ => {} _ => {}
},
Entry::Vacant(e) => {
e.insert(value);
} }
return;
} }
result.add_field(response_name, value);
} }
fn merge_maps(dest: &mut IndexMap<String, Value>, src: IndexMap<String, Value>) { fn merge_maps(dest: &mut Object, src: Object) {
for (key, value) in src { for (key, value) in src {
if dest.contains_key(&key) { if dest.contains_field(&key) {
merge_key_into(dest, &key, value); merge_key_into(dest, &key, value);
} else { } else {
dest.insert(key, value); dest.add_field(key, value);
} }
} }
} }

View file

@ -152,18 +152,18 @@ where
} }
} }
fn resolve_into_list<T: GraphQLType, I: Iterator<Item = T>>( fn resolve_into_list<T, I>(executor: &Executor<T::Context>, info: &T::TypeInfo, iter: I) -> Value
executor: &Executor<T::Context>, where
info: &T::TypeInfo, I: Iterator<Item = T> + ExactSizeIterator,
iter: I, T: GraphQLType,
) -> Value { {
let stop_on_null = executor let stop_on_null = executor
.current_type() .current_type()
.list_contents() .list_contents()
.expect("Current type is not a list type") .expect("Current type is not a list type")
.is_non_null(); .is_non_null();
let mut result = Vec::new(); let mut result = Vec::with_capacity(iter.len());
for o in iter { for o in iter {
let value = executor.resolve_into_value(info, &o); let value = executor.resolve_into_value(info, &o);

View file

@ -1,8 +1,7 @@
use indexmap::IndexMap;
use std::hash::Hash;
use ast::{InputValue, ToInputValue}; use ast::{InputValue, ToInputValue};
use parser::Spanning; use parser::Spanning;
use std::iter::FromIterator;
use std::vec::IntoIter;
/// Serializable value returned from query and field execution. /// Serializable value returned from query and field execution.
/// ///
@ -22,7 +21,152 @@ pub enum Value {
String(String), String(String),
Boolean(bool), Boolean(bool),
List(Vec<Value>), List(Vec<Value>),
Object(IndexMap<String, Value>), Object(Object),
}
/// A Object value
#[derive(Debug, PartialEq, Clone)]
pub struct Object {
key_value_list: Vec<(String, Value)>,
}
impl Object {
/// Create a new Object value with a fixed number of
/// preallocated slots for field-value pairs
pub fn with_capacity(size: usize) -> Self {
Object {
key_value_list: Vec::with_capacity(size),
}
}
/// Add a new field with a value
///
/// If there is already a field with the same name the old value
/// is returned
pub fn add_field<K>(&mut self, k: K, value: Value) -> Option<Value>
where
K: Into<String>,
for<'a> &'a str: PartialEq<K>,
{
if let Some(item) = self
.key_value_list
.iter_mut()
.find(|&&mut (ref key, _)| (key as &str) == k)
{
return Some(::std::mem::replace(&mut item.1, value));
}
self.key_value_list.push((k.into(), value));
None
}
/// Check if the object already contains a field with the given name
pub fn contains_field<K>(&self, f: K) -> bool
where
for<'a> &'a str: PartialEq<K>,
{
self.key_value_list
.iter()
.any(|&(ref key, _)| (key as &str) == f)
}
/// Get a iterator over all field value pairs
///
/// This method returns a iterator over `&'a (String, Value)`
// TODO: change this to `-> impl Iterator<Item = &(String, Value)>`
// as soon as juniper bumps the minimal supported rust verion to 1.26
pub fn iter(&self) -> FieldIter {
FieldIter {
inner: self.key_value_list.iter(),
}
}
/// Get a iterator over all mutable field value pairs
///
/// This method returns a iterator over `&mut 'a (String, Value)`
// TODO: change this to `-> impl Iterator<Item = &mut (String, Value)>`
// as soon as juniper bumps the minimal supported rust verion to 1.26
pub fn iter_mut(&mut self) -> FieldIterMut {
FieldIterMut {
inner: self.key_value_list.iter_mut(),
}
}
/// Get the current number of fields
pub fn field_count(&self) -> usize {
self.key_value_list.len()
}
/// Get the value for a given field
pub fn get_field_value<K>(&self, key: K) -> Option<&Value>
where
for<'a> &'a str: PartialEq<K>,
{
self.key_value_list
.iter()
.find(|&&(ref k, _)| (k as &str) == key)
.map(|&(_, ref value)| value)
}
}
impl IntoIterator for Object {
type Item = (String, Value);
type IntoIter = IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.key_value_list.into_iter()
}
}
impl From<Object> for Value {
fn from(o: Object) -> Self {
Value::Object(o)
}
}
impl<K> FromIterator<(K, Value)> for Object
where
K: Into<String>,
for<'a> &'a str: PartialEq<K>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, Value)>,
{
let iter = iter.into_iter();
let mut ret = Self {
key_value_list: Vec::with_capacity(iter.size_hint().0),
};
for (k, v) in iter {
ret.add_field(k, v);
}
ret
}
}
#[doc(hidden)]
pub struct FieldIter<'a> {
inner: ::std::slice::Iter<'a, (String, Value)>,
}
impl<'a> Iterator for FieldIter<'a> {
type Item = &'a (String, Value);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
#[doc(hidden)]
pub struct FieldIterMut<'a> {
inner: ::std::slice::IterMut<'a, (String, Value)>,
}
impl<'a> Iterator for FieldIterMut<'a> {
type Item = &'a mut (String, Value);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
} }
impl Value { impl Value {
@ -59,11 +203,8 @@ impl Value {
} }
/// Construct an object value. /// Construct an object value.
pub fn object<K>(o: IndexMap<K, Value>) -> Value pub fn object(o: Object) -> Value {
where Value::Object(o)
K: Into<String> + Eq + Hash,
{
Value::Object(o.into_iter().map(|(k, v)| (k.into(), v)).collect())
} }
// DISCRIMINATORS // DISCRIMINATORS
@ -85,7 +226,7 @@ impl Value {
} }
/// View the underlying object value, if present. /// View the underlying object value, if present.
pub fn as_object_value(&self) -> Option<&IndexMap<String, Value>> { pub fn as_object_value(&self) -> Option<&Object> {
match *self { match *self {
Value::Object(ref o) => Some(o), Value::Object(ref o) => Some(o),
_ => None, _ => None,
@ -93,7 +234,7 @@ impl Value {
} }
/// Mutable view into the underlying object value, if present. /// Mutable view into the underlying object value, if present.
pub fn as_mut_object_value(&mut self) -> Option<&mut IndexMap<String, Value>> { pub fn as_mut_object_value(&mut self) -> Option<&mut Object> {
match *self { match *self {
Value::Object(ref mut o) => Some(o), Value::Object(ref mut o) => Some(o),
_ => None, _ => None,
@ -132,7 +273,7 @@ impl ToInputValue for Value {
), ),
Value::Object(ref o) => InputValue::Object( Value::Object(ref o) => InputValue::Object(
o.iter() o.iter()
.map(|(k, v)| { .map(|&(ref k, ref v)| {
( (
Spanning::unlocated(k.clone()), Spanning::unlocated(k.clone()),
Spanning::unlocated(v.to_input_value()), Spanning::unlocated(v.to_input_value()),

View file

@ -1,7 +1,7 @@
#[cfg(test)] #[cfg(test)]
use fnv::FnvHashMap; use fnv::FnvHashMap;
#[cfg(test)] #[cfg(test)]
use indexmap::IndexMap; use juniper::Object;
#[cfg(test)] #[cfg(test)]
use juniper::{self, execute, EmptyMutation, GraphQLType, RootNode, Value, Variables}; use juniper::{self, execute, EmptyMutation, GraphQLType, RootNode, Value, Variables};
@ -235,8 +235,8 @@ fn check_descriptions(
object_name object_name
); );
run_type_info_query(&doc, |(type_info, values)| { run_type_info_query(&doc, |(type_info, values)| {
assert_eq!(type_info.get("name"), Some(&Value::string(object_name))); assert_eq!(type_info.get_field_value("name"), Some(&Value::string(object_name)));
assert_eq!(type_info.get("description"), Some(object_description)); assert_eq!(type_info.get_field_value("description"), Some(object_description));
assert!( assert!(
values.contains(&Value::object( values.contains(&Value::object(
vec![ vec![
@ -252,7 +252,7 @@ fn check_descriptions(
#[cfg(test)] #[cfg(test)]
fn run_type_info_query<F>(doc: &str, f: F) fn run_type_info_query<F>(doc: &str, f: F)
where where
F: Fn((&IndexMap<String, Value>, &Vec<Value>)) -> (), F: Fn((&Object, &Vec<Value>)) -> (),
{ {
let schema = RootNode::new(Query, EmptyMutation::<()>::new()); let schema = RootNode::new(Query, EmptyMutation::<()>::new());
@ -266,13 +266,13 @@ where
let type_info = result let type_info = result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")
.get("__type") .get_field_value("__type")
.expect("__type field missing") .expect("__type field missing")
.as_object_value() .as_object_value()
.expect("__type field not an object value"); .expect("__type field not an object value");
let fields = type_info let fields = type_info
.get("fields") .get_field_value("fields")
.expect("fields field missing") .expect("fields field missing")
.as_list_value() .as_list_value()
.expect("fields not a list"); .expect("fields not a list");