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
|
||||
# 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
|
||||
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 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])
|
||||
- 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])
|
||||
- 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_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
|
||||
|
||||
|
@ -145,11 +155,11 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
|
|||
[#1190]: /../../pull/1190
|
||||
[#1193]: /../../pull/1193
|
||||
[#1199]: /../../pull/1199
|
||||
[#1200]: /../../pull/1200
|
||||
[#1206]: /../../pull/1206
|
||||
[#1207]: /../../pull/1207
|
||||
[#1208]: /../../pull/1208
|
||||
[#1209]: /../../pull/1209
|
||||
[#1212]: /../../pull/1212
|
||||
[#1215]: /../../pull/1215
|
||||
[#1227]: /../../pull/1227
|
||||
[#1228]: /../../pull/1228
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@ use crate::{
|
|||
|
||||
pub use self::{
|
||||
look_ahead::{
|
||||
Applies, ConcreteLookAheadSelection, LookAheadArgument, LookAheadMethods,
|
||||
Applies, LookAheadArgument, LookAheadChildren, LookAheadList, LookAheadObject,
|
||||
LookAheadSelection, LookAheadValue,
|
||||
},
|
||||
owned_executor::OwnedExecutor,
|
||||
|
@ -698,48 +698,38 @@ where
|
|||
};
|
||||
self.parent_selection_set
|
||||
.and_then(|p| {
|
||||
// Search the parent's fields to find this field within the set
|
||||
let found_field = p.iter().find(|&x| {
|
||||
match *x {
|
||||
// Search the parent's fields to find this field within the selection set.
|
||||
p.iter().find_map(|x| {
|
||||
match x {
|
||||
Selection::Field(ref field) => {
|
||||
let field = &field.item;
|
||||
// TODO: support excludes.
|
||||
let name = field.name.item;
|
||||
let alias = field.alias.as_ref().map(|a| a.item);
|
||||
alias.unwrap_or(name) == field_name
|
||||
|
||||
(alias.unwrap_or(name) == field_name).then(|| {
|
||||
LookAheadSelection::new(
|
||||
look_ahead::SelectionSource::Field(field),
|
||||
self.variables,
|
||||
self.fragments,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => false,
|
||||
Selection::FragmentSpread(_) | Selection::InlineFragment(_) => None,
|
||||
}
|
||||
});
|
||||
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`
|
||||
if let Some(selection_set) = self.current_selection_set {
|
||||
for c in selection_set {
|
||||
LookAheadSelection::build_from_selection_with_parent(
|
||||
c,
|
||||
Some(&mut ret),
|
||||
self.variables,
|
||||
self.fragments,
|
||||
);
|
||||
}
|
||||
}
|
||||
ret
|
||||
// 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::{
|
||||
Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,
|
||||
FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadMethods,
|
||||
LookAheadSelection, LookAheadValue, OwnedExecutor, Registry, ValuesStream, Variables,
|
||||
FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadChildren,
|
||||
LookAheadList, LookAheadObject, LookAheadSelection, LookAheadValue, OwnedExecutor,
|
||||
Registry, ValuesStream, Variables,
|
||||
},
|
||||
introspection::IntrospectionFormat,
|
||||
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.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use juniper::{graphql_interface, graphql_object, Executor, LookAheadMethods as _, ScalarValue};
|
||||
/// # use juniper::{graphql_interface, graphql_object, Executor, ScalarValue};
|
||||
/// #
|
||||
/// #[graphql_interface]
|
||||
/// // NOTICE: Specifying `ScalarValue` as existing type parameter.
|
||||
|
@ -1754,7 +1754,7 @@ pub fn derive_object(body: TokenStream) -> TokenStream {
|
|||
/// [`Executor`] does so.
|
||||
///
|
||||
/// ```
|
||||
/// # use juniper::{graphql_object, Executor, GraphQLObject, LookAheadMethods as _, ScalarValue};
|
||||
/// # use juniper::{graphql_object, Executor, GraphQLObject, ScalarValue};
|
||||
/// #
|
||||
/// struct Human {
|
||||
/// name: String,
|
||||
|
|
|
@ -2655,8 +2655,6 @@ mod inferred_custom_context_from_field {
|
|||
}
|
||||
|
||||
mod executor {
|
||||
use juniper::LookAheadMethods as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[graphql_interface(for = [Human, Droid], scalar = S)]
|
||||
|
|
|
@ -1929,8 +1929,6 @@ mod inferred_custom_context_from_field {
|
|||
}
|
||||
|
||||
mod executor {
|
||||
use juniper::LookAheadMethods as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
struct Human;
|
||||
|
|
|
@ -1697,8 +1697,6 @@ mod inferred_custom_context_from_field {
|
|||
}
|
||||
|
||||
mod executor {
|
||||
use juniper::LookAheadMethods as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
struct Human;
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
//! Original author of this test is [@davidpdrsn](https://github.com/davidpdrsn).
|
||||
|
||||
use juniper::{
|
||||
graphql_object, graphql_vars, EmptyMutation, EmptySubscription, Executor,
|
||||
LookAheadMethods as _, RootNode, ScalarValue,
|
||||
graphql_object, graphql_vars, EmptyMutation, EmptySubscription, Executor, RootNode, ScalarValue,
|
||||
};
|
||||
|
||||
pub struct Context;
|
||||
|
@ -19,13 +18,21 @@ pub struct Query;
|
|||
impl Query {
|
||||
fn users<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<User> {
|
||||
let lh = executor.look_ahead();
|
||||
|
||||
assert_eq!(lh.field_name(), "users");
|
||||
|
||||
_ = lh.children();
|
||||
|
||||
vec![User]
|
||||
}
|
||||
|
||||
fn countries<__S: ScalarValue>(executor: &Executor<'_, '_, Context, __S>) -> Vec<Country> {
|
||||
let lh = executor.look_ahead();
|
||||
|
||||
assert_eq!(lh.field_name(), "countries");
|
||||
|
||||
_ = lh.children();
|
||||
|
||||
vec![Country]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ struct Query;
|
|||
#[graphql_object]
|
||||
impl Query {
|
||||
fn users<S: ScalarValue>(executor: &Executor<'_, '_, (), S>) -> Vec<User> {
|
||||
assert_eq!(executor.look_ahead().field_name(), "users");
|
||||
|
||||
// This doesn't cause a panic.
|
||||
executor.look_ahead();
|
||||
_ = executor.look_ahead().children();
|
||||
|
||||
vec![User {
|
||||
country: Country { id: 1 },
|
||||
|
@ -28,8 +30,10 @@ struct User {
|
|||
#[graphql_object]
|
||||
impl User {
|
||||
fn country<S: ScalarValue>(&self, executor: &Executor<'_, '_, (), S>) -> &Country {
|
||||
assert_eq!(executor.look_ahead().field_name(), "country");
|
||||
|
||||
// This panics!
|
||||
executor.look_ahead();
|
||||
_ = executor.look_ahead().children();
|
||||
|
||||
&self.country
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ struct Query;
|
|||
#[graphql_object]
|
||||
impl Query {
|
||||
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 {
|
||||
city: City {
|
||||
|
@ -27,7 +29,10 @@ struct User {
|
|||
#[graphql_object]
|
||||
impl User {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +44,10 @@ struct City {
|
|||
#[graphql_object]
|
||||
impl City {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue