Move the methods of the `Type` trait to `InputType` and `OutputType`.

This commit is contained in:
Sunli 2021-11-09 18:52:10 +08:00
parent b85815d84a
commit 0e9e087691
49 changed files with 947 additions and 654 deletions

View File

@ -115,7 +115,7 @@ impl FromMeta for Deprecation {
}
}
#[derive(FromField, Clone)]
#[derive(FromField)]
#[darling(attributes(graphql), forward_attrs(doc))]
pub struct SimpleObjectField {
pub ident: Option<Ident>,
@ -145,6 +145,17 @@ pub struct SimpleObjectField {
pub visible: Option<Visible>,
#[darling(default, multiple)]
pub derived: Vec<DerivedField>,
// for InputObject
#[darling(default)]
pub default: Option<DefaultValue>,
#[darling(default)]
pub default_with: Option<LitStr>,
#[darling(default)]
pub validator: Option<Meta>,
#[darling(default)]
pub flatten: bool,
#[darling(default)]
pub secret: bool,
}
#[derive(FromDeriveInput)]
@ -158,7 +169,7 @@ pub struct SimpleObject {
#[darling(default)]
pub internal: bool,
#[darling(default)]
pub dummy: bool,
pub fake: bool,
#[darling(default)]
pub complex: bool,
#[darling(default)]
@ -177,6 +188,9 @@ pub struct SimpleObject {
pub concretes: Vec<ConcreteType>,
#[darling(default)]
pub serial: bool,
// for InputObject
#[darling(default)]
pub input_name: Option<String>,
}
#[derive(FromMeta, Default)]
@ -362,6 +376,8 @@ pub struct InputObject {
#[darling(default)]
pub name: Option<String>,
#[darling(default)]
pub input_name: Option<String>,
#[darling(default)]
pub rename_fields: Option<RenameRule>,
#[darling(default)]
pub visible: Option<Visible>,

View File

@ -218,7 +218,7 @@ pub fn generate(
args.insert(#name, #crate_name::registry::MetaInputValue {
name: #name,
description: #desc,
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::InputType>::create_type_info(registry),
default_value: #schema_default,
validator: #validator,
visible: #visible,
@ -310,7 +310,7 @@ pub fn generate(
#(#schema_args)*
args
},
ty: <#schema_ty as #crate_name::Type>::create_type_info(registry),
ty: <#schema_ty as #crate_name::OutputType>::create_type_info(registry),
deprecation: #field_deprecation,
cache_control: #cache_control,
external: #external,

View File

@ -124,13 +124,13 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
}
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #ident {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
impl #ident {
fn __type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| {
fn __create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_input_type::<Self, _>(|registry| {
#crate_name::registry::MetaType::Enum {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
@ -148,6 +148,14 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::InputType for #ident {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
Self::__type_name()
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
Self::__create_type_info(registry)
}
fn parse(value: ::std::option::Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
#crate_name::resolver_utils::parse_enum(value.unwrap_or_default())
}
@ -159,6 +167,14 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
#[#crate_name::async_trait::async_trait]
impl #crate_name::OutputType for #ident {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
Self::__type_name()
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
Self::__create_type_info(registry)
}
async fn resolve(&self, _: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
::std::result::Result::Ok(#crate_name::resolver_utils::enum_value(*self))
}

View File

@ -44,6 +44,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
let gql_typename = object_args
.name
.clone()
.or_else(|| object_args.input_name.clone())
.unwrap_or_else(|| RenameTarget::Type.rename(ident.to_string()));
let desc = get_rustdoc(&object_args.attrs)?
@ -83,7 +84,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
#crate_name::static_assertions::assert_impl_one!(#ty: #crate_name::InputObjectType);
#ty::create_type_info(registry);
if let #crate_name::registry::MetaType::InputObject { input_fields, .. } =
registry.create_dummy_type::<#ty>() {
registry.create_fake_input_type::<#ty>() {
fields.extend(input_fields);
}
});
@ -161,7 +162,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
fields.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue {
name: #name,
description: #desc,
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::InputType>::create_type_info(registry),
default_value: #schema_default,
validator: #validator,
visible: #visible,
@ -200,13 +201,13 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
let expanded = if object_args.concretes.is_empty() {
quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #ident {
impl #crate_name::InputType for #ident {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::InputObject {
registry.create_input_type::<Self, _>(|registry| #crate_name::registry::MetaType::InputObject {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
input_fields: {
@ -218,10 +219,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
rust_typename: ::std::any::type_name::<Self>(),
})
}
}
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::InputType for #ident {
fn parse(value: ::std::option::Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
if let ::std::option::Option::Some(#crate_name::Value::Object(obj)) = value {
#(#get_fields)*
@ -251,7 +249,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #ident #ty_generics #where_clause {
fn __internal_create_type_info(registry: &mut #crate_name::registry::Registry, name: &str) -> ::std::string::String where Self: #crate_name::InputType {
registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::InputObject {
registry.create_input_type::<Self, _>(|registry| #crate_name::registry::MetaType::InputObject {
name: ::std::borrow::ToOwned::to_owned(name),
description: #desc,
input_fields: {
@ -292,7 +290,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #concrete_type {
impl #crate_name::InputType for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
@ -300,10 +298,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
Self::__internal_create_type_info(registry, #gql_typename)
}
}
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::InputType for #concrete_type {
fn parse(value: ::std::option::Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
Self::__internal_parse(value)
}

View File

@ -100,16 +100,16 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
enum_names.push(enum_name);
registry_types.push(quote! {
<#p as #crate_name::Type>::create_type_info(registry);
registry.add_implements(&<#p as #crate_name::Type>::type_name(), #gql_typename);
<#p as #crate_name::OutputType>::create_type_info(registry);
registry.add_implements(&<#p as #crate_name::OutputType>::type_name(), #gql_typename);
});
possible_types.push(quote! {
possible_types.insert(<#p as #crate_name::Type>::type_name().into_owned());
possible_types.insert(<#p as #crate_name::OutputType>::type_name().into_owned());
});
get_introspection_typename.push(quote! {
#ident::#enum_name(obj) => <#p as #crate_name::Type>::type_name()
#ident::#enum_name(obj) => <#p as #crate_name::OutputType>::type_name()
});
collect_all_fields.push(quote! {
@ -226,7 +226,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
args.insert(#name, #crate_name::registry::MetaInputValue {
name: #name,
description: #desc,
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::InputType>::create_type_info(registry),
default_value: #schema_default,
validator: ::std::option::Option::None,
visible: #visible,
@ -275,7 +275,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
#(#schema_args)*
args
},
ty: <#schema_ty as #crate_name::Type>::create_type_info(registry),
ty: <#schema_ty as #crate_name::OutputType>::create_type_info(registry),
deprecation: #deprecation,
cache_control: ::std::default::Default::default(),
external: #external,
@ -321,7 +321,23 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
}
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#(#resolvers)*
::std::result::Result::Ok(::std::option::Option::None)
}
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
@ -331,7 +347,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| {
registry.create_output_type::<Self, _>(|registry| {
#(#registry_types)*
#crate_name::registry::MetaType::Interface {
@ -354,26 +370,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
}
})
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#(#resolvers)*
::std::result::Result::Ok(::std::option::Option::None)
}
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
async fn resolve(
&self,
ctx: &#crate_name::ContextSelectionSet<'_>,

View File

@ -63,13 +63,26 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#create_merged_obj.resolve_field(ctx).await
}
async fn find_entity(&self, ctx: &#crate_name::Context<'_>, params: &#crate_name::Value) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#create_merged_obj.find_entity(ctx, params).await
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| {
registry.create_output_type::<Self, _>(|registry| {
let mut fields = ::std::default::Default::default();
let mut cache_control = ::std::default::Default::default();
@ -77,7 +90,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
fields: obj_fields,
cache_control: obj_cache_control,
..
} = registry.create_dummy_type::<#merged_type>() {
} = registry.create_fake_output_type::<#merged_type>() {
fields = obj_fields;
cache_control = obj_cache_control;
}
@ -95,23 +108,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
}
})
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#create_merged_obj.resolve_field(ctx).await
}
async fn find_entity(&self, ctx: &#crate_name::Context<'_>, params: &#crate_name::Value) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#create_merged_obj.find_entity(ctx, params).await
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
#resolve_container
}

View File

@ -48,19 +48,19 @@ pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<Token
let visible = visible_fn(&object_args.visible);
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #ident {
impl #crate_name::SubscriptionType for #ident {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| {
registry.create_subscription_type::<Self, _>(|registry| {
let mut fields = ::std::default::Default::default();
if let #crate_name::registry::MetaType::Object {
fields: obj_fields,
..
} = registry.create_dummy_type::<#merged_type>() {
} = registry.create_fake_subscription_type::<#merged_type>() {
fields = obj_fields;
}
@ -77,10 +77,7 @@ pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<Token
}
})
}
}
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::SubscriptionType for #ident {
fn create_field_stream<'__life>(
&'__life self,
ctx: &'__life #crate_name::Context<'__life>

View File

@ -35,7 +35,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
let inner_ty = &fields.fields[0];
let type_name = match &gql_typename {
Some(name) => quote! { ::std::borrow::Cow::Borrowed(#name) },
None => quote! { <#inner_ty as #crate_name::Type>::type_name() },
None => quote! { <#inner_ty as #crate_name::InputType>::type_name() },
};
let create_type_info = if let Some(name) = &gql_typename {
let specified_by_url = match &newtype_args.specified_by_url {
@ -44,7 +44,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
};
quote! {
registry.create_type::<#ident, _>(|_| #crate_name::registry::MetaType::Scalar {
registry.create_input_type::<#ident, _>(|_| #crate_name::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned(#name),
description: #desc,
is_valid: |value| <#ident as #crate_name::ScalarType>::is_valid(value),
@ -53,7 +53,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
})
}
} else {
quote! { <#inner_ty as #crate_name::Type>::create_type_info(registry) }
quote! { <#inner_ty as #crate_name::InputType>::create_type_info(registry) }
};
let expanded = quote! {
@ -81,7 +81,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
}
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
impl #impl_generics #crate_name::InputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
#type_name
}
@ -89,10 +89,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
#create_type_info
}
}
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::InputType for #ident #ty_generics #where_clause {
fn parse(value: ::std::option::Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
<#ident as #crate_name::ScalarType>::parse(value.unwrap_or_default())
}
@ -105,6 +102,14 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
#type_name
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
#create_type_info
}
async fn resolve(
&self,
_: &#crate_name::ContextSelectionSet<'_>,

View File

@ -210,11 +210,11 @@ pub fn generate(
{
let mut key_str = Vec::new();
#(#get_federation_key)*
registry.add_keys(&<#entity_type as #crate_name::Type>::type_name(), &key_str.join(" "));
registry.add_keys(&<#entity_type as #crate_name::OutputType>::type_name(), &key_str.join(" "));
}
});
create_entity_types.push(
quote! { <#entity_type as #crate_name::Type>::create_type_info(registry); },
quote! { <#entity_type as #crate_name::OutputType>::create_type_info(registry); },
);
let field_ident = &method.sig.ident;
@ -241,7 +241,7 @@ pub fn generate(
args.len(),
quote! {
#(#cfg_attrs)*
if typename == &<#entity_type as #crate_name::Type>::type_name() {
if typename == &<#entity_type as #crate_name::OutputType>::type_name() {
if let (#(#key_pat),*) = (#(#key_getter),*) {
let f = async move {
#(#requires_getter)*
@ -353,7 +353,7 @@ pub fn generate(
args.insert(#name, #crate_name::registry::MetaInputValue {
name: #name,
description: #desc,
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::InputType>::create_type_info(registry),
default_value: #schema_default,
validator: #validator,
visible: #visible,
@ -446,7 +446,7 @@ pub fn generate(
#(#schema_args)*
args
},
ty: <#schema_ty as #crate_name::Type>::create_type_info(registry),
ty: <#schema_ty as #crate_name::OutputType>::create_type_info(registry),
deprecation: #field_deprecation,
cache_control: #cache_control,
external: #external,
@ -544,34 +544,6 @@ pub fn generate(
quote! {
#item_impl
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #self_ty #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
let ty = registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
fields: {
let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)*
fields
},
cache_control: #cache_control,
extends: #extends,
keys: ::std::option::Option::None,
visible: #visible,
is_subscription: false,
rust_typename: ::std::any::type_name::<Self>(),
});
#(#create_entity_types)*
#(#add_keys)*
ty
}
}
#[allow(clippy::all, clippy::pedantic, clippy::suspicious_else_formatting)]
#[allow(unused_braces, unused_variables, unused_parens, unused_mut)]
#[#crate_name::async_trait::async_trait]
@ -601,6 +573,31 @@ pub fn generate(
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #self_ty #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
let ty = registry.create_output_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
fields: {
let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)*
fields
},
cache_control: #cache_control,
extends: #extends,
keys: ::std::option::Option::None,
visible: #visible,
is_subscription: false,
rust_typename: ::std::any::type_name::<Self>(),
});
#(#create_entity_types)*
#(#add_keys)*
ty
}
async fn resolve(
&self,
ctx: &#crate_name::ContextSelectionSet<'_>,
@ -620,7 +617,7 @@ pub fn generate(
impl #impl_generics #self_ty #where_clause {
fn __internal_create_type_info(registry: &mut #crate_name::registry::Registry, name: &str) -> ::std::string::String where Self: #crate_name::OutputType {
let ty = registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
let ty = registry.create_output_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(name),
description: #desc,
fields: {
@ -676,17 +673,6 @@ pub fn generate(
let concrete_type = quote! { #ty<#(#params),*> };
codes.push(quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
Self::__internal_create_type_info(registry, #gql_typename)
}
}
#[#crate_name::async_trait::async_trait]
impl #crate_name::resolver_utils::ContainerType for #concrete_type {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
@ -700,6 +686,14 @@ pub fn generate(
#[#crate_name::async_trait::async_trait]
impl #crate_name::OutputType for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
Self::__internal_create_type_info(registry, #gql_typename)
}
async fn resolve(
&self,
ctx: &#crate_name::ContextSelectionSet<'_>,

View File

@ -39,13 +39,13 @@ pub fn generate(
#item_impl
#[allow(clippy::all, clippy::pedantic)]
impl #generic #crate_name::Type for #self_ty #where_clause {
impl #generic #crate_name::InputType for #self_ty #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<#self_ty, _>(|_| #crate_name::registry::MetaType::Scalar {
registry.create_input_type::<#self_ty, _>(|_| #crate_name::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value),
@ -53,10 +53,7 @@ pub fn generate(
specified_by_url: #specified_by_url,
})
}
}
#[allow(clippy::all, clippy::pedantic)]
impl #generic #crate_name::InputType for #self_ty #where_clause {
fn parse(value: ::std::option::Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
<#self_ty as #crate_name::ScalarType>::parse(value.unwrap_or_default())
}
@ -69,6 +66,20 @@ pub fn generate(
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #generic #crate_name::OutputType for #self_ty #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_output_type::<#self_ty, _>(|_| #crate_name::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value),
visible: #visible,
specified_by_url: #specified_by_url,
})
}
async fn resolve(
&self,
_: &#crate_name::ContextSelectionSet<'_>,

View File

@ -157,7 +157,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
name: ::std::borrow::ToOwned::to_owned(#field_name),
description: #field_desc,
args: ::std::default::Default::default(),
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::OutputType>::create_type_info(registry),
deprecation: #field_deprecation,
cache_control: #cache_control,
external: #external,
@ -225,7 +225,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
});
}
if !object_args.dummy && resolvers.is_empty() {
if !object_args.fake && resolvers.is_empty() {
return Err(Error::new_spanned(
&ident,
"A GraphQL Object type must define one or more fields.",
@ -274,13 +274,25 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
}
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#(#resolvers)*
#complex_resolver
::std::result::Result::Ok(::std::option::Option::None)
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
registry.create_output_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
fields: {
@ -297,22 +309,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
rust_typename: ::std::any::type_name::<Self>(),
})
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#(#resolvers)*
#complex_resolver
::std::result::Result::Ok(::std::option::Option::None)
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
#resolve_container
}
@ -332,7 +329,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
name: &str,
complex_fields: #crate_name::indexmap::IndexMap<::std::string::String, #crate_name::registry::MetaField>,
) -> ::std::string::String where Self: #crate_name::OutputType {
registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
registry.create_output_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(name),
description: #desc,
fields: {
@ -363,19 +360,6 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
let concrete_type = quote! { #ident<#(#params),*> };
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::Type for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
let mut fields = #crate_name::indexmap::IndexMap::new();
#concat_complex_fields
Self::__internal_create_type_info(registry, #gql_typename, fields)
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #crate_name::resolver_utils::ContainerType for #concrete_type {
@ -388,6 +372,16 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #crate_name::OutputType for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
let mut fields = #crate_name::indexmap::IndexMap::new();
#concat_complex_fields
Self::__internal_create_type_info(registry, #gql_typename, fields)
}
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
#resolve_container
}

View File

@ -191,7 +191,7 @@ pub fn generate(
args.insert(#name, #crate_name::registry::MetaInputValue {
name: #name,
description: #desc,
ty: <#ty as #crate_name::Type>::create_type_info(registry),
ty: <#ty as #crate_name::InputType>::create_type_info(registry),
default_value: #schema_default,
validator: #validator,
visible: #visible,
@ -303,7 +303,7 @@ pub fn generate(
#(#schema_args)*
args
},
ty: <<#stream_ty as #crate_name::futures_util::stream::Stream>::Item as #crate_name::Type>::create_type_info(registry),
ty: <<#stream_ty as #crate_name::futures_util::stream::Stream>::Item as #crate_name::OutputType>::create_type_info(registry),
deprecation: #field_deprecation,
cache_control: ::std::default::Default::default(),
external: false,
@ -364,7 +364,7 @@ pub fn generate(
let ri = #crate_name::extensions::ResolveInfo {
path_node: ctx_selection_set.path_node.as_ref().unwrap(),
parent_type: #gql_typename,
return_type: &<<#stream_ty as #crate_name::futures_util::stream::Stream>::Item as #crate_name::Type>::qualified_type_name(),
return_type: &<<#stream_ty as #crate_name::futures_util::stream::Stream>::Item as #crate_name::OutputType>::qualified_type_name(),
name: field.node.name.node.as_str(),
alias: field.node.alias.as_ref().map(|alias| alias.node.as_str()),
};
@ -437,14 +437,15 @@ pub fn generate(
#item_impl
#[allow(clippy::all, clippy::pedantic)]
impl #generics #crate_name::Type for #self_ty #where_clause {
#[allow(unused_braces, unused_variables)]
impl #generics #crate_name::SubscriptionType for #self_ty #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
#[allow(bare_trait_objects)]
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
registry.create_subscription_type::<Self, _>(|registry| #crate_name::registry::MetaType::Object {
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
description: #desc,
fields: {
@ -460,11 +461,7 @@ pub fn generate(
rust_typename: ::std::any::type_name::<Self>(),
})
}
}
#[allow(clippy::all, clippy::pedantic)]
#[allow(unused_braces, unused_variables)]
impl #generics #crate_name::SubscriptionType for #self_ty #where_clause {
fn create_field_stream<'__life>(
&'__life self,
ctx: &'__life #crate_name::Context<'_>,

View File

@ -74,9 +74,9 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
enum_names.push(enum_name);
union_values.push(quote! {
union_values.insert(
<#p as #crate_name::Type>::type_name().into_owned(),
<#p as #crate_name::OutputType>::type_name().into_owned(),
#crate_name::registry::MetaUnionValue {
name: <#p as #crate_name::Type>::type_name().into_owned(),
name: <#p as #crate_name::OutputType>::type_name().into_owned(),
visible: #union_visible,
}
);
@ -119,15 +119,15 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
if !variant.flatten {
registry_types.push(quote! {
<#p as #crate_name::Type>::create_type_info(registry);
<#p as #crate_name::OutputType>::create_type_info(registry);
});
possible_types.push(quote! {
possible_types.insert(<#p as #crate_name::Type>::type_name().into_owned());
possible_types.insert(<#p as #crate_name::OutputType>::type_name().into_owned());
});
} else {
possible_types.push(quote! {
if let #crate_name::registry::MetaType::Union { possible_types: possible_types2, .. } =
registry.create_dummy_type::<#p>() {
registry.create_fake_output_type::<#p>() {
possible_types.extend(possible_types2);
}
});
@ -135,11 +135,11 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
if !variant.flatten {
get_introspection_typename.push(quote! {
#ident::#enum_name(obj) => <#p as #crate_name::Type>::type_name()
#ident::#enum_name(obj) => <#p as #crate_name::OutputType>::type_name()
});
} else {
get_introspection_typename.push(quote! {
#ident::#enum_name(obj) => <#p as #crate_name::Type>::introspection_type_name(obj)
#ident::#enum_name(obj) => <#p as #crate_name::OutputType>::introspection_type_name(obj)
});
}
@ -164,7 +164,23 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
#(#type_into_impls)*
#[allow(clippy::all, clippy::pedantic)]
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
::std::result::Result::Ok(::std::option::Option::None)
}
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
@ -176,7 +192,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
}
fn create_type_info(registry: &mut #crate_name::registry::Registry) -> ::std::string::String {
registry.create_type::<Self, _>(|registry| {
registry.create_output_type::<Self, _>(|registry| {
#(#registry_types)*
#crate_name::registry::MetaType::Union {
@ -197,26 +213,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
}
})
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::resolver_utils::ContainerType for #ident #ty_generics #where_clause {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
::std::result::Result::Ok(::std::option::Option::None)
}
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}
}
}
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
#crate_name::resolver_utils::resolve_container(ctx, self).await
}

View File

@ -15,10 +15,35 @@ pub trait Description {
fn description() -> &'static str;
}
/// Represents a GraphQL type.
///
/// All GraphQL types implement this trait, such as `Scalar`, `Object`, `Union` ...
pub trait Type {
/// Represents a GraphQL input type.
pub trait InputType: Send + Sync + Sized {
/// Type the name.
fn type_name() -> Cow<'static, str>;
/// Qualified typename.
fn qualified_type_name() -> String {
format!("{}!", Self::type_name())
}
/// Create type information in the registry and return qualified typename.
fn create_type_info(registry: &mut registry::Registry) -> String;
/// Parse from `Value`. None represents undefined.
fn parse(value: Option<Value>) -> InputValueResult<Self>;
/// Convert to a `Value` for introspection.
fn to_value(&self) -> Value;
/// Get the federation fields, only for InputObject.
#[doc(hidden)]
fn federation_fields() -> Option<String> {
None
}
}
/// Represents a GraphQL output type.
#[async_trait::async_trait]
pub trait OutputType: Send + Sync {
/// Type the name.
fn type_name() -> Cow<'static, str>;
@ -36,26 +61,7 @@ pub trait Type {
/// Create type information in the registry and return qualified typename.
fn create_type_info(registry: &mut registry::Registry) -> String;
}
/// Represents a GraphQL input value.
pub trait InputType: Type + Send + Sync + Sized {
/// Parse from `Value`. None represents undefined.
fn parse(value: Option<Value>) -> InputValueResult<Self>;
/// Convert to a `Value` for introspection.
fn to_value(&self) -> Value;
/// Get the federation fields, only for InputObject.
#[doc(hidden)]
fn federation_fields() -> Option<String> {
None
}
}
/// Represents a GraphQL output value.
#[async_trait::async_trait]
pub trait OutputType: Type + Send + Sync {
/// Resolve an output value to `async_graphql::Value`.
async fn resolve(
&self,
@ -64,7 +70,8 @@ pub trait OutputType: Type + Send + Sync {
) -> ServerResult<Value>;
}
impl<T: Type + ?Sized> Type for &T {
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for &T {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -72,10 +79,7 @@ impl<T: Type + ?Sized> Type for &T {
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for &T {
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn resolve(
&self,
@ -86,22 +90,16 @@ impl<T: OutputType + ?Sized> OutputType for &T {
}
}
impl<T: Type, E: Into<Error> + Send + Sync + Clone> Type for Result<T, E> {
#[async_trait::async_trait]
impl<T: OutputType + Sync, E: Into<Error> + Send + Sync + Clone> OutputType for Result<T, E> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn qualified_type_name() -> String {
T::qualified_type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl<T: OutputType + Sync, E: Into<Error> + Send + Sync + Clone> OutputType for Result<T, E> {
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,
@ -131,7 +129,8 @@ pub trait UnionType: ContainerType {}
/// A GraphQL input object.
pub trait InputObjectType: InputType {}
impl<T: Type + ?Sized> Type for Box<T> {
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for Box<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -139,10 +138,7 @@ impl<T: Type + ?Sized> Type for Box<T> {
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for Box<T> {
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn resolve(
&self,
@ -155,6 +151,14 @@ impl<T: OutputType + ?Sized> OutputType for Box<T> {
#[async_trait::async_trait]
impl<T: InputType> InputType for Box<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
fn parse(value: Option<ConstValue>) -> InputValueResult<Self> {
T::parse(value)
.map(Box::new)
@ -166,7 +170,8 @@ impl<T: InputType> InputType for Box<T> {
}
}
impl<T: Type + ?Sized> Type for Arc<T> {
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for Arc<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -174,10 +179,7 @@ impl<T: Type + ?Sized> Type for Arc<T> {
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl<T: OutputType + ?Sized> OutputType for Arc<T> {
#[allow(clippy::trivially_copy_pass_by_ref)]
async fn resolve(
&self,
@ -189,6 +191,14 @@ impl<T: OutputType + ?Sized> OutputType for Arc<T> {
}
impl<T: InputType> InputType for Arc<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
fn parse(value: Option<ConstValue>) -> InputValueResult<Self> {
T::parse(value)
.map(Arc::new)

View File

@ -206,7 +206,7 @@ pub use async_graphql_value::{
};
pub use base::{
ComplexObject, Description, InputObjectType, InputType, InterfaceType, ObjectType, OutputType,
Type, UnionType,
UnionType,
};
pub use error::{
Error, ErrorExtensionValues, ErrorExtensions, InputValueError, InputValueResult,

View File

@ -12,7 +12,10 @@ use crate::parser::types::{
BaseType as ParsedBaseType, Field, Type as ParsedType, VariableDefinition,
};
use crate::validators::InputValueValidator;
use crate::{model, Any, Context, Positioned, ServerResult, Type, Value, VisitorContext};
use crate::{
model, Any, Context, InputType, OutputType, Positioned, ServerResult, SubscriptionType, Value,
VisitorContext,
};
pub use cache_control::CacheControl;
@ -375,15 +378,41 @@ pub struct Registry {
}
impl Registry {
pub fn create_type<T: crate::Type + ?Sized, F: FnMut(&mut Registry) -> MetaType>(
pub fn create_input_type<T: InputType + ?Sized, F: FnMut(&mut Registry) -> MetaType>(
&mut self,
mut f: F,
) -> String {
let name = T::type_name();
self.create_type(&mut f, &*T::type_name(), std::any::type_name::<T>());
T::qualified_type_name()
}
match self.types.get(name.as_ref()) {
pub fn create_output_type<T: OutputType + ?Sized, F: FnMut(&mut Registry) -> MetaType>(
&mut self,
mut f: F,
) -> String {
self.create_type(&mut f, &*T::type_name(), std::any::type_name::<T>());
T::qualified_type_name()
}
pub fn create_subscription_type<
T: SubscriptionType + ?Sized,
F: FnMut(&mut Registry) -> MetaType,
>(
&mut self,
mut f: F,
) -> String {
self.create_type(&mut f, &*T::type_name(), std::any::type_name::<T>());
T::qualified_type_name()
}
fn create_type<F: FnMut(&mut Registry) -> MetaType>(
&mut self,
f: &mut F,
name: &str,
rust_typename: &str,
) {
match self.types.get(name) {
Some(ty) => {
let rust_typename = std::any::type_name::<T>();
if let Some(prev_typename) = ty.rust_typename() {
if prev_typename != "__fake_type__" && rust_typename != prev_typename {
panic!(
@ -396,7 +425,7 @@ impl Registry {
None => {
// Inserting a fake type before calling the function allows recursive types to exist.
self.types.insert(
name.clone().into_owned(),
name.to_string(),
MetaType::Object {
name: "".to_string(),
description: None,
@ -413,11 +442,25 @@ impl Registry {
*self.types.get_mut(&*name).unwrap() = ty;
}
}
T::qualified_type_name()
}
pub fn create_dummy_type<T: Type>(&mut self) -> MetaType {
pub fn create_fake_output_type<T: OutputType>(&mut self) -> MetaType {
T::create_type_info(self);
self.types
.get(&*T::type_name())
.cloned()
.expect("You definitely encountered a bug!")
}
pub fn create_fake_input_type<T: InputType>(&mut self) -> MetaType {
T::create_type_info(self);
self.types
.get(&*T::type_name())
.cloned()
.expect("You definitely encountered a bug!")
}
pub fn create_fake_subscription_type<T: SubscriptionType>(&mut self) -> MetaType {
T::create_type_info(self);
self.types
.get(&*T::type_name())
@ -512,7 +555,7 @@ impl Registry {
}
pub(crate) fn create_federation_types(&mut self) {
Any::create_type_info(self);
<Any as InputType>::create_type_info(self);
self.types.insert(
"_Service".to_string(),
@ -647,8 +690,8 @@ impl Registry {
names.into_iter().collect()
}
pub fn set_description<T: Type>(&mut self, desc: &'static str) {
match self.types.get_mut(&*T::type_name()) {
pub fn set_description(&mut self, name: &str, desc: &'static str) {
match self.types.get_mut(name) {
Some(MetaType::Scalar { description, .. }) => *description = Some(desc),
Some(MetaType::Object { description, .. }) => *description = Some(desc),
Some(MetaType::Interface { description, .. }) => *description = Some(desc),

View File

@ -1,4 +1,4 @@
use crate::{InputType, InputValueError, InputValueResult, Name, Type, Value};
use crate::{InputType, InputValueError, InputValueResult, Name, Value};
/// A variant of an enum.
pub struct EnumItem<T> {
@ -9,7 +9,7 @@ pub struct EnumItem<T> {
}
/// A GraphQL enum.
pub trait EnumType: Type + Sized + Eq + Send + Copy + Sized + 'static {
pub trait EnumType: Sized + Eq + Send + Copy + Sized + 'static {
/// Get a list of possible variants of the enum and their values.
fn items() -> &'static [EnumItem<Self>];
}

View File

@ -1,6 +1,6 @@
use crate::extensions::ResolveInfo;
use crate::parser::types::Field;
use crate::{ContextSelectionSet, OutputType, Positioned, ServerResult, Type, Value};
use crate::{ContextSelectionSet, OutputType, Positioned, ServerResult, Value};
/// Resolve an list by executing each of the items concurrently.
pub async fn resolve_list<'a, T: OutputType + 'a>(

View File

@ -136,24 +136,6 @@ macro_rules! scalar {
#[doc(hidden)]
macro_rules! scalar_internal {
($ty:ty, $name:expr, $desc:expr, $specified_by_url:expr) => {
impl $crate::Type for $ty {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed($name)
}
fn create_type_info(
registry: &mut $crate::registry::Registry,
) -> ::std::string::String {
registry.create_type::<$ty, _>(|_| $crate::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned($name),
description: $desc,
is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value),
visible: ::std::option::Option::None,
specified_by_url: $specified_by_url,
})
}
}
impl $crate::ScalarType for $ty {
fn parse(value: $crate::Value) -> $crate::InputValueResult<Self> {
::std::result::Result::Ok($crate::from_value(value)?)
@ -165,6 +147,22 @@ macro_rules! scalar_internal {
}
impl $crate::InputType for $ty {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed($name)
}
fn create_type_info(
registry: &mut $crate::registry::Registry,
) -> ::std::string::String {
registry.create_input_type::<$ty, _>(|_| $crate::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned($name),
description: $desc,
is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value),
visible: ::std::option::Option::None,
specified_by_url: $specified_by_url,
})
}
fn parse(
value: ::std::option::Option<$crate::Value>,
) -> $crate::InputValueResult<Self> {
@ -178,6 +176,22 @@ macro_rules! scalar_internal {
#[$crate::async_trait::async_trait]
impl $crate::OutputType for $ty {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed($name)
}
fn create_type_info(
registry: &mut $crate::registry::Registry,
) -> ::std::string::String {
registry.create_output_type::<$ty, _>(|_| $crate::registry::MetaType::Scalar {
name: ::std::borrow::ToOwned::to_owned($name),
description: $desc,
is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value),
visible: ::std::option::Option::None,
specified_by_url: $specified_by_url,
})
}
async fn resolve(
&self,
_: &$crate::ContextSelectionSet<'_>,

View File

@ -16,8 +16,8 @@ use crate::subscription::collect_subscription_streams;
use crate::types::QueryRoot;
use crate::validation::{check_rules, ValidationMode};
use crate::{
BatchRequest, BatchResponse, CacheControl, ContextBase, ObjectType, QueryEnv, Request,
Response, ServerError, SubscriptionType, Type, ID,
BatchRequest, BatchResponse, CacheControl, ContextBase, InputType, ObjectType, OutputType,
QueryEnv, Request, Response, ServerError, SubscriptionType, ID,
};
/// Schema builder
@ -34,10 +34,18 @@ pub struct SchemaBuilder<Query, Mutation, Subscription> {
}
impl<Query, Mutation, Subscription> SchemaBuilder<Query, Mutation, Subscription> {
/// Manually register a type in the schema.
/// Manually register a input type in the schema.
///
/// You can use this function to register schema types that are not directly referenced.
pub fn register_type<T: Type>(mut self) -> Self {
pub fn register_input_type<T: InputType>(mut self) -> Self {
T::create_type_info(&mut self.registry);
self
}
/// Manually register a output type in the schema.
///
/// You can use this function to register schema types that are not directly referenced.
pub fn register_output_type<T: OutputType>(mut self) -> Self {
T::create_type_info(&mut self.registry);
self
}
@ -111,9 +119,15 @@ impl<Query, Mutation, Subscription> SchemaBuilder<Query, Mutation, Subscription>
self
}
/// Override the name of the specified type.
pub fn override_description<T: Type>(mut self, desc: &'static str) -> Self {
self.registry.set_description::<T>(desc);
/// Override the name of the specified input type.
pub fn override_input_type_description<T: InputType>(mut self, desc: &'static str) -> Self {
self.registry.set_description(&*T::type_name(), desc);
self
}
/// Override the name of the specified output type.
pub fn override_output_type_description<T: OutputType>(mut self, desc: &'static str) -> Self {
self.registry.set_description(&*T::type_name(), desc);
self
}
@ -308,11 +322,11 @@ where
});
// register scalars
bool::create_type_info(&mut registry);
i32::create_type_info(&mut registry);
f32::create_type_info(&mut registry);
String::create_type_info(&mut registry);
ID::create_type_info(&mut registry);
<bool as InputType>::create_type_info(&mut registry);
<i32 as InputType>::create_type_info(&mut registry);
<f32 as InputType>::create_type_info(&mut registry);
<String as InputType>::create_type_info(&mut registry);
<ID as InputType>::create_type_info(&mut registry);
QueryRoot::<Query>::create_type_info(&mut registry);
if !Mutation::is_empty() {

View File

@ -1,12 +1,27 @@
use std::borrow::Cow;
use std::pin::Pin;
use futures_util::stream::{Stream, StreamExt};
use crate::parser::types::{Selection, TypeCondition};
use crate::{Context, ContextSelectionSet, PathSegment, Response, ServerError, ServerResult, Type};
use crate::registry::Registry;
use crate::{
registry, Context, ContextSelectionSet, PathSegment, Response, ServerError, ServerResult,
};
/// A GraphQL subscription object
pub trait SubscriptionType: Type + Send + Sync {
pub trait SubscriptionType: Send + Sync {
/// Type the name.
fn type_name() -> Cow<'static, str>;
/// Qualified typename.
fn qualified_type_name() -> String {
format!("{}!", Self::type_name())
}
/// Create type information in the registry and return qualified typename.
fn create_type_info(registry: &mut registry::Registry) -> String;
/// This function returns true of type `EmptySubscription` only.
#[doc(hidden)]
fn is_empty() -> bool {
@ -90,6 +105,14 @@ pub(crate) fn collect_subscription_streams<'a, T: SubscriptionType + 'static>(
}
impl<T: SubscriptionType> SubscriptionType for &T {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut Registry) -> String {
T::create_type_info(registry)
}
fn create_field_stream<'a>(
&'a self,
ctx: &'a Context<'_>,

View File

@ -10,7 +10,7 @@ use crate::resolver_utils::{resolve_container, ContainerType};
use crate::types::connection::{CursorType, EmptyFields};
use crate::{
registry, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, Result,
ServerResult, Type, Value,
ServerResult, Value,
};
/// Connection type
@ -119,84 +119,6 @@ impl<C, T, EC, EE> Connection<C, T, EC, EE> {
}
}
impl<C, T, EC, EE> Type for Connection<C, T, EC, EE>
where
C: CursorType,
T: OutputType,
EC: ObjectType,
EE: ObjectType,
{
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("{}Connection", T::type_name()))
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_type::<Self, _>(|registry| {
EC::create_type_info(registry);
let additional_fields = if let Some(registry::MetaType::Object { fields, .. }) =
registry.types.remove(EC::type_name().as_ref())
{
fields
} else {
unreachable!()
};
registry::MetaType::Object {
name: Self::type_name().to_string(),
description: None,
fields: {
let mut fields = IndexMap::new();
fields.insert(
"pageInfo".to_string(),
registry::MetaField {
name: "pageInfo".to_string(),
description: Some("Information to aid in pagination."),
args: Default::default(),
ty: PageInfo::create_type_info(registry),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.insert(
"edges".to_string(),
registry::MetaField {
name: "edges".to_string(),
description: Some("A list of edges."),
args: Default::default(),
ty: <Option<Vec<Option<Edge<C, T, EE>>>> as Type>::create_type_info(
registry,
),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.extend(additional_fields);
fields
},
cache_control: Default::default(),
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
}
})
}
}
#[async_trait::async_trait]
impl<C, T, EC, EE> ContainerType for Connection<C, T, EC, EE>
where
@ -236,6 +158,76 @@ where
EC: ObjectType,
EE: ObjectType,
{
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("{}Connection", T::type_name()))
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_output_type::<Self, _>(|registry| {
EC::create_type_info(registry);
let additional_fields = if let Some(registry::MetaType::Object { fields, .. }) =
registry.types.remove(EC::type_name().as_ref())
{
fields
} else {
unreachable!()
};
registry::MetaType::Object {
name: Self::type_name().to_string(),
description: None,
fields: {
let mut fields = IndexMap::new();
fields.insert(
"pageInfo".to_string(),
registry::MetaField {
name: "pageInfo".to_string(),
description: Some("Information to aid in pagination."),
args: Default::default(),
ty: PageInfo::create_type_info(registry),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.insert(
"edges".to_string(),
registry::MetaField {
name: "edges".to_string(),
description: Some("A list of edges."),
args: Default::default(),
ty: <Option<Vec<Option<Edge<C, T, EE>>>> as OutputType>::create_type_info(
registry,
),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.extend(additional_fields);
fields
},
cache_control: Default::default(),
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
}
})
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -7,8 +7,7 @@ use crate::parser::types::Field;
use crate::resolver_utils::{resolve_container, ContainerType};
use crate::types::connection::CursorType;
use crate::{
registry, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, ServerResult, Type,
Value,
registry, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, ServerResult, Value,
};
/// The edge type output by the data source
@ -40,9 +39,31 @@ impl<C: CursorType, T> Edge<C, T, EmptyFields> {
}
}
impl<C, T, E> Type for Edge<C, T, E>
#[async_trait::async_trait]
impl<C, T, E> ContainerType for Edge<C, T, E>
where
C: CursorType,
C: CursorType + Send + Sync,
T: OutputType,
E: ObjectType,
{
async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>> {
if ctx.item.node.name.node == "node" {
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
return OutputType::resolve(&self.node, &ctx_obj, ctx.item)
.await
.map(Some);
} else if ctx.item.node.name.node == "cursor" {
return Ok(Some(Value::String(self.cursor.encode_cursor())));
}
self.additional_fields.resolve_field(ctx).await
}
}
#[async_trait::async_trait]
impl<C, T, E> OutputType for Edge<C, T, E>
where
C: CursorType + Send + Sync,
T: OutputType,
E: ObjectType,
{
@ -51,9 +72,9 @@ where
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_type::<Self, _>(|registry| {
registry.create_output_type::<Self, _>(|registry| {
let additional_fields = if let registry::MetaType::Object { fields, .. } =
registry.create_dummy_type::<E>()
registry.create_fake_output_type::<E>()
{
fields
} else {
@ -112,36 +133,7 @@ where
}
})
}
}
#[async_trait::async_trait]
impl<C, T, E> ContainerType for Edge<C, T, E>
where
C: CursorType + Send + Sync,
T: OutputType,
E: ObjectType,
{
async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>> {
if ctx.item.node.name.node == "node" {
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
return OutputType::resolve(&self.node, &ctx_obj, ctx.item)
.await
.map(Some);
} else if ctx.item.node.name.node == "cursor" {
return Ok(Some(Value::String(self.cursor.encode_cursor())));
}
self.additional_fields.resolve_field(ctx).await
}
}
#[async_trait::async_trait]
impl<C, T, E> OutputType for Edge<C, T, E>
where
C: CursorType + Send + Sync,
T: OutputType,
E: ObjectType,
{
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -16,7 +16,7 @@ pub use page_info::PageInfo;
/// Empty additional fields
#[derive(SimpleObject)]
#[graphql(internal, dummy)]
#[graphql(internal, fake)]
pub struct EmptyFields;
/// Parses the parameters and executes the query.

View File

@ -4,7 +4,7 @@ use crate::parser::types::Field;
use crate::resolver_utils::ContainerType;
use crate::{
registry, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, ServerError,
ServerResult, Type, Value,
ServerResult, Value,
};
/// Empty mutation
@ -31,26 +31,6 @@ use crate::{
#[derive(Default, Copy, Clone)]
pub struct EmptyMutation;
impl Type for EmptyMutation {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("EmptyMutation")
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_type::<Self, _>(|_| registry::MetaType::Object {
name: "EmptyMutation".to_string(),
description: None,
fields: Default::default(),
cache_control: Default::default(),
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
})
}
}
#[async_trait::async_trait]
impl ContainerType for EmptyMutation {
fn is_empty() -> bool {
@ -64,6 +44,24 @@ impl ContainerType for EmptyMutation {
#[async_trait::async_trait]
impl OutputType for EmptyMutation {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("EmptyMutation")
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_output_type::<Self, _>(|_| registry::MetaType::Object {
name: "EmptyMutation".to_string(),
description: None,
fields: Default::default(),
cache_control: Default::default(),
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
})
}
async fn resolve(
&self,
_ctx: &ContextSelectionSet<'_>,

View File

@ -3,7 +3,7 @@ use std::pin::Pin;
use futures_util::stream::{self, Stream};
use crate::{registry, Context, Response, ServerError, SubscriptionType, Type};
use crate::{registry, Context, Response, ServerError, SubscriptionType};
/// Empty subscription
///
@ -11,13 +11,13 @@ use crate::{registry, Context, Response, ServerError, SubscriptionType, Type};
#[derive(Default, Copy, Clone)]
pub struct EmptySubscription;
impl Type for EmptySubscription {
impl SubscriptionType for EmptySubscription {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("EmptyMutation")
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_type::<Self, _>(|_| registry::MetaType::Object {
registry.create_subscription_type::<Self, _>(|_| registry::MetaType::Object {
name: "EmptySubscription".to_string(),
description: None,
fields: Default::default(),
@ -29,9 +29,7 @@ impl Type for EmptySubscription {
rust_typename: std::any::type_name::<Self>(),
})
}
}
impl SubscriptionType for EmptySubscription {
fn is_empty() -> bool {
true
}

View File

@ -1,28 +1,22 @@
use std::borrow::Cow;
use bytes::Bytes;
use crate::parser::types::Field;
use crate::parser::Positioned;
use crate::{registry, ContextSelectionSet, OutputType, ServerResult, Type, Value};
use crate::{InputValueError, InputValueResult, Scalar, ScalarType, Value};
impl Type for Bytes {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("Binary")
/// The `Binary` scalar type represents binary data.
#[Scalar(internal)]
impl ScalarType for Bytes {
fn parse(value: Value) -> InputValueResult<Self> {
match value {
Value::Binary(data) => Ok(data),
_ => Err(InputValueError::expected_type(value)),
}
}
fn create_type_info(registry: &mut registry::Registry) -> String {
<String as Type>::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl OutputType for Bytes {
async fn resolve(
&self,
_: &ContextSelectionSet<'_>,
_field: &Positioned<Field>,
) -> ServerResult<Value> {
Ok(Value::Binary(self.clone()))
fn is_valid(value: &Value) -> bool {
matches!(value, Value::Binary(_))
}
fn to_value(&self) -> Value {
Value::Binary(self.clone())
}
}

View File

@ -2,20 +2,7 @@ use std::borrow::Cow;
use async_graphql_parser::types::Field;
use crate::{registry, ContextSelectionSet, OutputType, Positioned, ServerResult, Type, Value};
impl<'a, T> Type for Cow<'a, T>
where
T: Type + ToOwned + ?Sized + Send + Sync,
{
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
<T as Type>::create_type_info(registry)
}
}
use crate::{registry, ContextSelectionSet, OutputType, Positioned, ServerResult, Value};
#[async_trait::async_trait]
impl<'a, T> OutputType for Cow<'a, T>
@ -23,6 +10,14 @@ where
T: OutputType + ToOwned + ?Sized,
<T as ToOwned>::Owned: Send + Sync,
{
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
<T as OutputType>::create_type_info(registry)
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -4,10 +4,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, ServerResult, Type, Value,
Positioned, ServerResult, Value,
};
impl<T: Type, const N: usize> Type for [T; N] {
impl<T: InputType, const N: usize> InputType for [T; N] {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -20,9 +20,7 @@ impl<T: Type, const N: usize> Type for [T; N] {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType, const N: usize> InputType for [T; N] {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
if let Some(Value::List(values)) = value {
let items: Vec<T> = values
@ -52,6 +50,19 @@ impl<T: InputType, const N: usize> InputType for [T; N] {
#[async_trait::async_trait]
impl<T: OutputType, const N: usize> OutputType for [T; N] {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -5,10 +5,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, ServerResult, Type, Value,
Positioned, ServerResult, Value,
};
impl<T: Type> Type for BTreeSet<T> {
impl<T: InputType + Ord> InputType for BTreeSet<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -21,9 +21,7 @@ impl<T: Type> Type for BTreeSet<T> {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType + Ord> InputType for BTreeSet<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::List(values) => values
@ -46,6 +44,19 @@ impl<T: InputType + Ord> InputType for BTreeSet<T> {
#[async_trait::async_trait]
impl<T: OutputType + Ord> OutputType for BTreeSet<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -7,10 +7,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, Result, ServerResult, Type, Value,
Positioned, Result, ServerResult, Value,
};
impl<T: Type> Type for HashSet<T> {
impl<T: InputType + Hash + Eq> InputType for HashSet<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -23,9 +23,7 @@ impl<T: Type> Type for HashSet<T> {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType + Hash + Eq> InputType for HashSet<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::List(values) => values
@ -48,6 +46,19 @@ impl<T: InputType + Hash + Eq> InputType for HashSet<T> {
#[async_trait::async_trait]
impl<T: OutputType + Hash + Eq> OutputType for HashSet<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -5,10 +5,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, ServerResult, Type, Value,
Positioned, ServerResult, Value,
};
impl<T: Type> Type for LinkedList<T> {
impl<T: InputType> InputType for LinkedList<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -21,9 +21,7 @@ impl<T: Type> Type for LinkedList<T> {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType> InputType for LinkedList<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::List(values) => values
@ -47,6 +45,19 @@ impl<T: InputType> InputType for LinkedList<T> {
#[async_trait::async_trait]
impl<T: OutputType> OutputType for LinkedList<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -2,9 +2,10 @@ use std::borrow::Cow;
use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{registry, ContextSelectionSet, OutputType, Positioned, ServerResult, Type, Value};
use crate::{registry, ContextSelectionSet, OutputType, Positioned, ServerResult, Value};
impl<'a, T: Type + 'a> Type for &'a [T] {
#[async_trait::async_trait]
impl<'a, T: OutputType + 'a> OutputType for &'a [T] {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -17,10 +18,7 @@ impl<'a, T: Type + 'a> Type for &'a [T] {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
#[async_trait::async_trait]
impl<T: OutputType> OutputType for &[T] {
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -4,10 +4,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, Result, ServerResult, Type, Value,
Positioned, Result, ServerResult, Value,
};
impl<T: Type> Type for Vec<T> {
impl<T: InputType> InputType for Vec<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -20,9 +20,7 @@ impl<T: Type> Type for Vec<T> {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType> InputType for Vec<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::List(values) => values
@ -43,6 +41,19 @@ impl<T: InputType> InputType for Vec<T> {
#[async_trait::async_trait]
impl<T: OutputType> OutputType for Vec<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -5,10 +5,10 @@ use crate::parser::types::Field;
use crate::resolver_utils::resolve_list;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, ServerResult, Type, Value,
Positioned, ServerResult, Value,
};
impl<T: Type> Type for VecDeque<T> {
impl<T: InputType> InputType for VecDeque<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
@ -21,9 +21,7 @@ impl<T: Type> Type for VecDeque<T> {
T::create_type_info(registry);
Self::qualified_type_name()
}
}
impl<T: InputType> InputType for VecDeque<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::List(values) => values
@ -47,6 +45,19 @@ impl<T: InputType> InputType for VecDeque<T> {
#[async_trait::async_trait]
impl<T: OutputType> OutputType for VecDeque<T> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("[{}]", T::qualified_type_name()))
}
fn qualified_type_name() -> String {
format!("[{}]!", T::qualified_type_name())
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
Self::qualified_type_name()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -3,10 +3,10 @@ use std::borrow::Cow;
use crate::parser::types::Field;
use crate::{
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
Positioned, ServerResult, Type, Value,
Positioned, ServerResult, Value,
};
impl<T: Type> Type for Option<T> {
impl<T: InputType> InputType for Option<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -19,9 +19,7 @@ impl<T: Type> Type for Option<T> {
T::create_type_info(registry);
T::type_name().to_string()
}
}
impl<T: InputType> InputType for Option<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value.unwrap_or_default() {
Value::Null => Ok(None),
@ -41,6 +39,19 @@ impl<T: InputType> InputType for Option<T> {
#[async_trait::async_trait]
impl<T: OutputType + Sync> OutputType for Option<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn qualified_type_name() -> String {
T::type_name().to_string()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
T::type_name().to_string()
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,
@ -62,7 +73,7 @@ impl<T: OutputType + Sync> OutputType for Option<T> {
#[cfg(test)]
mod tests {
use crate::Type;
use crate::InputType;
#[test]
fn test_optional_type() {

View File

@ -2,9 +2,9 @@ use std::borrow::Cow;
use secrecy::{Secret, Zeroize};
use crate::{registry, InputType, InputValueError, InputValueResult, Type, Value};
use crate::{registry, InputType, InputValueError, InputValueResult, Value};
impl<T: Type + Zeroize> Type for Secret<T> {
impl<T: InputType + Zeroize> InputType for Secret<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -16,9 +16,7 @@ impl<T: Type + Zeroize> Type for Secret<T> {
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry)
}
}
impl<T: InputType + Zeroize> InputType for Secret<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
T::parse(value)
.map(Secret::new)

View File

@ -3,7 +3,7 @@ use std::borrow::Cow;
use crate::parser::types::Field;
use crate::{
registry, ContextSelectionSet, InputValueError, InputValueResult, OutputType, Positioned,
Scalar, ScalarType, ServerResult, Type, Value,
Scalar, ScalarType, ServerResult, Value,
};
/// The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
@ -25,18 +25,16 @@ impl ScalarType for String {
}
}
impl Type for str {
#[async_trait::async_trait]
impl OutputType for str {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("String")
}
fn create_type_info(registry: &mut registry::Registry) -> String {
<String as Type>::create_type_info(registry)
<String as OutputType>::create_type_info(registry)
}
}
#[async_trait::async_trait]
impl OutputType for str {
async fn resolve(
&self,
_: &ContextSelectionSet<'_>,

View File

@ -8,7 +8,7 @@ use crate::parser::types::Field;
use crate::registry::{MetaType, Registry};
use crate::{
from_value, to_value, ContextSelectionSet, InputValueError, InputValueResult, OutputType,
Positioned, Scalar, ScalarType, ServerResult, Type, Value,
Positioned, Scalar, ScalarType, ServerResult, Value,
};
/// A scalar that can represent any JSON value.
@ -74,13 +74,14 @@ impl<T: Serialize> From<T> for OutputJson<T> {
}
}
impl<T> Type for OutputJson<T> {
#[async_trait::async_trait]
impl<T: Serialize + Send + Sync> OutputType for OutputJson<T> {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("Json")
}
fn create_type_info(registry: &mut Registry) -> String {
registry.create_type::<OutputJson<T>, _>(|_| MetaType::Scalar {
registry.create_output_type::<OutputJson<T>, _>(|_| MetaType::Scalar {
name: Self::type_name().to_string(),
description: None,
is_valid: |_| true,
@ -88,10 +89,7 @@ impl<T> Type for OutputJson<T> {
specified_by_url: None,
})
}
}
#[async_trait::async_trait]
impl<T: Serialize + Send + Sync> OutputType for OutputJson<T> {
async fn resolve(
&self,
_ctx: &ContextSelectionSet<'_>,

View File

@ -3,7 +3,7 @@ use std::ops::Deref;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{registry, InputType, InputValueError, InputValueResult, Type, Value};
use crate::{registry, InputType, InputValueError, InputValueResult, Value};
/// Similar to `Option`, but it has three states, `undefined`, `null` and `x`.
///
@ -174,7 +174,7 @@ impl<T> MaybeUndefined<T> {
}
}
impl<T: Type> Type for MaybeUndefined<T> {
impl<T: InputType> InputType for MaybeUndefined<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
@ -187,9 +187,7 @@ impl<T: Type> Type for MaybeUndefined<T> {
T::create_type_info(registry);
T::type_name().to_string()
}
}
impl<T: InputType> InputType for MaybeUndefined<T> {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
match value {
None => Ok(MaybeUndefined::Undefined),

View File

@ -1,62 +1,19 @@
use std::borrow::Cow;
use std::pin::Pin;
use indexmap::IndexMap;
use crate::futures_util::Stream;
use crate::parser::types::Field;
use crate::registry::{MetaType, Registry};
use crate::{
CacheControl, ContainerType, Context, ContextSelectionSet, OutputType, Positioned,
ServerResult, SimpleObject, Type, Value,
CacheControl, ContainerType, Context, ContextSelectionSet, OutputType, Positioned, Response,
ServerResult, SimpleObject, SubscriptionType, Value,
};
#[doc(hidden)]
pub struct MergedObject<A, B>(pub A, pub B);
impl<A: Type, B: Type> Type for MergedObject<A, B> {
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("{}_{}", A::type_name(), B::type_name()))
}
fn create_type_info(registry: &mut Registry) -> String {
registry.create_type::<Self, _>(|registry| {
let mut fields = IndexMap::new();
let mut cc = CacheControl::default();
if let MetaType::Object {
fields: b_fields,
cache_control: b_cc,
..
} = registry.create_dummy_type::<B>()
{
fields.extend(b_fields);
cc = cc.merge(&b_cc);
}
if let MetaType::Object {
fields: a_fields,
cache_control: a_cc,
..
} = registry.create_dummy_type::<A>()
{
fields.extend(a_fields);
cc = cc.merge(&a_cc);
}
MetaType::Object {
name: Self::type_name().to_string(),
description: None,
fields,
cache_control: cc,
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
}
})
}
}
#[async_trait::async_trait]
impl<A, B> ContainerType for MergedObject<A, B>
where
@ -83,9 +40,52 @@ where
#[async_trait::async_trait]
impl<A, B> OutputType for MergedObject<A, B>
where
A: ContainerType,
B: ContainerType,
A: OutputType,
B: OutputType,
{
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("{}_{}", A::type_name(), B::type_name()))
}
fn create_type_info(registry: &mut Registry) -> String {
registry.create_output_type::<Self, _>(|registry| {
let mut fields = IndexMap::new();
let mut cc = CacheControl::default();
if let MetaType::Object {
fields: b_fields,
cache_control: b_cc,
..
} = registry.create_fake_output_type::<B>()
{
fields.extend(b_fields);
cc = cc.merge(&b_cc);
}
if let MetaType::Object {
fields: a_fields,
cache_control: a_cc,
..
} = registry.create_fake_output_type::<A>()
{
fields.extend(a_fields);
cc = cc.merge(&a_cc);
}
MetaType::Object {
name: Self::type_name().to_string(),
description: None,
fields,
cache_control: cc,
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
}
})
}
async fn resolve(
&self,
_ctx: &ContextSelectionSet<'_>,
@ -95,7 +95,91 @@ where
}
}
#[async_trait::async_trait]
impl<A, B> SubscriptionType for MergedObject<A, B>
where
A: SubscriptionType,
B: SubscriptionType,
{
fn type_name() -> Cow<'static, str> {
Cow::Owned(format!("{}_{}", A::type_name(), B::type_name()))
}
fn create_type_info(registry: &mut Registry) -> String {
registry.create_subscription_type::<Self, _>(|registry| {
let mut fields = IndexMap::new();
let mut cc = CacheControl::default();
if let MetaType::Object {
fields: b_fields,
cache_control: b_cc,
..
} = registry.create_fake_subscription_type::<B>()
{
fields.extend(b_fields);
cc = cc.merge(&b_cc);
}
if let MetaType::Object {
fields: a_fields,
cache_control: a_cc,
..
} = registry.create_fake_subscription_type::<A>()
{
fields.extend(a_fields);
cc = cc.merge(&a_cc);
}
MetaType::Object {
name: Self::type_name().to_string(),
description: None,
fields,
cache_control: cc,
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
}
})
}
fn create_field_stream<'a>(
&'a self,
_ctx: &'a Context<'_>,
) -> Option<Pin<Box<dyn Stream<Item = Response> + Send + 'a>>> {
unreachable!()
}
}
#[doc(hidden)]
#[derive(SimpleObject, Default)]
#[graphql(internal, dummy)]
#[graphql(internal, fake)]
pub struct MergedObjectTail;
impl SubscriptionType for MergedObjectTail {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("MergedSubscriptionTail")
}
fn create_type_info(registry: &mut Registry) -> String {
registry.create_subscription_type::<Self, _>(|_| MetaType::Object {
name: "MergedSubscriptionTail".to_string(),
description: None,
fields: Default::default(),
cache_control: Default::default(),
extends: false,
keys: None,
visible: None,
is_subscription: false,
rust_typename: std::any::type_name::<Self>(),
})
}
fn create_field_stream<'a>(
&'a self,
_ctx: &'a Context<'_>,
) -> Option<Pin<Box<dyn Stream<Item = Response> + Send + 'a>>> {
unreachable!()
}
}

View File

@ -7,7 +7,7 @@ use crate::parser::types::Field;
use crate::resolver_utils::{resolve_container, ContainerType};
use crate::{
registry, Any, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, ServerError,
ServerResult, SimpleObject, Type, Value,
ServerResult, SimpleObject, Value,
};
/// Federation service
@ -21,74 +21,6 @@ pub(crate) struct QueryRoot<T> {
pub(crate) inner: T,
}
impl<T: Type> Type for QueryRoot<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
let root = T::create_type_info(registry);
if !registry.disable_introspection {
let schema_type = __Schema::create_type_info(registry);
if let Some(registry::MetaType::Object { fields, .. }) =
registry.types.get_mut(T::type_name().as_ref())
{
fields.insert(
"__schema".to_string(),
registry::MetaField {
name: "__schema".to_string(),
description: Some("Access the current type schema of this server."),
args: Default::default(),
ty: schema_type,
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.insert(
"__type".to_string(),
registry::MetaField {
name: "__type".to_string(),
description: Some("Request the type information of a single type."),
args: {
let mut args = IndexMap::new();
args.insert(
"name",
registry::MetaInputValue {
name: "name",
description: None,
ty: "String!".to_string(),
default_value: None,
validator: None,
visible: None,
is_secret: false,
},
);
args
},
ty: "__Type".to_string(),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
}
}
root
}
}
#[async_trait::async_trait]
impl<T: ObjectType> ContainerType for QueryRoot<T> {
async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>> {
@ -154,6 +86,72 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
#[async_trait::async_trait]
impl<T: ObjectType> OutputType for QueryRoot<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
let root = T::create_type_info(registry);
if !registry.disable_introspection {
let schema_type = __Schema::create_type_info(registry);
if let Some(registry::MetaType::Object { fields, .. }) =
registry.types.get_mut(T::type_name().as_ref())
{
fields.insert(
"__schema".to_string(),
registry::MetaField {
name: "__schema".to_string(),
description: Some("Access the current type schema of this server."),
args: Default::default(),
ty: schema_type,
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
fields.insert(
"__type".to_string(),
registry::MetaField {
name: "__type".to_string(),
description: Some("Request the type information of a single type."),
args: {
let mut args = IndexMap::new();
args.insert(
"name",
registry::MetaInputValue {
name: "name",
description: None,
ty: "String!".to_string(),
default_value: None,
validator: None,
visible: None,
is_secret: false,
},
);
args
},
ty: "__Type".to_string(),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
visible: None,
compute_complexity: None,
},
);
}
}
root
}
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,

View File

@ -5,7 +5,7 @@ use std::io::Read;
#[cfg(feature = "unblock")]
use futures_util::io::AsyncRead;
use crate::{registry, Context, InputType, InputValueError, InputValueResult, Type, Value};
use crate::{registry, Context, InputType, InputValueError, InputValueResult, Value};
/// A file upload value.
pub struct UploadValue {
@ -100,13 +100,13 @@ impl Upload {
}
}
impl Type for Upload {
impl InputType for Upload {
fn type_name() -> Cow<'static, str> {
Cow::Borrowed("Upload")
}
fn create_type_info(registry: &mut registry::Registry) -> String {
registry.create_type::<Self, _>(|_| registry::MetaType::Scalar {
registry.create_input_type::<Self, _>(|_| registry::MetaType::Scalar {
name: Self::type_name().to_string(),
description: None,
is_valid: |value| matches!(value, Value::String(_)),
@ -114,9 +114,7 @@ impl Type for Upload {
specified_by_url: Some("https://github.com/jaydenseric/graphql-multipart-request-spec"),
})
}
}
impl InputType for Upload {
fn parse(value: Option<Value>) -> InputValueResult<Self> {
const PREFIX: &str = "#__graphql_file__:";
let value = value.unwrap_or_default();

View File

@ -258,7 +258,7 @@ pub async fn test_generic_subscription() {
}
#[Subscription]
impl<T: OutputType + Type> MySubscription<T>
impl<T: OutputType> MySubscription<T>
where
T: Clone + Send + Sync + Unpin,
{

View File

@ -349,3 +349,60 @@ pub async fn test_box_input_object() {
})
);
}
#[tokio::test]
pub async fn test_both_input_output() {
#[derive(SimpleObject, InputObject)]
#[graphql(input_name = "MyObjectInput")]
#[allow(dead_code)]
struct MyObject {
#[graphql(default = 10)]
a: i32,
b: bool,
#[graphql(skip)]
c: String,
}
struct Query;
#[Object]
impl Query {
async fn obj(&self, input: MyObject) -> MyObject {
input
}
}
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
assert_eq!(
schema
.execute("{ obj(input: {a: 1, b: true}) { a b } }")
.await
.into_result()
.unwrap()
.data,
value!({
"obj": {
"a": 1,
"b": true,
}
})
);
assert_eq!(
schema
.execute("{ obj(input: {b: true}) { a b } }")
.await
.into_result()
.unwrap()
.data,
value!({
"obj": {
"a": 10,
"b": true,
}
})
);
assert_eq!(<MyObject as InputType>::type_name(), "MyObjectInput");
assert_eq!(<MyObject as OutputType>::type_name(), "MyObject");
}

View File

@ -131,7 +131,7 @@ pub async fn test_multiple_interfaces() {
}
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.register_type::<InterfaceA>() // `InterfaceA` is not directly referenced, so manual registration is required.
.register_output_type::<InterfaceA>() // `InterfaceA` is not directly referenced, so manual registration is required.
.finish();
let query = r#"{
myObj {
@ -209,7 +209,7 @@ pub async fn test_multiple_objects_in_multiple_interfaces() {
}
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.register_type::<InterfaceB>() // `InterfaceB` is not directly referenced, so manual registration is required.
.register_output_type::<InterfaceB>() // `InterfaceB` is not directly referenced, so manual registration is required.
.finish();
let query = r#"{
myObj {

View File

@ -229,7 +229,7 @@ pub async fn test_subscription_fragment() {
}
let schema = Schema::build(QueryRoot, EmptyMutation, SubscriptionRoot)
.register_type::<MyInterface>()
.register_output_type::<MyInterface>()
.finish();
let mut stream = schema
.execute_stream(
@ -278,7 +278,7 @@ pub async fn test_subscription_fragment2() {
}
let schema = Schema::build(QueryRoot, EmptyMutation, SubscriptionRoot)
.register_type::<MyInterface>()
.register_output_type::<MyInterface>()
.finish();
let mut stream = schema
.execute_stream(

View File

@ -130,7 +130,7 @@ pub async fn test_multiple_unions() {
}
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.register_type::<UnionA>() // `UnionA` is not directly referenced, so manual registration is required.
.register_output_type::<UnionA>() // `UnionA` is not directly referenced, so manual registration is required.
.finish();
let query = r#"{
unionA {
@ -214,7 +214,7 @@ pub async fn test_multiple_objects_in_multiple_unions() {
}
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.register_type::<UnionB>() // `UnionB` is not directly referenced, so manual registration is required.
.register_output_type::<UnionB>() // `UnionB` is not directly referenced, so manual registration is required.
.finish();
let query = r#"{
myObj {

View File

@ -152,8 +152,8 @@ pub async fn test_override_description() {
EmptyMutation,
EmptySubscription,
)
.override_description::<Query>("Hehe")
.override_description::<DateTime<Utc>>("DT")
.override_output_type_description::<Query>("Hehe")
.override_output_type_description::<DateTime<Utc>>("DT")
.finish();
assert_eq!(