Merge pull request #605 from oeed/master

Ignored items flagged @skip in SelectionField and Lookahead
This commit is contained in:
Sunli 2021-08-24 11:30:51 +08:00 committed by GitHub
commit 19bcc87154
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 8 deletions

View File

@ -603,7 +603,7 @@ impl<'a> ContextBase<'a, &'a Positioned<Field>> {
/// } /// }
/// ``` /// ```
pub fn look_ahead(&self) -> Lookahead { pub fn look_ahead(&self) -> Lookahead {
Lookahead::new(&self.query_env.fragments, &self.item.node) Lookahead::new(&self.query_env.fragments, &self.item.node, self)
} }
/// Get the current field. /// Get the current field.
@ -653,7 +653,7 @@ impl<'a> ContextBase<'a, &'a Positioned<Field>> {
pub struct SelectionField<'a> { pub struct SelectionField<'a> {
pub(crate) fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>, pub(crate) fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
pub(crate) field: &'a Field, pub(crate) field: &'a Field,
context: &'a Context<'a>, pub(crate) context: &'a Context<'a>,
} }
impl<'a> SelectionField<'a> { impl<'a> SelectionField<'a> {
@ -727,7 +727,20 @@ impl<'a> Iterator for SelectionFieldsIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
let it = self.iter.last_mut()?; let it = self.iter.last_mut()?;
match it.next() { let item = it.next();
if let Some(item) = item {
// ignore any items that are skipped (i.e. @skip/@include)
if self
.context
.is_skip(&item.node.directives())
.unwrap_or(false)
{
// TODO: should we throw errors here? they will be caught later in execution and it'd cause major backwards compatibility issues
continue;
}
}
match item {
Some(selection) => match &selection.node { Some(selection) => match &selection.node {
Selection::Field(field) => { Selection::Field(field) => {
return Some(SelectionField { return Some(SelectionField {

View File

@ -2,22 +2,26 @@ use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::parser::types::{Field, FragmentDefinition, Selection, SelectionSet}; use crate::parser::types::{Field, FragmentDefinition, Selection, SelectionSet};
use crate::Context;
use crate::{Name, Positioned, SelectionField}; use crate::{Name, Positioned, SelectionField};
/// A selection performed by a query. /// A selection performed by a query.
pub struct Lookahead<'a> { pub struct Lookahead<'a> {
fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>, fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
fields: Vec<&'a Field>, fields: Vec<&'a Field>,
context: &'a Context<'a>,
} }
impl<'a> Lookahead<'a> { impl<'a> Lookahead<'a> {
pub(crate) fn new( pub(crate) fn new(
fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>, fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
field: &'a Field, field: &'a Field,
context: &'a Context<'a>,
) -> Self { ) -> Self {
Self { Self {
fragments, fragments,
fields: vec![field], fields: vec![field],
context,
} }
} }
@ -29,12 +33,19 @@ impl<'a> Lookahead<'a> {
pub fn field(&self, name: &str) -> Self { pub fn field(&self, name: &str) -> Self {
let mut fields = Vec::new(); let mut fields = Vec::new();
for field in &self.fields { for field in &self.fields {
filter(&mut fields, self.fragments, &field.selection_set.node, name) filter(
&mut fields,
self.fragments,
&field.selection_set.node,
name,
self.context,
)
} }
Self { Self {
fragments: self.fragments, fragments: self.fragments,
fields, fields,
context: self.context,
} }
} }
@ -50,6 +61,7 @@ impl<'a> From<SelectionField<'a>> for Lookahead<'a> {
Lookahead { Lookahead {
fragments: selection_field.fragments, fragments: selection_field.fragments,
fields: vec![selection_field.field], fields: vec![selection_field.field],
context: selection_field.context,
} }
} }
} }
@ -71,6 +83,7 @@ impl<'a> TryFrom<&[SelectionField<'a>]> for Lookahead<'a> {
.iter() .iter()
.map(|selection_field| selection_field.field) .map(|selection_field| selection_field.field)
.collect(), .collect(),
context: selection_fields[0].context,
}) })
} }
} }
@ -81,22 +94,40 @@ fn filter<'a>(
fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>, fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
selection_set: &'a SelectionSet, selection_set: &'a SelectionSet,
name: &str, name: &str,
context: &'a Context<'a>,
) { ) {
for item in &selection_set.items { for item in &selection_set.items {
// doing this imperatively is a bit nasty, but using iterators would // doing this imperatively is a bit nasty, but using iterators would
// require a boxed return type (I believe) as its recusive // require a boxed return type (I believe) as its recusive
// ignore any items that are skipped (i.e. @skip/@include)
if context.is_skip(&item.node.directives()).unwrap_or(false) {
// TODO: should we throw errors here? they will be caught later in execution and it'd cause major backwards compatibility issues
continue;
}
match &item.node { match &item.node {
Selection::Field(field) => { Selection::Field(field) => {
if field.node.name.node == name { if field.node.name.node == name {
fields.push(&field.node) fields.push(&field.node)
} }
} }
Selection::InlineFragment(fragment) => { Selection::InlineFragment(fragment) => filter(
filter(fields, fragments, &fragment.node.selection_set.node, name) fields,
} fragments,
&fragment.node.selection_set.node,
name,
context,
),
Selection::FragmentSpread(spread) => { Selection::FragmentSpread(spread) => {
if let Some(fragment) = fragments.get(&spread.node.fragment_name.node) { if let Some(fragment) = fragments.get(&spread.node.fragment_name.node) {
filter(fields, fragments, &fragment.node.selection_set.node, name) filter(
fields,
fragments,
&fragment.node.selection_set.node,
name,
context,
)
} }
} }
} }