Rework look-ahead machinery as lazy-evaluated (#1212)
- make `LookAheadValue::List` to contain new iterable `LookAheadList` type - make `LookAheadValue::Object` to contain new iterable `LookAheadObject` type - remove `LookAheadMethods` trait and redundant `ConcreteLookAheadSelection` struct making all APIs accessible as inherent methods on `LookAheadSelection` and `LookAheadChildren` decoupled types - move `LookAheadMethods::child_names()` to `LookAheadChildren::names()` - move `LookAheadMethods::has_children()` to `LookAheadChildren::is_empty()` - move `LookAheadMethods::select_child()` to `LookAheadChildren::select()` - move `LookAheadSelection::for_explicit_type()` to `LookAheadSelection::children_for_explicit_type()` - make `LookAheadSelection::arguments()` returning iterator over `LookAheadArgument` - make `LookAheadSelection::children()` returning `LookAheadChildren` Co-authored-by: Kai Ren <tyranron@gmail.com>
This commit is contained in:
parent
e64287cfc8
commit
c54137f7b4
12 changed files with 1293 additions and 1017 deletions
|
@ -391,7 +391,7 @@ This requires to explicitly parametrize over [`ScalarValue`][3], as [`Executor`]
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate juniper;
|
# extern crate juniper;
|
||||||
use juniper::{graphql_interface, graphql_object, Executor, LookAheadMethods as _, ScalarValue};
|
use juniper::{graphql_interface, graphql_object, Executor, ScalarValue};
|
||||||
|
|
||||||
#[graphql_interface(for = Human, Scalar = S)] // notice specifying `ScalarValue` as existing type parameter
|
#[graphql_interface(for = Human, Scalar = S)] // notice specifying `ScalarValue` as existing type parameter
|
||||||
trait Character<S: ScalarValue> {
|
trait Character<S: ScalarValue> {
|
||||||
|
|
|
@ -52,12 +52,22 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
|
||||||
- Removed `scalar-naivetime` [Cargo feature].
|
- Removed `scalar-naivetime` [Cargo feature].
|
||||||
- Removed lifetime parameter from `ParseError`, `GraphlQLError`, `GraphQLBatchRequest` and `GraphQLRequest`. ([#1081], [#528])
|
- Removed lifetime parameter from `ParseError`, `GraphlQLError`, `GraphQLBatchRequest` and `GraphQLRequest`. ([#1081], [#528])
|
||||||
- Upgraded [GraphiQL] to 3.1.0 version (requires new [`graphql-transport-ws` GraphQL over WebSocket Protocol] integration on server, see `juniper_warp/examples/subscription.rs`). ([#1188], [#1193], [#1235])
|
- Upgraded [GraphiQL] to 3.1.0 version (requires new [`graphql-transport-ws` GraphQL over WebSocket Protocol] integration on server, see `juniper_warp/examples/subscription.rs`). ([#1188], [#1193], [#1235])
|
||||||
- Made `LookAheadMethods::children()` method to return slice instead of `Vec`. ([#1200])
|
|
||||||
- Abstracted `Spanning::start` and `Spanning::end` fields into separate struct `Span`. ([#1207], [#1208])
|
- Abstracted `Spanning::start` and `Spanning::end` fields into separate struct `Span`. ([#1207], [#1208])
|
||||||
- Added `Span` to `Arguments` and `LookAheadArguments`. ([#1206], [#1209])
|
|
||||||
- Removed `graphql-parser-integration` and `graphql-parser` [Cargo feature]s by merging them into `schema-language` [Cargo feature]. ([#1237])
|
- Removed `graphql-parser-integration` and `graphql-parser` [Cargo feature]s by merging them into `schema-language` [Cargo feature]. ([#1237])
|
||||||
- Renamed `RootNode::as_schema_language()` method as `RootNode::as_sdl()`. ([#1237])
|
- Renamed `RootNode::as_schema_language()` method as `RootNode::as_sdl()`. ([#1237])
|
||||||
- Renamed `RootNode::as_parser_document()` method as `RootNode::as_document()`. ([#1237])
|
- Renamed `RootNode::as_parser_document()` method as `RootNode::as_document()`. ([#1237])
|
||||||
|
- Reworked look-ahead machinery: ([#1212])
|
||||||
|
- Turned from eagerly-evaluated into lazy-evaluated:
|
||||||
|
- Made `LookAheadValue::List` to contain new iterable `LookAheadList` type.
|
||||||
|
- Made `LookAheadValue::Object` to contain new iterable `LookAheadObject` type.
|
||||||
|
- Removed `LookAheadMethods` trait and redundant `ConcreteLookAheadSelection` type, making all APIs accessible as inherent methods on `LookAheadSelection` and `LookAheadChildren` decoupled types:
|
||||||
|
- Moved `LookAheadMethods::child_names()` to `LookAheadChildren::names()`.
|
||||||
|
- Moved `LookAheadMethods::has_children()` to `LookAheadChildren::is_empty()`.
|
||||||
|
- Moved `LookAheadMethods::select_child()` to `LookAheadChildren::select()`.
|
||||||
|
- Moved `LookAheadSelection::for_explicit_type()` to `LookAheadSelection::children_for_explicit_type()`.
|
||||||
|
- Made `LookAheadSelection::arguments()` returning iterator over `LookAheadArgument`.
|
||||||
|
- Made `LookAheadSelection::children()` returning `LookAheadChildren`.
|
||||||
|
- Added `Span` to `Arguments` and `LookAheadArguments`. ([#1206], [#1209])
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
@ -145,11 +155,11 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
|
||||||
[#1190]: /../../pull/1190
|
[#1190]: /../../pull/1190
|
||||||
[#1193]: /../../pull/1193
|
[#1193]: /../../pull/1193
|
||||||
[#1199]: /../../pull/1199
|
[#1199]: /../../pull/1199
|
||||||
[#1200]: /../../pull/1200
|
|
||||||
[#1206]: /../../pull/1206
|
[#1206]: /../../pull/1206
|
||||||
[#1207]: /../../pull/1207
|
[#1207]: /../../pull/1207
|
||||||
[#1208]: /../../pull/1208
|
[#1208]: /../../pull/1208
|
||||||
[#1209]: /../../pull/1209
|
[#1209]: /../../pull/1209
|
||||||
|
[#1212]: /../../pull/1212
|
||||||
[#1215]: /../../pull/1215
|
[#1215]: /../../pull/1215
|
||||||
[#1227]: /../../pull/1227
|
[#1227]: /../../pull/1227
|
||||||
[#1228]: /../../pull/1228
|
[#1228]: /../../pull/1228
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@ use crate::{
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
look_ahead::{
|
look_ahead::{
|
||||||
Applies, ConcreteLookAheadSelection, LookAheadArgument, LookAheadMethods,
|
Applies, LookAheadArgument, LookAheadChildren, LookAheadList, LookAheadObject,
|
||||||
LookAheadSelection, LookAheadValue,
|
LookAheadSelection, LookAheadValue,
|
||||||
},
|
},
|
||||||
owned_executor::OwnedExecutor,
|
owned_executor::OwnedExecutor,
|
||||||
|
@ -698,48 +698,38 @@ where
|
||||||
};
|
};
|
||||||
self.parent_selection_set
|
self.parent_selection_set
|
||||||
.and_then(|p| {
|
.and_then(|p| {
|
||||||
// Search the parent's fields to find this field within the set
|
// Search the parent's fields to find this field within the selection set.
|
||||||
let found_field = p.iter().find(|&x| {
|
p.iter().find_map(|x| {
|
||||||
match *x {
|
match x {
|
||||||
Selection::Field(ref field) => {
|
Selection::Field(ref field) => {
|
||||||
let field = &field.item;
|
let field = &field.item;
|
||||||
// TODO: support excludes.
|
// TODO: support excludes.
|
||||||
let name = field.name.item;
|
let name = field.name.item;
|
||||||
let alias = field.alias.as_ref().map(|a| a.item);
|
let alias = field.alias.as_ref().map(|a| a.item);
|
||||||
alias.unwrap_or(name) == field_name
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if let Some(p) = found_field {
|
|
||||||
LookAheadSelection::build_from_selection(p, self.variables, self.fragments)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
// We didn't find a field in the parent's selection matching
|
|
||||||
// this field, which means we're inside a FragmentSpread
|
|
||||||
let mut ret = LookAheadSelection {
|
|
||||||
name: field_name,
|
|
||||||
alias: None,
|
|
||||||
arguments: Vec::new(),
|
|
||||||
children: Vec::new(),
|
|
||||||
applies_for: Applies::All,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add in all the children - this will mutate `ret`
|
(alias.unwrap_or(name) == field_name).then(|| {
|
||||||
if let Some(selection_set) = self.current_selection_set {
|
LookAheadSelection::new(
|
||||||
for c in selection_set {
|
look_ahead::SelectionSource::Field(field),
|
||||||
LookAheadSelection::build_from_selection_with_parent(
|
|
||||||
c,
|
|
||||||
Some(&mut ret),
|
|
||||||
self.variables,
|
self.variables,
|
||||||
self.fragments,
|
self.fragments,
|
||||||
);
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Selection::FragmentSpread(_) | Selection::InlineFragment(_) => None,
|
||||||
}
|
}
|
||||||
ret
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
// We didn't find this field in the parent's selection matching it, which means
|
||||||
|
// we're inside a `FragmentSpread`.
|
||||||
|
LookAheadSelection::new(
|
||||||
|
look_ahead::SelectionSource::Spread {
|
||||||
|
field_name,
|
||||||
|
set: self.current_selection_set,
|
||||||
|
},
|
||||||
|
self.variables,
|
||||||
|
self.fragments,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,9 @@ pub use crate::{
|
||||||
},
|
},
|
||||||
executor::{
|
executor::{
|
||||||
Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,
|
Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,
|
||||||
FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadMethods,
|
FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadChildren,
|
||||||
LookAheadSelection, LookAheadValue, OwnedExecutor, Registry, ValuesStream, Variables,
|
LookAheadList, LookAheadObject, LookAheadSelection, LookAheadValue, OwnedExecutor,
|
||||||
|
Registry, ValuesStream, Variables,
|
||||||
},
|
},
|
||||||
introspection::IntrospectionFormat,
|
introspection::IntrospectionFormat,
|
||||||
macros::helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
|
macros::helper::subscription::{ExtractTypeFromStream, IntoFieldResult},
|
||||||
|
|
|
@ -1247,7 +1247,7 @@ pub fn derive_scalar_value(input: TokenStream) -> TokenStream {
|
||||||
/// However, this requires to explicitly parametrize over [`ScalarValue`], as [`Executor`] does so.
|
/// However, this requires to explicitly parametrize over [`ScalarValue`], as [`Executor`] does so.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use juniper::{graphql_interface, graphql_object, Executor, LookAheadMethods as _, ScalarValue};
|
/// # use juniper::{graphql_interface, graphql_object, Executor, ScalarValue};
|
||||||
/// #
|
/// #
|
||||||
/// #[graphql_interface]
|
/// #[graphql_interface]
|
||||||
/// // NOTICE: Specifying `ScalarValue` as existing type parameter.
|
/// // NOTICE: Specifying `ScalarValue` as existing type parameter.
|
||||||
|
@ -1754,7 +1754,7 @@ pub fn derive_object(body: TokenStream) -> TokenStream {
|
||||||
/// [`Executor`] does so.
|
/// [`Executor`] does so.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use juniper::{graphql_object, Executor, GraphQLObject, LookAheadMethods as _, ScalarValue};
|
/// # use juniper::{graphql_object, Executor, GraphQLObject, ScalarValue};
|
||||||
/// #
|
/// #
|
||||||
/// struct Human {
|
/// struct Human {
|
||||||
/// name: String,
|
/// name: String,
|
||||||
|
|
|
@ -2655,8 +2655,6 @@ mod inferred_custom_context_from_field {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod executor {
|
mod executor {
|
||||||
use juniper::LookAheadMethods as _;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[graphql_interface(for = [Human, Droid], scalar = S)]
|
#[graphql_interface(for = [Human, Droid], scalar = S)]
|
||||||
|
|
|
@ -1929,8 +1929,6 @@ mod inferred_custom_context_from_field {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod executor {
|
mod executor {
|
||||||
use juniper::LookAheadMethods as _;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct Human;
|
struct Human;
|
||||||
|
|
|
@ -1697,8 +1697,6 @@ mod inferred_custom_context_from_field {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod executor {
|
mod executor {
|
||||||
use juniper::LookAheadMethods as _;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct Human;
|
struct Human;
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
//! Original author of this test is [@davidpdrsn](https://github.com/davidpdrsn).
|
//! Original author of this test is [@davidpdrsn](https://github.com/davidpdrsn).
|
||||||
|
|
||||||
use juniper::{
|
use juniper::{
|
||||||
graphql_object, graphql_vars, EmptyMutation, EmptySubscription, Executor,
|
graphql_object, graphql_vars, EmptyMutation, EmptySubscription, Executor, RootNode, ScalarValue,
|
||||||
LookAheadMethods as _, RootNode, ScalarValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Context;
|
pub struct Context;
|
||||||
|
@ -19,13 +18,21 @@ pub struct Query;
|
||||||
impl Query {
|
impl Query {
|
||||||
fn users<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<User> {
|
fn users<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<User> {
|
||||||
let lh = executor.look_ahead();
|
let lh = executor.look_ahead();
|
||||||
|
|
||||||
assert_eq!(lh.field_name(), "users");
|
assert_eq!(lh.field_name(), "users");
|
||||||
|
|
||||||
|
_ = lh.children();
|
||||||
|
|
||||||
vec![User]
|
vec![User]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn countries<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<Country> {
|
fn countries<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<Country> {
|
||||||
let lh = executor.look_ahead();
|
let lh = executor.look_ahead();
|
||||||
|
|
||||||
assert_eq!(lh.field_name(), "countries");
|
assert_eq!(lh.field_name(), "countries");
|
||||||
|
|
||||||
|
_ = lh.children();
|
||||||
|
|
||||||
vec![Country]
|
vec![Country]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,10 @@ struct Query;
|
||||||
#[graphql_object]
|
#[graphql_object]
|
||||||
impl Query {
|
impl Query {
|
||||||
fn users<S: ScalarValue>(executor: &Executor<'_, '_, (), S>) -> Vec<User> {
|
fn users<S: ScalarValue>(executor: &Executor<'_, '_, (), S>) -> Vec<User> {
|
||||||
|
assert_eq!(executor.look_ahead().field_name(), "users");
|
||||||
|
|
||||||
// This doesn't cause a panic.
|
// This doesn't cause a panic.
|
||||||
executor.look_ahead();
|
_ = executor.look_ahead().children();
|
||||||
|
|
||||||
vec![User {
|
vec![User {
|
||||||
country: Country { id: 1 },
|
country: Country { id: 1 },
|
||||||
|
@ -28,8 +30,10 @@ struct User {
|
||||||
#[graphql_object]
|
#[graphql_object]
|
||||||
impl User {
|
impl User {
|
||||||
fn country<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &Country {
|
fn country<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &Country {
|
||||||
|
assert_eq!(executor.look_ahead().field_name(), "country");
|
||||||
|
|
||||||
// This panics!
|
// This panics!
|
||||||
executor.look_ahead();
|
_ = executor.look_ahead().children();
|
||||||
|
|
||||||
&self.country
|
&self.country
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@ struct Query;
|
||||||
#[graphql_object]
|
#[graphql_object]
|
||||||
impl Query {
|
impl Query {
|
||||||
fn users<S: ScalarValue>(executor: &Executor<'_, '_, (), S>) -> Vec<User> {
|
fn users<S: ScalarValue>(executor: &Executor<'_, '_, (), S>) -> Vec<User> {
|
||||||
executor.look_ahead();
|
assert_eq!(executor.look_ahead().field_name(), "users");
|
||||||
|
|
||||||
|
_ = executor.look_ahead().children();
|
||||||
|
|
||||||
vec![User {
|
vec![User {
|
||||||
city: City {
|
city: City {
|
||||||
|
@ -27,7 +29,10 @@ struct User {
|
||||||
#[graphql_object]
|
#[graphql_object]
|
||||||
impl User {
|
impl User {
|
||||||
fn city<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &City {
|
fn city<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &City {
|
||||||
executor.look_ahead();
|
assert_eq!(executor.look_ahead().field_name(), "city");
|
||||||
|
|
||||||
|
_ = executor.look_ahead().children();
|
||||||
|
|
||||||
&self.city
|
&self.city
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +44,10 @@ struct City {
|
||||||
#[graphql_object]
|
#[graphql_object]
|
||||||
impl City {
|
impl City {
|
||||||
fn country<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &Country {
|
fn country<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &Country {
|
||||||
executor.look_ahead();
|
assert_eq!(executor.look_ahead().field_name(), "country");
|
||||||
|
|
||||||
|
_ = executor.look_ahead().children();
|
||||||
|
|
||||||
&self.country
|
&self.country
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue