Modify the location of the Guard call.

This commit is contained in:
sunli 2020-05-05 13:02:24 +08:00
parent 40e78a02b7
commit 9b917e19b3
4 changed files with 42 additions and 227 deletions

View File

@ -3,7 +3,6 @@ use crate::output_type::OutputType;
use crate::utils::{build_value_repr, check_reserved_name, get_crate_name};
use inflector::Inflector;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{Block, Error, FnArg, ImplItem, ItemImpl, Pat, Result, ReturnType, Type, TypeReference};
@ -52,7 +51,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
};
let mut create_ctx = true;
let mut arg_ctx = Ident::new("ctx", Span::call_site());
let mut args = Vec::new();
for (idx, arg) in method.sig.inputs.iter_mut().enumerate() {
@ -91,18 +89,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
));
} else {
create_ctx = false;
match arg {
Pat::Wild(_) => {
pat.pat = Box::new(
syn::parse2::<Pat>(quote! { #arg_ctx })
.unwrap(),
);
}
Pat::Ident(arg_ident) => {
arg_ctx = arg_ident.ident.clone();
}
_ => {}
}
}
}
}
@ -112,8 +98,8 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
if create_ctx {
let arg = syn::parse2::<FnArg>(quote! { #arg_ctx: &#crate_name::Context<'_> })
.unwrap();
let arg =
syn::parse2::<FnArg>(quote! { _: &#crate_name::Context<'_> }).unwrap();
method.sig.inputs.insert(1, arg);
}
@ -168,19 +154,16 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
let do_find = quote! { self.#field_ident(ctx, #(#use_keys),*).await.map_err(|err| err.into_error(pos))? };
if let Some(guard) = &entity.guard {
method.block.stmts.insert(
0,
syn::parse2(quote! { #guard.check(#arg_ctx).await?; })
.expect("invalid guard"),
);
}
let guard = entity.guard.map(
|guard| quote! { #guard.check(ctx).await.map_err(|err| err.into_error(pos))?; },
);
find_entities.push((
args.len(),
quote! {
if typename == &<#entity_type as #crate_name::Type>::type_name() {
if let (#(#key_pat),*) = (#(#key_getter),*) {
#guard
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
return #crate_name::OutputValueType::resolve(&#do_find, &ctx_obj, pos).await;
}
@ -243,7 +226,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
};
let mut create_ctx = true;
let mut arg_ctx = Ident::new("ctx", Span::call_site());
let mut args = Vec::new();
for (idx, arg) in method.sig.inputs.iter_mut().enumerate() {
@ -283,17 +265,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
create_ctx = false;
match arg {
Pat::Wild(_) => {
pat.pat = Box::new(
syn::parse2::<Pat>(quote! { #arg_ctx }).unwrap(),
);
}
Pat::Ident(arg_ident) => {
arg_ctx = arg_ident.ident.clone();
}
_ => {}
}
}
}
_ => return Err(Error::new_spanned(arg, "Invalid argument type.")),
@ -302,8 +273,8 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
if create_ctx {
let arg = syn::parse2::<FnArg>(quote! { #arg_ctx: &#crate_name::Context<'_> })
.unwrap();
let arg =
syn::parse2::<FnArg>(quote! { _: &#crate_name::Context<'_> }).unwrap();
method.sig.inputs.insert(1, arg);
}
@ -399,27 +370,27 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
let resolve_obj = quote! {
{
let res:#crate_name::FieldResult<_> = self.#field_ident(ctx, #(#use_params),*).await;
let res = self.#field_ident(ctx, #(#use_params),*).await;
res.map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?
}
};
let guard = field
.guard
.map(|guard| quote! {
#guard.check(ctx).await
.map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?;
});
resolvers.push(quote! {
if ctx.name.as_str() == #field_name {
#guard
#(#get_params)*
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
return #crate_name::OutputValueType::resolve(&#resolve_obj, &ctx_obj, ctx.position).await;
}
});
if let Some(guard) = field.guard {
method.block.stmts.insert(
0,
syn::parse2(quote! { #guard.check(#arg_ctx).await?; })
.expect("invalid guard"),
);
}
if let Some((idx, _)) = method
.attrs
.iter()

View File

@ -91,17 +91,14 @@ pub fn generate(object_args: &args::Object, input: &mut DeriveInput) -> Result<T
});
let ident = &item.ident;
let guard = if let Some(guard) = &field.guard {
quote! { #guard.check(ctx).await?; }
} else {
quote! {}
};
let guard = field
.guard
.map(|guard| quote! { #guard.check(ctx).await.map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?; });
if field.is_ref {
getters.push(quote! {
#[inline]
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<&#ty> {
#guard
Ok(&self.#ident)
}
});
@ -109,7 +106,6 @@ pub fn generate(object_args: &args::Object, input: &mut DeriveInput) -> Result<T
getters.push(quote! {
#[inline]
#vis async fn #ident(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::FieldResult<#ty> {
#guard
Ok(self.#ident.clone())
}
});
@ -117,6 +113,7 @@ pub fn generate(object_args: &args::Object, input: &mut DeriveInput) -> Result<T
resolvers.push(quote! {
if ctx.name.as_str() == #field_name {
#guard
let res = self.#ident(ctx).await.map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?;
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
return #crate_name::OutputValueType::resolve(&res, &ctx_obj, ctx.position).await;

View File

@ -3,7 +3,6 @@ use crate::output_type::OutputType;
use crate::utils::{build_value_repr, check_reserved_name, get_crate_name};
use inflector::Inflector;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{
Block, Error, FnArg, ImplItem, ItemImpl, Pat, Result, ReturnType, Type, TypeImplTrait,
@ -75,7 +74,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
};
let mut create_ctx = true;
let mut arg_ctx = Ident::new("ctx", Span::call_site());
let mut args = Vec::new();
for (idx, arg) in method.sig.inputs.iter_mut().enumerate() {
@ -114,18 +112,6 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
));
} else {
create_ctx = false;
match arg {
Pat::Wild(_) => {
pat.pat = Box::new(
syn::parse2::<Pat>(quote! { #arg_ctx })
.unwrap(),
);
}
Pat::Ident(arg_ident) => {
arg_ctx = arg_ident.ident.clone();
}
_ => {}
}
}
}
}
@ -139,8 +125,8 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
}
if create_ctx {
let arg = syn::parse2::<FnArg>(quote! { #arg_ctx: &#crate_name::Context<'_> })
.unwrap();
let arg =
syn::parse2::<FnArg>(quote! { _: &#crate_name::Context<'_> }).unwrap();
method.sig.inputs.insert(1, arg);
}
@ -244,18 +230,16 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?)
};
if let Some(guard) = &field.guard {
method.block.stmts.insert(
0,
syn::parse2(quote! { #guard.check(#arg_ctx).await?; })
.expect("invalid guard"),
);
}
let guard = field.guard.map(|guard| quote! {
#guard.check(ctx).await.map_err(|err| err.into_error_with_path(ctx.position, ctx.path_node.as_ref().unwrap().to_json()))?;
});
create_stream.push(quote! {
if ctx.name.as_str() == #field_name {
use #crate_name::futures::stream::{StreamExt, TryStreamExt};
#guard
let field_name = std::sync::Arc::new(ctx.result_name().to_string());
#(#get_params)*
let field_selection_set = std::sync::Arc::new(ctx.selection_set.clone());

View File

@ -54,18 +54,8 @@ pub async fn test_guard() {
#[Object]
impl Query {
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn value1(&self) -> FieldResult<i32> {
Ok(1)
}
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn value2(&self, ctx1: &Context<'_>) -> FieldResult<i32> {
Ok(2)
}
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn value3(&self, _: &Context<'_>) -> i32 {
3
async fn value(&self) -> i32 {
1
}
async fn obj(&self) -> MyObj {
@ -73,19 +63,7 @@ pub async fn test_guard() {
}
#[entity(guard(RoleGuard(role = "Role::Admin")))]
async fn find_obj1(&self, value: i32) -> FieldResult<MyObj> {
Ok(MyObj { value })
}
#[entity(guard(RoleGuard(role = "Role::Admin")))]
#[allow(unused_variables)]
async fn find_obj2(&self, ctx1: &Context<'_>, value: i32, n: i32) -> FieldResult<MyObj> {
Ok(MyObj { value })
}
#[entity(guard(RoleGuard(role = "Role::Admin")))]
#[allow(unused_variables)]
async fn find_obj3(&self, _: &Context<'_>, value: i32, a: i32, b: i32) -> MyObj {
async fn find_obj(&self, value: i32) -> MyObj {
MyObj { value }
}
}
@ -95,17 +73,7 @@ pub async fn test_guard() {
#[Subscription]
impl Subscription {
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn values1(&self) -> FieldResult<impl Stream<Item = i32>> {
Ok(futures::stream::iter(vec![1, 2, 3]))
}
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn values2(&self, ctx1: &Context<'_>) -> FieldResult<impl Stream<Item = i32>> {
Ok(futures::stream::iter(vec![1, 2, 3]))
}
#[field(guard(RoleGuard(role = "Role::Admin")))]
async fn values3(&self, _: &Context<'_>) -> impl Stream<Item = i32> {
async fn values(&self) -> impl Stream<Item = i32> {
futures::stream::iter(vec![1, 2, 3])
}
}
@ -125,19 +93,6 @@ pub async fn test_guard() {
})
);
let query = "{ obj { value } }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({
"obj": {"value": 99}
})
);
let query = "{ obj { value } }";
assert_eq!(
QueryBuilder::new(query)
@ -155,7 +110,7 @@ pub async fn test_guard() {
}
);
let query = "{ value1 value2 value3 }";
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
@ -164,13 +119,11 @@ pub async fn test_guard() {
.unwrap()
.data,
serde_json::json!({
"value1": 1,
"value2": 2,
"value3": 3,
"value": 1,
})
);
let query = "{ value1 }";
let query = "{ value }";
assert_eq!(
QueryBuilder::new(query)
.data(Role::Guest)
@ -179,7 +132,7 @@ pub async fn test_guard() {
.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["value1"])),
path: Some(serde_json::json!(["value"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
@ -190,7 +143,7 @@ pub async fn test_guard() {
assert_eq!(
schema
.create_subscription_stream(
"subscription { values1 }",
"subscription { values }",
None,
Variables::default(),
Some(Arc::new({
@ -204,62 +157,16 @@ pub async fn test_guard() {
.collect::<Vec<_>>()
.await,
vec![
Ok(serde_json::json! ({"values1": 1})),
Ok(serde_json::json! ({"values1": 2})),
Ok(serde_json::json! ({"values1": 3}))
Ok(serde_json::json! ({"values": 1})),
Ok(serde_json::json! ({"values": 2})),
Ok(serde_json::json! ({"values": 3}))
]
);
assert_eq!(
schema
.create_subscription_stream(
"subscription { values2 }",
None,
Variables::default(),
Some(Arc::new({
let mut data = Data::default();
data.insert(Role::Admin);
data
})),
)
.await
.unwrap()
.collect::<Vec<_>>()
.await,
vec![
Ok(serde_json::json! ({"values2": 1})),
Ok(serde_json::json! ({"values2": 2})),
Ok(serde_json::json! ({"values2": 3}))
]
);
assert_eq!(
schema
.create_subscription_stream(
"subscription { values3 }",
None,
Variables::default(),
Some(Arc::new({
let mut data = Data::default();
data.insert(Role::Admin);
data
})),
)
.await
.unwrap()
.collect::<Vec<_>>()
.await,
vec![
Ok(serde_json::json! ({"values3": 1})),
Ok(serde_json::json! ({"values3": 2})),
Ok(serde_json::json! ({"values3": 3}))
]
);
assert_eq!(
schema
.create_subscription_stream(
"subscription { values1 }",
"subscription { values }",
None,
Variables::default(),
Some(Arc::new({
@ -276,7 +183,7 @@ pub async fn test_guard() {
line: 1,
column: 16
},
path: Some(serde_json::json!(["values1"])),
path: Some(serde_json::json!(["values"])),
err: QueryError::FieldError {
err: "Forbidden".to_string(),
extended_error: None,
@ -306,50 +213,6 @@ pub async fn test_guard() {
})
);
let query = r#"{
_entities(representations: [{__typename: "MyObj", value: 1, n: 1}]) {
__typename
... on MyObj {
value
}
}
}"#;
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({
"_entities": [
{"__typename": "MyObj", "value": 1},
]
})
);
let query = r#"{
_entities(representations: [{__typename: "MyObj", value: 1, a: 1, b: 2}]) {
__typename
... on MyObj {
value
}
}
}"#;
assert_eq!(
QueryBuilder::new(query)
.data(Role::Admin)
.execute(&schema)
.await
.unwrap()
.data,
serde_json::json!({
"_entities": [
{"__typename": "MyObj", "value": 1},
]
})
);
let query = r#"{
_entities(representations: [{__typename: "MyObj", value: 1}]) {
__typename