Skip to content

Commit

Permalink
Merge branch 'master' into remove-iron
Browse files Browse the repository at this point in the history
  • Loading branch information
tyranron authored Nov 9, 2023
2 parents afa2286 + e75cf26 commit e126ba6
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 55 deletions.
3 changes: 3 additions & 0 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- Upgraded [GraphiQL] to 3.0.9 version (requires new [`graphql-transport-ws` GraphQL over WebSocket Protocol] integration on server, see `juniper_warp/examples/subscription.rs`). ([#1188], [#1193], [#1204])
- Made `LookAheadMethods::children()` method to return slice instead of `Vec`. ([#1200])
- Abstracted `Spanning::start` and `Spanning::end` fields into separate struct `Span`. ([#1207], [#1208])
- Added `Span` to `Arguments` and `LookAheadArguments`. ([#1206], [#1209])

### Added

Expand Down Expand Up @@ -132,8 +133,10 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
[#1199]: /../../pull/1199
[#1200]: /../../pull/1200
[#1204]: /../../pull/1204
[#1206]: /../../pull/1206
[#1207]: /../../pull/1207
[#1208]: /../../pull/1208
[#1209]: /../../pull/1209
[ba1ed85b]: /../../commit/ba1ed85b3c3dd77fbae7baf6bc4e693321a94083
[CVE-2022-31173]: /../../security/advisories/GHSA-4rx6-g5vg-5f3j

Expand Down
137 changes: 96 additions & 41 deletions juniper/src/executor/look_ahead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;

use crate::{
ast::{Directive, Fragment, InputValue, Selection},
parser::Spanning,
parser::{Span, Spanning},
value::ScalarValue,
};

Expand All @@ -18,48 +18,71 @@ pub enum Applies<'a> {
OnlyType(&'a str),
}

/// A JSON-like value that can is used as argument in the query execution
/// Shortcut for a [`Spanning`] containing a borrowed [`Span`].
type BorrowedSpanning<'a, T> = Spanning<T, &'a Span>;

/// JSON-like value that can be used as an argument in the query execution.
///
/// In contrast to `InputValue` these values do only contain constants,
/// In contrast to an [`InputValue`], these values do only contain constants,
/// meaning that variables are already resolved.
#[derive(Debug, Clone, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum LookAheadValue<'a, S: 'a> {
Null,
Scalar(&'a S),
Enum(&'a str),
List(Vec<LookAheadValue<'a, S>>),
Object(Vec<(&'a str, LookAheadValue<'a, S>)>),
List(Vec<BorrowedSpanning<'a, LookAheadValue<'a, S>>>),
Object(
Vec<(
BorrowedSpanning<'a, &'a str>,
BorrowedSpanning<'a, LookAheadValue<'a, S>>,
)>,
),
}

impl<'a, S> LookAheadValue<'a, S>
where
S: ScalarValue,
{
fn from_input_value(input_value: &'a InputValue<S>, vars: &'a Variables<S>) -> Self {
match *input_value {
InputValue::Null => LookAheadValue::Null,
InputValue::Scalar(ref s) => LookAheadValue::Scalar(s),
InputValue::Enum(ref e) => LookAheadValue::Enum(e),
InputValue::Variable(ref name) => vars
.get(name)
.map(|v| Self::from_input_value(v, vars))
.unwrap_or(LookAheadValue::Null),
InputValue::List(ref l) => LookAheadValue::List(
l.iter()
.map(|i| LookAheadValue::from_input_value(&i.item, vars))
.collect(),
),
InputValue::Object(ref o) => LookAheadValue::Object(
o.iter()
.map(|(n, i)| {
(
&n.item as &str,
LookAheadValue::from_input_value(&i.item, vars),
)
fn from_input_value(
input_value: BorrowedSpanning<'a, &'a InputValue<S>>,
vars: &'a Variables<S>,
) -> BorrowedSpanning<'a, Self> {
Spanning {
span: input_value.span,
item: match input_value.item {
InputValue::Null => Self::Null,
InputValue::Scalar(s) => Self::Scalar(s),
InputValue::Enum(e) => Self::Enum(e),
InputValue::Variable(name) => vars
.get(name)
.map(|item| {
let input_value = Spanning {
span: input_value.span,
item,
};
Self::from_input_value(input_value, vars).item
})
.collect(),
),
.unwrap_or(Self::Null),
InputValue::List(l) => Self::List(
l.iter()
.map(|i| Self::from_input_value(i.as_ref(), vars))
.collect(),
),
InputValue::Object(o) => Self::Object(
o.iter()
.map(|(n, i)| {
(
Spanning {
span: &n.span,
item: n.item.as_str(),
},
Self::from_input_value(i.as_ref(), vars),
)
})
.collect(),
),
},
}
}
}
Expand All @@ -68,7 +91,7 @@ where
#[derive(Debug, Clone, PartialEq)]
pub struct LookAheadArgument<'a, S: 'a> {
name: &'a str,
value: LookAheadValue<'a, S>,
value: BorrowedSpanning<'a, LookAheadValue<'a, S>>,
}

impl<'a, S> LookAheadArgument<'a, S>
Expand All @@ -81,7 +104,7 @@ where
) -> Self {
LookAheadArgument {
name: name.item,
value: LookAheadValue::from_input_value(&value.item, vars),
value: LookAheadValue::from_input_value(value.as_ref(), vars),
}
}

Expand All @@ -92,7 +115,12 @@ where

/// The value of the argument
pub fn value(&'a self) -> &LookAheadValue<'a, S> {
&self.value
&self.value.item
}

/// The input source span of the argument
pub fn span(&self) -> &Span {
self.value.span
}
}

Expand Down Expand Up @@ -145,7 +173,7 @@ where
.find(|item| item.0.item == "if")
.map(|(_, v)| {
if let LookAheadValue::Scalar(s) =
LookAheadValue::from_input_value(&v.item, vars)
LookAheadValue::from_input_value(v.as_ref(), vars).item
{
s.as_bool().unwrap_or(false)
} else {
Expand All @@ -160,7 +188,7 @@ where
.find(|item| item.0.item == "if")
.map(|(_, v)| {
if let LookAheadValue::Scalar(b) =
LookAheadValue::from_input_value(&v.item, vars)
LookAheadValue::from_input_value(v.as_ref(), vars).item
{
b.as_bool().map(::std::ops::Not::not).unwrap_or(false)
} else {
Expand Down Expand Up @@ -472,12 +500,12 @@ impl<'a, S> LookAheadMethods<'a, S> for LookAheadSelection<'a, S> {

#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::{collections::HashMap, ops::Range};

use crate::{
ast::{Document, OwnedDocument},
graphql_vars,
parser::UnlocatedParseResult,
parser::{SourcePosition, UnlocatedParseResult},
schema::model::SchemaType,
validation::test_harness::{MutationRoot, QueryRoot, SubscriptionRoot},
value::{DefaultScalarValue, ScalarValue},
Expand Down Expand Up @@ -509,6 +537,13 @@ mod tests {
fragments
}

fn span(range: Range<(usize, usize, usize)>) -> Span {
Span {
start: SourcePosition::new(range.start.0, range.start.1, range.start.2),
end: SourcePosition::new(range.end.0, range.end.1, range.end.2),
}
}

#[test]
fn check_simple_query() {
let docs = parse_document_source::<DefaultScalarValue>(
Expand Down Expand Up @@ -711,12 +746,17 @@ query Hero {
&fragments,
)
.unwrap();
let span0 = span((32, 2, 18)..(38, 2, 24));
let span1 = span((77, 4, 24)..(81, 4, 28));
let expected = LookAheadSelection {
name: "hero",
alias: None,
arguments: vec![LookAheadArgument {
name: "episode",
value: LookAheadValue::Enum("EMPIRE"),
value: Spanning {
item: LookAheadValue::Enum("EMPIRE"),
span: &span0,
},
}],
applies_for: Applies::All,
children: vec![
Expand All @@ -732,7 +772,10 @@ query Hero {
alias: None,
arguments: vec![LookAheadArgument {
name: "uppercase",
value: LookAheadValue::Scalar(&DefaultScalarValue::Boolean(true)),
value: Spanning {
item: LookAheadValue::Scalar(&DefaultScalarValue::Boolean(true)),
span: &span1,
},
}],
children: Vec::new(),
applies_for: Applies::All,
Expand Down Expand Up @@ -768,12 +811,16 @@ query Hero($episode: Episode) {
&fragments,
)
.unwrap();
let span0 = span((51, 2, 18)..(59, 2, 26));
let expected = LookAheadSelection {
name: "hero",
alias: None,
arguments: vec![LookAheadArgument {
name: "episode",
value: LookAheadValue::Enum("JEDI"),
value: Spanning {
item: LookAheadValue::Enum("JEDI"),
span: &span0,
},
}],
applies_for: Applies::All,
children: vec![
Expand Down Expand Up @@ -821,12 +868,16 @@ query Hero($episode: Episode) {
&fragments,
)
.unwrap();
let span0 = span((51, 2, 18)..(59, 2, 26));
let expected = LookAheadSelection {
name: "hero",
alias: None,
arguments: vec![LookAheadArgument {
name: "episode",
value: LookAheadValue::Null,
value: Spanning {
item: LookAheadValue::Null,
span: &span0,
},
}],
applies_for: Applies::All,
children: vec![LookAheadSelection {
Expand Down Expand Up @@ -1121,12 +1172,16 @@ fragment comparisonFields on Character {
&fragments,
)
.unwrap();
let span0 = span((85, 2, 11)..(88, 2, 14));
let expected = LookAheadSelection {
name: "hero",
alias: None,
arguments: vec![LookAheadArgument {
name: "id",
value: LookAheadValue::Scalar(&DefaultScalarValue::Int(42)),
value: Spanning {
item: LookAheadValue::Scalar(&DefaultScalarValue::Int(42)),
span: &span0,
},
}],
applies_for: Applies::All,
children: vec![
Expand Down
14 changes: 11 additions & 3 deletions juniper/src/parser/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ impl Span {

/// Data structure used to wrap items into a [`Span`].
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Spanning<T> {
pub struct Spanning<T, Sp = Span> {
/// Wrapped item.
pub item: T,

/// [`Span`] of the wrapped item.
pub span: Span,
pub span: Sp,
}

impl<T> Spanning<T> {
impl<T> Spanning<T, Span> {
#[doc(hidden)]
pub fn new(span: Span, item: T) -> Self {
Self { item, span }
Expand Down Expand Up @@ -126,6 +126,14 @@ impl<T> Spanning<T> {
pub fn and_then<O, F: Fn(T) -> Option<O>>(self, f: F) -> Option<Spanning<O>> {
f(self.item).map(|item| Spanning::new(self.span, item))
}

/// Converts into a [`Spanning`] containing a borrowed item and a borrowed [`Span`].
pub(crate) fn as_ref(&self) -> Spanning<&'_ T, &'_ Span> {
Spanning {
item: &self.item,
span: &self.span,
}
}
}

impl<T: fmt::Display> fmt::Display for Spanning<T> {
Expand Down
3 changes: 2 additions & 1 deletion juniper/src/types/async_await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ where
m.item
.iter()
.filter_map(|(k, v)| {
v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
let val = v.item.clone().into_const(exec_vars)?;
Some((k.item, Spanning::new(v.span, val)))
})
.collect()
}),
Expand Down
15 changes: 11 additions & 4 deletions juniper/src/types/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ pub enum TypeKind {
/// Field argument container
#[derive(Debug)]
pub struct Arguments<'a, S = DefaultScalarValue> {
args: Option<IndexMap<&'a str, InputValue<S>>>,
args: Option<IndexMap<&'a str, Spanning<InputValue<S>>>>,
}

impl<'a, S> Arguments<'a, S> {
#[doc(hidden)]
pub fn new(
mut args: Option<IndexMap<&'a str, InputValue<S>>>,
mut args: Option<IndexMap<&'a str, Spanning<InputValue<S>>>>,
meta_args: &'a Option<Vec<Argument<S>>>,
) -> Self
where
Expand All @@ -89,7 +89,7 @@ impl<'a, S> Arguments<'a, S> {
let arg_name = arg.name.as_str();
if args.get(arg_name).is_none() {
if let Some(val) = arg.default_value.as_ref() {
args.insert(arg_name, val.clone());
args.insert(arg_name, Spanning::unlocated(val.clone()));
}
}
}
Expand Down Expand Up @@ -117,10 +117,16 @@ impl<'a, S> Arguments<'a, S> {
self.args
.as_ref()
.and_then(|args| args.get(name))
.map(|spanning| &spanning.item)
.map(InputValue::convert)
.transpose()
.map_err(IntoFieldError::into_field_error)
}

/// Gets a direct reference to the [`Spanning`] argument [`InputValue`].
pub fn get_input_value(&self, name: &str) -> Option<&Spanning<InputValue<S>>> {
self.args.as_ref().and_then(|args| args.get(name))
}
}

/// Primary trait used to resolve GraphQL values.
Expand Down Expand Up @@ -472,7 +478,8 @@ where
m.item
.iter()
.filter_map(|(k, v)| {
v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
let val = v.item.clone().into_const(exec_vars)?;
Some((k.item, Spanning::new(v.span, val)))
})
.collect()
}),
Expand Down
3 changes: 2 additions & 1 deletion juniper/src/types/subscriptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,8 @@ where
m.item
.iter()
.filter_map(|(k, v)| {
v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
let val = v.item.clone().into_const(exec_vars)?;
Some((k.item, Spanning::new(v.span, val)))
})
.collect()
}),
Expand Down
Loading

0 comments on commit e126ba6

Please sign in to comment.