Make Object and Subscription macros support #cfg(...)
attribute. #281
This commit is contained in:
parent
b47d08c5b5
commit
7d3eb9b62c
|
@ -205,7 +205,6 @@ pub struct Field {
|
||||||
pub owned: bool,
|
pub owned: bool,
|
||||||
pub guard: Option<TokenStream>,
|
pub guard: Option<TokenStream>,
|
||||||
pub post_guard: Option<TokenStream>,
|
pub post_guard: Option<TokenStream>,
|
||||||
pub features: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Field {
|
impl Field {
|
||||||
|
@ -217,7 +216,6 @@ impl Field {
|
||||||
let mut external = false;
|
let mut external = false;
|
||||||
let mut provides = None;
|
let mut provides = None;
|
||||||
let mut requires = None;
|
let mut requires = None;
|
||||||
let mut features = Vec::new();
|
|
||||||
let mut owned = false;
|
let mut owned = false;
|
||||||
let mut guard = None;
|
let mut guard = None;
|
||||||
let mut post_guard = None;
|
let mut post_guard = None;
|
||||||
|
@ -290,20 +288,6 @@ impl Field {
|
||||||
"Attribute 'requires' should be a string.",
|
"Attribute 'requires' should be a string.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else if nv.path.is_ident("feature") {
|
|
||||||
if let syn::Lit::Str(lit) = &nv.lit {
|
|
||||||
features = lit
|
|
||||||
.value()
|
|
||||||
.to_string()
|
|
||||||
.split(',')
|
|
||||||
.map(|s| s.trim().to_string())
|
|
||||||
.collect();
|
|
||||||
} else {
|
|
||||||
return Err(Error::new_spanned(
|
|
||||||
&nv.lit,
|
|
||||||
"Attribute 'feature' should be a string.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NestedMeta::Meta(Meta::List(ls)) => {
|
NestedMeta::Meta(Meta::List(ls)) => {
|
||||||
|
@ -334,7 +318,6 @@ impl Field {
|
||||||
owned,
|
owned,
|
||||||
guard,
|
guard,
|
||||||
post_guard,
|
post_guard,
|
||||||
features,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::output_type::OutputType;
|
use crate::output_type::OutputType;
|
||||||
use crate::utils::{feature_block, get_crate_name, get_param_getter_ident, get_rustdoc};
|
use crate::utils::{get_cfg_attrs, get_crate_name, get_param_getter_ident, get_rustdoc};
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -45,6 +45,8 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
for item in &mut item_impl.items {
|
for item in &mut item_impl.items {
|
||||||
if let ImplItem::Method(method) = item {
|
if let ImplItem::Method(method) = item {
|
||||||
if args::Entity::parse(&crate_name, &method.attrs)?.is_some() {
|
if args::Entity::parse(&crate_name, &method.attrs)?.is_some() {
|
||||||
|
let cfg_attrs = get_cfg_attrs(&method.attrs);
|
||||||
|
|
||||||
if method.sig.asyncness.is_none() {
|
if method.sig.asyncness.is_none() {
|
||||||
return Err(Error::new_spanned(&method, "Must be asynchronous"));
|
return Err(Error::new_spanned(&method, "Must be asynchronous"));
|
||||||
}
|
}
|
||||||
|
@ -182,6 +184,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
find_entities.push((
|
find_entities.push((
|
||||||
args.len(),
|
args.len(),
|
||||||
quote! {
|
quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
if typename == &<#entity_type as #crate_name::Type>::type_name() {
|
if typename == &<#entity_type as #crate_name::Type>::type_name() {
|
||||||
if let (#(#key_pat),*) = (#(#key_getter),*) {
|
if let (#(#key_pat),*) = (#(#key_getter),*) {
|
||||||
#(#requires_getter)*
|
#(#requires_getter)*
|
||||||
|
@ -221,7 +224,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
.map(|s| quote! {Some(#s)})
|
.map(|s| quote! {Some(#s)})
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
let external = field.external;
|
let external = field.external;
|
||||||
let features = field.features;
|
|
||||||
let requires = match &field.requires {
|
let requires = match &field.requires {
|
||||||
Some(requires) => quote! { Some(#requires) },
|
Some(requires) => quote! { Some(#requires) },
|
||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
|
@ -246,6 +248,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let cfg_attrs = get_cfg_attrs(&method.attrs);
|
||||||
|
|
||||||
let mut create_ctx = true;
|
let mut create_ctx = true;
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
|
@ -357,6 +360,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
let schema_ty = ty.value_type();
|
let schema_ty = ty.value_type();
|
||||||
|
|
||||||
schema_fields.push(quote! {
|
schema_fields.push(quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
fields.insert(#field_name.to_string(), #crate_name::registry::MetaField {
|
fields.insert(#field_name.to_string(), #crate_name::registry::MetaField {
|
||||||
name: #field_name.to_string(),
|
name: #field_name.to_string(),
|
||||||
description: #field_desc,
|
description: #field_desc,
|
||||||
|
@ -390,13 +394,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
.expect("invalid result type");
|
.expect("invalid result type");
|
||||||
}
|
}
|
||||||
|
|
||||||
method.block =
|
|
||||||
syn::parse2::<Block>(feature_block(&crate_name, &features, &field_name, {
|
|
||||||
let block = &method.block;
|
|
||||||
quote! { #block }
|
|
||||||
}))
|
|
||||||
.expect("invalid block");
|
|
||||||
|
|
||||||
let resolve_obj = quote! {
|
let resolve_obj = quote! {
|
||||||
{
|
{
|
||||||
let res = self.#field_ident(ctx, #(#use_params),*).await;
|
let res = self.#field_ident(ctx, #(#use_params),*).await;
|
||||||
|
@ -418,6 +415,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
});
|
});
|
||||||
|
|
||||||
resolvers.push(quote! {
|
resolvers.push(quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
if ctx.item.node.name.node == #field_name {
|
if ctx.item.node.name.node == #field_name {
|
||||||
#(#get_params)*
|
#(#get_params)*
|
||||||
#guard
|
#guard
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::utils::{feature_block, get_crate_name, get_rustdoc};
|
use crate::utils::{get_crate_name, get_rustdoc};
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -103,33 +103,20 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
||||||
.post_guard
|
.post_guard
|
||||||
.map(|guard| quote! { #guard.check(ctx, &res).await.map_err(|err| err.into_error_with_path(ctx.item.pos, ctx.path_node.as_ref()))?; });
|
.map(|guard| quote! { #guard.check(ctx, &res).await.map_err(|err| err.into_error_with_path(ctx.item.pos, ctx.path_node.as_ref()))?; });
|
||||||
|
|
||||||
let features = &field.features;
|
|
||||||
getters.push(if !field.owned {
|
getters.push(if !field.owned {
|
||||||
let block = feature_block(
|
|
||||||
&crate_name,
|
|
||||||
&features,
|
|
||||||
&field_name,
|
|
||||||
quote! { Ok(&self.#ident) },
|
|
||||||
);
|
|
||||||
quote! {
|
quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<&#ty> {
|
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<&#ty> {
|
||||||
#block
|
Ok(&self.#ident)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let block = feature_block(
|
|
||||||
&crate_name,
|
|
||||||
&features,
|
|
||||||
&field_name,
|
|
||||||
quote! { Ok(self.#ident.clone()) },
|
|
||||||
);
|
|
||||||
quote! {
|
quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<#ty> {
|
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<#ty> {
|
||||||
#block
|
Ok(self.#ident.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::output_type::OutputType;
|
use crate::output_type::OutputType;
|
||||||
use crate::utils::{feature_block, get_crate_name, get_param_getter_ident, get_rustdoc};
|
use crate::utils::{get_cfg_attrs, get_crate_name, get_param_getter_ident, get_rustdoc};
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -59,7 +59,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| quote! {Some(#s)})
|
.map(|s| quote! {Some(#s)})
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
let features = field.features;
|
let cfg_attrs = get_cfg_attrs(&method.attrs);
|
||||||
|
|
||||||
if method.sig.asyncness.is_none() {
|
if method.sig.asyncness.is_none() {
|
||||||
return Err(Error::new_spanned(
|
return Err(Error::new_spanned(
|
||||||
|
@ -207,14 +207,8 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
.expect("invalid result type");
|
.expect("invalid result type");
|
||||||
}
|
}
|
||||||
|
|
||||||
method.block =
|
|
||||||
syn::parse2::<Block>(feature_block(&crate_name, &features, &field_name, {
|
|
||||||
let block = &method.block;
|
|
||||||
quote! { #block }
|
|
||||||
}))
|
|
||||||
.expect("invalid block");
|
|
||||||
|
|
||||||
schema_fields.push(quote! {
|
schema_fields.push(quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
fields.insert(#field_name.to_string(), #crate_name::registry::MetaField {
|
fields.insert(#field_name.to_string(), #crate_name::registry::MetaField {
|
||||||
name: #field_name.to_string(),
|
name: #field_name.to_string(),
|
||||||
description: #field_desc,
|
description: #field_desc,
|
||||||
|
@ -327,6 +321,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
||||||
};
|
};
|
||||||
|
|
||||||
create_stream.push(quote! {
|
create_stream.push(quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
if ctx.item.node.name.node == #field_name {
|
if ctx.item.node.name.node == #field_name {
|
||||||
return ::std::boxed::Box::pin(
|
return ::std::boxed::Box::pin(
|
||||||
#crate_name::futures::TryStreamExt::try_flatten(
|
#crate_name::futures::TryStreamExt::try_flatten(
|
||||||
|
|
|
@ -278,29 +278,10 @@ pub fn get_param_getter_ident(name: &str) -> Ident {
|
||||||
Ident::new(&format!("__{}_getter", name), Span::call_site())
|
Ident::new(&format!("__{}_getter", name), Span::call_site())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn feature_block(
|
pub fn get_cfg_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
|
||||||
crate_name: &TokenStream,
|
attrs
|
||||||
features: &[String],
|
.iter()
|
||||||
field_name: &str,
|
.filter(|attr| !attr.path.segments.is_empty() && attr.path.segments[0].ident == "cfg")
|
||||||
block: TokenStream,
|
.cloned()
|
||||||
) -> TokenStream {
|
.collect()
|
||||||
if !features.is_empty() {
|
|
||||||
let error_message = format!(
|
|
||||||
"`{}` is only available if the features `{}` are enabled",
|
|
||||||
field_name,
|
|
||||||
features.join(",")
|
|
||||||
);
|
|
||||||
quote!({
|
|
||||||
#[cfg(not(all(#(feature = #features),*)))]
|
|
||||||
{
|
|
||||||
return Err(#crate_name::FieldError::from(#error_message)).map_err(::std::convert::Into::into);
|
|
||||||
}
|
|
||||||
#[cfg(all(#(feature = #features),*))]
|
|
||||||
{
|
|
||||||
#block
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
block
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,6 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||||
/// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
/// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
||||||
/// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
/// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
||||||
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
|
|
||||||
///
|
///
|
||||||
/// # Field argument parameters
|
/// # Field argument parameters
|
||||||
///
|
///
|
||||||
|
@ -319,7 +318,6 @@ pub use async_graphql_derive::Object;
|
||||||
/// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
/// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
||||||
/// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
/// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
||||||
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -672,7 +670,6 @@ pub use async_graphql_derive::Union;
|
||||||
/// | desc | Field description | string | Y |
|
/// | desc | Field description | string | Y |
|
||||||
/// | deprecation | Field deprecation reason | string | Y |
|
/// | deprecation | Field deprecation reason | string | Y |
|
||||||
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
||||||
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
|
|
||||||
///
|
///
|
||||||
/// # Field argument parameters
|
/// # Field argument parameters
|
||||||
///
|
///
|
||||||
|
|
|
@ -2,35 +2,32 @@
|
||||||
|
|
||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
pub async fn test_field_features() {
|
pub async fn test_field_features() {
|
||||||
#[derive(SimpleObject)]
|
#[derive(SimpleObject)]
|
||||||
struct MyObj {
|
struct MyObj {
|
||||||
value: i32,
|
value: i32,
|
||||||
|
#[cfg(feature = "bson")]
|
||||||
#[field(feature = "bson")]
|
|
||||||
value_bson: i32,
|
value_bson: i32,
|
||||||
|
#[cfg(feature = "abc")]
|
||||||
#[field(feature = "abc")]
|
|
||||||
value_abc: i32,
|
value_abc: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Subscription;
|
struct SubscriptionRoot;
|
||||||
|
|
||||||
#[Subscription]
|
#[Subscription]
|
||||||
impl Subscription {
|
impl SubscriptionRoot {
|
||||||
async fn values(&self) -> impl Stream<Item = i32> {
|
async fn values(&self) -> impl Stream<Item = i32> {
|
||||||
futures::stream::once(async move { 10 })
|
futures::stream::once(async move { 10 })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[field(feature = "bson")]
|
#[cfg(feature = "bson")]
|
||||||
async fn values_bson(&self) -> impl Stream<Item = i32> {
|
async fn values_bson(&self) -> impl Stream<Item = i32> {
|
||||||
futures::stream::once(async move { 10 })
|
futures::stream::once(async move { 10 })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[field(feature = "abc")]
|
#[cfg(feature = "abc")]
|
||||||
async fn values_abc(
|
async fn values_abc(
|
||||||
&self,
|
&self,
|
||||||
) -> Pin<Box<dyn async_graphql::futures::Stream<Item = i32> + Send + 'static>> {
|
) -> Pin<Box<dyn async_graphql::futures::Stream<Item = i32> + Send + 'static>> {
|
||||||
|
@ -46,12 +43,12 @@ pub async fn test_field_features() {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
|
||||||
#[field(feature = "bson")]
|
#[cfg(feature = "bson")]
|
||||||
async fn value_bson(&self) -> i32 {
|
async fn value_bson(&self) -> i32 {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
|
||||||
#[field(feature = "abc")]
|
#[cfg(feature = "abc")]
|
||||||
async fn value_abc(&self) -> i32 {
|
async fn value_abc(&self) -> i32 {
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
@ -59,13 +56,15 @@ pub async fn test_field_features() {
|
||||||
async fn obj(&self) -> MyObj {
|
async fn obj(&self) -> MyObj {
|
||||||
MyObj {
|
MyObj {
|
||||||
value: 10,
|
value: 10,
|
||||||
|
#[cfg(feature = "bson")]
|
||||||
value_bson: 10,
|
value_bson: 10,
|
||||||
|
#[cfg(feature = "abc")]
|
||||||
value_abc: 10,
|
value_abc: 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let schema = Schema::new(QueryRoot, EmptyMutation, Subscription);
|
let schema = Schema::new(QueryRoot, EmptyMutation, SubscriptionRoot);
|
||||||
let query = "{ value }";
|
let query = "{ value }";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
schema.execute(query).await.data,
|
schema.execute(query).await.data,
|
||||||
|
@ -85,13 +84,13 @@ pub async fn test_field_features() {
|
||||||
let query = "{ valueAbc }";
|
let query = "{ valueAbc }";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
schema.execute(query).await.into_result().unwrap_err(),
|
schema.execute(query).await.into_result().unwrap_err(),
|
||||||
Error::Query {
|
Error::Rule {
|
||||||
pos: Pos { column: 3, line: 1 },
|
errors: vec![RuleError {
|
||||||
path: Some(serde_json::json!(["valueAbc"])),
|
locations: vec![Pos { line: 1, column: 3 }],
|
||||||
err: QueryError::FieldError {
|
message: r#"Unknown field "valueAbc" on type "QueryRoot". Did you mean "value"?"#
|
||||||
err: "`valueAbc` is only available if the features `abc` are enabled".to_string(),
|
.to_string(),
|
||||||
extended_error: None
|
}]
|
||||||
}
|
.into(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -114,13 +113,13 @@ pub async fn test_field_features() {
|
||||||
let query = "{ obj { valueAbc } }";
|
let query = "{ obj { valueAbc } }";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
schema.execute(query).await.into_result().unwrap_err(),
|
schema.execute(query).await.into_result().unwrap_err(),
|
||||||
Error::Query {
|
Error::Rule {
|
||||||
pos: Pos { column: 9, line: 1 },
|
errors: vec![RuleError {
|
||||||
path: Some(serde_json::json!(["obj", "valueAbc"])),
|
locations: vec![Pos { line: 1, column: 9 }],
|
||||||
err: QueryError::FieldError {
|
message: r#"Unknown field "valueAbc" on type "MyObj". Did you mean "value"?"#
|
||||||
err: "`valueAbc` is only available if the features `abc` are enabled".to_string(),
|
.to_string(),
|
||||||
extended_error: None
|
}]
|
||||||
}
|
.into(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -152,16 +151,17 @@ pub async fn test_field_features() {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.error
|
.error
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Error::Query {
|
Error::Rule {
|
||||||
pos: Pos {
|
errors: vec![RuleError {
|
||||||
column: 16,
|
locations: vec![Pos {
|
||||||
line: 1
|
line: 1,
|
||||||
},
|
column: 16
|
||||||
path: Some(serde_json::json!(["valuesAbc"])),
|
}],
|
||||||
err: QueryError::FieldError {
|
message:
|
||||||
err: "`valuesAbc` is only available if the features `abc` are enabled".to_string(),
|
r#"Unknown field "valuesAbc" on type "SubscriptionRoot". Did you mean "values", "valuesBson"?"#
|
||||||
extended_error: None
|
.to_string(),
|
||||||
}
|
}]
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user