v1.5.1
This commit is contained in:
parent
0769513c8b
commit
b0369860dd
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "The GraphQL server library implemented by rust"
|
||||
|
@ -18,21 +18,20 @@ default = ["bson", "chrono", "uuid", "url", "validators"]
|
|||
validators = ["regex", "once_cell"]
|
||||
|
||||
[dependencies]
|
||||
async-graphql-derive = { path = "async-graphql-derive", version = "1.5.0" }
|
||||
async-graphql-derive = { path = "async-graphql-derive", version = "1.5.1" }
|
||||
graphql-parser = "0.2.3"
|
||||
anyhow = "1.0.26"
|
||||
thiserror = "1.0.11"
|
||||
async-trait = "0.1.24"
|
||||
serde = "1.0.104"
|
||||
serde_derive = "1.0.104"
|
||||
serde_json = { version = "1.0.48", features = ["raw_value"] }
|
||||
serde_json = "1.0.48"
|
||||
fnv = "1.0.6"
|
||||
bytes = "0.5.4"
|
||||
Inflector = "0.11.4"
|
||||
base64 = "0.12.0"
|
||||
byteorder = "1.3.4"
|
||||
itoa = "0.4.5"
|
||||
ryu = "1.0.3"
|
||||
futures = "0.3.0"
|
||||
once_cell = { version = "1.3.1", optional = true }
|
||||
regex = { version = "1.3.5", optional = true }
|
||||
bson = { version = "0.14.1", optional = true }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql-actix-web"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "async-graphql for actix-web"
|
||||
|
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
|
|||
categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
async-graphql = { path = "..", version = "1.5.0" }
|
||||
async-graphql = { path = "..", version = "1.5.1" }
|
||||
actix-web = "2.0.0"
|
||||
actix-multipart = "0.2.0"
|
||||
actix-web-actors = "2.0.0"
|
||||
|
|
|
@ -250,10 +250,9 @@ where
|
|||
let mut gql_req = web::Json::<GQLRequest>::from_request(&req, &mut payload.0)
|
||||
.await?
|
||||
.into_inner();
|
||||
let prepared = match gql_req.prepare(&schema) {
|
||||
Ok(prepared) => prepared,
|
||||
Err(err) => return Ok(web::Json(GQLResponse(Err(err))).respond_to(&req).await?),
|
||||
};
|
||||
let prepared = gql_req
|
||||
.prepare(&schema)
|
||||
.map_err(actix_web::error::ErrorBadRequest)?;
|
||||
let mut cache_control = prepared.cache_control().value();
|
||||
let gql_resp = prepared.execute().await;
|
||||
if gql_resp.is_err() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql-derive"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "Macros for async-graphql"
|
||||
|
|
|
@ -112,8 +112,8 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
|
|||
|
||||
#[#crate_name::async_trait::async_trait]
|
||||
impl #crate_name::OutputValueType for #ident {
|
||||
async fn resolve(value: &Self, _: &#crate_name::ContextSelectionSet<'_>, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
#crate_name::EnumType::resolve_enum(value, w)
|
||||
async fn resolve(value: &Self, _: &#crate_name::ContextSelectionSet<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
#crate_name::EnumType::resolve_enum(value)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
.unwrap_or_else(|| quote! {None});
|
||||
let mut registry_types = Vec::new();
|
||||
let mut possible_types = Vec::new();
|
||||
let mut inline_fragment_resolvers = Vec::new();
|
||||
let mut collect_inline_fields = Vec::new();
|
||||
|
||||
for field in &fields.unnamed {
|
||||
if let Type::Path(p) = &field.ty {
|
||||
|
@ -58,13 +58,13 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
possible_types.push(quote! {
|
||||
possible_types.insert(<#p as #crate_name::Type>::type_name().to_string());
|
||||
});
|
||||
inline_fragment_resolvers.push(quote! {
|
||||
if name == <#p as #crate_name::Type>::type_name() {
|
||||
if let #ident::#enum_name(obj) = self {
|
||||
return #crate_name::do_resolve(ctx, obj, w).await;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
collect_inline_fields.push(quote! {
|
||||
// if name == <#p as #crate_name::Type>::type_name() {
|
||||
// if let #ident::#enum_name(obj) = self {
|
||||
// return &obj;
|
||||
// }
|
||||
// unreachable!()
|
||||
// }
|
||||
});
|
||||
} else {
|
||||
return Err(Error::new_spanned(field, "Invalid type"));
|
||||
|
@ -205,7 +205,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
if field.name.as_str() == #name {
|
||||
#(#get_params)*
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
return #crate_name::OutputValueType::resolve(&#resolve_obj, &ctx_obj, w).await.
|
||||
return #crate_name::OutputValueType::resolve(&#resolve_obj, &ctx_obj).await.
|
||||
map_err(|err| err.with_position(field.position).into());
|
||||
}
|
||||
});
|
||||
|
@ -250,7 +250,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
|
||||
#[#crate_name::async_trait::async_trait]
|
||||
impl #generics #crate_name::ObjectType for #ident #generics {
|
||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>, field: &#crate_name::graphql_parser::query::Field, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>, field: &#crate_name::graphql_parser::query::Field) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
use #crate_name::ErrorWithPosition;
|
||||
|
||||
#(#resolvers)*
|
||||
|
@ -262,8 +262,13 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
.with_position(field.position));
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(&self, name: &str, ctx: &#crate_name::ContextSelectionSet<'_>, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
#(#inline_fragment_resolvers)*
|
||||
fn collect_inline_fields<'a>(
|
||||
&'a self,
|
||||
name: &str,
|
||||
ctx: #crate_name::ContextSelectionSet<'a>,
|
||||
futures: &mut Vec<#crate_name::BoxFieldFuture<'a>>,
|
||||
) -> #crate_name::Result<()> {
|
||||
#(#collect_inline_fields)*
|
||||
#crate_name::anyhow::bail!(#crate_name::QueryError::UnrecognizedInlineFragment {
|
||||
object: #gql_typename.to_string(),
|
||||
name: name.to_string(),
|
||||
|
@ -273,11 +278,8 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
|
||||
#[#crate_name::async_trait::async_trait]
|
||||
impl #generics #crate_name::OutputValueType for #ident #generics {
|
||||
async fn resolve(value: &Self, ctx: &#crate_name::ContextSelectionSet<'_>, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
w.begin_object();
|
||||
#crate_name::do_resolve(ctx, value, w).await?;
|
||||
w.end_object();
|
||||
Ok(())
|
||||
async fn resolve(value: &Self, ctx: &#crate_name::ContextSelectionSet<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
#crate_name::do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -211,7 +211,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
if field.name.as_str() == #field_name {
|
||||
#(#get_params)*
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
return #crate_name::OutputValueType::resolve(&#resolve_obj, &ctx_obj, w).await.
|
||||
return #crate_name::OutputValueType::resolve(&#resolve_obj, &ctx_obj).await.
|
||||
map_err(|err| err.with_position(field.position).into());
|
||||
}
|
||||
});
|
||||
|
@ -256,7 +256,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
|
||||
#[#crate_name::async_trait::async_trait]
|
||||
impl#generics #crate_name::ObjectType for #self_ty {
|
||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>, field: &#crate_name::graphql_parser::query::Field, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>, field: &#crate_name::graphql_parser::query::Field) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
use #crate_name::ErrorWithPosition;
|
||||
|
||||
#(#resolvers)*
|
||||
|
@ -267,22 +267,12 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
}
|
||||
.with_position(field.position));
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(&self, name: &str, ctx: &#crate_name::ContextSelectionSet<'_>, _w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
#crate_name::anyhow::bail!(#crate_name::QueryError::UnrecognizedInlineFragment {
|
||||
object: #gql_typename.to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[#crate_name::async_trait::async_trait]
|
||||
impl #generics #crate_name::OutputValueType for #self_ty {
|
||||
async fn resolve(value: &Self, ctx: &#crate_name::ContextSelectionSet<'_>, w: &mut #crate_name::JsonWriter) -> #crate_name::Result<()> {
|
||||
w.begin_object();
|
||||
#crate_name::do_resolve(ctx, value, w).await?;
|
||||
w.end_object();
|
||||
Ok(())
|
||||
async fn resolve(value: &Self, ctx: &#crate_name::ContextSelectionSet<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
#crate_name::do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -211,22 +211,12 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
if let Some(msg) = msg.downcast_ref::<#ty>() {
|
||||
#(#get_params)*
|
||||
if self.#ident(msg, #(#use_params)*) {
|
||||
let mut w = #crate_name::JsonWriter::default();
|
||||
let ctx_selection_set = ctx_field.with_item(&field.selection_set);
|
||||
|
||||
w.begin_object();
|
||||
|
||||
w.begin_object_key();
|
||||
w.string(ctx_field.result_name());
|
||||
w.end_object_key();
|
||||
|
||||
w.begin_object_value();
|
||||
#crate_name::OutputValueType::resolve(msg, &ctx_selection_set, &mut w).await?;
|
||||
w.end_object_value();
|
||||
|
||||
w.end_object();
|
||||
|
||||
return Ok(Some(w.into_string()));
|
||||
let value =
|
||||
#crate_name::OutputValueType::resolve(msg, &ctx_selection_set).await?;
|
||||
let mut res = #crate_name::serde_json::Map::new();
|
||||
res.insert(ctx_field.result_name(), value);
|
||||
return Ok(Some(res.into()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -275,7 +265,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
ctx: &#crate_name::ContextBase<'_, ()>,
|
||||
types: &std::collections::HashMap<std::any::TypeId, #crate_name::graphql_parser::query::Field>,
|
||||
msg: &(dyn std::any::Any + Send + Sync),
|
||||
) -> #crate_name::Result<Option<String>> {
|
||||
) -> #crate_name::Result<Option<#crate_name::serde_json::Value>> {
|
||||
let tid = msg.type_id();
|
||||
if let Some(field) = types.get(&tid) {
|
||||
let ctx_field = ctx.with_item(field);
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
.unwrap_or_else(|| quote! {None});
|
||||
let mut registry_types = Vec::new();
|
||||
let mut possible_types = Vec::new();
|
||||
let mut inline_fragment_resolvers = Vec::new();
|
||||
let mut collect_inline_fields = Vec::new();
|
||||
|
||||
for field in &fields.unnamed {
|
||||
if let Type::Path(p) = &field.ty {
|
||||
|
@ -54,13 +54,13 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
possible_types.push(quote! {
|
||||
possible_types.insert(<#p as #crate_name::Type>::type_name().to_string());
|
||||
});
|
||||
inline_fragment_resolvers.push(quote! {
|
||||
if name == <#p as #crate_name::Type>::type_name() {
|
||||
if let #ident::#enum_name(obj) = self {
|
||||
#crate_name::do_resolve(ctx, obj, result).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
collect_inline_fields.push(quote! {
|
||||
// if name == <#p as #crate_name::Type>::type_name() {
|
||||
// if let #ident::#enum_name(obj) = self {
|
||||
// return &obj;
|
||||
// }
|
||||
// unreachable!()
|
||||
// }
|
||||
});
|
||||
} else {
|
||||
return Err(Error::new_spanned(field, "Invalid type"));
|
||||
|
@ -106,9 +106,14 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
.with_position(field.position));
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(&self, name: &str, ctx: &#crate_name::ContextSelectionSet<'_>, result: &mut #crate_name::serde_json::Map<String, #crate_name::serde_json::Value>) -> #crate_name::Result<()> {
|
||||
#(#inline_fragment_resolvers)*
|
||||
anyhow::bail!(#crate_name::QueryError::UnrecognizedInlineFragment {
|
||||
fn collect_inline_fields<'a>(
|
||||
&'a self,
|
||||
name: &str,
|
||||
ctx: #crate_name::ContextSelectionSet<'a>,
|
||||
futures: &mut Vec<#crate_name::BoxFieldFuture<'a>>,
|
||||
) -> #crate_name::Result<()> {
|
||||
#(#collect_inline_fields)*
|
||||
#crate_name::anyhow::bail!(#crate_name::QueryError::UnrecognizedInlineFragment {
|
||||
object: #gql_typename.to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
|
@ -118,10 +123,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
#[#crate_name::async_trait::async_trait]
|
||||
impl #generics #crate_name::OutputValueType for #ident #generics {
|
||||
async fn resolve(value: &Self, ctx: &#crate_name::ContextSelectionSet<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
w.begin_object();
|
||||
#crate_name::do_resolve(ctx, value).await?;
|
||||
w.end_object();
|
||||
Ok(())
|
||||
#crate_name::do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -161,7 +161,7 @@ pub fn parse_validator(crate_name: &TokenStream, args: &MetaList) -> Result<Toke
|
|||
return Err(Error::new_spanned(ls,
|
||||
"Only one validator can be defined. You can connect combine validators with `and` or `or`"));
|
||||
}
|
||||
if ls.nested.is_empty() {
|
||||
if ls.nested.len() == 0 {
|
||||
return Err(Error::new_spanned(
|
||||
ls,
|
||||
"At least one validator must be defined",
|
||||
|
|
60
src/base.rs
60
src/base.rs
|
@ -1,7 +1,9 @@
|
|||
use crate::registry::Registry;
|
||||
use crate::{registry, Context, ContextSelectionSet, JsonWriter, QueryError, Result, ID};
|
||||
use crate::{registry, Context, ContextSelectionSet, QueryError, Result, ID};
|
||||
use graphql_parser::query::{Field, Value};
|
||||
use std::borrow::Cow;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
/// Represents a GraphQL type
|
||||
///
|
||||
|
@ -50,10 +52,13 @@ pub trait InputValueType: Type + Sized {
|
|||
#[async_trait::async_trait]
|
||||
pub trait OutputValueType: Type {
|
||||
/// Resolve an output value to `serde_json::Value`.
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>, w: &mut JsonWriter)
|
||||
-> Result<()>;
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value>;
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub type BoxFieldFuture<'a> =
|
||||
Pin<Box<dyn Future<Output = Result<(String, serde_json::Value)>> + 'a + Send>>;
|
||||
|
||||
/// Represents a GraphQL object
|
||||
#[async_trait::async_trait]
|
||||
pub trait ObjectType: OutputValueType {
|
||||
|
@ -64,20 +69,20 @@ pub trait ObjectType: OutputValueType {
|
|||
}
|
||||
|
||||
/// Resolves a field value and outputs it as a json value `serde_json::Value`.
|
||||
async fn resolve_field(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
field: &Field,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()>;
|
||||
async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value>;
|
||||
|
||||
/// Resolve an inline fragment with the `name`.
|
||||
async fn resolve_inline_fragment(
|
||||
&self,
|
||||
/// Collect the fields with the `name` inline object
|
||||
fn collect_inline_fields<'a>(
|
||||
&'a self,
|
||||
name: &str,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()>;
|
||||
_ctx: ContextSelectionSet<'a>,
|
||||
_futures: &mut Vec<BoxFieldFuture<'a>>,
|
||||
) -> Result<()> {
|
||||
anyhow::bail!(QueryError::UnrecognizedInlineFragment {
|
||||
object: Self::type_name().to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a GraphQL input object
|
||||
|
@ -107,9 +112,8 @@ pub trait InputObjectType: InputValueType {}
|
|||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
/// w.int(self.0 as i64);
|
||||
/// Ok(())
|
||||
/// fn to_json(&self) -> Result<serde_json::Value> {
|
||||
/// Ok(self.0.into())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
@ -135,7 +139,7 @@ pub trait Scalar: Sized + Send {
|
|||
}
|
||||
|
||||
/// Convert the scalar value to json value.
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()>;
|
||||
fn to_json(&self) -> Result<serde_json::Value>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -168,9 +172,8 @@ macro_rules! impl_scalar_internal {
|
|||
async fn resolve(
|
||||
value: &Self,
|
||||
_: &crate::ContextSelectionSet<'_>,
|
||||
w: &mut crate::JsonWriter,
|
||||
) -> crate::Result<()> {
|
||||
value.to_json(w)
|
||||
) -> crate::Result<serde_json::Value> {
|
||||
value.to_json()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -206,9 +209,8 @@ macro_rules! impl_scalar {
|
|||
async fn resolve(
|
||||
value: &Self,
|
||||
_: &async_graphql::ContextSelectionSet<'_>,
|
||||
w: &mut async_graphql::JsonWriter,
|
||||
) -> async_graphql::Result<()> {
|
||||
value.to_json(w)
|
||||
) -> async_graphql::Result<serde_json::Value> {
|
||||
value.to_json()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -227,11 +229,7 @@ impl<T: Type + Send + Sync> Type for &T {
|
|||
#[async_trait::async_trait]
|
||||
impl<T: OutputValueType + Send + Sync> OutputValueType for &T {
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
T::resolve(*value, ctx, w).await
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
T::resolve(*value, ctx).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,7 @@ pub type ContextSelectionSet<'a> = ContextBase<'a, &'a SelectionSet>;
|
|||
pub type Context<'a> = ContextBase<'a, &'a Field>;
|
||||
|
||||
/// Query context
|
||||
#[derive(Clone)]
|
||||
pub struct ContextBase<'a, T> {
|
||||
pub(crate) item: T,
|
||||
pub(crate) variables: &'a Variables,
|
||||
|
@ -333,10 +334,7 @@ impl<'a> ContextBase<'a, &'a Field> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn result_name(&self) -> &str {
|
||||
self.item
|
||||
.alias
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| self.name.as_str())
|
||||
pub fn result_name(&self) -> String {
|
||||
self.item.alias.clone().unwrap_or_else(|| self.name.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ impl GQLRequest {
|
|||
}
|
||||
|
||||
/// Serializable query result type
|
||||
pub struct GQLResponse(pub Result<String>);
|
||||
pub struct GQLResponse(pub Result<serde_json::Value>);
|
||||
|
||||
impl Serialize for GQLResponse {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
|
||||
|
@ -82,13 +82,10 @@ impl Serialize for GQLResponse {
|
|||
Ok(res) => {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
map.serialize_key("data")?;
|
||||
map.serialize_value(
|
||||
&serde_json::value::RawValue::from_string(res.clone()).unwrap(),
|
||||
)?;
|
||||
map.serialize_value(&res)?;
|
||||
map.end()
|
||||
}
|
||||
Err(err) => {
|
||||
println!("err: {}", err);
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
map.serialize_key("errors")?;
|
||||
map.serialize_value(&GQLError(err))?;
|
||||
|
@ -242,7 +239,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_response_data() {
|
||||
let resp = GQLResponse(Ok(serde_json::to_string(&json!({"ok": true})).unwrap()));
|
||||
let resp = GQLResponse(Ok(json!({"ok": true})));
|
||||
assert_eq!(
|
||||
serde_json::to_value(resp).unwrap(),
|
||||
json! ({
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use serde_json::ser::CharEscape;
|
||||
|
||||
const BB: u8 = b'b'; // \x08
|
||||
const TT: u8 = b't'; // \x09
|
||||
const NN: u8 = b'n'; // \x0A
|
||||
const FF: u8 = b'f'; // \x0C
|
||||
const RR: u8 = b'r'; // \x0D
|
||||
const QU: u8 = b'"'; // \x22
|
||||
const BS: u8 = b'\\'; // \x5C
|
||||
const UU: u8 = b'u'; // \x00...\x1F except the ones above
|
||||
const __: u8 = 0;
|
||||
|
||||
#[inline]
|
||||
fn from_escape_table(escape: u8, byte: u8) -> CharEscape {
|
||||
match escape {
|
||||
self::BB => CharEscape::Backspace,
|
||||
self::TT => CharEscape::Tab,
|
||||
self::NN => CharEscape::LineFeed,
|
||||
self::FF => CharEscape::FormFeed,
|
||||
self::RR => CharEscape::CarriageReturn,
|
||||
self::QU => CharEscape::Quote,
|
||||
self::BS => CharEscape::ReverseSolidus,
|
||||
self::UU => CharEscape::AsciiControl(byte),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
static ESCAPE: [u8; 256] = [
|
||||
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0
|
||||
UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1
|
||||
__, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
|
||||
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
|
||||
];
|
||||
|
||||
#[inline]
|
||||
fn write_char_escape(data: &mut Vec<u8>, char_escape: CharEscape) {
|
||||
use self::CharEscape::*;
|
||||
|
||||
let s = match char_escape {
|
||||
Quote => b"\\\"",
|
||||
ReverseSolidus => b"\\\\",
|
||||
Solidus => b"\\/",
|
||||
Backspace => b"\\b",
|
||||
FormFeed => b"\\f",
|
||||
LineFeed => b"\\n",
|
||||
CarriageReturn => b"\\r",
|
||||
Tab => b"\\t",
|
||||
AsciiControl(byte) => {
|
||||
static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
|
||||
let bytes = &[
|
||||
b'\\',
|
||||
b'u',
|
||||
b'0',
|
||||
b'0',
|
||||
HEX_DIGITS[(byte >> 4) as usize],
|
||||
HEX_DIGITS[(byte & 0xF) as usize],
|
||||
];
|
||||
data.extend_from_slice(bytes);
|
||||
return;
|
||||
}
|
||||
};
|
||||
data.extend_from_slice(s);
|
||||
}
|
||||
|
||||
/// JSON Writer
|
||||
#[derive(Default)]
|
||||
pub struct JsonWriter {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl JsonWriter {
|
||||
#[inline]
|
||||
pub fn into_string(self) -> String {
|
||||
unsafe { String::from_utf8_unchecked(self.data) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn null(&mut self) {
|
||||
self.data.extend_from_slice(b"null");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bool(&mut self, value: bool) {
|
||||
if value {
|
||||
self.data.extend_from_slice(b"true");
|
||||
} else {
|
||||
self.data.extend_from_slice(b"false");
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn int(&mut self, value: i64) {
|
||||
let mut buffer = itoa::Buffer::new();
|
||||
self.data.extend_from_slice(buffer.format(value).as_bytes());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn float(&mut self, value: f64) {
|
||||
let mut buffer = ryu::Buffer::new();
|
||||
let s = buffer.format_finite(value);
|
||||
self.data.extend_from_slice(s.as_bytes());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn string(&mut self, value: &str) {
|
||||
self.data.push(b'"');
|
||||
let bytes = value.as_bytes();
|
||||
|
||||
let mut start = 0;
|
||||
|
||||
for (i, &byte) in bytes.iter().enumerate() {
|
||||
let escape = ESCAPE[byte as usize];
|
||||
if escape == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if start < i {
|
||||
self.data.extend_from_slice(&bytes[start..i]);
|
||||
}
|
||||
|
||||
let char_escape = from_escape_table(escape, byte);
|
||||
write_char_escape(&mut self.data, char_escape);
|
||||
|
||||
start = i + 1;
|
||||
}
|
||||
|
||||
if start != bytes.len() {
|
||||
self.data.extend_from_slice(&bytes[start..]);
|
||||
}
|
||||
self.data.push(b'"');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_array(&mut self) {
|
||||
self.data.push(b'[');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_array(&mut self) {
|
||||
if let Some(lc) = self.data.last_mut() {
|
||||
if *lc == b',' {
|
||||
*lc = b']';
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.data.push(b']');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_array_value(&mut self) {}
|
||||
|
||||
#[inline]
|
||||
pub fn end_array_value(&mut self) {
|
||||
self.data.push(b',');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_object(&mut self) {
|
||||
self.data.push(b'{');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_object(&mut self) {
|
||||
if let Some(lc) = self.data.last_mut() {
|
||||
if *lc == b',' {
|
||||
*lc = b'}';
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.data.push(b'}');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_object_key(&mut self) {}
|
||||
|
||||
#[inline]
|
||||
pub fn end_object_key(&mut self) {}
|
||||
|
||||
#[inline]
|
||||
pub fn begin_object_value(&mut self) {
|
||||
self.data.push(b':');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_object_value(&mut self) {
|
||||
self.data.push(b',');
|
||||
}
|
||||
}
|
20
src/lib.rs
20
src/lib.rs
|
@ -69,7 +69,6 @@ extern crate serde_derive;
|
|||
mod base;
|
||||
mod context;
|
||||
mod error;
|
||||
mod json_writer;
|
||||
mod model;
|
||||
mod query;
|
||||
mod resolver;
|
||||
|
@ -98,7 +97,6 @@ pub use base::{Scalar, Type};
|
|||
pub use context::{Context, Variables};
|
||||
pub use error::{ErrorWithPosition, PositionError, QueryError, QueryParseError};
|
||||
pub use graphql_parser::query::Value;
|
||||
pub use json_writer::JsonWriter;
|
||||
pub use query::{PreparedQuery, QueryBuilder};
|
||||
pub use registry::CacheControl;
|
||||
pub use scalars::ID;
|
||||
|
@ -121,11 +119,11 @@ pub use context::ContextSelectionSet;
|
|||
#[doc(hidden)]
|
||||
pub mod registry;
|
||||
#[doc(hidden)]
|
||||
pub use base::{InputObjectType, InputValueType, ObjectType, OutputValueType};
|
||||
pub use base::{BoxFieldFuture, InputObjectType, InputValueType, ObjectType, OutputValueType};
|
||||
#[doc(hidden)]
|
||||
pub use context::ContextBase;
|
||||
#[doc(hidden)]
|
||||
pub use resolver::do_resolve;
|
||||
pub use resolver::{collect_fields, do_resolve};
|
||||
#[doc(hidden)]
|
||||
pub use subscription::{Subscribe, SubscriptionType};
|
||||
#[doc(hidden)]
|
||||
|
@ -216,13 +214,13 @@ pub use types::{EnumItem, EnumType};
|
|||
/// #[async_std::main]
|
||||
/// async fn main() {
|
||||
/// let schema = Schema::new(MyObject{ value: 10 }, EmptyMutation, EmptySubscription);
|
||||
/// let res = serde_json::from_str::<serde_json::Value>(&schema.query(r#"{
|
||||
/// let res = schema.query(r#"{
|
||||
/// value
|
||||
/// valueRef
|
||||
/// valueWithError
|
||||
/// valueWithArg1: valueWithArg
|
||||
/// valueWithArg2: valueWithArg(a: 99)
|
||||
/// }"#).execute().await.unwrap()).unwrap();
|
||||
/// }"#).execute().await.unwrap();
|
||||
/// assert_eq!(res, serde_json::json!({
|
||||
/// "value": 10,
|
||||
/// "valueRef": 10,
|
||||
|
@ -283,7 +281,7 @@ pub use async_graphql_derive::Object;
|
|||
/// #[async_std::main]
|
||||
/// async fn main() {
|
||||
/// let schema = Schema::new(MyObject{ value1: MyEnum::A, value2: MyEnum::B }, EmptyMutation, EmptySubscription);
|
||||
/// let res = serde_json::from_str::<serde_json::Value>(&schema.query("{ value1 value2 }").execute().await.unwrap()).unwrap();
|
||||
/// let res = schema.query("{ value1 value2 }").execute().await.unwrap();
|
||||
/// assert_eq!(res, serde_json::json!({ "value1": "A", "value2": "b" }));
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -332,11 +330,11 @@ pub use async_graphql_derive::Enum;
|
|||
/// #[async_std::main]
|
||||
/// async fn main() {
|
||||
/// let schema = Schema::new(MyObject, EmptyMutation, EmptySubscription);
|
||||
/// let res = serde_json::from_str::<serde_json::Value>(&schema.query(r#"
|
||||
/// let res = schema.query(r#"
|
||||
/// {
|
||||
/// value1: value(input:{a:9, b:3})
|
||||
/// value2: value(input:{a:9})
|
||||
/// }"#).execute().await.unwrap()).unwrap();
|
||||
/// }"#).execute().await.unwrap();
|
||||
/// assert_eq!(res, serde_json::json!({ "value1": 27, "value2": 90 }));
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -437,14 +435,14 @@ pub use async_graphql_derive::InputObject;
|
|||
/// #[async_std::main]
|
||||
/// async fn main() {
|
||||
/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription).data("hello".to_string());
|
||||
/// let res = serde_json::from_str::<serde_json::Value>(&schema.query(r#"
|
||||
/// let res = schema.query(r#"
|
||||
/// {
|
||||
/// typeA {
|
||||
/// valueA
|
||||
/// valueB
|
||||
/// valueC(a: 3, b: 2)
|
||||
/// }
|
||||
/// }"#).execute().await.unwrap()).unwrap();
|
||||
/// }"#).execute().await.unwrap();
|
||||
/// assert_eq!(res, serde_json::json!({
|
||||
/// "typeA": {
|
||||
/// "valueA": "hello",
|
||||
|
|
12
src/query.rs
12
src/query.rs
|
@ -2,7 +2,7 @@ use crate::context::Data;
|
|||
use crate::registry::{CacheControl, Registry};
|
||||
use crate::types::QueryRoot;
|
||||
use crate::validation::check_rules;
|
||||
use crate::{ContextBase, JsonWriter, OutputValueType, Result};
|
||||
use crate::{ContextBase, OutputValueType, Result};
|
||||
use crate::{ObjectType, QueryError, QueryParseError, Variables};
|
||||
use bytes::Bytes;
|
||||
use graphql_parser::parse_query;
|
||||
|
@ -111,7 +111,7 @@ impl<'a, Query, Mutation> QueryBuilder<'a, Query, Mutation> {
|
|||
}
|
||||
|
||||
/// Execute the query.
|
||||
pub async fn execute(self) -> Result<String>
|
||||
pub async fn execute(self) -> Result<serde_json::Value>
|
||||
where
|
||||
Query: ObjectType + Send + Sync,
|
||||
Mutation: ObjectType + Send + Sync,
|
||||
|
@ -160,7 +160,7 @@ impl<'a, Query, Mutation> PreparedQuery<'a, Query, Mutation> {
|
|||
}
|
||||
|
||||
/// Execute the query.
|
||||
pub async fn execute(self) -> Result<String>
|
||||
pub async fn execute(self) -> Result<serde_json::Value>
|
||||
where
|
||||
Query: ObjectType + Send + Sync,
|
||||
Mutation: ObjectType + Send + Sync,
|
||||
|
@ -173,13 +173,11 @@ impl<'a, Query, Mutation> PreparedQuery<'a, Query, Mutation> {
|
|||
data: self.data,
|
||||
fragments: &self.fragments,
|
||||
};
|
||||
let mut w = JsonWriter::default();
|
||||
|
||||
match self.root {
|
||||
Root::Query(query) => OutputValueType::resolve(query, &ctx, &mut w).await?,
|
||||
Root::Mutation(mutation) => OutputValueType::resolve(mutation, &ctx, &mut w).await?,
|
||||
Root::Query(query) => OutputValueType::resolve(query, &ctx).await,
|
||||
Root::Mutation(mutation) => OutputValueType::resolve(mutation, &ctx).await,
|
||||
}
|
||||
Ok(w.into_string())
|
||||
}
|
||||
|
||||
/// Get cache control value
|
||||
|
|
176
src/resolver.rs
176
src/resolver.rs
|
@ -1,103 +1,91 @@
|
|||
use crate::{ContextSelectionSet, ErrorWithPosition, JsonWriter, ObjectType, QueryError, Result};
|
||||
use crate::base::BoxFieldFuture;
|
||||
use crate::{ContextSelectionSet, Error, ErrorWithPosition, ObjectType, QueryError, Result};
|
||||
use futures::{future, TryFutureExt};
|
||||
use graphql_parser::query::{Selection, TypeCondition};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Resolver<'a, T> {
|
||||
ctx: &'a ContextSelectionSet<'a>,
|
||||
obj: &'a T,
|
||||
w: &'a mut JsonWriter,
|
||||
}
|
||||
|
||||
impl<'a, T: ObjectType + Send + Sync> Resolver<'a, T> {
|
||||
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) => {
|
||||
if self.ctx.is_skip(&field.directives)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ctx_field = self.ctx.with_item(field);
|
||||
if field.name.as_str() == "__typename" {
|
||||
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();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
Selection::FragmentSpread(fragment_spread) => {
|
||||
if self.ctx.is_skip(&fragment_spread.directives)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(fragment) =
|
||||
self.ctx.fragments.get(&fragment_spread.fragment_name)
|
||||
{
|
||||
let mut r = Resolver {
|
||||
ctx: &self.ctx.with_item(&fragment.selection_set),
|
||||
obj: self.obj,
|
||||
w: self.w,
|
||||
};
|
||||
r.resolve().await?;
|
||||
} else {
|
||||
return Err(QueryError::UnknownFragment {
|
||||
name: fragment_spread.fragment_name.clone(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
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.w,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[inline]
|
||||
pub async fn do_resolve<'a, T: ObjectType + Send + Sync>(
|
||||
ctx: &'a ContextSelectionSet<'a>,
|
||||
root: &'a T,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<serde_json::Value> {
|
||||
let mut futures = Vec::new();
|
||||
collect_fields(ctx.clone(), root, &mut futures)?;
|
||||
let res = futures::future::try_join_all(futures).await?;
|
||||
let map = serde_json::Map::from_iter(res);
|
||||
Ok(map.into())
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn collect_fields<'a, T: ObjectType + Send + Sync>(
|
||||
ctx: ContextSelectionSet<'a>,
|
||||
root: &'a T,
|
||||
futures: &mut Vec<BoxFieldFuture<'a>>,
|
||||
) -> Result<()> {
|
||||
Resolver { ctx, obj: root, w }.resolve().await?;
|
||||
if ctx.items.is_empty() {
|
||||
anyhow::bail!(QueryError::MustHaveSubFields {
|
||||
object: T::type_name().to_string(),
|
||||
}
|
||||
.with_position(ctx.span.0));
|
||||
}
|
||||
|
||||
for selection in &ctx.item.items {
|
||||
match selection {
|
||||
Selection::Field(field) => {
|
||||
if ctx.is_skip(&field.directives)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ctx_field = ctx.with_item(field);
|
||||
let field_name = ctx_field.result_name();
|
||||
|
||||
if field.name.as_str() == "__typename" {
|
||||
// Get the typename
|
||||
futures.push(Box::pin(
|
||||
future::ok::<serde_json::Value, Error>(T::type_name().to_string().into())
|
||||
.map_ok(move |value| (field_name, value)),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
futures.push(Box::pin({
|
||||
let ctx_field = ctx_field.clone();
|
||||
async move {
|
||||
root.resolve_field(&ctx_field, field)
|
||||
.map_ok(move |value| (field_name, value))
|
||||
.await
|
||||
}
|
||||
}))
|
||||
}
|
||||
Selection::FragmentSpread(fragment_spread) => {
|
||||
if ctx.is_skip(&fragment_spread.directives)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(fragment) = ctx.fragments.get(&fragment_spread.fragment_name) {
|
||||
collect_fields(ctx.with_item(&fragment.selection_set), root, futures)?;
|
||||
} else {
|
||||
return Err(QueryError::UnknownFragment {
|
||||
name: fragment_spread.fragment_name.clone(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Selection::InlineFragment(inline_fragment) => {
|
||||
if ctx.is_skip(&inline_fragment.directives)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(TypeCondition::On(name)) = &inline_fragment.type_condition {
|
||||
root.collect_inline_fields(
|
||||
name,
|
||||
ctx.with_item(&inline_fragment.selection_set),
|
||||
futures,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
|
||||
impl Scalar for bool {
|
||||
fn type_name() -> &'static str {
|
||||
|
@ -16,9 +16,8 @@ impl Scalar for bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.bool(*self);
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok((*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
use bson::oid::ObjectId;
|
||||
|
||||
impl Scalar for ObjectId {
|
||||
|
@ -13,9 +13,8 @@ impl Scalar for ObjectId {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(&self.to_string());
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
/// Implement the DateTime<Utc> scalar
|
||||
|
@ -16,9 +16,8 @@ impl Scalar for DateTime<Utc> {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(&self.to_rfc3339());
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.to_rfc3339().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
|
||||
macro_rules! impl_float_scalars {
|
||||
($($ty:ty),*) => {
|
||||
|
@ -20,9 +20,8 @@ macro_rules! impl_float_scalars {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.float(*self as f64);
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok((*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// ID scalar
|
||||
|
@ -58,9 +58,8 @@ impl Scalar for ID {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(&self.0);
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.0.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
|
||||
macro_rules! impl_integer_scalars {
|
||||
($($ty:ty),*) => {
|
||||
|
@ -19,9 +19,8 @@ macro_rules! impl_integer_scalars {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.int(*self as i64);
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok((*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
impl_scalar_internal, registry, ContextSelectionSet, JsonWriter, OutputValueType, Result,
|
||||
Scalar, Type, Value,
|
||||
impl_scalar_internal, registry, ContextSelectionSet, OutputValueType, Result, Scalar, Type,
|
||||
Value,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
@ -29,9 +29,8 @@ impl Scalar for String {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(self.as_str());
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,8 +55,7 @@ impl<'a> Type for &'a str {
|
|||
|
||||
#[async_trait::async_trait]
|
||||
impl<'a> OutputValueType for &'a str {
|
||||
async fn resolve(value: &Self, _: &ContextSelectionSet<'_>, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(*value);
|
||||
Ok(())
|
||||
async fn resolve(value: &Self, _: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
Ok((*value).into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
use url::Url;
|
||||
|
||||
impl Scalar for Url {
|
||||
|
@ -13,9 +13,8 @@ impl Scalar for Url {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(&self.to_string());
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{impl_scalar_internal, JsonWriter, Result, Scalar, Value};
|
||||
use crate::{impl_scalar_internal, Result, Scalar, Value};
|
||||
use uuid::Uuid;
|
||||
|
||||
impl Scalar for Uuid {
|
||||
|
@ -13,9 +13,8 @@ impl Scalar for Uuid {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_json(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
w.string(&self.to_string());
|
||||
Ok(())
|
||||
fn to_json(&self) -> Result<serde_json::Value> {
|
||||
Ok(self.to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ impl Subscribe {
|
|||
&self,
|
||||
schema: &Schema<Query, Mutation, Subscription>,
|
||||
msg: &(dyn Any + Send + Sync),
|
||||
) -> Result<Option<String>>
|
||||
) -> Result<Option<serde_json::Value>>
|
||||
where
|
||||
Subscription: SubscriptionType + Sync + Send + 'static,
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ pub trait SubscriptionType: Type {
|
|||
ctx: &ContextBase<'_, ()>,
|
||||
types: &HashMap<TypeId, Field>,
|
||||
msg: &(dyn Any + Send + Sync),
|
||||
) -> Result<Option<String>>;
|
||||
) -> Result<Option<serde_json::Value>>;
|
||||
}
|
||||
|
||||
fn create_types<T: SubscriptionType>(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::types::connection::edge::Edge;
|
||||
use crate::types::connection::page_info::PageInfo;
|
||||
use crate::{
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, JsonWriter, ObjectType,
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, ObjectType,
|
||||
OutputValueType, QueryError, Result, Type,
|
||||
};
|
||||
use graphql_parser::query::Field;
|
||||
|
@ -127,16 +127,11 @@ impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> Type for Con
|
|||
impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> ObjectType
|
||||
for Connection<T, E>
|
||||
{
|
||||
async fn resolve_field(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
field: &Field,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value> {
|
||||
if field.name.as_str() == "pageInfo" {
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
let page_info = &self.page_info;
|
||||
return OutputValueType::resolve(page_info, &ctx_obj, w)
|
||||
return OutputValueType::resolve(page_info, &ctx_obj)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
} else if field.name.as_str() == "edges" {
|
||||
|
@ -150,16 +145,14 @@ impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> ObjectType
|
|||
node,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
return OutputValueType::resolve(&edges, &ctx_obj, w)
|
||||
return OutputValueType::resolve(&edges, &ctx_obj)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
} else if field.name.as_str() == "totalCount" {
|
||||
if let Some(total_count) = self.total_count {
|
||||
w.int(total_count as i64);
|
||||
} else {
|
||||
w.null();
|
||||
}
|
||||
return Ok(());
|
||||
return Ok(self
|
||||
.total_count
|
||||
.map(|n| (n as i32).into())
|
||||
.unwrap_or_else(|| serde_json::Value::Null));
|
||||
} else if field.name.as_str() == T::type_name().to_plural().to_camel_case() {
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
let items = self
|
||||
|
@ -167,7 +160,7 @@ impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> ObjectType
|
|||
.iter()
|
||||
.map(|(_, _, item)| item)
|
||||
.collect::<Vec<_>>();
|
||||
return OutputValueType::resolve(&items, &ctx_obj, w)
|
||||
return OutputValueType::resolve(&items, &ctx_obj)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
}
|
||||
|
@ -178,29 +171,13 @@ impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> ObjectType
|
|||
}
|
||||
.with_position(field.position))
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(
|
||||
&self,
|
||||
name: &str,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
anyhow::bail!(QueryError::UnrecognizedInlineFragment {
|
||||
object: Connection::<T, E>::type_name().to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> OutputValueType
|
||||
for Connection<T, E>
|
||||
{
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
do_resolve(ctx, value, w).await
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, JsonWriter, ObjectType,
|
||||
OutputValueType, QueryError, Result, Type,
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, ObjectType,
|
||||
OutputValueType, Result, Type,
|
||||
};
|
||||
use graphql_parser::query::Field;
|
||||
use std::borrow::Cow;
|
||||
|
@ -78,35 +78,17 @@ where
|
|||
T: OutputValueType + Send + Sync + 'a,
|
||||
E: ObjectType + Sync + Send + 'a,
|
||||
{
|
||||
async fn resolve_field(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
field: &Field,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value> {
|
||||
if field.name.as_str() == "node" {
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
return OutputValueType::resolve(self.node, &ctx_obj, w)
|
||||
return OutputValueType::resolve(self.node, &ctx_obj)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
} else if field.name.as_str() == "cursor" {
|
||||
w.string(self.cursor);
|
||||
return Ok(());
|
||||
return Ok(self.cursor.into());
|
||||
}
|
||||
|
||||
self.extra_type.resolve_field(ctx, field, w).await
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(
|
||||
&self,
|
||||
name: &str,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
anyhow::bail!(QueryError::UnrecognizedInlineFragment {
|
||||
object: <Edge<T, E> as Type>::type_name().to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
self.extra_type.resolve_field(ctx, field).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,11 +98,7 @@ where
|
|||
T: OutputValueType + Send + Sync + 'a,
|
||||
E: ObjectType + Sync + Send + 'a,
|
||||
{
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
do_resolve(ctx, value, w).await
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ impl EmptyEdgeFields {}
|
|||
/// async fn main() {
|
||||
/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
|
||||
///
|
||||
/// assert_eq!(serde_json::from_str::<serde_json::Value>(&schema.query("{ numbers(first: 2) { edges { node } } }").execute().await.unwrap()).unwrap(), serde_json::json!({
|
||||
/// assert_eq!(schema.query("{ numbers(first: 2) { edges { node } } }").execute().await.unwrap(), serde_json::json!({
|
||||
/// "numbers": {
|
||||
/// "edges": [
|
||||
/// {"node": 0},
|
||||
|
@ -115,7 +115,7 @@ impl EmptyEdgeFields {}
|
|||
/// },
|
||||
/// }));
|
||||
///
|
||||
/// assert_eq!(serde_json::from_str::<serde_json::Value>(&schema.query("{ numbers(last: 2) { edges { node diff } } }").execute().await.unwrap()).unwrap(), serde_json::json!({
|
||||
/// assert_eq!(schema.query("{ numbers(last: 2) { edges { node diff } } }").execute().await.unwrap(), serde_json::json!({
|
||||
/// "numbers": {
|
||||
/// "edges": [
|
||||
/// {"node": -2, "diff": -1002},
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{
|
||||
registry, Context, ContextSelectionSet, JsonWriter, ObjectType, OutputValueType, QueryError,
|
||||
Result, Type,
|
||||
registry, Context, ContextSelectionSet, ObjectType, OutputValueType, QueryError, Result, Type,
|
||||
};
|
||||
use graphql_parser::query::Field;
|
||||
use std::borrow::Cow;
|
||||
|
@ -46,32 +45,14 @@ impl ObjectType for EmptyMutation {
|
|||
true
|
||||
}
|
||||
|
||||
async fn resolve_field(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_name: &Field,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(
|
||||
&self,
|
||||
_name: &str,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve_field(&self, _ctx: &Context<'_>, _name: &Field) -> Result<serde_json::Value> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl OutputValueType for EmptyMutation {
|
||||
async fn resolve(
|
||||
_value: &Self,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve(_value: &Self, _ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
Err(QueryError::NotConfiguredMutations.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::{
|
||||
registry, ContextBase, ContextSelectionSet, JsonWriter, OutputValueType, QueryError, Result,
|
||||
registry, ContextBase, ContextSelectionSet, OutputValueType, QueryError, Result,
|
||||
SubscriptionType, Type,
|
||||
};
|
||||
use graphql_parser::query::Field;
|
||||
use serde_json::Value;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::RandomState;
|
||||
|
@ -43,18 +44,14 @@ impl SubscriptionType for EmptySubscription {
|
|||
_ctx: &ContextBase<'_, ()>,
|
||||
_types: &HashMap<TypeId, Field, RandomState>,
|
||||
_msg: &(dyn Any + Send + Sync),
|
||||
) -> Result<Option<String>> {
|
||||
) -> Result<Option<Value>> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl OutputValueType for EmptySubscription {
|
||||
async fn resolve(
|
||||
_value: &Self,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve(_value: &Self, _ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
Err(QueryError::NotConfiguredSubscriptions.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{JsonWriter, Result, Type};
|
||||
use crate::{Result, Type};
|
||||
use graphql_parser::query::Value;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
|
@ -30,12 +30,11 @@ pub trait EnumType: Type + Sized + Eq + Send + Copy + Sized + 'static {
|
|||
})
|
||||
}
|
||||
|
||||
fn resolve_enum(&self, w: &mut JsonWriter) -> Result<()> {
|
||||
fn resolve_enum(&self) -> Result<serde_json::Value> {
|
||||
let items = Self::items();
|
||||
for item in items {
|
||||
if item.value == *self {
|
||||
w.string(item.name);
|
||||
return Ok(());
|
||||
return Ok(item.name.into());
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::{
|
||||
registry, ContextSelectionSet, InputValueType, JsonWriter, OutputValueType, Result, Type, Value,
|
||||
};
|
||||
use crate::{registry, ContextSelectionSet, InputValueType, OutputValueType, Result, Type, Value};
|
||||
use std::borrow::Cow;
|
||||
|
||||
impl<T: Type> Type for Vec<T> {
|
||||
|
@ -36,19 +34,12 @@ impl<T: InputValueType> InputValueType for Vec<T> {
|
|||
#[allow(clippy::ptr_arg)]
|
||||
#[async_trait::async_trait]
|
||||
impl<T: OutputValueType + Send + Sync> OutputValueType for Vec<T> {
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
w.begin_array();
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
let mut futures = Vec::with_capacity(value.len());
|
||||
for item in value {
|
||||
w.begin_array_value();
|
||||
OutputValueType::resolve(item, &ctx, w).await?;
|
||||
w.end_array_value();
|
||||
futures.push(OutputValueType::resolve(item, &ctx));
|
||||
}
|
||||
w.end_array();
|
||||
Ok(())
|
||||
Ok(futures::future::try_join_all(futures).await?.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,19 +55,12 @@ impl<T: Type> Type for &[T] {
|
|||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: OutputValueType + Send + Sync> OutputValueType for &[T] {
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
w.begin_array();
|
||||
for item in value.iter() {
|
||||
w.begin_array_value();
|
||||
OutputValueType::resolve(item, &ctx, w).await?;
|
||||
w.end_array_value();
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
let mut futures = Vec::with_capacity(value.len());
|
||||
for item in *value {
|
||||
futures.push(OutputValueType::resolve(item, &ctx));
|
||||
}
|
||||
w.end_array();
|
||||
Ok(())
|
||||
Ok(futures::future::try_join_all(futures).await?.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::{
|
||||
registry, ContextSelectionSet, InputValueType, JsonWriter, OutputValueType, Result, Type, Value,
|
||||
};
|
||||
use crate::{registry, ContextSelectionSet, InputValueType, OutputValueType, Result, Type, Value};
|
||||
use std::borrow::Cow;
|
||||
|
||||
impl<T: Type> Type for Option<T> {
|
||||
|
@ -29,16 +27,12 @@ impl<T: InputValueType> InputValueType for Option<T> {
|
|||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: OutputValueType + Sync> OutputValueType for Option<T> {
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> where {
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> where
|
||||
{
|
||||
if let Some(inner) = value {
|
||||
OutputValueType::resolve(inner, ctx, w).await
|
||||
OutputValueType::resolve(inner, ctx).await
|
||||
} else {
|
||||
w.null();
|
||||
Ok(())
|
||||
Ok(serde_json::Value::Null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::model::{__Schema, __Type};
|
||||
use crate::{
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, JsonWriter, ObjectType,
|
||||
OutputValueType, QueryError, Result, Type, Value,
|
||||
do_resolve, registry, Context, ContextSelectionSet, ErrorWithPosition, ObjectType,
|
||||
OutputValueType, Result, Type, Value,
|
||||
};
|
||||
use graphql_parser::query::Field;
|
||||
use std::borrow::Cow;
|
||||
|
@ -65,12 +65,7 @@ impl<T: Type> Type for QueryRoot<T> {
|
|||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: ObjectType + Send + Sync> ObjectType for QueryRoot<T> {
|
||||
async fn resolve_field(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
field: &Field,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value> {
|
||||
if field.name.as_str() == "__schema" {
|
||||
let ctx_obj = ctx.with_item(&field.selection_set);
|
||||
return OutputValueType::resolve(
|
||||
|
@ -78,7 +73,6 @@ impl<T: ObjectType + Send + Sync> ObjectType for QueryRoot<T> {
|
|||
registry: &ctx.registry,
|
||||
},
|
||||
&ctx_obj,
|
||||
w,
|
||||
)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
|
@ -91,38 +85,18 @@ impl<T: ObjectType + Send + Sync> ObjectType for QueryRoot<T> {
|
|||
.get(&type_name)
|
||||
.map(|ty| __Type::new_simple(ctx.registry, ty)),
|
||||
&ctx_obj,
|
||||
w,
|
||||
)
|
||||
.await
|
||||
.map_err(|err| err.with_position(field.position).into());
|
||||
}
|
||||
|
||||
self.inner.resolve_field(ctx, field, w).await
|
||||
}
|
||||
|
||||
async fn resolve_inline_fragment(
|
||||
&self,
|
||||
name: &str,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
anyhow::bail!(QueryError::UnrecognizedInlineFragment {
|
||||
object: T::type_name().to_string(),
|
||||
name: name.to_string(),
|
||||
});
|
||||
self.inner.resolve_field(ctx, field).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: ObjectType + Send + Sync> OutputValueType for QueryRoot<T> {
|
||||
async fn resolve(
|
||||
value: &Self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
w: &mut JsonWriter,
|
||||
) -> Result<()> {
|
||||
w.begin_object();
|
||||
do_resolve(ctx, value, w).await?;
|
||||
w.end_object();
|
||||
Ok(())
|
||||
async fn resolve(value: &Self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
|
||||
do_resolve(ctx, value).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use crate::error::RuleErrors;
|
||||
use crate::registry::Registry;
|
||||
use crate::validation::visitor::{visit, VisitorContext, VisitorNil};
|
||||
use crate::{CacheControl, Result};
|
||||
use graphql_parser::query::Document;
|
||||
|
||||
mod rules;
|
||||
mod utils;
|
||||
mod visitor;
|
||||
|
||||
use crate::error::RuleErrors;
|
||||
use crate::registry::Registry;
|
||||
use crate::{CacheControl, Result};
|
||||
use graphql_parser::query::Document;
|
||||
use visitor::{visit, VisitorContext, VisitorNil};
|
||||
|
||||
pub fn check_rules(registry: &Registry, doc: &Document) -> Result<CacheControl> {
|
||||
let mut ctx = VisitorContext::new(registry, doc);
|
||||
let mut cache_control = CacheControl::default();
|
||||
|
|
|
@ -44,8 +44,7 @@ pub async fn test_enum_type() {
|
|||
"#
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<serde_json::Value>(&schema.query(&query).execute().await.unwrap())
|
||||
.unwrap(),
|
||||
schema.query(&query).execute().await.unwrap(),
|
||||
serde_json::json!({
|
||||
"value": "A",
|
||||
"testArg": "A",
|
||||
|
|
|
@ -81,8 +81,7 @@ pub async fn test_input_object_default_value() {
|
|||
}}"#
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<serde_json::Value>(&schema.query(&query).execute().await.unwrap())
|
||||
.unwrap(),
|
||||
schema.query(&query).execute().await.unwrap(),
|
||||
serde_json::json!({
|
||||
"a": {
|
||||
"a": 999,
|
||||
|
|
|
@ -52,8 +52,7 @@ pub async fn test_list_type() {
|
|||
json_value
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<serde_json::Value>(&schema.query(&query).execute().await.unwrap())
|
||||
.unwrap(),
|
||||
schema.query(&query).execute().await.unwrap(),
|
||||
serde_json::json!({
|
||||
"valueVec": vec![1, 2, 3, 4, 5],
|
||||
"valueSlice": vec![1, 2, 3, 4, 5],
|
||||
|
|
|
@ -66,8 +66,7 @@ pub async fn test_optional_type() {
|
|||
}}"#
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<serde_json::Value>(&schema.query(&query).execute().await.unwrap())
|
||||
.unwrap(),
|
||||
schema.query(&query).execute().await.unwrap(),
|
||||
serde_json::json!({
|
||||
"value1": 10,
|
||||
"value1Ref": 10,
|
||||
|
|
|
@ -35,7 +35,7 @@ macro_rules! test_scalars {
|
|||
let json_value: serde_json::Value = $value.into();
|
||||
let query = format!("{{ value testArg(input: {0}) testInput(input: {{value: {0}}}) }}", json_value);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<serde_json::Value>(&schema.query(&query).execute().await.unwrap()).unwrap(),
|
||||
schema.query(&query).execute().await.unwrap(),
|
||||
serde_json::json!({ "value": $value, "testArg": $value, "testInput": $value })
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user