2020-03-19 09:20:12 +00:00
|
|
|
use crate::{ContextSelectionSet, ErrorWithPosition, 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,
|
|
|
|
result: &'a mut serde_json::Map<String, serde_json::Value>,
|
|
|
|
}
|
|
|
|
|
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" {
|
|
|
|
self.result
|
|
|
|
.insert(ctx_field.result_name(), T::type_name().to_string().into());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.result.insert(
|
|
|
|
ctx_field.result_name(),
|
|
|
|
self.obj.resolve_field(&ctx_field, field).await?,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
Resolver {
|
|
|
|
ctx: &self.ctx.with_item(&fragment.selection_set),
|
|
|
|
obj: self.obj,
|
|
|
|
result: self.result,
|
|
|
|
}
|
|
|
|
.resolve()
|
|
|
|
.await?;
|
|
|
|
} 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),
|
|
|
|
self.result,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
}
|
|
|
|
}
|
2020-03-06 15:58:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
) -> Result<serde_json::Value> {
|
|
|
|
let mut result = serde_json::Map::<String, serde_json::Value>::new();
|
|
|
|
Resolver {
|
|
|
|
ctx,
|
|
|
|
obj: root,
|
|
|
|
result: &mut result,
|
|
|
|
}
|
|
|
|
.resolve()
|
|
|
|
.await?;
|
|
|
|
Ok(result.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn do_resolve_values<'a, T: ObjectType + Send + Sync>(
|
2020-03-06 15:58:43 +00:00
|
|
|
ctx: &'a ContextSelectionSet<'a>,
|
|
|
|
root: &'a T,
|
2020-03-07 02:39:55 +00:00
|
|
|
result: &mut serde_json::Map<String, serde_json::Value>,
|
|
|
|
) -> Result<()> {
|
2020-03-06 15:58:43 +00:00
|
|
|
Resolver {
|
|
|
|
ctx,
|
|
|
|
obj: root,
|
2020-03-19 09:20:12 +00:00
|
|
|
result: result,
|
2020-03-06 15:58:43 +00:00
|
|
|
}
|
|
|
|
.resolve()
|
|
|
|
.await?;
|
2020-03-07 02:39:55 +00:00
|
|
|
Ok(())
|
2020-03-06 15:58:43 +00:00
|
|
|
}
|