Move context type parameter to associated type of GraphQLType

This commit is contained in:
Magnus Hallin 2016-12-22 16:25:39 +01:00
parent 885fe8b09b
commit 6b8f4c9562
36 changed files with 469 additions and 283 deletions

View file

@ -9,7 +9,7 @@ use std::env;
use mount::Mount;
use logger::Logger;
use iron::prelude::*;
use juniper::FieldResult;
use juniper::EmptyMutation;
use juniper::iron_handlers::{GraphQLHandler, GraphiQLHandler};
use juniper::tests::model::Database;
@ -20,7 +20,11 @@ fn context_factory(_: &mut Request) -> Database {
fn main() {
let mut mount = Mount::new();
let graphql_endpoint = GraphQLHandler::new(context_factory, Database::new(), ());
let graphql_endpoint = GraphQLHandler::new(
context_factory,
Database::new(),
EmptyMutation::<Database>::new(),
);
let graphiql_endpoint = GraphiQLHandler::new("/graphql");
mount.mount("/", graphiql_endpoint);

View file

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::RwLock;
use ::GraphQLError;
@ -20,10 +19,9 @@ use types::base::GraphQLType;
/// The registry gathers metadata for all types in a schema. It provides
/// convenience methods to convert types implementing the `GraphQLType` trait
/// into `Type` instances and automatically registers them.
pub struct Registry<CtxT> {
pub struct Registry {
/// Currently registered types
pub types: HashMap<String, MetaType>,
phantom: PhantomData<CtxT>,
}
#[derive(Clone)]
@ -80,9 +78,46 @@ impl<T> IntoFieldResult<T> for FieldResult<T> {
}
}
/// Conversion trait for context types
///
/// This is currently only used for converting arbitrary contexts into
/// the empty tuple, but will in the future be used to support general
/// context conversion for larger schemas.
pub trait FromContext<T> {
/// Perform the conversion
fn from_context(value: &T) -> &Self;
}
/// Marker trait for types that can act as context objects for GraphQL types.
pub trait Context { }
static NULL_CONTEXT: () = ();
impl<T> FromContext<T> for () {
fn from_context(_: &T) -> &Self {
&NULL_CONTEXT
}
}
impl<T> FromContext<T> for T where T: Context {
fn from_context(value: &T) -> &Self {
value
}
}
impl<'a, CtxT> Executor<'a, CtxT> {
/// Resolve a single arbitrary value, mapping the context to a new type
pub fn resolve_with_ctx<NewCtxT, T: GraphQLType<Context=NewCtxT>>(
&self, value: &T
) -> ExecutionResult
where NewCtxT: FromContext<CtxT>,
{
self.replaced_context(<NewCtxT as FromContext<CtxT>>::from_context(&self.context))
.resolve(value)
}
/// Resolve a single arbitrary value into an `ExecutionResult`
pub fn resolve<T: GraphQLType<CtxT>>(&self, value: &T) -> ExecutionResult {
pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> ExecutionResult {
Ok(value.resolve(
match self.current_selection_set {
Some(ref sel) => Some(sel.clone()),
@ -94,7 +129,7 @@ impl<'a, CtxT> Executor<'a, CtxT> {
/// Resolve a single arbitrary value into a return value
///
/// If the field fails to resolve, `null` will be returned.
pub fn resolve_into_value<T: GraphQLType<CtxT>>(&self, value: &T) -> Value {
pub fn resolve_into_value<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> Value {
match self.resolve(value) {
Ok(v) => v,
Err(e) => {
@ -230,13 +265,13 @@ impl ExecutionError {
pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
document: Document,
operation_name: Option<&str>,
root_node: &RootNode<CtxT, QueryT, MutationT>,
root_node: &RootNode<QueryT, MutationT>,
variables: &HashMap<String, InputValue>,
context: &CtxT
)
-> Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>
where QueryT: GraphQLType<CtxT>,
MutationT: GraphQLType<CtxT>
where QueryT: GraphQLType<Context=CtxT>,
MutationT: GraphQLType<Context=CtxT>
{
let mut fragments = vec![];
let mut operation = None;
@ -290,12 +325,11 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
Ok((value, errors))
}
impl<CtxT> Registry<CtxT> {
impl Registry {
/// Construct a new registry
pub fn new(types: HashMap<String, MetaType>) -> Registry<CtxT> {
pub fn new(types: HashMap<String, MetaType>) -> Registry {
Registry {
types: types,
phantom: PhantomData,
}
}
@ -303,7 +337,7 @@ impl<CtxT> Registry<CtxT> {
///
/// If the registry hasn't seen a type with this name before, it will
/// construct its metadata and store it.
pub fn get_type<T>(&mut self) -> Type where T: GraphQLType<CtxT> {
pub fn get_type<T>(&mut self) -> Type where T: GraphQLType {
if let Some(name) = T::name() {
if !self.types.contains_key(name) {
self.insert_placeholder(name, Type::NonNullNamed(name.to_owned()));
@ -318,7 +352,7 @@ impl<CtxT> Registry<CtxT> {
}
/// Create a field with the provided name
pub fn field<T>(&mut self, name: &str) -> Field where T: GraphQLType<CtxT> {
pub fn field<T>(&mut self, name: &str) -> Field where T: GraphQLType {
Field {
name: name.to_owned(),
description: None,
@ -329,7 +363,7 @@ impl<CtxT> Registry<CtxT> {
}
#[doc(hidden)]
pub fn field_convert<T: IntoFieldResult<I>, I>(&mut self, name: &str) -> Field where I: GraphQLType<CtxT> {
pub fn field_convert<T: IntoFieldResult<I>, I>(&mut self, name: &str) -> Field where I: GraphQLType {
Field {
name: name.to_owned(),
description: None,
@ -340,7 +374,7 @@ impl<CtxT> Registry<CtxT> {
}
#[doc(hidden)]
pub fn field_inside_result<T>(&mut self, name: &str, _: FieldResult<T>) -> Field where T: GraphQLType<CtxT> {
pub fn field_inside_result<T>(&mut self, name: &str, _: FieldResult<T>) -> Field where T: GraphQLType {
Field {
name: name.to_owned(),
description: None,
@ -351,7 +385,7 @@ impl<CtxT> Registry<CtxT> {
}
/// Create an argument with the provided name
pub fn arg<T>(&mut self, name: &str) -> Argument where T: GraphQLType<CtxT> + FromInputValue {
pub fn arg<T>(&mut self, name: &str) -> Argument where T: GraphQLType + FromInputValue {
Argument::new(name, self.get_type::<T>())
}
@ -365,7 +399,7 @@ impl<CtxT> Registry<CtxT> {
value: &T,
)
-> Argument
where T: GraphQLType<CtxT> + ToInputValue + FromInputValue
where T: GraphQLType + ToInputValue + FromInputValue
{
Argument::new(name, self.get_type::<Option<T>>())
.default_value(value.to())
@ -384,20 +418,20 @@ impl<CtxT> Registry<CtxT> {
/// This expects the type to implement `FromInputValue`.
pub fn build_scalar_type<T>(&mut self)
-> ScalarMeta
where T: FromInputValue + GraphQLType<CtxT>
where T: FromInputValue + GraphQLType
{
let name = T::name().expect("Scalar types must be named. Implement name()");
ScalarMeta::new::<T>(name)
}
/// Create a list meta type
pub fn build_list_type<T: GraphQLType<CtxT>>(&mut self) -> ListMeta {
pub fn build_list_type<T: GraphQLType>(&mut self) -> ListMeta {
let of_type = self.get_type::<T>();
ListMeta::new(of_type)
}
/// Create a nullable meta type
pub fn build_nullable_type<T: GraphQLType<CtxT>>(&mut self) -> NullableMeta {
pub fn build_nullable_type<T: GraphQLType>(&mut self) -> NullableMeta {
let of_type = self.get_type::<T>();
NullableMeta::new(of_type)
}
@ -408,7 +442,7 @@ impl<CtxT> Registry<CtxT> {
/// function that needs to be called with the list of fields on the object.
pub fn build_object_type<T>(&mut self)
-> Box<Fn(&[Field]) -> ObjectMeta>
where T: GraphQLType<CtxT>
where T: GraphQLType
{
let name = T::name().expect("Object types must be named. Implement name()");
let typename_field = self.field::<String>("__typename");
@ -423,7 +457,7 @@ impl<CtxT> Registry<CtxT> {
/// Create an enum meta type
pub fn build_enum_type<T>(&mut self)
-> Box<Fn(&[EnumValue]) -> EnumMeta>
where T: FromInputValue + GraphQLType<CtxT>
where T: FromInputValue + GraphQLType
{
let name = T::name().expect("Enum types must be named. Implement name()");
@ -433,7 +467,7 @@ impl<CtxT> Registry<CtxT> {
/// Create an interface meta type builder
pub fn build_interface_type<T>(&mut self)
-> Box<Fn(&[Field]) -> InterfaceMeta>
where T: GraphQLType<CtxT>
where T: GraphQLType
{
let name = T::name().expect("Interface types must be named. Implement name()");
let typename_field = self.field::<String>("__typename");
@ -448,7 +482,7 @@ impl<CtxT> Registry<CtxT> {
/// Create a union meta type builder
pub fn build_union_type<T>(&mut self)
-> Box<Fn(&[Type]) -> UnionMeta>
where T: GraphQLType<CtxT>
where T: GraphQLType
{
let name = T::name().expect("Union types must be named. Implement name()");
@ -458,7 +492,7 @@ impl<CtxT> Registry<CtxT> {
/// Create an input object meta type builder
pub fn build_input_object_type<T>(&mut self)
-> Box<Fn(&[Argument]) -> InputObjectMeta>
where T: FromInputValue + GraphQLType<CtxT>
where T: FromInputValue + GraphQLType
{
let name = T::name().expect("Input object types must be named. Implement name()");

View file

@ -3,6 +3,7 @@ use std::collections::HashMap;
use value::Value;
use ast::InputValue;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct TestType;
@ -19,7 +20,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
where F: Fn(&HashMap<String, Value>) -> ()
{
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let (result, errs) = ::execute(query, None, &schema, &vars, &())
.expect("Execution failed");

View file

@ -6,6 +6,7 @@ use schema::model::RootNode;
use ::GraphQLError::ValidationError;
use validation::RuleError;
use parser::SourcePosition;
use types::scalars::EmptyMutation;
#[derive(Debug)]
enum Color { Red, Green, Blue }
@ -30,7 +31,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
where F: Fn(&HashMap<String, Value>) -> ()
{
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let (result, errs) = ::execute(query, None, &schema, &vars, &())
.expect("Execution failed");
@ -74,7 +75,7 @@ fn serializes_as_output() {
#[test]
fn does_not_accept_string_literals() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"{ toString(color: "RED") }"#;
let vars = vec![
@ -107,7 +108,7 @@ fn accepts_strings_in_variables() {
#[test]
fn does_not_accept_incorrect_enum_name_in_variables() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($color: Color!) { toString(color: $color) }"#;
let vars = vec![
@ -127,7 +128,7 @@ fn does_not_accept_incorrect_enum_name_in_variables() {
#[test]
fn does_not_accept_incorrect_type_in_variables() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($color: Color!) { toString(color: $color) }"#;
let vars = vec![

View file

@ -2,6 +2,7 @@ mod field_execution {
use value::Value;
use ast::InputValue;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct DataType;
struct DeepDataType;
@ -33,7 +34,7 @@ mod field_execution {
#[test]
fn test() {
let schema = RootNode::new(DataType, ());
let schema = RootNode::new(DataType, EmptyMutation::<()>::new());
let doc = r"
query Example($size: Int) {
a,
@ -109,6 +110,7 @@ mod field_execution {
mod merge_parallel_fragments {
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct Type;
@ -121,7 +123,7 @@ mod merge_parallel_fragments {
#[test]
fn test() {
let schema = RootNode::new(Type, ());
let schema = RootNode::new(Type, EmptyMutation::<()>::new());
let doc = r"
{ a, ...FragOne, ...FragTwo }
fragment FragOne on Type {
@ -162,6 +164,7 @@ mod merge_parallel_fragments {
mod threads_context_correctly {
use value::Value;
use types::scalars::EmptyMutation;
use schema::model::RootNode;
struct Schema;
@ -172,7 +175,7 @@ mod threads_context_correctly {
#[test]
fn test() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<String>::new());
let doc = r"{ a }";
let vars = vec![].into_iter().collect();
@ -197,6 +200,7 @@ mod nulls_out_errors {
use schema::model::RootNode;
use executor::{ExecutionError, FieldResult};
use parser::SourcePosition;
use types::scalars::EmptyMutation;
struct Schema;
@ -207,7 +211,7 @@ mod nulls_out_errors {
#[test]
fn test() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"{ sync, syncError }";
let vars = vec![].into_iter().collect();
@ -239,6 +243,7 @@ mod nulls_out_errors {
mod named_operations {
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
use ::GraphQLError;
struct Schema;
@ -249,7 +254,7 @@ mod named_operations {
#[test]
fn uses_inline_operation_if_no_name_provided() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"{ a }";
let vars = vec![].into_iter().collect();
@ -268,7 +273,7 @@ mod named_operations {
#[test]
fn uses_only_named_operation() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"query Example { a }";
let vars = vec![].into_iter().collect();
@ -287,7 +292,7 @@ mod named_operations {
#[test]
fn uses_named_operation_if_name_provided() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"query Example { first: a } query OtherExample { second: a }";
let vars = vec![].into_iter().collect();
@ -306,7 +311,7 @@ mod named_operations {
#[test]
fn error_if_multiple_operations_provided_but_no_name() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"query Example { first: a } query OtherExample { second: a }";
let vars = vec![].into_iter().collect();
@ -319,7 +324,7 @@ mod named_operations {
#[test]
fn error_if_unknown_operation_name_provided() {
let schema = RootNode::new(Schema, ());
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
let doc = r"query Example { first: a } query OtherExample { second: a }";
let vars = vec![].into_iter().collect();

View file

@ -1,6 +1,7 @@
mod interface {
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
trait Pet {
fn name(&self) -> &str;
@ -71,7 +72,7 @@ mod interface {
Box::new(Cat { name: "Garfield".to_owned(), meows: false }),
],
},
());
EmptyMutation::<()>::new());
let doc = r"
{
pets {
@ -118,6 +119,7 @@ mod interface {
mod union {
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
trait Pet {
fn as_dog(&self) -> Option<&Dog> { None }
@ -178,7 +180,7 @@ mod union {
Box::new(Cat { name: "Garfield".to_owned(), meows: false }),
],
},
());
EmptyMutation::<()>::new());
let doc = r"
{
pets {

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
enum Sample {
One,
@ -67,7 +68,7 @@ fn test_execution() {
second: sampleScalar(first: 10 second: 20)
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");
@ -104,7 +105,7 @@ fn enum_introspection() {
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");
@ -182,7 +183,7 @@ fn interface_introspection() {
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");
@ -283,7 +284,7 @@ fn object_introspection() {
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");
@ -395,7 +396,7 @@ fn scalar_introspection() {
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");

View file

@ -6,6 +6,7 @@ use schema::model::RootNode;
use ::GraphQLError::ValidationError;
use validation::RuleError;
use parser::SourcePosition;
use types::scalars::EmptyMutation;
#[derive(Debug)]
struct TestComplexScalar;
@ -88,7 +89,7 @@ graphql_object!(TestType: () |&self| {
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
where F: Fn(&HashMap<String, Value>) -> ()
{
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let (result, errs) = ::execute(query, None, &schema, &vars, &())
.expect("Execution failed");
@ -196,7 +197,7 @@ fn variable_runs_from_input_value_on_scalar() {
#[test]
fn variable_error_on_nested_non_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![
@ -220,7 +221,7 @@ fn variable_error_on_nested_non_null() {
#[test]
fn variable_error_on_incorrect_type() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![
@ -240,7 +241,7 @@ fn variable_error_on_incorrect_type() {
#[test]
fn variable_error_on_omit_non_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![
@ -263,7 +264,7 @@ fn variable_error_on_omit_non_null() {
#[test]
fn variable_multiple_errors_with_nesting() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestNestedInputObject) { fieldWithNestedObjectInput(input: $input) }"#;
let vars = vec![
@ -291,7 +292,7 @@ fn variable_multiple_errors_with_nesting() {
#[test]
fn variable_error_on_additional_field() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestInputObject) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![
@ -377,7 +378,7 @@ fn allow_nullable_inputs_to_be_set_to_value_directly() {
#[test]
fn does_not_allow_non_nullable_input_to_be_omitted_in_variable() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($value: String!) { fieldWithNonNullableStringInput(input: $value) }"#;
let vars = vec![
@ -396,7 +397,7 @@ fn does_not_allow_non_nullable_input_to_be_omitted_in_variable() {
#[test]
fn does_not_allow_non_nullable_input_to_be_set_to_null_in_variable() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($value: String!) { fieldWithNonNullableStringInput(input: $value) }"#;
let vars = vec![
@ -489,7 +490,7 @@ fn allow_lists_to_contain_null() {
#[test]
fn does_not_allow_non_null_lists_to_be_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String]!) { nnList(input: $input) }"#;
let vars = vec![
@ -572,7 +573,7 @@ fn allow_lists_of_non_null_to_contain_values() {
#[test]
fn does_not_allow_lists_of_non_null_to_contain_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]) { listNn(input: $input) }"#;
let vars = vec![
@ -596,7 +597,7 @@ fn does_not_allow_lists_of_non_null_to_contain_null() {
#[test]
fn does_not_allow_non_null_lists_of_non_null_to_contain_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]!) { nnListNn(input: $input) }"#;
let vars = vec![
@ -620,7 +621,7 @@ fn does_not_allow_non_null_lists_of_non_null_to_contain_null() {
#[test]
fn does_not_allow_non_null_lists_of_non_null_to_be_null() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: [String!]!) { nnListNn(input: $input) }"#;
let vars = vec![
@ -656,7 +657,7 @@ fn allow_non_null_lists_of_non_null_to_contain_values() {
#[test]
fn does_not_allow_invalid_types_to_be_used_as_values() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: TestType!) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![
@ -679,7 +680,7 @@ fn does_not_allow_invalid_types_to_be_used_as_values() {
#[test]
fn does_not_allow_unknown_types_to_be_used_as_values() {
let schema = RootNode::new(TestType, ());
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
let query = r#"query q($input: UnknownType!) { fieldWithObjectInput(input: $input) }"#;
let vars = vec![

View file

@ -25,11 +25,11 @@ use ::{InputValue, GraphQLType, RootNode, execute};
pub struct GraphQLHandler<CtxFactory, Query, Mutation, CtxT>
where CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
CtxT: 'static,
Query: GraphQLType<CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<CtxT> + Send + Sync + 'static,
Query: GraphQLType<Context=CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static,
{
context_factory: CtxFactory,
root_node: RootNode<CtxT, Query, Mutation>,
root_node: RootNode<Query, Mutation>,
}
/// Handler that renders GraphiQL - a graphical query editor interface
@ -41,8 +41,8 @@ impl<CtxFactory, Query, Mutation, CtxT>
GraphQLHandler<CtxFactory, Query, Mutation, CtxT>
where CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
CtxT: 'static,
Query: GraphQLType<CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<CtxT> + Send + Sync + 'static,
Query: GraphQLType<Context=CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static,
{
/// Build a new GraphQL handler
///
@ -150,8 +150,8 @@ impl<CtxFactory, Query, Mutation, CtxT>
for GraphQLHandler<CtxFactory, Query, Mutation, CtxT>
where CtxFactory: Fn(&mut Request) -> CtxT + Send + Sync + 'static,
CtxT: 'static,
Query: GraphQLType<CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<CtxT> + Send + Sync + 'static,
Query: GraphQLType<Context=CtxT> + Send + Sync + 'static,
Mutation: GraphQLType<Context=CtxT> + Send + Sync + 'static,
{
fn handle(&self, req: &mut Request) -> IronResult<Response> {
match req.method {
@ -248,6 +248,7 @@ mod tests {
use iron::{Handler, Headers};
use ::tests::model::Database;
use types::scalars::EmptyMutation;
use super::GraphQLHandler;
@ -259,7 +260,7 @@ mod tests {
Box::new(GraphQLHandler::new(
context_factory,
Database::new(),
(),
EmptyMutation::<Database>::new(),
))
}

View file

@ -33,14 +33,18 @@ existing object types as GraphQL objects:
```rust
#[macro_use] extern crate juniper;
# use std::collections::HashMap;
use juniper::FieldResult;
use juniper::{Context, FieldResult};
struct User { id: String, name: String, friend_ids: Vec<String> }
struct QueryRoot;
struct Database { users: HashMap<String, User> }
impl Context for Database {}
// GraphQL objects can access a "context object" during execution. Use this
// object to provide e.g. database access to the field accessors.
// object to provide e.g. database access to the field accessors. This object
// must implement the `Context` trait. If you don't need a context, use the
// empty tuple `()` to indicate this.
//
// In this example, we use the Database struct as our context.
graphql_object!(User: Database |&self| {
@ -105,6 +109,7 @@ extern crate iron;
use iron::prelude::*;
use juniper::iron_handlers::GraphQLHandler;
use juniper::{Context, EmptyMutation};
# use juniper::FieldResult;
#
@ -150,11 +155,14 @@ fn context_factory(_: &mut Request) -> Database {
}
}
impl Context for Database {}
fn main() {
// GraphQLHandler takes a context factory function, the root object,
// and the mutation object. If we don't have any mutations to expose, we
// can use the empty tuple () to indicate absence.
let graphql_endpoint = GraphQLHandler::new(context_factory, QueryRoot, ());
let graphql_endpoint = GraphQLHandler::new(
context_factory, QueryRoot, EmptyMutation::<Database>::new());
// Start serving the schema at the root on port 8080.
Iron::new(graphql_endpoint).http("localhost:8080").unwrap();
@ -212,10 +220,11 @@ pub use ast::{ToInputValue, FromInputValue, InputValue, Type, Selection};
pub use value::Value;
pub use types::base::{Arguments, GraphQLType, TypeKind};
pub use executor::{
Context, FromContext,
Executor, Registry, ExecutionResult, ExecutionError, FieldResult, IntoFieldResult,
};
pub use validation::RuleError;
pub use types::scalars::ID;
pub use types::scalars::{EmptyMutation, ID};
pub use schema::model::RootNode;
pub use result_ext::ResultExt;
@ -238,13 +247,13 @@ pub enum GraphQLError<'a> {
pub fn execute<'a, CtxT, QueryT, MutationT>(
document_source: &'a str,
operation_name: Option<&str>,
root_node: &RootNode<CtxT, QueryT, MutationT>,
root_node: &RootNode<QueryT, MutationT>,
variables: &HashMap<String, InputValue>,
context: &CtxT,
)
-> Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>
where QueryT: GraphQLType<CtxT>,
MutationT: GraphQLType<CtxT>,
where QueryT: GraphQLType<Context=CtxT>,
MutationT: GraphQLType<Context=CtxT>,
{
let document = try!(parse_document_source(document_source));

View file

@ -59,12 +59,14 @@ macro_rules! graphql_enum {
( $name:path, $outname:tt, $descr:tt ),
[ $( ( $eval:tt, $ename:tt, $edescr:tt, $edepr:tt ) , )* ]
) => {
impl<CtxT> $crate::GraphQLType<CtxT> for $name {
impl $crate::GraphQLType for $name {
type Context = ();
fn name() -> Option<&'static str> {
Some(graphql_enum!(@as_expr, $outname))
}
fn meta(registry: &mut $crate::Registry<CtxT>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
graphql_enum!(
@maybe_apply, $descr, description,
registry.build_enum_type::<$name>()(&[
@ -81,7 +83,7 @@ macro_rules! graphql_enum {
.into_meta()
}
fn resolve(&self, _: Option<Vec<$crate::Selection>>, _: &$crate::Executor<CtxT>) -> $crate::Value {
fn resolve(&self, _: Option<Vec<$crate::Selection>>, _: &$crate::Executor<Self::Context>) -> $crate::Value {
match self {
$(
&graphql_enum!(@as_pattern, $eval) =>

View file

@ -77,7 +77,8 @@ macro_rules! __graphql__build_field_matches {
$body
})();
return ($crate::IntoFieldResult::into(result)).and_then(|r| $executorvar.resolve(&r))
return ($crate::IntoFieldResult::into(result)).and_then(
|r| $executorvar.resolve_with_ctx(&r))
}
)*
panic!("Field {} not found on type {}", $fieldvar, $outname);

View file

@ -148,12 +148,14 @@ macro_rules! graphql_input_object {
}
}
impl<CtxT> $crate::GraphQLType<CtxT> for $name {
impl $crate::GraphQLType for $name {
type Context = ();
fn name() -> Option<&'static str> {
Some($outname)
}
fn meta(registry: &mut $crate::Registry<CtxT>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
graphql_input_object!(
@maybe_apply, $descr, description,
registry.build_input_object_type::<$name>()(

View file

@ -192,7 +192,7 @@ macro_rules! graphql_interface {
$(
if let Some(_) = $resolver as Option<$srctype> {
return (<$srctype as $crate::GraphQLType<$ctxttype>>::name()).unwrap().to_owned();
return (<$srctype as $crate::GraphQLType>::name()).unwrap().to_owned();
}
)*
@ -208,7 +208,7 @@ macro_rules! graphql_interface {
let $ctxtvar = &$execarg.context();
$(
if $typenamearg == (<$srctype as $crate::GraphQLType<$ctxttype>>::name()).unwrap().to_owned() {
if $typenamearg == (<$srctype as $crate::GraphQLType>::name()).unwrap().to_owned() {
return $execarg.resolve(&$resolver);
}
)*
@ -227,14 +227,16 @@ macro_rules! graphql_interface {
$( $items:tt )*
}
) => {
graphql_interface!(@as_item, impl<$($lifetime)*> $crate::GraphQLType<$ctxt> for $name {
graphql_interface!(@as_item, impl<$($lifetime)*> $crate::GraphQLType for $name {
type Context = $ctxt;
fn name() -> Option<&'static str> {
Some($outname)
}
#[allow(unused_assignments)]
#[allow(unused_mut)]
fn meta(registry: &mut $crate::Registry<$ctxt>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
let mut fields = Vec::new();
let mut description = None;
graphql_interface!(@ gather_meta, (registry, fields, description), $($items)*);
@ -249,14 +251,14 @@ macro_rules! graphql_interface {
#[allow(unused_variables)]
#[allow(unused_mut)]
fn resolve_field(&$mainself, field: &str, args: &$crate::Arguments, mut executor: &$crate::Executor<$ctxt>) -> $crate::ExecutionResult {
fn resolve_field(&$mainself, field: &str, args: &$crate::Arguments, mut executor: &$crate::Executor<Self::Context>) -> $crate::ExecutionResult {
__graphql__build_field_matches!(
($outname, $mainself, field, args, executor),
(),
$($items)*);
}
fn concrete_type_name(&$mainself, context: &$ctxt) -> String {
fn concrete_type_name(&$mainself, context: &Self::Context) -> String {
graphql_interface!(
@ concrete_type_name,
($outname, context, $ctxt),
@ -267,7 +269,7 @@ macro_rules! graphql_interface {
&$mainself,
type_name: &str,
_: Option<Vec<$crate::Selection>>,
executor: &$crate::Executor<$ctxt>,
executor: &$crate::Executor<Self::Context>,
)
-> $crate::ExecutionResult
{

View file

@ -348,14 +348,16 @@ macro_rules! graphql_object {
( $($lifetime:tt)* );
$name:ty; $ctxt:ty; $outname:expr; $mainself:ident; $($items:tt)*
) => {
graphql_object!(@as_item, impl<$($lifetime)*> $crate::GraphQLType<$ctxt> for $name {
graphql_object!(@as_item, impl<$($lifetime)*> $crate::GraphQLType for $name {
type Context = $ctxt;
fn name() -> Option<&'static str> {
Some($outname)
}
#[allow(unused_assignments)]
#[allow(unused_mut)]
fn meta(registry: &mut $crate::Registry<$ctxt>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
let mut fields = Vec::new();
let mut description = None;
let mut interfaces: Option<Vec<$crate::Type>> = None;
@ -382,7 +384,7 @@ macro_rules! graphql_object {
&$mainself,
field: &str,
args: &$crate::Arguments,
executor: &$crate::Executor<$ctxt>
executor: &$crate::Executor<Self::Context>
)
-> $crate::ExecutionResult
{

View file

@ -61,12 +61,14 @@ macro_rules! graphql_scalar {
( $fiv_arg:ident, $fiv_result:ty, $fiv_body:block )
)
) => {
impl<CtxT> $crate::GraphQLType<CtxT> for $name {
impl $crate::GraphQLType for $name {
type Context = ();
fn name() -> Option<&'static str> {
Some($outname)
}
fn meta(registry: &mut $crate::Registry<CtxT>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
graphql_scalar!(
@maybe_apply, $descr, description,
registry.build_scalar_type::<Self>())
@ -76,7 +78,7 @@ macro_rules! graphql_scalar {
fn resolve(
&$resolve_selfvar,
_: Option<Vec<$crate::Selection>>,
_: &$crate::Executor<CtxT>) -> $crate::Value {
_: &$crate::Executor<Self::Context>) -> $crate::Value {
$resolve_body
}
}

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct Root;
@ -87,7 +88,7 @@ fn run_args_info_query<F>(field_name: &str, f: F)
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
enum DefaultName { Foo, Bar }
@ -67,7 +68,7 @@ graphql_object!(Root: () |&self| {
});
fn run_type_info_query<F>(doc: &str, f: F) where F: Fn((&HashMap<String, Value>, &Vec<Value>)) -> () {
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");

View file

@ -4,6 +4,7 @@ use value::Value;
use ast::InputValue;
use schema::model::RootNode;
use executor::FieldResult;
use types::scalars::EmptyMutation;
struct Interface;
struct Root;
@ -71,7 +72,7 @@ fn run_field_info_query<F>(type_name: &str, field_name: &str, f: F)
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let vars = vec![
("typeName".to_owned(), InputValue::string(type_name)),
].into_iter().collect();

View file

@ -3,6 +3,7 @@ use std::collections::HashMap;
use ast::{InputValue, FromInputValue};
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct Root;
@ -62,7 +63,7 @@ graphql_object!(Root: () |&self| {
});
fn run_type_info_query<F>(doc: &str, f: F) where F: Fn(&HashMap<String, Value>, &Vec<Value>) -> () {
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");

View file

@ -4,6 +4,7 @@ use std::marker::PhantomData;
use ast::InputValue;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
/*
@ -142,7 +143,7 @@ fn run_type_info_query<F>(type_name: &str, f: F)
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let vars = vec![
("typeName".to_owned(), InputValue::string(type_name)),
].into_iter().collect();

View file

@ -4,6 +4,7 @@ use std::marker::PhantomData;
use ast::InputValue;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
/*
@ -130,7 +131,7 @@ fn run_type_info_query<F>(type_name: &str, f: F)
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let vars = vec![
("typeName".to_owned(), InputValue::string(type_name)),
].into_iter().collect();

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
struct DefaultName(i64);
struct OtherOrder(i64);
@ -69,7 +70,7 @@ graphql_object!(Root: () |&self| {
});
fn run_type_info_query<F>(doc: &str, f: F) where F: Fn(&HashMap<String, Value>) -> () {
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let (result, errs) = ::execute(doc, None, &schema, &HashMap::new(), &())
.expect("Execution failed");

View file

@ -4,6 +4,7 @@ use std::marker::PhantomData;
use ast::InputValue;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
/*
@ -109,7 +110,7 @@ fn run_type_info_query<F>(type_name: &str, f: F)
}
}
"#;
let schema = RootNode::new(Root {}, ());
let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());
let vars = vec![
("typeName".to_owned(), InputValue::string(type_name)),
].into_iter().collect();

View file

@ -62,7 +62,7 @@ macro_rules! graphql_union {
$(
if let Some(_) = $resolver as Option<$srctype> {
return (<$srctype as $crate::GraphQLType<$ctxttype>>::name()).unwrap().to_owned();
return (<$srctype as $crate::GraphQLType>::name()).unwrap().to_owned();
}
)*
@ -79,7 +79,7 @@ macro_rules! graphql_union {
let $ctxtvar = &$execarg.context();
$(
if $typenamearg == (<$srctype as $crate::GraphQLType<$ctxttype>>::name()).unwrap().to_owned() {
if $typenamearg == (<$srctype as $crate::GraphQLType>::name()).unwrap().to_owned() {
return $execarg.resolve(&$resolver);
}
)*
@ -105,14 +105,16 @@ macro_rules! graphql_union {
$( $items:tt )*
}
) => {
graphql_union!(@as_item, impl<$($lifetime)*> $crate::GraphQLType<$ctxt> for $name {
graphql_union!(@as_item, impl<$($lifetime)*> $crate::GraphQLType for $name {
type Context = $ctxt;
fn name() -> Option<&'static str> {
Some($outname)
}
#[allow(unused_assignments)]
#[allow(unused_mut)]
fn meta(registry: &mut $crate::Registry<$ctxt>) -> $crate::meta::MetaType {
fn meta(registry: &mut $crate::Registry) -> $crate::meta::MetaType {
let mut types;
let mut description = None;
graphql_union!(@ gather_meta, (registry, types, description), $($items)*);
@ -125,7 +127,7 @@ macro_rules! graphql_union {
mt.into_meta()
}
fn concrete_type_name(&$mainself, context: &$ctxt) -> String {
fn concrete_type_name(&$mainself, context: &Self::Context) -> String {
graphql_union!(
@ concrete_type_name,
($outname, context, $ctxt),
@ -136,7 +138,7 @@ macro_rules! graphql_union {
&$mainself,
type_name: &str,
_: Option<Vec<$crate::Selection>>,
executor: &$crate::Executor<$ctxt>,
executor: &$crate::Executor<Self::Context>,
)
-> $crate::ExecutionResult
{

View file

@ -1,37 +1,24 @@
use std::collections::HashMap;
use std::marker::PhantomData;
use std::fmt;
use types::base::{GraphQLType};
use executor::Registry;
use executor::{Registry, Context};
use ast::Type;
use schema::meta::{MetaType, ObjectMeta, PlaceholderMeta, UnionMeta, InterfaceMeta, Argument};
/// Root query node of a schema
///
/// This brings the mutatino and query types together, and provides the
/// This brings the mutation and query types together, and provides the
/// predefined metadata fields.
pub struct RootNode<InnerT, QueryT, MutationT=()> {
pub struct RootNode<QueryT, MutationT> {
#[doc(hidden)]
pub query_type: QueryT,
#[doc(hidden)]
pub mutation_type: MutationT,
#[doc(hidden)]
pub schema: SchemaType,
phantom_wrapped: PhantomData<InnerT>,
}
// RootNode implements Send + Sync if both the mutation type and query
// type implements them. SchemaType also needs to implement them.
//
// InnerT does _not_ need to implement Send + Sync because it does not
// actually appear in the struct.
unsafe impl<InnerT, QueryT, MutationT> Send for RootNode<InnerT, QueryT, MutationT>
where QueryT: Send, MutationT: Send, SchemaType: Send { }
unsafe impl<InnerT, QueryT, MutationT> Sync for RootNode<InnerT, QueryT, MutationT>
where QueryT: Sync, MutationT: Sync, SchemaType: Sync { }
/// Metadata for a schema
pub struct SchemaType {
types: HashMap<String, MetaType>,
@ -40,6 +27,8 @@ pub struct SchemaType {
directives: HashMap<String, DirectiveType>,
}
impl Context for SchemaType {}
pub enum TypeType<'a> {
Concrete(&'a MetaType),
NonNull(Box<TypeType<'a>>),
@ -63,82 +52,72 @@ pub enum DirectiveLocation {
InlineFragment,
}
impl<InnerT, QueryT, MutationT> RootNode<InnerT, QueryT, MutationT>
where QueryT: GraphQLType<InnerT>,
MutationT: GraphQLType<InnerT>,
impl<QueryT, MutationT> RootNode<QueryT, MutationT>
where QueryT: GraphQLType,
MutationT: GraphQLType,
{
/// Construct a new root node from query and mutation nodes
///
/// If the schema should not support mutations, you can pass in `()` to
/// remove the mutation type from the schema.
pub fn new(query_obj: QueryT, mutation_obj: MutationT) -> RootNode<InnerT, QueryT, MutationT> {
/// If the schema should not support mutations, use the
/// `new` constructor instead.
pub fn new(query_obj: QueryT, mutation_obj: MutationT) -> RootNode<QueryT, MutationT> {
RootNode {
query_type: query_obj,
mutation_type: mutation_obj,
schema: SchemaType::new::<InnerT, QueryT, MutationT>(),
phantom_wrapped: PhantomData,
schema: SchemaType::new::<QueryT, MutationT>(),
}
}
}
impl SchemaType {
pub fn new<CtxT, QueryT, MutationT>() -> SchemaType
where QueryT: GraphQLType<CtxT>,
MutationT: GraphQLType<CtxT>,
pub fn new<QueryT, MutationT>() -> SchemaType
where QueryT: GraphQLType,
MutationT: GraphQLType,
{
let mut types = HashMap::new();
let mut directives = HashMap::new();
let query_type_name: String;
let mutation_type_name: String;
{
let mut registry = Registry::<CtxT>::new(types);
query_type_name = registry.get_type::<QueryT>().innermost_name().to_owned();
mutation_type_name = registry.get_type::<MutationT>().innermost_name().to_owned();
types = registry.types;
}
let mut registry = Registry::new(HashMap::new());
query_type_name = registry.get_type::<QueryT>().innermost_name().to_owned();
mutation_type_name = registry.get_type::<MutationT>().innermost_name().to_owned();
{
let mut registry = Registry::<SchemaType>::new(types);
registry.get_type::<SchemaType>();
directives.insert(
"skip".to_owned(),
DirectiveType::new_skip(&mut registry));
directives.insert(
"include".to_owned(),
DirectiveType::new_include(&mut registry));
registry.get_type::<SchemaType>();
directives.insert(
"skip".to_owned(),
DirectiveType::new_skip(&mut registry));
directives.insert(
"include".to_owned(),
DirectiveType::new_include(&mut registry));
let mut meta_fields = vec![
registry.field::<SchemaType>("__schema"),
registry.field::<TypeType>("__type")
.argument(registry.arg::<String>("name")),
];
let mut meta_fields = vec![
registry.field::<SchemaType>("__schema"),
registry.field::<TypeType>("__type")
.argument(registry.arg::<String>("name")),
];
if let Some(root_type) = registry.types.get_mut(&query_type_name) {
if let &mut MetaType::Object(ObjectMeta { ref mut fields, .. }) = root_type {
fields.append(&mut meta_fields);
}
else {
panic!("Root type is not an object");
}
if let Some(root_type) = registry.types.get_mut(&query_type_name) {
if let &mut MetaType::Object(ObjectMeta { ref mut fields, .. }) = root_type {
fields.append(&mut meta_fields);
}
else {
panic!("Root type not found");
panic!("Root type is not an object");
}
types = registry.types;
}
else {
panic!("Root type not found");
}
for meta_type in types.values() {
for meta_type in registry.types.values() {
if let MetaType::Placeholder(PlaceholderMeta { ref of_type }) = *meta_type {
panic!("Type {:?} is still a placeholder type", of_type);
}
}
SchemaType {
types: types,
types: registry.types,
query_type_name: query_type_name,
mutation_type_name: if &mutation_type_name != "__Unit" { Some(mutation_type_name) } else { None },
mutation_type_name: if &mutation_type_name != "__EmptyMutation" { Some(mutation_type_name) } else { None },
directives: directives,
}
}
@ -305,7 +284,7 @@ impl DirectiveType {
}
}
fn new_skip<CtxT>(registry: &mut Registry<CtxT>) -> DirectiveType {
fn new_skip(registry: &mut Registry) -> DirectiveType {
Self::new(
"skip",
&[
@ -318,7 +297,7 @@ impl DirectiveType {
])
}
fn new_include<CtxT>(registry: &mut Registry<CtxT>) -> DirectiveType {
fn new_include(registry: &mut Registry) -> DirectiveType {
Self::new(
"include",
&[

View file

@ -7,15 +7,17 @@ use schema::meta::{MetaType, ObjectMeta, EnumMeta, InputObjectMeta, UnionMeta, I
Field, Argument, EnumValue};
use schema::model::{RootNode, SchemaType, TypeType, DirectiveType, DirectiveLocation};
impl<CtxT, QueryT, MutationT> GraphQLType<CtxT> for RootNode<CtxT, QueryT, MutationT>
where QueryT: GraphQLType<CtxT>,
MutationT: GraphQLType<CtxT>
impl<CtxT, QueryT, MutationT> GraphQLType for RootNode<QueryT, MutationT>
where QueryT: GraphQLType<Context=CtxT>,
MutationT: GraphQLType<Context=CtxT>
{
type Context = CtxT;
fn name() -> Option<&'static str> {
QueryT::name()
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
QueryT::meta(registry)
}

View file

@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet};
use value::Value;
use schema::model::RootNode;
use tests::model::Database;
use types::scalars::EmptyMutation;
#[test]
fn test_query_type_name() {
@ -15,7 +16,7 @@ fn test_query_type_name() {
}
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -38,7 +39,7 @@ fn test_specific_type_name() {
}
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -61,7 +62,7 @@ fn test_specific_object_type_name_and_kind() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -85,7 +86,7 @@ fn test_specific_interface_type_name_and_kind() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -109,7 +110,7 @@ fn test_documentation() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -135,7 +136,7 @@ fn test_possible_types() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
let result = ::execute(doc, None, &schema, &HashMap::new(), &database);

View file

@ -3,6 +3,7 @@ use std::collections::HashMap;
use ast::InputValue;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;
use tests::model::Database;
#[test]
@ -14,7 +15,7 @@ fn test_hero_name() {
}
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -39,7 +40,7 @@ fn test_hero_name_and_friends() {
}
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -80,7 +81,7 @@ fn test_hero_name_and_friends_and_friends_of_friends() {
}
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -162,7 +163,7 @@ fn test_hero_name_and_friends_and_friends_of_friends() {
fn test_query_name() {
let doc = r#"{ human(id: "1000") { name } }"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -178,7 +179,7 @@ fn test_query_name() {
fn test_query_alias_single() {
let doc = r#"{ luke: human(id: "1000") { name } }"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -198,7 +199,7 @@ fn test_query_alias_multiple() {
leia: human(id: "1003") { name }
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -226,7 +227,7 @@ fn test_query_alias_multiple_with_fragment() {
homePlanet
}"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -247,7 +248,7 @@ fn test_query_alias_multiple_with_fragment() {
fn test_query_name_variable() {
let doc = r#"query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } }"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
let vars = vec![
("someId".to_owned(), InputValue::string("1000")),
@ -267,7 +268,7 @@ fn test_query_name_variable() {
fn test_query_name_invalid_variable() {
let doc = r#"query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } }"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
let vars = vec![
("someId".to_owned(), InputValue::string("some invalid id")),
@ -285,7 +286,7 @@ fn test_query_name_invalid_variable() {
fn test_query_friends_names() {
let doc = r#"{ human(id: "1000") { friends { name } } }"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -325,7 +326,7 @@ fn test_query_inline_fragments_droid() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),
@ -350,7 +351,7 @@ fn test_query_inline_fragments_human() {
}
"#;
let database = Database::new();
let schema = RootNode::new(&database, ());
let schema = RootNode::new(&database, EmptyMutation::<Database>::new());
assert_eq!(
::execute(doc, None, &schema, &HashMap::new(), &database),

View file

@ -1,4 +1,7 @@
use tests::model::{Character, Human, Droid, Database, Episode};
use executor::Context;
impl Context for Database {}
graphql_enum!(Episode {
Episode::NewHope => "NEW_HOPE",

View file

@ -135,7 +135,7 @@ equivalent of the `User` object as shown in the example in the documentation
root:
```rust
use juniper::{GraphQLType, Registry, FieldResult,
use juniper::{GraphQLType, Registry, FieldResult, Context,
Arguments, Executor, ExecutionResult};
use juniper::meta::MetaType;
# use std::collections::HashMap;
@ -143,15 +143,19 @@ use juniper::meta::MetaType;
struct User { id: String, name: String, friend_ids: Vec<String> }
struct Database { users: HashMap<String, User> }
impl GraphQLType<Database> for User {
impl Context for Database {}
impl GraphQLType for User {
type Context = Database;
fn name() -> Option<&'static str> {
Some("User")
}
fn meta(registry: &mut Registry<Database>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
// First, we need to define all fields and their types on this type.
//
// If need arguments, want to implement interfaces, or want to add
// If we need arguments, want to implement interfaces, or want to add
// documentation strings, we can do it here.
registry.build_object_type::<User>()(&[
registry.field::<&String>("id"),
@ -171,12 +175,15 @@ impl GraphQLType<Database> for User {
{
// Next, we need to match the queried field name. All arms of this
// match statement return `ExecutionResult`, which makes it hard to
// statically verify that the type you pass on to `executor.resolve`
// statically verify that the type you pass on to `executor.resolve*`
// actually matches the one that you defined in `meta()` above.
let database = executor.context();
match field_name {
"id" => executor.resolve(&self.id),
"name" => executor.resolve(&self.name),
// Because scalars are defined with another `Context` associated
// type, you must use resolve_with_ctx here to make the executor
// perform automatic type conversion of its argument.
"id" => executor.resolve_with_ctx(&self.id),
"name" => executor.resolve_with_ctx(&self.name),
// You pass a vector of User objects to `executor.resolve`, and it
// will determine which fields of the sub-objects to actually
@ -201,7 +208,14 @@ impl GraphQLType<Database> for User {
```
*/
pub trait GraphQLType<CtxT>: Sized {
pub trait GraphQLType: Sized {
/// The expected context type for this GraphQL type
///
/// The context is threaded through query execution to all affected nodes,
/// and can be used to hold common data, e.g. database connections or
/// request session information.
type Context;
/// The name of the GraphQL type to expose.
///
/// This function will be called multiple times during schema construction.
@ -210,7 +224,7 @@ pub trait GraphQLType<CtxT>: Sized {
fn name() -> Option<&'static str>;
/// The meta type representing this GraphQL type.
fn meta(registry: &mut Registry<CtxT>) -> MetaType;
fn meta(registry: &mut Registry) -> MetaType;
/// Resolve the value of a single field on this type.
///
@ -221,7 +235,7 @@ pub trait GraphQLType<CtxT>: Sized {
///
/// The default implementation panics.
#[allow(unused_variables)]
fn resolve_field(&self, field_name: &str, arguments: &Arguments, executor: &Executor<CtxT>)
fn resolve_field(&self, field_name: &str, arguments: &Arguments, executor: &Executor<Self::Context>)
-> ExecutionResult
{
panic!("resolve_field must be implemented by object types");
@ -234,7 +248,7 @@ pub trait GraphQLType<CtxT>: Sized {
///
/// The default implementation panics.
#[allow(unused_variables)]
fn resolve_into_type(&self, type_name: &str, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> ExecutionResult {
fn resolve_into_type(&self, type_name: &str, selection_set: Option<Vec<Selection>>, executor: &Executor<Self::Context>) -> ExecutionResult {
if Self::name().unwrap() == type_name {
Ok(self.resolve(selection_set, executor))
} else {
@ -246,7 +260,7 @@ pub trait GraphQLType<CtxT>: Sized {
///
/// The default implementation panics.
#[allow(unused_variables)]
fn concrete_type_name(&self, context: &CtxT) -> String {
fn concrete_type_name(&self, context: &Self::Context) -> String {
panic!("concrete_type_name must be implemented by unions and interfaces");
}
@ -260,7 +274,7 @@ pub trait GraphQLType<CtxT>: Sized {
/// The default implementation uses `resolve_field` to resolve all fields,
/// including those through fragment expansion, for object types. For
/// non-object types, this method panics.
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value {
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &Executor<Self::Context>) -> Value {
if let Some(selection_set) = selection_set {
let mut result = HashMap::new();
resolve_selection_set_into(self, selection_set, executor, &mut result);
@ -277,7 +291,7 @@ fn resolve_selection_set_into<T, CtxT>(
selection_set: Vec<Selection>,
executor: &Executor<CtxT>,
result: &mut HashMap<String, Value>)
where T: GraphQLType<CtxT>
where T: GraphQLType<Context=CtxT>
{
let meta_type = executor.schema()
.concrete_type_by_name(T::name().expect("Resolving named type's selection set"))

View file

@ -5,12 +5,14 @@ use schema::meta::MetaType;
use executor::{Executor, Registry, IntoFieldResult, FieldResult};
use types::base::{GraphQLType};
impl<T, CtxT> GraphQLType<CtxT> for Option<T> where T: GraphQLType<CtxT> {
impl<T, CtxT> GraphQLType for Option<T> where T: GraphQLType<Context=CtxT> {
type Context = CtxT;
fn name() -> Option<&'static str> {
None
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_nullable_type::<T>().into_meta()
}
@ -50,12 +52,14 @@ impl<T> IntoFieldResult<Option<T>> for Option<T> {
}
impl<T, CtxT> GraphQLType<CtxT> for Vec<T> where T: GraphQLType<CtxT> {
impl<T, CtxT> GraphQLType for Vec<T> where T: GraphQLType<Context=CtxT> {
type Context = CtxT;
fn name() -> Option<&'static str> {
None
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_list_type::<T>().into_meta()
}
@ -102,12 +106,14 @@ impl<T> IntoFieldResult<Vec<T>> for Vec<T> {
}
impl<'a, T, CtxT> GraphQLType<CtxT> for &'a [T] where T: GraphQLType<CtxT> {
impl<'a, T, CtxT> GraphQLType for &'a [T] where T: GraphQLType<Context=CtxT> {
type Context = CtxT;
fn name() -> Option<&'static str> {
None
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_list_type::<T>().into_meta()
}

View file

@ -5,12 +5,14 @@ use schema::meta::MetaType;
use executor::{Executor, Registry, ExecutionResult, IntoFieldResult, FieldResult};
use types::base::{Arguments, GraphQLType};
impl<T, CtxT> GraphQLType<CtxT> for Box<T> where T: GraphQLType<CtxT> {
impl<T, CtxT> GraphQLType for Box<T> where T: GraphQLType<Context=CtxT> {
type Context = CtxT;
fn name() -> Option<&'static str> {
T::name()
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
T::meta(registry)
}
@ -49,12 +51,14 @@ impl<T> IntoFieldResult<Box<T>> for Box<T> {
}
}
impl<'a, T, CtxT> GraphQLType<CtxT> for &'a T where T: GraphQLType<CtxT> {
impl<'a, T, CtxT> GraphQLType for &'a T where T: GraphQLType<Context=CtxT> {
type Context = CtxT;
fn name() -> Option<&'static str> {
T::name()
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
T::meta(registry)
}

View file

@ -1,3 +1,5 @@
use std::marker::PhantomData;
use ast::{InputValue, Selection, FromInputValue, ToInputValue};
use value::Value;
@ -40,16 +42,18 @@ graphql_scalar!(String as "String" {
});
impl<'a, CtxT> GraphQLType<CtxT> for &'a str {
impl<'a> GraphQLType for &'a str {
type Context = ();
fn name() -> Option<&'static str> {
Some("String")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_scalar_type::<String>().into_meta()
}
fn resolve(&self, _: Option<Vec<Selection>>, _: &Executor<CtxT>) -> Value {
fn resolve(&self, _: Option<Vec<Selection>>, _: &Executor<Self::Context>) -> Value {
Value::string(self)
}
}
@ -111,12 +115,14 @@ graphql_scalar!(f64 as "Float" {
});
impl<CtxT> GraphQLType<CtxT> for () {
impl GraphQLType for () {
type Context = ();
fn name() -> Option<&'static str> {
Some("__Unit")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_scalar_type::<Self>().into_meta()
}
}
@ -132,3 +138,39 @@ impl IntoFieldResult<()> for () {
Ok(self)
}
}
/// Utility type to define read-only schemas
///
/// If you instantiate `RootNode` with this as the mutation, no mutation will be
/// generated for the schema.
pub struct EmptyMutation<T> {
phantom: PhantomData<T>,
}
impl<T> EmptyMutation<T> {
/// Construct a new empty mutation
pub fn new() -> EmptyMutation<T> {
EmptyMutation {
phantom: PhantomData,
}
}
}
impl<T> GraphQLType for EmptyMutation<T> {
type Context = T;
fn name() -> Option<&'static str> {
Some("__EmptyMutation")
}
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[]).into_meta()
}
}
impl<T> IntoFieldResult<EmptyMutation<T>> for EmptyMutation<T> {
fn into(self) -> FieldResult<EmptyMutation<T>> {
Ok(self)
}
}

View file

@ -1164,12 +1164,14 @@ mod tests {
struct Node;
struct QueryRoot;
impl<CtxT> GraphQLType<CtxT> for SomeBox {
impl GraphQLType for SomeBox {
type Context = ();
fn name() -> Option<&'static str> {
Some("SomeBox")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<Option<SomeBox>>("deepBox"),
registry.field::<Option<String>>("unrelatedField"),
@ -1178,12 +1180,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for StringBox {
impl GraphQLType for StringBox {
type Context = ();
fn name() -> Option<&'static str> {
Some("StringBox")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("scalar"),
registry.field::<Option<StringBox>>("deepBox"),
@ -1199,12 +1203,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for IntBox {
impl GraphQLType for IntBox {
type Context = ();
fn name() -> Option<&'static str> {
Some("IntBox")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<i64>>("scalar"),
registry.field::<Option<IntBox>>("deepBox"),
@ -1220,12 +1226,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for NonNullStringBox1 {
impl GraphQLType for NonNullStringBox1 {
type Context = ();
fn name() -> Option<&'static str> {
Some("NonNullStringBox1")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<String>("scalar"),
])
@ -1233,12 +1241,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for NonNullStringBox1Impl {
impl GraphQLType for NonNullStringBox1Impl {
type Context = ();
fn name() -> Option<&'static str> {
Some("NonNullStringBox1Impl")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<String>("scalar"),
registry.field::<Option<SomeBox>>("deepBox"),
@ -1252,12 +1262,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for NonNullStringBox2 {
impl GraphQLType for NonNullStringBox2 {
type Context = ();
fn name() -> Option<&'static str> {
Some("NonNullStringBox2")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<String>("scalar"),
])
@ -1265,12 +1277,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for NonNullStringBox2Impl {
impl GraphQLType for NonNullStringBox2Impl {
type Context = ();
fn name() -> Option<&'static str> {
Some("NonNullStringBox2Impl")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<String>("scalar"),
registry.field::<Option<SomeBox>>("deepBox"),
@ -1284,12 +1298,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for Node {
impl GraphQLType for Node {
type Context = ();
fn name() -> Option<&'static str> {
Some("Node")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<ID>>("id"),
registry.field::<Option<String>>("name"),
@ -1298,12 +1314,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for Edge {
impl GraphQLType for Edge {
type Context = ();
fn name() -> Option<&'static str> {
Some("Edge")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<Node>>("node"),
])
@ -1311,12 +1329,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for Connection {
impl GraphQLType for Connection {
type Context = ();
fn name() -> Option<&'static str> {
Some("Connection")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<Vec<Option<Edge>>>>("edges"),
])
@ -1324,12 +1344,14 @@ mod tests {
}
}
impl<CtxT> GraphQLType<CtxT> for QueryRoot {
impl GraphQLType for QueryRoot {
type Context = ();
fn name() -> Option<&'static str> {
Some("QueryRoot")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.get_type::<IntBox>();
registry.get_type::<StringBox>();
registry.get_type::<NonNullStringBox1Impl>();

View file

@ -2,7 +2,7 @@ use parser::parse_document_source;
use ast::{FromInputValue, InputValue};
use types::base::GraphQLType;
use executor::Registry;
use types::scalars::ID;
use types::scalars::{EmptyMutation, ID};
use schema::model::{DirectiveType, DirectiveLocation, RootNode};
use schema::meta::{EnumValue, MetaType};
use validation::{Visitor, RuleError, ValidatorContext, MultiVisitor, visit};
@ -51,12 +51,14 @@ struct ComplexInput {
string_list_field: Option<Vec<Option<String>>>,
}
impl<CtxT> GraphQLType<CtxT> for Being {
impl GraphQLType for Being {
type Context = ();
fn name() -> Option<&'static str> {
Some("Being")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -65,12 +67,14 @@ impl<CtxT> GraphQLType<CtxT> for Being {
}
}
impl<CtxT> GraphQLType<CtxT> for Pet {
impl GraphQLType for Pet {
type Context = ();
fn name() -> Option<&'static str> {
Some("Pet")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -79,12 +83,14 @@ impl<CtxT> GraphQLType<CtxT> for Pet {
}
}
impl<CtxT> GraphQLType<CtxT> for Canine {
impl GraphQLType for Canine {
type Context = ();
fn name() -> Option<&'static str> {
Some("Canine")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -93,12 +99,14 @@ impl<CtxT> GraphQLType<CtxT> for Canine {
}
}
impl<CtxT> GraphQLType<CtxT> for DogCommand {
impl GraphQLType for DogCommand {
type Context = ();
fn name() -> Option<&'static str> {
Some("DogCommand")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_enum_type::<Self>()(&[
EnumValue::new("SIT"),
EnumValue::new("HEEL"),
@ -119,12 +127,14 @@ impl FromInputValue for DogCommand {
}
}
impl<CtxT> GraphQLType<CtxT> for Dog {
impl GraphQLType for Dog {
type Context = ();
fn name() -> Option<&'static str> {
Some("Dog")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -148,12 +158,14 @@ impl<CtxT> GraphQLType<CtxT> for Dog {
}
}
impl<CtxT> GraphQLType<CtxT> for FurColor {
impl GraphQLType for FurColor {
type Context = ();
fn name() -> Option<&'static str> {
Some("FurColor")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_enum_type::<Self>()(&[
EnumValue::new("BROWN"),
EnumValue::new("BLACK"),
@ -176,12 +188,14 @@ impl FromInputValue for FurColor {
}
}
impl<CtxT> GraphQLType<CtxT> for Cat {
impl GraphQLType for Cat {
type Context = ();
fn name() -> Option<&'static str> {
Some("Cat")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -198,12 +212,14 @@ impl<CtxT> GraphQLType<CtxT> for Cat {
}
}
impl<CtxT> GraphQLType<CtxT> for CatOrDog {
impl GraphQLType for CatOrDog {
type Context = ();
fn name() -> Option<&'static str> {
Some("CatOrDog")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_union_type::<Self>()(&[
registry.get_type::<Cat>(),
registry.get_type::<Dog>(),
@ -212,12 +228,14 @@ impl<CtxT> GraphQLType<CtxT> for CatOrDog {
}
}
impl<CtxT> GraphQLType<CtxT> for Intelligent {
impl GraphQLType for Intelligent {
type Context = ();
fn name() -> Option<&'static str> {
Some("Intelligent")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_interface_type::<Self>()(&[
registry.field::<Option<i64>>("iq"),
])
@ -225,12 +243,14 @@ impl<CtxT> GraphQLType<CtxT> for Intelligent {
}
}
impl<CtxT> GraphQLType<CtxT> for Human {
impl GraphQLType for Human {
type Context = ();
fn name() -> Option<&'static str> {
Some("Human")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -246,12 +266,14 @@ impl<CtxT> GraphQLType<CtxT> for Human {
}
}
impl<CtxT> GraphQLType<CtxT> for Alien {
impl GraphQLType for Alien {
type Context = ();
fn name() -> Option<&'static str> {
Some("Alien")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("name")
.argument(registry.arg::<Option<bool>>("surname")),
@ -266,12 +288,14 @@ impl<CtxT> GraphQLType<CtxT> for Alien {
}
}
impl<CtxT> GraphQLType<CtxT> for DogOrHuman {
impl GraphQLType for DogOrHuman {
type Context = ();
fn name() -> Option<&'static str> {
Some("DogOrHuman")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_union_type::<Self>()(&[
registry.get_type::<Dog>(),
registry.get_type::<Human>(),
@ -280,12 +304,14 @@ impl<CtxT> GraphQLType<CtxT> for DogOrHuman {
}
}
impl<CtxT> GraphQLType<CtxT> for HumanOrAlien {
impl GraphQLType for HumanOrAlien {
type Context = ();
fn name() -> Option<&'static str> {
Some("HumanOrAlien")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_union_type::<Self>()(&[
registry.get_type::<Human>(),
registry.get_type::<Alien>(),
@ -294,12 +320,14 @@ impl<CtxT> GraphQLType<CtxT> for HumanOrAlien {
}
}
impl<CtxT> GraphQLType<CtxT> for ComplexInput {
impl GraphQLType for ComplexInput {
type Context = ();
fn name() -> Option<&'static str> {
Some("ComplexInput")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_input_object_type::<Self>()(&[
registry.arg::<bool>("requiredField"),
registry.arg::<Option<i64>>("intField"),
@ -331,12 +359,14 @@ impl FromInputValue for ComplexInput {
}
}
impl<CtxT> GraphQLType<CtxT> for ComplicatedArgs {
impl GraphQLType for ComplicatedArgs {
type Context = ();
fn name() -> Option<&'static str> {
Some("ComplicatedArgs")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<String>>("intArgField")
.argument(registry.arg::<Option<i64>>("intArg")),
@ -372,12 +402,14 @@ impl<CtxT> GraphQLType<CtxT> for ComplicatedArgs {
}
}
impl<CtxT> GraphQLType<CtxT> for QueryRoot {
impl GraphQLType for QueryRoot {
type Context = ();
fn name() -> Option<&'static str> {
Some("QueryRoot")
}
fn meta(registry: &mut Registry<CtxT>) -> MetaType {
fn meta(registry: &mut Registry) -> MetaType {
registry.build_object_type::<Self>()(&[
registry.field::<Option<Human>>("human")
.argument(registry.arg::<Option<ID>>("id")),
@ -396,11 +428,11 @@ impl<CtxT> GraphQLType<CtxT> for QueryRoot {
pub fn validate<'a, R, V, F>(r: R, q: &str, factory: F)
-> Vec<RuleError>
where R: GraphQLType<()>,
where R: GraphQLType,
V: Visitor<'a> + 'a,
F: Fn() -> V
{
let mut root = RootNode::<(), R, ()>::new(r, ());
let mut root = RootNode::new(r, EmptyMutation::<()>::new());
root.schema.add_directive(DirectiveType::new("onQuery", &[DirectiveLocation::Query], &[]));
root.schema.add_directive(DirectiveType::new("onMutation", &[DirectiveLocation::Mutation], &[]));
@ -429,7 +461,7 @@ pub fn expect_passes_rule<'a, V, F>(factory: F, q: &str)
}
pub fn expect_passes_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &str)
where R: GraphQLType<()>,
where R: GraphQLType,
V: Visitor<'a> + 'a,
F: Fn() -> V
{
@ -449,7 +481,7 @@ pub fn expect_fails_rule<'a, V, F>(factory: F, q: &str, expected_errors: &[RuleE
}
pub fn expect_fails_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &str, expected_errors: &[RuleError])
where R: GraphQLType<()>,
where R: GraphQLType,
V: Visitor<'a> + 'a,
F: Fn() -> V
{