Skip to content

Commit 133e943

Browse files
committed
Implement support for dynamic schemas
1 parent 2ffa31b commit 133e943

27 files changed

+516
-313
lines changed

juniper/src/ast.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt;
2+
use std::borrow::Cow;
23
use std::collections::HashMap;
34
use std::hash::Hash;
45
use std::vec;
@@ -14,13 +15,13 @@ use parser::Spanning;
1415
#[derive(Clone, Eq, PartialEq, Debug)]
1516
pub enum Type<'a> {
1617
/// A nullable named type, e.g. `String`
17-
Named(&'a str),
18+
Named(Cow<'a, str>),
1819
/// A nullable list type, e.g. `[String]`
1920
///
2021
/// The list itself is what's nullable, the containing type might be non-null.
2122
List(Box<Type<'a>>),
2223
/// A non-null named type, e.g. `String!`
23-
NonNullNamed(&'a str),
24+
NonNullNamed(Cow<'a, str>),
2425
/// A non-null list type, e.g. `[String]!`.
2526
///
2627
/// The list itself is what's non-null, the containing type might be null.
@@ -168,7 +169,7 @@ impl<'a> Type<'a> {
168169
/// Only applies to named types; lists will return `None`.
169170
pub fn name(&self) -> Option<&str> {
170171
match *self {
171-
Type::Named(n) | Type::NonNullNamed(n) => Some(n),
172+
Type::Named(ref n) | Type::NonNullNamed(ref n) => Some(n),
172173
_ => None
173174
}
174175
}
@@ -178,7 +179,7 @@ impl<'a> Type<'a> {
178179
/// All type literals contain exactly one named type.
179180
pub fn innermost_name(&self) -> &str {
180181
match *self {
181-
Type::Named(n) | Type::NonNullNamed(n) => n,
182+
Type::Named(ref n) | Type::NonNullNamed(ref n) => n,
182183
Type::List(ref l) | Type::NonNullList(ref l) => l.innermost_name(),
183184
}
184185
}
@@ -195,8 +196,8 @@ impl<'a> Type<'a> {
195196
impl<'a> fmt::Display for Type<'a> {
196197
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197198
match *self {
198-
Type::Named(n) => write!(f, "{}", n),
199-
Type::NonNullNamed(n) => write!(f, "{}!", n),
199+
Type::Named(ref n) => write!(f, "{}", n),
200+
Type::NonNullNamed(ref n) => write!(f, "{}!", n),
200201
Type::List(ref t) => write!(f, "[{}]", t),
201202
Type::NonNullList(ref t) => write!(f, "[{}]!", t),
202203
}

juniper/src/executor.rs

Lines changed: 128 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::collections::HashMap;
23
use std::sync::RwLock;
34

@@ -144,24 +145,24 @@ impl<T> FromContext<T> for T where T: Context {
144145
impl<'a, CtxT> Executor<'a, CtxT> {
145146
/// Resolve a single arbitrary value, mapping the context to a new type
146147
pub fn resolve_with_ctx<NewCtxT, T: GraphQLType<Context=NewCtxT>>(
147-
&self, value: &T
148+
&self, info: &T::TypeInfo, value: &T
148149
) -> ExecutionResult
149150
where NewCtxT: FromContext<CtxT>,
150151
{
151152
self.replaced_context(<NewCtxT as FromContext<CtxT>>::from(self.context))
152-
.resolve(value)
153+
.resolve(info, value)
153154
}
154155

155156
/// Resolve a single arbitrary value into an `ExecutionResult`
156-
pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> ExecutionResult {
157-
Ok(value.resolve(self.current_selection_set, self))
157+
pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult {
158+
Ok(value.resolve(info, self.current_selection_set, self))
158159
}
159160

160161
/// Resolve a single arbitrary value into a return value
161162
///
162163
/// If the field fails to resolve, `null` will be returned.
163-
pub fn resolve_into_value<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> Value {
164-
match self.resolve(value) {
164+
pub fn resolve_into_value<T: GraphQLType<Context=CtxT>>(&self, info: &T::TypeInfo, value: &T) -> Value {
165+
match self.resolve(info, value) {
165166
Ok(v) => v,
166167
Err(e) => {
167168
let position = self.field_path.location().clone();
@@ -364,8 +365,8 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
364365
};
365366

366367
value = match op.item.operation_type {
367-
OperationType::Query => executor.resolve_into_value(&root_node),
368-
OperationType::Mutation => executor.resolve_into_value(&root_node.mutation_type),
368+
OperationType::Query => executor.resolve_into_value(&root_node.query_info, &root_node),
369+
OperationType::Mutation => executor.resolve_into_value(&root_node.mutation_info, &root_node.mutation_type),
369370
};
370371
}
371372

@@ -387,62 +388,107 @@ impl<'r> Registry<'r> {
387388
///
388389
/// If the registry hasn't seen a type with this name before, it will
389390
/// construct its metadata and store it.
390-
pub fn get_type<T>(&mut self) -> Type<'r> where T: GraphQLType {
391-
if let Some(name) = T::name() {
392-
if !self.types.contains_key(name) {
393-
self.insert_placeholder(name, Type::NonNullNamed(name));
394-
let meta = T::meta(self);
395-
self.types.insert(name.to_owned(), meta);
391+
pub fn get_type<T>(&mut self) -> Type<'r> where T: GraphQLType<TypeInfo=()> {
392+
self.get_type_with_info::<T>(&())
393+
}
394+
395+
/// Get the `Type` instance for a given GraphQL type,
396+
/// by providing a type info object.
397+
///
398+
/// If the registry hasn't seen a type with this name before, it will
399+
/// construct its metadata and store it.
400+
pub fn get_type_with_info<T>(&mut self, info: &T::TypeInfo) -> Type<'r> where T: GraphQLType {
401+
if let Some(name) = T::name(info) {
402+
if !self.types.contains_key(&name.to_string()) {
403+
self.insert_placeholder(&name, Type::NonNullNamed(Cow::Owned(name.to_string())));
404+
let meta = T::meta(info, self);
405+
self.types.insert(name.to_string(), meta);
396406
}
397-
self.types[name].as_type()
407+
self.types[&name.to_string()].as_type()
398408
}
399409
else {
400-
T::meta(self).as_type()
410+
T::meta(info, self).as_type()
401411
}
402412
}
403413

404414
/// Create a field with the provided name
405-
pub fn field<T>(&mut self, name: &str) -> Field<'r> where T: GraphQLType {
415+
pub fn field<T>(&mut self, name: &str) -> Field<'r> where T: GraphQLType<TypeInfo=()> {
416+
self.field_with_info::<T>(name, &())
417+
}
418+
419+
/// Create a field with the provided name,
420+
/// by providing a type info object.
421+
pub fn field_with_info<T>(&mut self, name: &str, info: &T::TypeInfo) -> Field<'r> where T: GraphQLType {
406422
Field {
407423
name: name.to_owned(),
408424
description: None,
409425
arguments: None,
410-
field_type: self.get_type::<T>(),
426+
field_type: self.get_type_with_info::<T>(info),
411427
deprecation_reason: None,
412428
}
413429
}
414430

415431
#[doc(hidden)]
416432
pub fn field_convert<'a, T: IntoResolvable<'a, I, C>, I, C>(&mut self, name: &str) -> Field<'r>
433+
where I: GraphQLType<TypeInfo=()>
434+
{
435+
self.field_convert_with_info::<'a, T, I, C>(name, &())
436+
}
437+
438+
#[doc(hidden)]
439+
pub fn field_convert_with_info<'a, T: IntoResolvable<'a, I, C>, I, C>(&mut self, name: &str, info: &I::TypeInfo) -> Field<'r>
417440
where I: GraphQLType
418441
{
419442
Field {
420443
name: name.to_owned(),
421444
description: None,
422445
arguments: None,
423-
field_type: self.get_type::<I>(),
446+
field_type: self.get_type_with_info::<I>(info),
424447
deprecation_reason: None,
425448
}
426449
}
427450

428451
/// Create an argument with the provided name
429-
pub fn arg<T>(&mut self, name: &str) -> Argument<'r> where T: GraphQLType + FromInputValue {
430-
Argument::new(name, self.get_type::<T>())
452+
pub fn arg<T>(&mut self, name: &str) -> Argument<'r> where T: GraphQLType<TypeInfo=()> + FromInputValue {
453+
self.arg_with_info::<T>(name, &())
454+
}
455+
456+
/// Create an argument with the provided name,
457+
/// by providing a type info object.
458+
pub fn arg_with_info<T>(&mut self, name: &str, info: &T::TypeInfo) -> Argument<'r> where T: GraphQLType + FromInputValue {
459+
Argument::new(name, self.get_type_with_info::<T>(info))
431460
}
432461

433462
/// Create an argument with a default value
434463
///
435464
/// When called with type `T`, the actual argument will be given the type
436465
/// `Option<T>`.
437466
pub fn arg_with_default<T>(
467+
&mut self,
468+
name: &str,
469+
value: &T
470+
)
471+
-> Argument<'r>
472+
where T: GraphQLType<TypeInfo=()> + ToInputValue + FromInputValue
473+
{
474+
self.arg_with_default_with_info(name, value, &())
475+
}
476+
477+
/// Create an argument with a default value,
478+
/// by providing a type info object.
479+
///
480+
/// When called with type `T`, the actual argument will be given the type
481+
/// `Option<T>`.
482+
pub fn arg_with_default_with_info<T>(
438483
&mut self,
439484
name: &str,
440485
value: &T,
486+
info: &T::TypeInfo
441487
)
442488
-> Argument<'r>
443489
where T: GraphQLType + ToInputValue + FromInputValue
444490
{
445-
Argument::new(name, self.get_type::<Option<T>>())
491+
Argument::new(name, self.get_type_with_info::<Option<T>>(info))
446492
.default_value(value.to())
447493
}
448494

@@ -457,22 +503,22 @@ impl<'r> Registry<'r> {
457503
/// Create a scalar meta type
458504
///
459505
/// This expects the type to implement `FromInputValue`.
460-
pub fn build_scalar_type<T>(&mut self) -> ScalarMeta<'r>
506+
pub fn build_scalar_type<T>(&mut self, info: &T::TypeInfo) -> ScalarMeta<'r>
461507
where T: FromInputValue + GraphQLType
462508
{
463-
let name = T::name().expect("Scalar types must be named. Implement name()");
464-
ScalarMeta::new::<T>(name)
509+
let name = T::name(info).expect("Scalar types must be named. Implement name()");
510+
ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
465511
}
466512

467513
/// Create a list meta type
468-
pub fn build_list_type<T: GraphQLType>(&mut self) -> ListMeta<'r> {
469-
let of_type = self.get_type::<T>();
514+
pub fn build_list_type<T: GraphQLType>(&mut self, info: &T::TypeInfo) -> ListMeta<'r> {
515+
let of_type = self.get_type_with_info::<T>(info);
470516
ListMeta::new(of_type)
471517
}
472518

473519
/// Create a nullable meta type
474-
pub fn build_nullable_type<T: GraphQLType>(&mut self) -> NullableMeta<'r> {
475-
let of_type = self.get_type::<T>();
520+
pub fn build_nullable_type<T: GraphQLType>(&mut self, info: &T::TypeInfo) -> NullableMeta<'r> {
521+
let of_type = self.get_type_with_info::<T>(info);
476522
NullableMeta::new(of_type)
477523
}
478524

@@ -481,50 +527,93 @@ impl<'r> Registry<'r> {
481527
/// To prevent infinite recursion by enforcing ordering, this returns a
482528
/// function that needs to be called with the list of fields on the object.
483529
pub fn build_object_type<T>(&mut self, fields: &[Field<'r>]) -> ObjectMeta<'r>
530+
where T: GraphQLType<TypeInfo=()>
531+
{
532+
self.build_object_type_with_info::<T>(&(), fields)
533+
}
534+
535+
/// Create an object meta type builder,
536+
/// by providing a type info object.
537+
///
538+
/// To prevent infinite recursion by enforcing ordering, this returns a
539+
/// function that needs to be called with the list of fields on the object.
540+
pub fn build_object_type_with_info<T>(&mut self, info: &T::TypeInfo, fields: &[Field<'r>]) -> ObjectMeta<'r>
484541
where T: GraphQLType
485542
{
486-
let name = T::name().expect("Object types must be named. Implement name()");
543+
let name = T::name(info).expect("Object types must be named. Implement name()");
487544

488545
let mut v = fields.to_vec();
489546
v.push(self.field::<String>("__typename"));
490-
ObjectMeta::new(name, &v)
547+
ObjectMeta::new(Cow::Owned(name.to_string()), &v)
491548
}
492549

493550
/// Create an enum meta type
494551
pub fn build_enum_type<T>(&mut self, values: &[EnumValue]) -> EnumMeta<'r>
552+
where T: FromInputValue + GraphQLType<TypeInfo=()>
553+
{
554+
self.build_enum_type_with_info::<T>(&(), values)
555+
}
556+
557+
/// Create an enum meta type,
558+
/// by providing a type info object.
559+
pub fn build_enum_type_with_info<T>(&mut self, info: &T::TypeInfo, values: &[EnumValue]) -> EnumMeta<'r>
495560
where T: FromInputValue + GraphQLType
496561
{
497-
let name = T::name().expect("Enum types must be named. Implement name()");
562+
let name = T::name(info).expect("Enum types must be named. Implement name()");
498563

499-
EnumMeta::new::<T>(name, values)
564+
EnumMeta::new::<T>(Cow::Owned(name.to_string()), values)
500565
}
501566

502567
/// Create an interface meta type builder
503568
pub fn build_interface_type<T>(&mut self, fields: &[Field<'r>]) -> InterfaceMeta<'r>
569+
where T: GraphQLType<TypeInfo=()>
570+
{
571+
self.build_interface_type_with_info::<T>(&(), fields)
572+
}
573+
574+
/// Create an interface meta type builder,
575+
/// by providing a type info object.
576+
pub fn build_interface_type_with_info<T>(&mut self, info: &T::TypeInfo, fields: &[Field<'r>]) -> InterfaceMeta<'r>
504577
where T: GraphQLType
505578
{
506-
let name = T::name().expect("Interface types must be named. Implement name()");
579+
let name = T::name(info).expect("Interface types must be named. Implement name()");
507580

508581
let mut v = fields.to_vec();
509582
v.push(self.field::<String>("__typename"));
510-
InterfaceMeta::new(name, &v)
583+
InterfaceMeta::new(Cow::Owned(name.to_string()), &v)
511584
}
512585

513586
/// Create a union meta type builder
514587
pub fn build_union_type<T>(&mut self, types: &[Type<'r>]) -> UnionMeta<'r>
588+
where T: GraphQLType<TypeInfo=()>
589+
{
590+
self.build_union_type_with_info::<T>(&(), types)
591+
}
592+
593+
/// Create a union meta type builder,
594+
/// by providing a type info object.
595+
pub fn build_union_type_with_info<T>(&mut self, info: &T::TypeInfo, types: &[Type<'r>]) -> UnionMeta<'r>
515596
where T: GraphQLType
516597
{
517-
let name = T::name().expect("Union types must be named. Implement name()");
598+
let name = T::name(info).expect("Union types must be named. Implement name()");
518599

519-
UnionMeta::new(name, types)
600+
UnionMeta::new(Cow::Owned(name.to_string()), types)
520601
}
521602

522603
/// Create an input object meta type builder
523604
pub fn build_input_object_type<T>(&mut self, args: &[Argument<'r>]) -> InputObjectMeta<'r>
605+
where T: FromInputValue + GraphQLType<TypeInfo=()>
606+
{
607+
self.build_input_object_type_with_info::<T>(&(), args)
608+
}
609+
610+
/// Create an input object meta type builder,
611+
/// by providing a type info object.
612+
pub fn build_input_object_type_with_info<T>(&mut self, info: &T::TypeInfo, args: &[Argument<'r>]) -> InputObjectMeta<'r>
524613
where T: FromInputValue + GraphQLType
525614
{
526-
let name = T::name().expect("Input object types must be named. Implement name()");
615+
let name = T::name(info).expect("Input object types must be named. Implement name()");
527616

528-
InputObjectMeta::new::<T>(name, args)
617+
InputObjectMeta::new::<T>(Cow::Owned(name.to_string()), args)
529618
}
530619
}

0 commit comments

Comments
 (0)