Specified By - [GraphQL - October 2021] #677

This commit is contained in:
Sunli 2021-10-28 15:21:42 +08:00
parent 38dcc7d582
commit c6d26884a9
10 changed files with 74 additions and 8 deletions

View File

@ -446,6 +446,7 @@ pub struct Scalar {
pub name: Option<String>,
pub use_type_description: bool,
pub visible: Option<Visible>,
pub specified_by_url: Option<String>,
}
#[derive(FromMeta, Default)]
@ -652,6 +653,8 @@ pub struct NewType {
pub name: NewTypeName,
#[darling(default)]
pub visible: Option<Visible>,
#[darling(default)]
pub specified_by_url: Option<String>,
}
#[derive(FromMeta, Default)]

View File

@ -38,12 +38,18 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult<TokenStream> {
None => quote! { <#inner_ty as #crate_name::Type>::type_name() },
};
let create_type_info = if let Some(name) = &gql_typename {
let specified_by_url = match &newtype_args.specified_by_url {
Some(specified_by_url) => quote! { ::std::option::Option::Some(#specified_by_url) },
None => quote! { ::std::option::Option::None },
};
quote! {
registry.create_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),
visible: #visible,
specified_by_url: #specified_by_url,
})
}
} else {

View File

@ -30,6 +30,11 @@ pub fn generate(
let generic = &item_impl.generics;
let where_clause = &item_impl.generics.where_clause;
let visible = visible_fn(&scalar_args.visible);
let specified_by_url = match &scalar_args.specified_by_url {
Some(specified_by_url) => quote! { ::std::option::Option::Some(#specified_by_url) },
None => quote! { ::std::option::Option::None },
};
let expanded = quote! {
#item_impl
@ -45,6 +50,7 @@ pub fn generate(
description: #desc,
is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value),
visible: #visible,
specified_by_url: #specified_by_url,
})
}
}

View File

@ -987,6 +987,7 @@ pub use async_graphql_derive::Subscription;
/// | Attribute | description | Type | Optional |
/// |-------------|---------------------------|----------|----------|
/// | name | Scalar name | string | Y |
/// | specified_by_url | Provide a specification URL for this scalar type, it must link to a human-readable specification of the data format, serialization and coercion rules for this scalar. | string | Y |
///
pub use async_graphql_derive::Scalar;
@ -1000,8 +1001,9 @@ pub use async_graphql_derive::Scalar;
/// |-------------|---------------------------|----------|----------|
/// | name | If this attribute is provided then define a new scalar, otherwise it is just a transparent proxy for the internal scalar. | string | Y |
/// | name | If this attribute is provided then define a new scalar, otherwise it is just a transparent proxy for the internal scalar. | bool | Y |
/// | visible(Only valid for new scalars.) | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
/// | visible(Only valid for new scalars.) | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
/// | visible(Only valid for new scalars) | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
/// | visible(Only valid for new scalars) | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
/// | specified_by_url(Only valid for new scalars) | Provide a specification URL for this scalar type, it must link to a human-readable specification of the data format, serialization and coercion rules for this scalar. | string | Y |
///
/// # Examples
///

View File

@ -218,4 +218,16 @@ impl<'a> __Type<'a> {
None
}
}
#[graphql(name = "specifiedByURL")]
async fn specified_by_url(&self) -> Option<&'a str> {
if let TypeDetail::Named(registry::MetaType::Scalar {
specified_by_url, ..
}) = &self.detail
{
*specified_by_url
} else {
None
}
}
}

View File

@ -189,6 +189,7 @@ pub enum MetaType {
description: Option<&'static str>,
is_valid: fn(value: &Value) -> bool,
visible: Option<MetaVisibleFn>,
specified_by_url: Option<&'static str>,
},
Object {
name: String,

View File

@ -68,6 +68,9 @@ pub trait ScalarType: Sized + Send {
/// // Rename to `MV` and add description.
/// // scalar!(MyValue, "MV", "This is my value");
///
/// // Rename to `MV`, add description and specifiedByURL.
/// // scalar!(MyValue, "MV", "This is my value", "https://tools.ietf.org/html/rfc4122");
///
/// struct Query;
///
/// #[Object]
@ -92,23 +95,47 @@ pub trait ScalarType: Sized + Send {
/// ```
#[macro_export]
macro_rules! scalar {
($ty:ty, $name:literal, $desc:literal, $specified_by_url:literal) => {
$crate::scalar_internal!(
$ty,
$name,
::std::option::Option::Some($desc),
::std::option::Option::Some($specified_by_url)
);
};
($ty:ty, $name:literal, $desc:literal) => {
$crate::scalar_internal!($ty, $name, ::std::option::Option::Some($desc));
$crate::scalar_internal!(
$ty,
$name,
::std::option::Option::Some($desc),
::std::option::Option::None
);
};
($ty:ty, $name:literal) => {
$crate::scalar_internal!($ty, $name, ::std::option::Option::None);
$crate::scalar_internal!(
$ty,
$name,
::std::option::Option::None,
::std::option::Option::None
);
};
($ty:ty) => {
$crate::scalar_internal!($ty, ::std::stringify!($ty), ::std::option::Option::None);
$crate::scalar_internal!(
$ty,
::std::stringify!($ty),
::std::option::Option::None,
::std::option::Option::None
);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! scalar_internal {
($ty:ty, $name:expr, $desc:expr) => {
($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)
@ -122,6 +149,7 @@ macro_rules! scalar_internal {
description: $desc,
is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value),
visible: ::std::option::Option::None,
specified_by_url: $specified_by_url,
})
}
}

View File

@ -85,6 +85,7 @@ impl<T> Type for OutputJson<T> {
description: None,
is_valid: |_| true,
visible: None,
specified_by_url: None,
})
}
}

View File

@ -111,6 +111,7 @@ impl Type for Upload {
description: None,
is_valid: |value| matches!(value, Value::String(_)),
visible: None,
specified_by_url: None,
})
}
}

View File

@ -11,7 +11,12 @@ mod test_mod {
#[tokio::test]
pub async fn test_scalar_macro() {
scalar!(test_mod::MyValue, "MV", "DESC");
scalar!(
test_mod::MyValue,
"MV",
"DESC",
"https://tools.ietf.org/html/rfc4122"
);
struct Query;
@ -26,7 +31,7 @@ pub async fn test_scalar_macro() {
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
assert_eq!(
schema
.execute(r#"{ __type(name:"MV") { name description } }"#)
.execute(r#"{ __type(name:"MV") { name description specifiedByURL } }"#)
.await
.into_result()
.unwrap()
@ -35,6 +40,7 @@ pub async fn test_scalar_macro() {
"__type": {
"name": "MV",
"description": "DESC",
"specifiedByURL": "https://tools.ietf.org/html/rfc4122",
}
})
);