Improve lookahead

This commit is contained in:
Koxiaet 2020-09-13 08:02:14 +01:00
parent 55753983a9
commit 42c3cfc17c
2 changed files with 30 additions and 29 deletions

View File

@ -517,9 +517,6 @@ impl<'a> ContextBase<'a, &'a Positioned<Field>> {
/// } /// }
/// ``` /// ```
pub fn look_ahead(&self) -> Lookahead { pub fn look_ahead(&self) -> Lookahead {
Lookahead { Lookahead::new(&self.query_env.document, &self.item.node)
document: &self.query_env.document,
field: Some(&self.item.node),
}
} }
} }

View File

@ -1,13 +1,24 @@
use crate::parser::types::{ExecutableDocumentData, Field, Selection, SelectionSet}; use crate::parser::types::{ExecutableDocumentData, Field, Selection, SelectionSet};
/// A selection performed by a query /// A selection performed by a query.
pub struct Lookahead<'a> { pub struct Lookahead<'a> {
pub(crate) document: &'a ExecutableDocumentData, document: &'a ExecutableDocumentData,
pub(crate) field: Option<&'a Field>, field: Option<&'a Field>,
} }
impl<'a> Lookahead<'a> { impl<'a> Lookahead<'a> {
/// Check if the specified field exists in the current selection. pub(crate) fn new(document: &'a ExecutableDocumentData, field: &'a Field) -> Self {
Self {
document,
field: Some(field),
}
}
/// Get the first subfield of the selection set with the specified name. This will ignore
/// aliases.
///
/// For example, calling `.field("a")` on `{ a { b } }` will return a lookahead that
/// represents `{ b }`.
pub fn field(&self, name: &str) -> Self { pub fn field(&self, name: &str) -> Self {
Self { Self {
document: self.document, document: self.document,
@ -29,32 +40,25 @@ fn find<'a>(
selection_set: &'a SelectionSet, selection_set: &'a SelectionSet,
name: &str, name: &str,
) -> Option<&'a Field> { ) -> Option<&'a Field> {
for item in &selection_set.items { selection_set
match &item.node { .items
.iter()
.find_map(|item| match &item.node {
Selection::Field(field) => { Selection::Field(field) => {
if field.node.name.node == name { if field.node.name.node == name {
return Some(&field.node); Some(&field.node)
} else {
None
} }
} }
Selection::InlineFragment(inline_fragment) => { Selection::InlineFragment(fragment) => {
if let Some(field) = find(document, &inline_fragment.node.selection_set.node, name) find(document, &fragment.node.selection_set.node, name)
{
return Some(field);
}
} }
Selection::FragmentSpread(fragment_spread) => { Selection::FragmentSpread(spread) => document
if let Some(fragment) = document .fragments
.fragments .get(&spread.node.fragment_name.node)
.get(&fragment_spread.node.fragment_name.node) .and_then(|fragment| find(document, &fragment.node.selection_set.node, name)),
{ })
if let Some(field) = find(document, &fragment.node.selection_set.node, name) {
return Some(field);
}
}
}
}
}
None
} }
#[cfg(test)] #[cfg(test)]