Skip to content

Commit 805db63

Browse files
committed
Introduce a abstraction for scalar values
Before this possible scalar values where hard coded to be representable in one of the following types: `i32`, `f64`, `String` or `bool`. This restricts what types of custom scalar values could be defined. (For example it was not possible to define a scalar value that represents a `i64` without mapping it to a string (that would be not efficient)) One solution to fix that example above would simply be to change the internal representation to allow it represent a `i64`, but this would only fix the problem for one type (till someone want's to support `i128` for example…). Also this would make juniper not following the graphql standard closely. This commit tries to explore another approach, by making the exact "internal" representation of scalar values swappable (in such a way that a down stream crate could provide it's own representation tailored to their needs). This allows juniper to provide a default type that only contains the types described in the standard whereas other crates could define custom scalars following their needs. To that we need to change several things in the current implementation * Add some traits that abstract the behaviour of such a scalar value representation * Change `Value` and `InputValue` to have a scalar variant (with a generic type) instead of hard coded variants for the standard types. This implies adding a generic parameter to both enums that needs to be added in the whole crate. * Change the parser to allow deciding between different types of scalar values. The problem is basically that the original parser implementation had no way to know whether a parsed integer number is a `i32` or a `i64` for example. To fix this we added some knowlege from the existing schema to the parser. * Fix some macros and derives to follow the new behaviour This also contains a unrelated change about the way `juniper_codegen` resolves items from juniper. In detail the `_internal` flag is removed the the resolution is replaced by an macro. This is a drive by change because I was annoyed of adding new items to that list.
1 parent ec59766 commit 805db63

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+6003
-3308
lines changed

juniper/src/ast.rs

Lines changed: 136 additions & 110 deletions
Large diffs are not rendered by default.

juniper/src/executor/look_ahead.rs

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use ast::{Directive, Fragment, InputValue, Selection};
22
use parser::Spanning;
3+
use value::ScalarValue;
34

45
use std::collections::HashMap;
56

