async-graphql/src/resolver.rs

104 lines
3.8 KiB
Rust
Raw Normal View History

2020-03-24 10:54:22 +00:00
use crate::{ContextSelectionSet, ErrorWithPosition, JsonWriter, ObjectType, QueryError, Result};
2020-03-07 02:39:55 +00:00
use graphql_parser::query::{Selection, TypeCondition};
2020-03-06 15:58:43 +00:00
use std::future::Future;
use std::pin::Pin;
struct Resolver<'a, T> {
ctx: &'a ContextSelectionSet<'a>,
obj: &'a T,
2020-03-24 10:54:22 +00:00
w: &'a mut JsonWriter,
2020-03-06 15:58:43 +00:00
}
2020-03-19 09:20:12 +00:00
impl<'a, T: ObjectType + Send + Sync> Resolver<'a, T> {
2020-03-06 15:58:43 +00:00
pub fn resolve(&'a mut self) -> Pin<Box<dyn Future<Output = Result<()>> + 'a + Send>> {
Box::pin(async move {
if self.ctx.items.is_empty() {
anyhow::bail!(QueryError::MustHaveSubFields {
object: T::type_name().to_string(),
}
.with_position(self.ctx.span.0));
}
for selection in &self.ctx.item.items {
match selection {
Selection::Field(field) => {
2020-03-07 02:39:55 +00:00
if self.ctx.is_skip(&field.directives)? {
2020-03-06 15:58:43 +00:00
continue;
}
2020-03-07 02:39:55 +00:00
let ctx_field = self.ctx.with_item(field);
2020-03-06 15:58:43 +00:00
if field.name.as_str() == "__typename" {
2020-03-24 10:54:22 +00:00
self.w.begin_object_key();
self.w.string(ctx_field.result_name());
self.w.end_object_key();
self.w.begin_object_value();
self.w.string(&T::type_name());
self.w.end_object_value();
2020-03-06 15:58:43 +00:00
continue;
}
2020-03-24 10:54:22 +00:00
self.w.begin_object_key();
self.w.string(ctx_field.result_name());
self.w.end_object_key();
self.w.begin_object_value();
self.obj.resolve_field(&ctx_field, field, self.w).await?;
self.w.end_object_value();
2020-03-06 15:58:43 +00:00
}
Selection::FragmentSpread(fragment_spread) => {
2020-03-07 02:39:55 +00:00
if self.ctx.is_skip(&fragment_spread.directives)? {
continue;
}
2020-03-06 15:58:43 +00:00
if let Some(fragment) =
self.ctx.fragments.get(&fragment_spread.fragment_name)
{
2020-03-24 10:54:22 +00:00
let mut r = Resolver {
2020-03-06 15:58:43 +00:00
ctx: &self.ctx.with_item(&fragment.selection_set),
obj: self.obj,
2020-03-24 10:54:22 +00:00
w: self.w,
};
r.resolve().await?;
2020-03-06 15:58:43 +00:00
} else {
return Err(QueryError::UnknownFragment {
name: fragment_spread.fragment_name.clone(),
}
.into());
}
}
2020-03-07 02:39:55 +00:00
Selection::InlineFragment(inline_fragment) => {
if self.ctx.is_skip(&inline_fragment.directives)? {
continue;
}
if let Some(TypeCondition::On(name)) = &inline_fragment.type_condition {
self.obj
.resolve_inline_fragment(
&name,
&self.ctx.with_item(&inline_fragment.selection_set),
2020-03-24 10:54:22 +00:00
self.w,
2020-03-07 02:39:55 +00:00
)
.await?;
}
}
2020-03-06 15:58:43 +00:00
}
}
Ok(())
})
}
}
2020-03-20 03:56:08 +00:00
#[allow(missing_docs)]
2020-03-24 10:54:22 +00:00
#[inline]
2020-03-19 09:20:12 +00:00
pub async fn do_resolve<'a, T: ObjectType + Send + Sync>(
ctx: &'a ContextSelectionSet<'a>,
root: &'a T,
2020-03-24 10:54:22 +00:00
w: &mut JsonWriter,
2020-03-07 02:39:55 +00:00
) -> Result<()> {
2020-03-24 10:54:22 +00:00
Resolver { ctx, obj: root, w }.resolve().await?;
2020-03-07 02:39:55 +00:00
Ok(())
2020-03-06 15:58:43 +00:00
}