Add or operator
This commit is contained in:
parent
49811a47cc
commit
bca3489776
|
@ -156,6 +156,24 @@ pub fn generate_guards(
|
|||
}
|
||||
Ok(Some(quote! { #crate_name::guard::GuardExt::and(#first_rule, #second_rule) }))
|
||||
}
|
||||
"or" => {
|
||||
if args.nested.len() != 2 {
|
||||
return Err(Error::new_spanned(args, "or operator support only 2 operands.").into());
|
||||
}
|
||||
let first_rule: Option<TokenStream>;
|
||||
let second_rule: Option<TokenStream>;
|
||||
if let NestedMeta::Meta(rule) = &args.nested[0] {
|
||||
first_rule = generate_guards(crate_name, rule)?;
|
||||
} else {
|
||||
return Err(Error::new_spanned(&args.nested[0], "Invalid rule.").into());
|
||||
}
|
||||
if let NestedMeta::Meta(rule) = &args.nested[1] {
|
||||
second_rule = generate_guards(crate_name, rule)?;
|
||||
} else {
|
||||
return Err(Error::new_spanned(&args.nested[1], "Invalid rule.").into());
|
||||
}
|
||||
Ok(Some(quote! { #crate_name::guard::GuardExt::or(#first_rule, #second_rule) }))
|
||||
}
|
||||
_ => {
|
||||
let ty = &args.path;
|
||||
let mut params = Vec::new();
|
||||
|
|
20
src/guard.rs
20
src/guard.rs
|
@ -16,10 +16,15 @@ pub trait Guard {
|
|||
|
||||
/// An extension trait for `Guard`.
|
||||
pub trait GuardExt: Guard + Sized {
|
||||
/// Merge the two guards.
|
||||
/// Perform `and` operator on two rules
|
||||
fn and<R: Guard>(self, other: R) -> And<Self, R> {
|
||||
And(self, other)
|
||||
}
|
||||
|
||||
/// Perform `or` operator on two rules
|
||||
fn or<R: Guard>(self, other: R) -> Or<Self, R> {
|
||||
Or(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Guard> GuardExt for T {}
|
||||
|
@ -30,8 +35,17 @@ pub struct And<A: Guard, B: Guard>(A, B);
|
|||
#[async_trait::async_trait]
|
||||
impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for And<A, B> {
|
||||
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
|
||||
self.0.check(ctx).await?;
|
||||
self.1.check(ctx).await
|
||||
self.0.check(ctx).await.and(self.1.check(ctx).await)
|
||||
}
|
||||
}
|
||||
|
||||
/// Guard for [`GuardExt::or`](trait.GuardExt.html#method.or).
|
||||
pub struct Or<A: Guard, B: Guard>(A, B);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for Or<A, B> {
|
||||
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
|
||||
self.0.check(ctx).await.or(self.1.check(ctx).await)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
140
tests/guard.rs
140
tests/guard.rs
|
@ -41,7 +41,49 @@ impl Guard for UserGuard {
|
|||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_multiple_guards() {
|
||||
pub async fn test_guard_simple_rule() {
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Query {
|
||||
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
||||
value: i32,
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query { value: 10 }, EmptyMutation, EmptySubscription);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Admin)
|
||||
)
|
||||
.await
|
||||
.data,
|
||||
serde_json::json!({"value": 10})
|
||||
);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Guest)
|
||||
)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap_err(),
|
||||
vec![ServerError {
|
||||
message: "Forbidden".to_string(),
|
||||
locations: vec![Pos { line: 1, column: 3 }],
|
||||
path: vec![PathSegment::Field("value".to_owned())],
|
||||
extensions: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_guard_and_operator() {
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Query {
|
||||
|
@ -49,13 +91,7 @@ pub async fn test_multiple_guards() {
|
|||
value: i32,
|
||||
}
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Mutation {
|
||||
value_m: i32,
|
||||
}
|
||||
|
||||
|
||||
let schema = Schema::new(Query { value: 10 }, Mutation {valueM: 11}, EmptySubscription);
|
||||
let schema = Schema::new(Query { value: 10 }, EmptyMutation, EmptySubscription);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
|
@ -108,4 +144,92 @@ pub async fn test_multiple_guards() {
|
|||
}]
|
||||
);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Guest)
|
||||
.data(Username("test1".to_string()))
|
||||
)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap_err(),
|
||||
vec![ServerError {
|
||||
message: "Forbidden".to_string(),
|
||||
locations: vec![Pos { line: 1, column: 3 }],
|
||||
path: vec![PathSegment::Field("value".to_owned())],
|
||||
extensions: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_guard_or_operator() {
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct Query {
|
||||
#[graphql(guard(or(RoleGuard(role = "Role::Admin"), UserGuard(username = r#""test""#))))]
|
||||
value: i32,
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query { value: 10 }, EmptyMutation, EmptySubscription);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Admin)
|
||||
.data(Username("test".to_string()))
|
||||
)
|
||||
.await
|
||||
.data,
|
||||
serde_json::json!({"value": 10})
|
||||
);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Guest)
|
||||
.data(Username("test".to_string()))
|
||||
)
|
||||
.await
|
||||
.data,
|
||||
serde_json::json!({"value": 10})
|
||||
);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Admin)
|
||||
.data(Username("test1".to_string()))
|
||||
)
|
||||
.await
|
||||
.data,
|
||||
serde_json::json!({"value": 10})
|
||||
);
|
||||
|
||||
let query = "{ value }";
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
Request::new(query)
|
||||
.data(Role::Guest)
|
||||
.data(Username("test1".to_string()))
|
||||
)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap_err(),
|
||||
vec![ServerError {
|
||||
message: "Forbidden".to_string(),
|
||||
locations: vec![Pos { line: 1, column: 3 }],
|
||||
path: vec![PathSegment::Field("value".to_owned())],
|
||||
extensions: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user