async_graphql/
guard.rs

1//! Field guards
2#[cfg(not(feature = "boxed-trait"))]
3use std::future::Future;
4
5use crate::{Context, Result};
6
7/// Field guard
8///
9/// Guard is a pre-condition for a field that is resolved if `Ok(())` is
10/// returned, otherwise an error is returned.
11#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
12pub trait Guard {
13    /// Check whether the guard will allow access to the field.
14    #[cfg(feature = "boxed-trait")]
15    async fn check(&self, ctx: &Context<'_>) -> Result<()>;
16
17    /// Check whether the guard will allow access to the field.
18    #[cfg(not(feature = "boxed-trait"))]
19    fn check(&self, ctx: &Context<'_>) -> impl Future<Output = Result<()>> + Send;
20}
21
22#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
23impl<T> Guard for T
24where
25    T: Fn(&Context<'_>) -> Result<()> + Send + Sync + 'static,
26{
27    async fn check(&self, ctx: &Context<'_>) -> Result<()> {
28        self(ctx)
29    }
30}
31
32/// An extension trait for `Guard`.
33pub trait GuardExt: Guard + Sized {
34    /// Perform `and` operator on two rules
35    fn and<R: Guard>(self, other: R) -> And<Self, R> {
36        And(self, other)
37    }
38
39    /// Perform `or` operator on two rules
40    fn or<R: Guard>(self, other: R) -> Or<Self, R> {
41        Or(self, other)
42    }
43}
44
45impl<T: Guard> GuardExt for T {}
46
47/// Guard for [`GuardExt::and`](trait.GuardExt.html#method.and).
48pub struct And<A: Guard, B: Guard>(A, B);
49
50#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
51impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for And<A, B> {
52    async fn check(&self, ctx: &Context<'_>) -> Result<()> {
53        self.0.check(ctx).await?;
54        self.1.check(ctx).await
55    }
56}
57
58/// Guard for [`GuardExt::or`](trait.GuardExt.html#method.or).
59pub struct Or<A: Guard, B: Guard>(A, B);
60
61#[cfg_attr(feature = "boxed-trait", async_trait::async_trait)]
62impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for Or<A, B> {
63    async fn check(&self, ctx: &Context<'_>) -> Result<()> {
64        if self.0.check(ctx).await.is_ok() {
65            return Ok(());
66        }
67        self.1.check(ctx).await
68    }
69}