Merge master
This commit is contained in:
commit
f6e05d47a1
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -28,3 +28,14 @@ jobs:
|
|||
run: cargo build --all --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --all --verbose
|
||||
|
||||
# build on nightly
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: clippy, rustfmt
|
||||
- name: Build on nightly without features
|
||||
run: cargo build --no-default-features
|
||||
- name: Build on nightly
|
||||
run: cargo build --all --verbose
|
||||
|
|
|
@ -75,7 +75,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
get_fields.push(quote! {
|
||||
let #ident: #ty = #crate_name::InputValueType::parse(
|
||||
Some(#crate_name::Value::Object(obj.clone()))
|
||||
).map_err(#crate_name::InputValueError::propogate)?;
|
||||
).map_err(#crate_name::InputValueError::propagate)?;
|
||||
});
|
||||
|
||||
fields.push(ident);
|
||||
|
@ -111,7 +111,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
let #ident: #ty = {
|
||||
match obj.get(#name) {
|
||||
Some(value) => #crate_name::InputValueType::parse(Some(value.clone()))
|
||||
.map_err(#crate_name::InputValueError::propogate)?,
|
||||
.map_err(#crate_name::InputValueError::propagate)?,
|
||||
None => #default,
|
||||
}
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
} else {
|
||||
get_fields.push(quote! {
|
||||
let #ident: #ty = #crate_name::InputValueType::parse(obj.get(#name).cloned())
|
||||
.map_err(#crate_name::InputValueError::propogate)?;
|
||||
.map_err(#crate_name::InputValueError::propagate)?;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ impl ScalarType for StringNumber {
|
|||
Ok(value.parse().map(StringNumber)?)
|
||||
} else {
|
||||
// If the type does not match
|
||||
Err(InputValueError::ExpectedType(value))
|
||||
Err(InputValueError::expected_type(value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,11 @@ This attribute support 4 operators to create complex rules :
|
|||
|
||||
- `and` : perform a `and` operation between two rules. (If one rule return an error the `and` operator will return the error. If both rules return a error it's the first one that will be returned).
|
||||
|
||||
- `or` : perform a `and` operation between two rules. (If both rules return an error the error returned is the first one)
|
||||
- `or` : perform a `or` operation between two rules. (If both rules return an error the error returned is the first one)
|
||||
|
||||
- `chain` : take a set of rules and run them until one return an error or return `Ok()` if all rules pass.
|
||||
- `chain` : take a set of rules and run them until one return an error or return `Ok` if all rules pass.
|
||||
|
||||
- `race` : take a set of rules and run them until one return `Ok()` if they all fail it return the last error.
|
||||
- `race` : take a set of rules and run them until one return `Ok` if they all fail it return the last error.
|
||||
|
||||
```rust
|
||||
#[derive(SimpleObject)]
|
||||
|
|
|
@ -20,7 +20,7 @@ impl ScalarType for StringNumber {
|
|||
Ok(value.parse().map(StringNumber)?)
|
||||
} else {
|
||||
// 类型不匹配
|
||||
Err(InputValueError::ExpectedType(value))
|
||||
Err(InputValueError::expected_type(value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
68
docs/zh-CN/src/field_guard.md
Normal file
68
docs/zh-CN/src/field_guard.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
# 字段守卫(Field Guard)
|
||||
|
||||
您可以在给`Object`的字段定义`守卫`。 这允许在运行字段的代码逻辑之前添加检查。
|
||||
义`守卫`由你预先定义的规则组成。 规则是一种实现`Guard`特质的结构。
|
||||
```rust
|
||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||
enum Role {
|
||||
Admin,
|
||||
Guest,
|
||||
}
|
||||
|
||||
struct RoleGuard {
|
||||
role: Role,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Guard for RoleGuard {
|
||||
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
|
||||
if ctx.data_opt::<Role>() == Some(&self.role) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Forbidden".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
一旦定义了规则,就可以在`guard`字段属性中使用它。
|
||||
此属性支持4个运算符创建复杂的规则:
|
||||
|
||||
-`and`:在两个规则之间执行`与`运算。 (如果一个规则返回错误,则`and`运算符将返回错误。如果两个规则均返回错误,则将是第一个返回的错误)。
|
||||
|
||||
-`or`:在两个规则之间执行`或`运算。 (如果两个规则都返回错误,则返回的错误是第一个)
|
||||
|
||||
-`chain`:采用一组规则并运行它们,直到返回错误或如果所有规则都通过则返回`Ok`。
|
||||
|
||||
-`race`:采用一组规则并运行它们,直到其中一个返回`Ok`。
|
||||
|
||||
```rust
|
||||
#[derive(SimpleObject)]
|
||||
struct Query {
|
||||
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
||||
value: i32,
|
||||
#[graphql(guard(and(
|
||||
RoleGuard(role = "Role::Admin"),
|
||||
UserGuard(username = r#""test""#)
|
||||
)))]
|
||||
value2: i32,
|
||||
#[graphql(guard(or(
|
||||
RoleGuard(role = "Role::Admin"),
|
||||
UserGuard(username = r#""test""#)
|
||||
)))]
|
||||
value3: i32,
|
||||
#[graphql(guard(chain(
|
||||
RoleGuard(role = "Role::Admin"),
|
||||
UserGuard(username = r#""test""#),
|
||||
AgeGuard(age = r#"21"#)
|
||||
)))]
|
||||
value4: i32,
|
||||
#[graphql(guard(race(
|
||||
RoleGuard(role = "Role::Admin"),
|
||||
UserGuard(username = r#""test""#),
|
||||
AgeGuard(age = r#"21"#)
|
||||
)))]
|
||||
value5: i32,
|
||||
}
|
||||
```
|
||||
|
|
@ -122,8 +122,8 @@ impl<T: InputValueType> InputValueError<T> {
|
|||
Self::new(format!(r#"Failed to parse "{}": {}"#, T::type_name(), msg))
|
||||
}
|
||||
|
||||
/// Propogate the error message to a different type.
|
||||
pub fn propogate<U: InputValueType>(self) -> InputValueError<U> {
|
||||
/// Propagate the error message to a different type.
|
||||
pub fn propagate<U: InputValueType>(self) -> InputValueError<U> {
|
||||
InputValueError::new(format!(
|
||||
r#"{} (occurred while parsing "{}")"#,
|
||||
self.message,
|
||||
|
|
35
src/guard.rs
35
src/guard.rs
|
@ -1,7 +1,6 @@
|
|||
//! Field guards
|
||||
|
||||
use crate::{Context, Result};
|
||||
use serde::export::PhantomData;
|
||||
|
||||
/// Field guard
|
||||
///
|
||||
|
@ -50,37 +49,3 @@ impl<A: Guard + Send + Sync, B: Guard + Send + Sync> Guard for Or<A, B> {
|
|||
self.0.check(ctx).await.or(second_result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Field post guard
|
||||
///
|
||||
/// This is a post-condition for a field that is resolved if `Ok(()` is returned, otherwise an error is returned.
|
||||
///
|
||||
/// This trait is defined through the [`async-trait`](https://crates.io/crates/async-trait) macro.
|
||||
#[async_trait::async_trait]
|
||||
pub trait PostGuard<T: Send + Sync> {
|
||||
/// Check whether to allow the result of the field through.
|
||||
async fn check(&self, ctx: &Context<'_>, result: &T) -> Result<()>;
|
||||
}
|
||||
|
||||
/// An extension trait for `PostGuard<T>`
|
||||
pub trait PostGuardExt<T: Send + Sync>: PostGuard<T> + Sized {
|
||||
/// Merge the two guards.
|
||||
fn and<R: PostGuard<T>>(self, other: R) -> PostAnd<T, Self, R> {
|
||||
PostAnd(self, other, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PostGuard<R>, R: Send + Sync> PostGuardExt<R> for T {}
|
||||
|
||||
/// PostGuard for [`PostGuardExt<T>::and`](trait.PostGuardExt.html#method.and).
|
||||
pub struct PostAnd<T: Send + Sync, A: PostGuard<T>, B: PostGuard<T>>(A, B, PhantomData<T>);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: Send + Sync, A: PostGuard<T> + Send + Sync, B: PostGuard<T> + Send + Sync> PostGuard<T>
|
||||
for PostAnd<T, A, B>
|
||||
{
|
||||
async fn check(&self, ctx: &Context<'_>, result: &T) -> Result<()> {
|
||||
self.0.check(ctx, result).await?;
|
||||
self.1.check(ctx, result).await
|
||||
}
|
||||
}
|
||||
|
|
2
src/types/external/bson.rs
vendored
2
src/types/external/bson.rs
vendored
|
@ -24,7 +24,7 @@ impl ScalarType for ObjectId {
|
|||
impl ScalarType for UtcDateTime {
|
||||
fn parse(value: Value) -> InputValueResult<Self> {
|
||||
<DateTime<Utc>>::parse(value)
|
||||
.map_err(InputValueError::propogate)
|
||||
.map_err(InputValueError::propagate)
|
||||
.map(UtcDateTime::from)
|
||||
}
|
||||
|
||||
|
|
2
src/types/external/json_object/btreemap.rs
vendored
2
src/types/external/json_object/btreemap.rs
vendored
|
@ -16,7 +16,7 @@ where
|
|||
.into_iter()
|
||||
.map(|(name, value)| Ok((name.into_string(), T::parse(Some(value))?)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
_ => Err(InputValueError::expected_type(value)),
|
||||
}
|
||||
}
|
||||
|
|
2
src/types/external/json_object/hashmap.rs
vendored
2
src/types/external/json_object/hashmap.rs
vendored
|
@ -16,7 +16,7 @@ where
|
|||
.into_iter()
|
||||
.map(|(name, value)| Ok((name.into_string(), T::parse(Some(value))?)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
_ => Err(InputValueError::expected_type(value)),
|
||||
}
|
||||
}
|
||||
|
|
4
src/types/external/list/btree_set.rs
vendored
4
src/types/external/list/btree_set.rs
vendored
|
@ -29,11 +29,11 @@ impl<T: InputValueType + Ord> InputValueType for BTreeSet<T> {
|
|||
.into_iter()
|
||||
.map(|value| InputValueType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
value => Ok({
|
||||
let mut result = Self::default();
|
||||
result.insert(
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
);
|
||||
result
|
||||
}),
|
||||
|
|
4
src/types/external/list/hash_set.rs
vendored
4
src/types/external/list/hash_set.rs
vendored
|
@ -31,11 +31,11 @@ impl<T: InputValueType + Hash + Eq> InputValueType for HashSet<T> {
|
|||
.into_iter()
|
||||
.map(|value| InputValueType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
value => Ok({
|
||||
let mut result = Self::default();
|
||||
result.insert(
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
);
|
||||
result
|
||||
}),
|
||||
|
|
4
src/types/external/list/linked_list.rs
vendored
4
src/types/external/list/linked_list.rs
vendored
|
@ -29,11 +29,11 @@ impl<T: InputValueType> InputValueType for LinkedList<T> {
|
|||
.into_iter()
|
||||
.map(|value| InputValueType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
value => Ok({
|
||||
let mut result = Self::default();
|
||||
result.push_front(
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
);
|
||||
result
|
||||
}),
|
||||
|
|
4
src/types/external/list/vec.rs
vendored
4
src/types/external/list/vec.rs
vendored
|
@ -28,9 +28,9 @@ impl<T: InputValueType> InputValueType for Vec<T> {
|
|||
.into_iter()
|
||||
.map(|value| InputValueType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
value => Ok(vec![
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propogate)?
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propagate)?
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
|
4
src/types/external/list/vec_deque.rs
vendored
4
src/types/external/list/vec_deque.rs
vendored
|
@ -29,11 +29,11 @@ impl<T: InputValueType> InputValueType for VecDeque<T> {
|
|||
.into_iter()
|
||||
.map(|value| InputValueType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propogate),
|
||||
.map_err(InputValueError::propagate),
|
||||
value => Ok({
|
||||
let mut result = Self::default();
|
||||
result.push_back(
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
InputValueType::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
);
|
||||
result
|
||||
}),
|
||||
|
|
2
src/types/external/optional.rs
vendored
2
src/types/external/optional.rs
vendored
|
@ -25,7 +25,7 @@ impl<T: InputValueType> InputValueType for Option<T> {
|
|||
match value.unwrap_or_default() {
|
||||
Value::Null => Ok(None),
|
||||
value => Ok(Some(
|
||||
T::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
T::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ impl<T: InputValueType> InputValueType for MaybeUndefined<T> {
|
|||
None => Ok(MaybeUndefined::Undefined),
|
||||
Some(Value::Null) => Ok(MaybeUndefined::Null),
|
||||
Some(value) => Ok(MaybeUndefined::Value(
|
||||
T::parse(Some(value)).map_err(InputValueError::propogate)?,
|
||||
T::parse(Some(value)).map_err(InputValueError::propagate)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user