Skip to content

Commit 6b8f4c9

Browse files
committed
Move context type parameter to associated type of GraphQLType
1 parent 885fe8b commit 6b8f4c9

36 files changed

+472
-286
lines changed

examples/server.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::env;
99
use mount::Mount;
1010
use logger::Logger;
1111
use iron::prelude::*;
12-
use juniper::FieldResult;
12+
use juniper::EmptyMutation;
1313
use juniper::iron_handlers::{GraphQLHandler, GraphiQLHandler};
1414
use juniper::tests::model::Database;
1515

@@ -20,7 +20,11 @@ fn context_factory(_: &mut Request) -> Database {
2020
fn main() {
2121
let mut mount = Mount::new();
2222

23-
let graphql_endpoint = GraphQLHandler::new(context_factory, Database::new(), ());
23+
let graphql_endpoint = GraphQLHandler::new(
24+
context_factory,
25+
Database::new(),
26+
EmptyMutation::<Database>::new(),
27+
);
2428
let graphiql_endpoint = GraphiQLHandler::new("/graphql");
2529

2630
mount.mount("/", graphiql_endpoint);

src/executor.rs

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::collections::HashMap;
2-
use std::marker::PhantomData;
32
use std::sync::RwLock;
43

54
use ::GraphQLError;
@@ -20,10 +19,9 @@ use types::base::GraphQLType;
2019
/// The registry gathers metadata for all types in a schema. It provides
2120
/// convenience methods to convert types implementing the `GraphQLType` trait
2221
/// into `Type` instances and automatically registers them.
23-
pub struct Registry<CtxT> {
22+
pub struct Registry {
2423
/// Currently registered types
2524
pub types: HashMap<String, MetaType>,
26-
phantom: PhantomData<CtxT>,
2725
}
2826

2927
#[derive(Clone)]
@@ -80,9 +78,46 @@ impl<T> IntoFieldResult<T> for FieldResult<T> {
8078
}
8179
}
8280

81+
/// Conversion trait for context types
82+
///
83+
/// This is currently only used for converting arbitrary contexts into
84+
/// the empty tuple, but will in the future be used to support general
85+
/// context conversion for larger schemas.
86+
pub trait FromContext<T> {
87+
/// Perform the conversion
88+
fn from_context(value: &T) -> &Self;
89+
}
90+
91+
/// Marker trait for types that can act as context objects for GraphQL types.
92+
pub trait Context { }
93+
94+
static NULL_CONTEXT: () = ();
95+
96+
impl<T> FromContext<T> for () {
97+
fn from_context(_: &T) -> &Self {
98+
&NULL_CONTEXT
99+
}
100+
}
101+
102+
impl<T> FromContext<T> for T where T: Context {
103+
fn from_context(value: &T) -> &Self {
104+
value
105+
}
106+
}
107+
83108
impl<'a, CtxT> Executor<'a, CtxT> {
109+
/// Resolve a single arbitrary value, mapping the context to a new type
110+
pub fn resolve_with_ctx<NewCtxT, T: GraphQLType<Context=NewCtxT>>(
111+
&self, value: &T
112+
) -> ExecutionResult
113+
where NewCtxT: FromContext<CtxT>,
114+
{
115+
self.replaced_context(<NewCtxT as FromContext<CtxT>>::from_context(&self.context))
116+
.resolve(value)
117+
}
118+
84119
/// Resolve a single arbitrary value into an `ExecutionResult`
85-
pub fn resolve<T: GraphQLType<CtxT>>(&self, value: &T) -> ExecutionResult {
120+
pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> ExecutionResult {
86121
Ok(value.resolve(
87122
match self.current_selection_set {
88123
Some(ref sel) => Some(sel.clone()),
@@ -94,7 +129,7 @@ impl<'a, CtxT> Executor<'a, CtxT> {
94129
/// Resolve a single arbitrary value into a return value
95130
///
96131
/// If the field fails to resolve, `null` will be returned.
97-
pub fn resolve_into_value<T: GraphQLType<CtxT>>(&self, value: &T) -> Value {
132+
pub fn resolve_into_value<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> Value {
98133
match self.resolve(value) {
99134
Ok(v) => v,
100135
Err(e) => {
@@ -230,13 +265,13 @@ impl ExecutionError {
230265
pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
231266
document: Document,
232267
operation_name: Option<&str>,
233-
root_node: &RootNode<CtxT, QueryT, MutationT>,
268+
root_node: &RootNode<QueryT, MutationT>,
234269
variables: &HashMap<String, InputValue>,
235270
context: &CtxT
236271
)
237272
-> Result<(Value, Vec<ExecutionError>), GraphQLError<'a>>
238-
where QueryT: GraphQLType<CtxT>,
239-
MutationT: GraphQLType<CtxT>
273+
where QueryT: GraphQLType<Context=CtxT>,
274+
MutationT: GraphQLType<Context=CtxT>
240275
{
241276
let mut fragments = vec![];
242277
let mut operation = None;
@@ -290,20 +325,19 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
290325
Ok((value, errors))
291326
}
292327

293-
impl<CtxT> Registry<CtxT> {
328+
impl Registry {
294329
/// Construct a new registry
295-
pub fn new(types: HashMap<String, MetaType>) -> Registry<CtxT> {
330+
pub fn new(types: HashMap<String, MetaType>) -> Registry {
296331
Registry {
297332
types: types,
298-
phantom: PhantomData,
299333
}
300334
}
301335

302336
/// Get the `Type` instance for a given GraphQL type
303337
///
304338
/// If the registry hasn't seen a type with this name before, it will
305339
/// construct its metadata and store it.
306-
pub fn get_type<T>(&mut self) -> Type where T: GraphQLType<CtxT> {
340+
pub fn get_type<T>(&mut self) -> Type where T: GraphQLType {
307341
if let Some(name) = T::name() {
308342
if !self.types.contains_key(name) {
309343
self.insert_placeholder(name, Type::NonNullNamed(name.to_owned()));
@@ -318,7 +352,7 @@ impl<CtxT> Registry<CtxT> {
318352
}
319353

320354
/// Create a field with the provided name
321-
pub fn field<T>(&mut self, name: &str) -> Field where T: GraphQLType<CtxT> {
355+
pub fn field<T>(&mut self, name: &str) -> Field where T: GraphQLType {
322356
Field {
323357
name: name.to_owned(),
324358
description: None,
@@ -329,7 +363,7 @@ impl<CtxT> Registry<CtxT> {
329363
}
330364

331365
#[doc(hidden)]
332-
pub fn field_convert<T: IntoFieldResult<I>, I>(&mut self, name: &str) -> Field where I: GraphQLType<CtxT> {
366+
pub fn field_convert<T: IntoFieldResult<I>, I>(&mut self, name: &str) -> Field where I: GraphQLType {
333367
Field {
334368
name: name.to_owned(),
335369
description: None,
@@ -340,7 +374,7 @@ impl<CtxT> Registry<CtxT> {
340374
}
341375

342376
#[doc(hidden)]
343-
pub fn field_inside_result<T>(&mut self, name: &str, _: FieldResult<T>) -> Field where T: GraphQLType<CtxT> {
377+
pub fn field_inside_result<T>(&mut self, name: &str, _: FieldResult<T>) -> Field where T: GraphQLType {
344378
Field {
345379
name: name.to_owned(),
346380
description: None,
@@ -351,7 +385,7 @@ impl<CtxT> Registry<CtxT> {
351385
}
352386

353387
/// Create an argument with the provided name
354-
pub fn arg<T>(&mut self, name: &str) -> Argument where T: GraphQLType<CtxT> + FromInputValue {
388+
pub fn arg<T>(&mut self, name: &str) -> Argument where T: GraphQLType + FromInputValue {
355389
Argument::new(name, self.get_type::<T>())
356390
}
357391

@@ -365,7 +399,7 @@ impl<CtxT> Registry<CtxT> {
365399
value: &T,
366400
)
367401
-> Argument
368-
where T: GraphQLType<CtxT> + ToInputValue + FromInputValue
402+
where T: GraphQLType + ToInputValue + FromInputValue
369403
{
370404
Argument::new(name, self.get_type::<Option<T>>())
371405
.default_value(value.to())
@@ -384,20 +418,20 @@ impl<CtxT> Registry<CtxT> {
384418
/// This expects the type to implement `FromInputValue`.
385419
pub fn build_scalar_type<T>(&mut self)
386420
-> ScalarMeta
387-
where T: FromInputValue + GraphQLType<CtxT>
421+
where T: FromInputValue + GraphQLType
388422
{
389423
let name = T::name().expect("Scalar types must be named. Implement name()");
390424
ScalarMeta::new::<T>(name)
391425
}
392426

393427
/// Create a list meta type
394-
pub fn build_list_type<T: GraphQLType<CtxT>>(&mut self) -> ListMeta {
428+
pub fn build_list_type<T: GraphQLType>(&mut self) -> ListMeta {
395429
let of_type = self.get_type::<T>();
396430
ListMeta::new(of_type)
397431
}
398432

399433
/// Create a nullable meta type
400-
pub fn build_nullable_type<T: GraphQLType<CtxT>>(&mut self) -> NullableMeta {
434+
pub fn build_nullable_type<T: GraphQLType>(&mut self) -> NullableMeta {
401435
let of_type = self.get_type::<T>();
402436
NullableMeta::new(of_type)
403437
}
@@ -408,7 +442,7 @@ impl<CtxT> Registry<CtxT> {
408442
/// function that needs to be called with the list of fields on the object.
409443
pub fn build_object_type<T>(&mut self)
410444
-> Box<Fn(&[Field]) -> ObjectMeta>
411-
where T: GraphQLType<CtxT>
445+
where T: GraphQLType
412446
{
413447
let name = T::name().expect("Object types must be named. Implement name()");
414448
let typename_field = self.field::<String>("__typename");
@@ -423,7 +457,7 @@ impl<CtxT> Registry<CtxT> {
423457
/// Create an enum meta type
424458
pub fn build_enum_type<T>(&mut self)
425459
-> Box<Fn(&[EnumValue]) -> EnumMeta>
426-
where T: FromInputValue + GraphQLType<CtxT>
460+
where T: FromInputValue + GraphQLType
427461
{
428462
let name = T::name().expect("Enum types must be named. Implement name()");
429463

@@ -433,7 +467,7 @@ impl<CtxT> Registry<CtxT> {
433467
/// Create an interface meta type builder
434468
pub fn build_interface_type<T>(&mut self)
435469
-> Box<Fn(&[Field]) -> InterfaceMeta>
436-
where T: GraphQLType<CtxT>
470+
where T: GraphQLType
437471
{
438472
let name = T::name().expect("Interface types must be named. Implement name()");
439473
let typename_field = self.field::<String>("__typename");
@@ -448,7 +482,7 @@ impl<CtxT> Registry<CtxT> {
448482
/// Create a union meta type builder
449483
pub fn build_union_type<T>(&mut self)
450484
-> Box<Fn(&[Type]) -> UnionMeta>
451-
where T: GraphQLType<CtxT>
485+
where T: GraphQLType
452486
{
453487
let name = T::name().expect("Union types must be named. Implement name()");
454488

@@ -458,7 +492,7 @@ impl<CtxT> Registry<CtxT> {
458492
/// Create an input object meta type builder
459493
pub fn build_input_object_type<T>(&mut self)
460494
-> Box<Fn(&[Argument]) -> InputObjectMeta>
461-
where T: FromInputValue + GraphQLType<CtxT>
495+
where T: FromInputValue + GraphQLType
462496
{
463497
let name = T::name().expect("Input object types must be named. Implement name()");
464498

src/executor_tests/directives.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::HashMap;
33
use value::Value;
44
use ast::InputValue;
55
use schema::model::RootNode;
6+
use types::scalars::EmptyMutation;
67

78
struct TestType;
89

@@ -19,7 +20,7 @@ graphql_object!(TestType: () |&self| {
1920
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
2021
where F: Fn(&HashMap<String, Value>) -> ()
2122
{
22-
let schema = RootNode::new(TestType, ());
23+
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
2324

2425
let (result, errs) = ::execute(query, None, &schema, &vars, &())
2526
.expect("Execution failed");

src/executor_tests/enums.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use schema::model::RootNode;
66
use ::GraphQLError::ValidationError;
77
use validation::RuleError;
88
use parser::SourcePosition;
9+
use types::scalars::EmptyMutation;
910

1011
#[derive(Debug)]
1112
enum Color { Red, Green, Blue }
@@ -30,7 +31,7 @@ graphql_object!(TestType: () |&self| {
3031
fn run_variable_query<F>(query: &str, vars: HashMap<String, InputValue>, f: F)
3132
where F: Fn(&HashMap<String, Value>) -> ()
3233
{
33-
let schema = RootNode::new(TestType, ());
34+
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
3435

3536
let (result, errs) = ::execute(query, None, &schema, &vars, &())
3637
.expect("Execution failed");
@@ -74,7 +75,7 @@ fn serializes_as_output() {
7475

7576
#[test]
7677
fn does_not_accept_string_literals() {
77-
let schema = RootNode::new(TestType, ());
78+
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
7879

7980
let query = r#"{ toString(color: "RED") }"#;
8081
let vars = vec![
@@ -107,7 +108,7 @@ fn accepts_strings_in_variables() {
107108

108109
#[test]
109110
fn does_not_accept_incorrect_enum_name_in_variables() {
110-
let schema = RootNode::new(TestType, ());
111+
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
111112

112113
let query = r#"query q($color: Color!) { toString(color: $color) }"#;
113114
let vars = vec![
@@ -127,7 +128,7 @@ fn does_not_accept_incorrect_enum_name_in_variables() {
127128

128129
#[test]
129130
fn does_not_accept_incorrect_type_in_variables() {
130-
let schema = RootNode::new(TestType, ());
131+
let schema = RootNode::new(TestType, EmptyMutation::<()>::new());
131132

132133
let query = r#"query q($color: Color!) { toString(color: $color) }"#;
133134
let vars = vec![

0 commit comments

Comments
 (0)