Skip to content

Commit f974b2b

Browse files
committed
Implement support for dynamic schemas
1 parent a826b22 commit f974b2b

30 files changed

+800
-502
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: 77 additions & 48 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

@@ -156,25 +157,34 @@ impl<'a, CtxT> Executor<'a, CtxT> {
156157
/// Resolve a single arbitrary value, mapping the context to a new type
157158
pub fn resolve_with_ctx<NewCtxT, T: GraphQLType<Context = NewCtxT>>(
158159
&self,
160+
info: &T::TypeInfo,
159161
value: &T,
160162
) -> ExecutionResult
161163
where
162164
NewCtxT: FromContext<CtxT>,
163165
{
164166
self.replaced_context(<NewCtxT as FromContext<CtxT>>::from(self.context))
165-
.resolve(value)
167+
.resolve(info, value)
166168
}
167169

168170
/// Resolve a single arbitrary value into an `ExecutionResult`
169-
pub fn resolve<T: GraphQLType<Context = CtxT>>(&self, value: &T) -> ExecutionResult {
170-
Ok(value.resolve(self.current_selection_set, self))
171+
pub fn resolve<T: GraphQLType<Context = CtxT>>(
172+
&self,
173+
info: &T::TypeInfo,
174+
value: &T,
175+
) -> ExecutionResult {
176+
Ok(value.resolve(info, self.current_selection_set, self))
171177
}
172178

173179
/// Resolve a single arbitrary value into a return value
174180
///
175181
/// If the field fails to resolve, `null` will be returned.
176-
pub fn resolve_into_value<T: GraphQLType<Context = CtxT>>(&self, value: &T) -> Value {
177-
match self.resolve(value) {
182+
pub fn resolve_into_value<T: GraphQLType<Context = CtxT>>(
183+
&self,
184+
info: &T::TypeInfo,
185+
value: &T,
186+
) -> Value {
187+
match self.resolve(info, value) {
178188
Ok(v) => v,
179189
Err(e) => {
180190
let position = self.field_path.location().clone();
@@ -383,8 +393,10 @@ where
383393
};
384394

385395
value = match op.item.operation_type {
386-
OperationType::Query => executor.resolve_into_value(&root_node),
387-
OperationType::Mutation => executor.resolve_into_value(&root_node.mutation_type),
396+
OperationType::Query => executor.resolve_into_value(&root_node.query_info, &root_node),
397+
OperationType::Mutation => {
398+
executor.resolve_into_value(&root_node.mutation_info, &root_node.mutation_type)
399+
}
388400
};
389401
}
390402

@@ -404,67 +416,71 @@ impl<'r> Registry<'r> {
404416
///
405417
/// If the registry hasn't seen a type with this name before, it will
406418
/// construct its metadata and store it.
407-
pub fn get_type<T>(&mut self) -> Type<'r>
419+
pub fn get_type<T>(&mut self, info: &T::TypeInfo) -> Type<'r>
408420
where
409421
T: GraphQLType,
410422
{
411-
if let Some(name) = T::name() {
412-
if !self.types.contains_key(name) {
413-
self.insert_placeholder(name, Type::NonNullNamed(name));
414-
let meta = T::meta(self);
415-
self.types.insert(name.to_owned(), meta);
423+
if let Some(name) = T::name(info) {
424+
if !self.types.contains_key(&name.to_string()) {
425+
self.insert_placeholder(&name, Type::NonNullNamed(Cow::Owned(name.to_string())));
426+
let meta = T::meta(info, self);
427+
self.types.insert(name.to_string(), meta);
416428
}
417-
self.types[name].as_type()
429+
self.types[&name.to_string()].as_type()
418430
} else {
419-
T::meta(self).as_type()
431+
T::meta(info, self).as_type()
420432
}
421433
}
422434

423435
/// Create a field with the provided name
424-
pub fn field<T>(&mut self, name: &str) -> Field<'r>
436+
pub fn field<T>(&mut self, name: &str, info: &T::TypeInfo) -> Field<'r>
425437
where
426438
T: GraphQLType,
427439
{
428440
Field {
429441
name: name.to_owned(),
430442
description: None,
431443
arguments: None,
432-
field_type: self.get_type::<T>(),
444+
field_type: self.get_type::<T>(info),
433445
deprecation_reason: None,
434446
}
435447
}
436448

437449
#[doc(hidden)]
438-
pub fn field_convert<'a, T: IntoResolvable<'a, I, C>, I, C>(&mut self, name: &str) -> Field<'r>
450+
pub fn field_convert<'a, T: IntoResolvable<'a, I, C>, I, C>(
451+
&mut self,
452+
name: &str,
453+
info: &I::TypeInfo,
454+
) -> Field<'r>
439455
where
440456
I: GraphQLType,
441457
{
442458
Field {
443459
name: name.to_owned(),
444460
description: None,
445461
arguments: None,
446-
field_type: self.get_type::<I>(),
462+
field_type: self.get_type::<I>(info),
447463
deprecation_reason: None,
448464
}
449465
}
450466

451467
/// Create an argument with the provided name
452-
pub fn arg<T>(&mut self, name: &str) -> Argument<'r>
468+
pub fn arg<T>(&mut self, name: &str, info: &T::TypeInfo) -> Argument<'r>
453469
where
454470
T: GraphQLType + FromInputValue,
455471
{
456-
Argument::new(name, self.get_type::<T>())
472+
Argument::new(name, self.get_type::<T>(info))
457473
}
458474

459475
/// Create an argument with a default value
460476
///
461477
/// When called with type `T`, the actual argument will be given the type
462478
/// `Option<T>`.
463-
pub fn arg_with_default<T>(&mut self, name: &str, value: &T) -> Argument<'r>
479+
pub fn arg_with_default<T>(&mut self, name: &str, value: &T, info: &T::TypeInfo) -> Argument<'r>
464480
where
465481
T: GraphQLType + ToInputValue + FromInputValue,
466482
{
467-
Argument::new(name, self.get_type::<Option<T>>()).default_value(value.to())
483+
Argument::new(name, self.get_type::<Option<T>>(info)).default_value(value.to())
468484
}
469485

470486
fn insert_placeholder(&mut self, name: &str, of_type: Type<'r>) {
@@ -479,80 +495,93 @@ impl<'r> Registry<'r> {
479495
/// Create a scalar meta type
480496
///
481497
/// This expects the type to implement `FromInputValue`.
482-
pub fn build_scalar_type<T>(&mut self) -> ScalarMeta<'r>
498+
pub fn build_scalar_type<T>(&mut self, info: &T::TypeInfo) -> ScalarMeta<'r>
483499
where
484500
T: FromInputValue + GraphQLType,
485501
{
486-
let name = T::name().expect("Scalar types must be named. Implement name()");
487-
ScalarMeta::new::<T>(name)
502+
let name = T::name(info).expect("Scalar types must be named. Implement name()");
503+
ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
488504
}
489505

490506
/// Create a list meta type
491-
pub fn build_list_type<T: GraphQLType>(&mut self) -> ListMeta<'r> {
492-
let of_type = self.get_type::<T>();
507+
pub fn build_list_type<T: GraphQLType>(&mut self, info: &T::TypeInfo) -> ListMeta<'r> {
508+
let of_type = self.get_type::<T>(info);
493509
ListMeta::new(of_type)
494510
}
495511

496512
/// Create a nullable meta type
497-
pub fn build_nullable_type<T: GraphQLType>(&mut self) -> NullableMeta<'r> {
498-
let of_type = self.get_type::<T>();
513+
pub fn build_nullable_type<T: GraphQLType>(&mut self, info: &T::TypeInfo) -> NullableMeta<'r> {
514+
let of_type = self.get_type::<T>(info);
499515
NullableMeta::new(of_type)
500516
}
501517

502518
/// Create an object meta type builder
503519
///
504520
/// To prevent infinite recursion by enforcing ordering, this returns a
505521
/// function that needs to be called with the list of fields on the object.
506-
pub fn build_object_type<T>(&mut self, fields: &[Field<'r>]) -> ObjectMeta<'r>
522+
pub fn build_object_type<T>(
523+
&mut self,
524+
info: &T::TypeInfo,
525+
fields: &[Field<'r>],
526+
) -> ObjectMeta<'r>
507527
where
508528
T: GraphQLType,
509529
{
510-
let name = T::name().expect("Object types must be named. Implement name()");
530+
let name = T::name(info).expect("Object types must be named. Implement name()");
511531

512532
let mut v = fields.to_vec();
513-
v.push(self.field::<String>("__typename"));
514-
ObjectMeta::new(name, &v)
533+
v.push(self.field::<String>("__typename", &()));
534+
ObjectMeta::new(Cow::Owned(name.to_string()), &v)
515535
}
516536

517537
/// Create an enum meta type
518-
pub fn build_enum_type<T>(&mut self, values: &[EnumValue]) -> EnumMeta<'r>
538+
pub fn build_enum_type<T>(&mut self, info: &T::TypeInfo, values: &[EnumValue]) -> EnumMeta<'r>
519539
where
520540
T: FromInputValue + GraphQLType,
521541
{
522-
let name = T::name().expect("Enum types must be named. Implement name()");
542+
let name = T::name(info).expect("Enum types must be named. Implement name()");
523543

524-
EnumMeta::new::<T>(name, values)
544+
EnumMeta::new::<T>(Cow::Owned(name.to_string()), values)
525545
}
526546

527-
/// Create an interface meta type builder
528-
pub fn build_interface_type<T>(&mut self, fields: &[Field<'r>]) -> InterfaceMeta<'r>
547+
/// Create an interface meta type builder,
548+
/// by providing a type info object.
549+
pub fn build_interface_type<T>(
550+
&mut self,
551+
info: &T::TypeInfo,
552+
fields: &[Field<'r>],
553+
) -> InterfaceMeta<'r>
529554
where
530555
T: GraphQLType,
531556
{
532-
let name = T::name().expect("Interface types must be named. Implement name()");
557+
let name = T::name(info).expect("Interface types must be named. Implement name()");
533558

534559
let mut v = fields.to_vec();
535-
v.push(self.field::<String>("__typename"));
536-
InterfaceMeta::new(name, &v)
560+
v.push(self.field::<String>("__typename", &()));
561+
InterfaceMeta::new(Cow::Owned(name.to_string()), &v)
537562
}
538563

539564
/// Create a union meta type builder
540-
pub fn build_union_type<T>(&mut self, types: &[Type<'r>]) -> UnionMeta<'r>
565+
pub fn build_union_type<T>(&mut self, info: &T::TypeInfo, types: &[Type<'r>]) -> UnionMeta<'r>
541566
where
542567
T: GraphQLType,
543568
{
544-
let name = T::name().expect("Union types must be named. Implement name()");
569+
let name = T::name(info).expect("Union types must be named. Implement name()");
545570

546-
UnionMeta::new(name, types)
571+
UnionMeta::new(Cow::Owned(name.to_string()), types)
547572
}
548573

549574
/// Create an input object meta type builder
550-
pub fn build_input_object_type<T>(&mut self, args: &[Argument<'r>]) -> InputObjectMeta<'r>
575+
pub fn build_input_object_type<T>(
576+
&mut self,
577+
info: &T::TypeInfo,
578+
args: &[Argument<'r>],
579+
) -> InputObjectMeta<'r>
551580
where
552581
T: FromInputValue + GraphQLType,
553582
{
554-
let name = T::name().expect("Input object types must be named. Implement name()");
583+
let name = T::name(info).expect("Input object types must be named. Implement name()");
555584

556-
InputObjectMeta::new::<T>(name, args)
585+
InputObjectMeta::new::<T>(Cow::Owned(name.to_string()), args)
557586
}
558587
}

0 commit comments

Comments
 (0)