@@ -21,25 +22,22 @@ pub enum Applies<'a> {
2122
/// meaning that variables are already resolved.
2223
#[derive(Debug, Clone, PartialEq)]
2324
#[allow(missing_docs)]
24-
pub enum LookAheadValue<'a> {
25+
pub enum LookAheadValue<'a, S: 'a> {
2526
Null,
26-
Int(i32),
27-
Float(f64),
28-
String(&'a str),
29-
Boolean(bool),
27+
Scalar(&'a S),
3028
Enum(&'a str),
31-
List(Vec<LookAheadValue<'a>>),
32-
Object(Vec<(&'a str, LookAheadValue<'a>)>),
29+
List(Vec<LookAheadValue<'a, S>>),
30+
Object(Vec<(&'a str, LookAheadValue<'a, S>)>),
3331
}
3432

35-
impl<'a> LookAheadValue<'a> {
36-
fn from_input_value(input_value: &'a InputValue, vars: &'a Variables) -> Self {
33+
impl<'a, S> LookAheadValue<'a, S>
34+
where
35+
S: ScalarValue,
36+
{
37+
fn from_input_value(input_value: &'a InputValue<S>, vars: &'a Variables<S>) -> Self {
3738
match *input_value {
3839
InputValue::Null => LookAheadValue::Null,
39-
InputValue::Int(i) => LookAheadValue::Int(i),
40-
InputValue::Float(f) => LookAheadValue::Float(f),
41-
InputValue::String(ref s) => LookAheadValue::String(s),
42-
InputValue::Boolean(b) => LookAheadValue::Boolean(b),
40+
InputValue::Scalar(ref s) => LookAheadValue::Scalar(s),
4341
InputValue::Enum(ref e) => LookAheadValue::Enum(e),
4442
InputValue::Variable(ref v) => Self::from_input_value(vars.get(v).unwrap(), vars),
4543
InputValue::List(ref l) => LookAheadValue::List(
@@ -54,24 +52,26 @@ impl<'a> LookAheadValue<'a> {
5452
&n.item as &str,
5553
LookAheadValue::from_input_value(&i.item, vars),
5654
)
57-
})
58-
.collect(),
55+
}).collect(),
5956
),
6057
}
6158
}
6259
}
6360

6461
/// An argument passed into the query
6562
#[derive(Debug, Clone, PartialEq)]
66-
pub struct LookAheadArgument<'a> {
63+
pub struct LookAheadArgument<'a, S: 'a> {
6764
name: &'a str,
68-
value: LookAheadValue<'a>,
65+
value: LookAheadValue<'a, S>,
6966
}
7067

71-
impl<'a> LookAheadArgument<'a> {
68+
impl<'a, S> LookAheadArgument<'a, S>
69+
where
70+
S: ScalarValue,
71+
{
7272
pub(super) fn new(
73-
&(ref name, ref value): &'a (Spanning<&'a str>, Spanning<InputValue>),
74-
vars: &'a Variables,
73+
&(ref name, ref value): &'a (Spanning<&'a str>, Spanning<InputValue<S>>),
74+
vars: &'a Variables<S>,
7575
) -> Self {
7676
LookAheadArgument {
7777
name: name.item,
@@ -80,86 +80,96 @@ impl<'a> LookAheadArgument<'a> {
8080
}
8181

8282
/// The value of the argument
83-
pub fn value(&'a self) -> &LookAheadValue<'a> {
83+
pub fn value(&'a self) -> &LookAheadValue<'a, S> {
8484
&self.value
8585
}
8686
}
8787

8888
#[derive(Debug, Clone, PartialEq)]
89-
pub struct ChildSelection<'a> {
90-
pub(super) inner: LookAheadSelection<'a>,
89+
pub struct ChildSelection<'a, S: 'a> {
90+
pub(super) inner: LookAheadSelection<'a, S>,
9191
pub(super) applies_for: Applies<'a>,
9292
}
9393

9494
/// A selection performed by a query
9595
#[derive(Debug, Clone, PartialEq)]
96-
pub struct LookAheadSelection<'a> {
96+
pub struct LookAheadSelection<'a, S: 'a> {
9797
pub(super) name: &'a str,
9898
pub(super) alias: Option<&'a str>,
99-
pub(super) arguments: Vec<LookAheadArgument<'a>>,
100-
pub(super) children: Vec<ChildSelection<'a>>,
99+
pub(super) arguments: Vec<LookAheadArgument<'a, S>>,
100+
pub(super) children: Vec<ChildSelection<'a, S>>,
101101
}
102102

103-
impl<'a> LookAheadSelection<'a> {
104-
fn should_include(directives: Option<&Vec<Spanning<Directive>>>, vars: &Variables) -> bool {
103+
impl<'a, S> LookAheadSelection<'a, S>
104+
where
105+
S: ScalarValue,
106+
&'a S: Into<Option<bool>>,
107+
{
108+
fn should_include<'b, 'c>(
109+
directives: Option<&'b Vec<Spanning<Directive<S>>>>,
110+
vars: &'c Variables<S>,
111+
) -> bool
112+
where
113+
'b: 'a,
114+
'c: 'a,
115+
{
105116
directives
106117
.map(|d| {
107118
d.iter().all(|d| {
108119
let d = &d.item;
109120
let arguments = &d.arguments;
110121
match (d.name.item, arguments) {
111-
("include", &Some(ref a)) => a.item
122+
("include", &Some(ref a)) => a
123+
.item
112124
.items
113125
.iter()
114126
.find(|item| item.0.item == "if")
115127
.map(|&(_, ref v)| {
116-
if let LookAheadValue::Boolean(b) =
128+
if let LookAheadValue::Scalar(s) =
117129
LookAheadValue::from_input_value(&v.item, vars)
118130
{
119-
b
131+
s.into().unwrap_or(false)
120132
} else {
121133
false
122134
}
123-
})
124-
.unwrap_or(false),
125-
("skip", &Some(ref a)) => a.item
135+
}).unwrap_or(false),
136+
("skip", &Some(ref a)) => a
137+
.item
126138
.items
127139
.iter()
128140
.find(|item| item.0.item == "if")
129141
.map(|&(_, ref v)| {
130-
if let LookAheadValue::Boolean(b) =
142+
if let LookAheadValue::Scalar(b) =
131143
LookAheadValue::from_input_value(&v.item, vars)
132144
{
133-
!b
145+
b.into().map(::std::ops::Not::not).unwrap_or(false)
134146
} else {
135147
false
136148
}
137-
})
138-
.unwrap_or(false),
149+
}).unwrap_or(false),
139150
("skip", &None) => false,
140151
("include", &None) => true,
141152
(_, _) => unreachable!(),
142153
}
143154
})
144-
})
145-
.unwrap_or(true)
155+
}).unwrap_or(true)
146156
}
147157

148158
pub(super) fn build_from_selection(
149-
s: &'a Selection<'a>,
150-
vars: &'a Variables,
151-
fragments: &'a HashMap<&'a str, &'a Fragment<'a>>,
152-
) -> LookAheadSelection<'a> {
159+
s: &'a Selection<'a, S>,
160+
vars: &'a Variables<S>,
161+
fragments: &'a HashMap<&'a str, &'a Fragment<'a, S>>,
162+
) -> LookAheadSelection<'a, S> {
153163
Self::build_from_selection_with_parent(s, None, vars, fragments).unwrap()
154164
}
155165

156166
fn build_from_selection_with_parent(
157-
s: &'a Selection<'a>,
167+
s: &'a Selection<'a, S>,
158168
parent: Option<&mut Self>,
159-
vars: &'a Variables,
160-
fragments: &'a HashMap<&'a str, &'a Fragment<'a>>,
161-
) -> Option<LookAheadSelection<'a>> {
162-
let empty: &[Selection] = &[];
169+
vars: &'a Variables<S>,
170+
fragments: &'a HashMap<&'a str, &'a Fragment<'a, S>>,
171+
) -> Option<LookAheadSelection<'a, S>> {
172+
let empty: &[Selection<S>] = &[];
163173
match *s {
164174
Selection::Field(ref field) => {
165175
let field = &field.item;
@@ -178,8 +188,7 @@ impl<'a> LookAheadSelection<'a> {
178188
.iter()
179189
.map(|p| LookAheadArgument::new(p, vars))
180190
.collect()
181-
})
182-
.unwrap_or_else(Vec::new);
191+
}).unwrap_or_else(Vec::new);
183192
let mut ret = LookAheadSelection {
184193
name,
185194
alias,
@@ -256,18 +265,18 @@ impl<'a> LookAheadSelection<'a> {
256265
}
257266

258267
/// Convert a eventually type independent selection into one for a concrete type
259-
pub fn for_explicit_type(&self, type_name: &str) -> ConcreteLookAheadSelection<'a> {
268+
pub fn for_explicit_type(&self, type_name: &str) -> ConcreteLookAheadSelection<'a, S> {
260269
ConcreteLookAheadSelection {
261-
children: self.children
270+
children: self
271+
.children
262272
.iter()
263273
.filter_map(|c| match c.applies_for {
264274
Applies::OnlyType(ref t) if *t == type_name => {
265275
Some(c.inner.for_explicit_type(type_name))
266276
}
267277
Applies::All => Some(c.inner.for_explicit_type(type_name)),
268278
Applies::OnlyType(_) => None,
269-
})
270-
.collect(),
279+
}).collect(),
271280
name: self.name,
272281
alias: self.alias,
273282
arguments: self.arguments.clone(),
@@ -277,15 +286,15 @@ impl<'a> LookAheadSelection<'a> {
277286

278287
/// A selection performed by a query on a concrete type
279288
#[derive(Debug, PartialEq)]
280-
pub struct ConcreteLookAheadSelection<'a> {
289+
pub struct ConcreteLookAheadSelection<'a, S: 'a> {
281290
name: &'a str,
282291
alias: Option<&'a str>,
283-
arguments: Vec<LookAheadArgument<'a>>,
284-
children: Vec<ConcreteLookAheadSelection<'a>>,
292+
arguments: Vec<LookAheadArgument<'a, S>>,
293+
children: Vec<ConcreteLookAheadSelection<'a, S>>,
285294
}
286295

287296
/// A set of common methods for `ConcreteLookAheadSelection` and `LookAheadSelection`
288-
pub trait LookAheadMethods {
297+
pub trait LookAheadMethods<S> {
289298
/// Get the name of the field represented by the current selection
290299
fn field_name(&self) -> &str;
291300

@@ -298,15 +307,15 @@ pub trait LookAheadMethods {
298307
}
299308

300309
/// Get the top level arguments for the current selection
301-
fn arguments(&self) -> &[LookAheadArgument];
310+
fn arguments(&self) -> &[LookAheadArgument<S>];
302311

303312
/// Get the top level argument with a given name from the current selection
304-
fn argument(&self, name: &str) -> Option<&LookAheadArgument> {
313+
fn argument(&self, name: &str) -> Option<&LookAheadArgument<S>> {
305314
self.arguments().iter().find(|a| a.name == name)
306315
}
307316
}
308317

309-
impl<'a> LookAheadMethods for ConcreteLookAheadSelection<'a> {
318+
impl<'a, S> LookAheadMethods<S> for ConcreteLookAheadSelection<'a, S> {
310319
fn field_name(&self) -> &str {
311320
self.alias.unwrap_or(self.name)
312321
}
@@ -315,12 +324,12 @@ impl<'a> LookAheadMethods for ConcreteLookAheadSelection<'a> {
315324
self.children.iter().find(|c| c.name == name)
316325
}
317326

318-
fn arguments(&self) -> &[LookAheadArgument] {
327+
fn arguments(&self) -> &[LookAheadArgument<S>] {
319328
&self.arguments
320329
}
321330
}
322331

323-
impl<'a> LookAheadMethods for LookAheadSelection<'a> {
332+
impl<'a, S> LookAheadMethods<S> for LookAheadSelection<'a, S> {
324333
fn field_name(&self) -> &str {
325334
self.alias.unwrap_or(self.name)
326335
}
@@ -332,7 +341,7 @@ impl<'a> LookAheadMethods for LookAheadSelection<'a> {
332341
.map(|s| &s.inner)
333342
}
334343

335-
fn arguments(&self) -> &[LookAheadArgument] {
344+
fn arguments(&self) -> &[LookAheadArgument<S>] {
336345
&self.arguments
337346
}
338347
}

0 commit comments

Comments
 (0)