implemented query fragment
This commit is contained in:
parent
3346184f42
commit
b3974737fc
|
@ -235,12 +235,9 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
resolvers.push(quote! {
|
||||
if field.name.as_str() == #field_name {
|
||||
#(#get_params)*
|
||||
let obj = #resolve_obj;
|
||||
let ctx_obj = ctx_field.with_item(&field.selection_set);
|
||||
let value = obj.resolve(&ctx_obj).await.
|
||||
map_err(|err| err.with_position(field.position))?;
|
||||
let name = field.alias.clone().unwrap_or_else(|| field.name.clone());
|
||||
result.insert(name, value.into());
|
||||
let value = #resolve_obj.resolve(&ctx_obj).await.map_err(|err| err.with_position(field.position))?;
|
||||
result.insert(field.alias.clone().unwrap_or_else(|| field.name.clone()), value.into());
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
@ -279,29 +276,25 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
}
|
||||
|
||||
let mut result = #crate_name::serde_json::Map::<String, #crate_name::serde_json::Value>::new();
|
||||
for selection in &ctx.items {
|
||||
match selection {
|
||||
#crate_name::graphql_parser::query::Selection::Field(field) => {
|
||||
let ctx_field = ctx.with_item(field);
|
||||
if ctx_field.is_skip_this()? {
|
||||
continue;
|
||||
}
|
||||
if field.name.as_str() == "__typename" {
|
||||
let name = field.alias.clone().unwrap_or_else(|| field.name.clone());
|
||||
result.insert(name, #gql_typename.into());
|
||||
continue;
|
||||
}
|
||||
if field.name.as_str() == "__schema" {
|
||||
continue;
|
||||
}
|
||||
#(#resolvers)*
|
||||
#crate_name::anyhow::bail!(#crate_name::QueryError::FieldNotFound {
|
||||
field_name: field.name.clone(),
|
||||
object: #gql_typename,
|
||||
}.with_position(field.position));
|
||||
}
|
||||
_ => {}
|
||||
for field in ctx.fields(&*ctx) {
|
||||
let field = field?;
|
||||
let ctx_field = ctx.with_item(field);
|
||||
if ctx_field.is_skip_this()? {
|
||||
continue;
|
||||
}
|
||||
if field.name.as_str() == "__typename" {
|
||||
let name = field.alias.clone().unwrap_or_else(|| field.name.clone());
|
||||
result.insert(name, #gql_typename.into());
|
||||
continue;
|
||||
}
|
||||
if field.name.as_str() == "__schema" {
|
||||
continue;
|
||||
}
|
||||
#(#resolvers)*
|
||||
#crate_name::anyhow::bail!(#crate_name::QueryError::FieldNotFound {
|
||||
field_name: field.name.clone(),
|
||||
object: #gql_typename,
|
||||
}.with_position(field.position));
|
||||
}
|
||||
|
||||
Ok(#crate_name::serde_json::Value::Object(result))
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::registry::Registry;
|
||||
use crate::{ErrorWithPosition, GQLInputValue, GQLType, QueryError, Result};
|
||||
use fnv::FnvHasher;
|
||||
use graphql_parser::query::{Field, SelectionSet, Value, VariableDefinition};
|
||||
use graphql_parser::query::{
|
||||
Field, FragmentDefinition, Selection, SelectionSet, Value, VariableDefinition,
|
||||
};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
@ -73,6 +75,7 @@ pub struct ContextBase<'a, T> {
|
|||
pub(crate) variable_definitions: Option<&'a [VariableDefinition]>,
|
||||
pub(crate) registry: &'a Registry,
|
||||
pub(crate) data: &'a Data,
|
||||
pub(crate) fragments: &'a HashMap<String, &'a FragmentDefinition>,
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for ContextBase<'a, T> {
|
||||
|
@ -83,6 +86,41 @@ impl<'a, T> Deref for ContextBase<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FieldIter<'a> {
|
||||
fragments: &'a HashMap<String, &'a FragmentDefinition>,
|
||||
stack: Vec<std::slice::Iter<'a, Selection>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for FieldIter<'a> {
|
||||
type Item = Result<&'a Field>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(it) = self.stack.last_mut() {
|
||||
if let Some(selection) = it.next() {
|
||||
match selection {
|
||||
Selection::Field(field) => {
|
||||
return Some(Ok(field));
|
||||
}
|
||||
Selection::FragmentSpread(fragment_spread) => {
|
||||
if let Some(fragment) = self.fragments.get(&fragment_spread.fragment_name) {
|
||||
self.stack.push(fragment.selection_set.items.iter());
|
||||
} else {
|
||||
return Some(Err(QueryError::UnknownFragment {
|
||||
name: fragment_spread.fragment_name.clone(),
|
||||
}
|
||||
.into()));
|
||||
}
|
||||
}
|
||||
Selection::InlineFragment(_) => {}
|
||||
}
|
||||
} else {
|
||||
self.stack.pop();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ContextBase<'a, T> {
|
||||
#[doc(hidden)]
|
||||
pub fn with_item<R>(&self, item: R) -> ContextBase<'a, R> {
|
||||
|
@ -92,6 +130,7 @@ impl<'a, T> ContextBase<'a, T> {
|
|||
variable_definitions: self.variable_definitions,
|
||||
registry: self.registry.clone(),
|
||||
data: self.data,
|
||||
fragments: self.fragments,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +140,14 @@ impl<'a, T> ContextBase<'a, T> {
|
|||
.get(&TypeId::of::<D>())
|
||||
.and_then(|d| d.downcast_ref::<D>())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn fields(&self, selection_set: &'a SelectionSet) -> FieldIter {
|
||||
FieldIter {
|
||||
fragments: self.fragments,
|
||||
stack: vec![selection_set.items.iter()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ContextBase<'a, &'a Field> {
|
||||
|
|
|
@ -59,6 +59,9 @@ pub enum QueryError {
|
|||
|
||||
#[error("Unknown directive \"{name}\".")]
|
||||
UnknownDirective { name: String },
|
||||
|
||||
#[error("Unknown fragment \"{name}\".")]
|
||||
UnknownFragment { name: String },
|
||||
}
|
||||
|
||||
pub trait ErrorWithPosition {
|
||||
|
|
|
@ -133,7 +133,7 @@ impl<'a> __Type<'a> {
|
|||
None
|
||||
}
|
||||
|
||||
#[field]
|
||||
#[field(name = "possibleTypes")]
|
||||
async fn possible_types(&self) -> Option<Vec<__Type<'a>>> {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ use crate::model::__DirectiveLocation;
|
|||
use crate::registry::{Directive, InputValue, Registry};
|
||||
use crate::types::QueryRoot;
|
||||
use crate::{
|
||||
ContextBase, ErrorWithPosition, GQLObject, GQLOutputValue, GQLType, QueryError,
|
||||
QueryParseError, Result, Variables,
|
||||
ContextBase, GQLObject, GQLOutputValue, GQLType, QueryError, QueryParseError, Result, Variables,
|
||||
};
|
||||
use graphql_parser::parse_query;
|
||||
use graphql_parser::query::{Definition, OperationDefinition};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Schema<Query, Mutation> {
|
||||
query: QueryRoot<Query>,
|
||||
|
@ -116,6 +116,13 @@ impl<'a, Query, Mutation> QueryBuilder<'a, Query, Mutation> {
|
|||
{
|
||||
let document =
|
||||
parse_query(self.query_source).map_err(|err| QueryParseError(err.to_string()))?;
|
||||
let mut fragments = HashMap::new();
|
||||
|
||||
for definition in &document.definitions {
|
||||
if let Definition::Fragment(fragment) = definition {
|
||||
fragments.insert(fragment.name.clone(), fragment);
|
||||
}
|
||||
}
|
||||
|
||||
for definition in &document.definitions {
|
||||
match definition {
|
||||
|
@ -127,6 +134,7 @@ impl<'a, Query, Mutation> QueryBuilder<'a, Query, Mutation> {
|
|||
variable_definitions: None,
|
||||
registry: &self.registry,
|
||||
data: self.data,
|
||||
fragments: &fragments,
|
||||
};
|
||||
return self.query.resolve(&ctx).await;
|
||||
}
|
||||
|
@ -141,6 +149,7 @@ impl<'a, Query, Mutation> QueryBuilder<'a, Query, Mutation> {
|
|||
variable_definitions: Some(&query.variable_definitions),
|
||||
registry: self.registry.clone(),
|
||||
data: self.data,
|
||||
fragments: &fragments,
|
||||
};
|
||||
return self.query.resolve(&ctx).await;
|
||||
}
|
||||
|
@ -155,16 +164,12 @@ impl<'a, Query, Mutation> QueryBuilder<'a, Query, Mutation> {
|
|||
variable_definitions: Some(&mutation.variable_definitions),
|
||||
registry: self.registry.clone(),
|
||||
data: self.data,
|
||||
fragments: &fragments,
|
||||
};
|
||||
return self.mutation.resolve(&ctx).await;
|
||||
}
|
||||
}
|
||||
Definition::Operation(OperationDefinition::Subscription(subscription)) => {
|
||||
anyhow::bail!(QueryError::NotSupported.with_position(subscription.position));
|
||||
}
|
||||
Definition::Fragment(fragment) => {
|
||||
anyhow::bail!(QueryError::NotSupported.with_position(fragment.position));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue