v1.4.2
This commit is contained in:
parent
646a7c06c3
commit
788a3b558b
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "The GraphQL server library implemented by rust"
|
||||
|
@ -18,7 +18,7 @@ default = ["bson", "chrono", "uuid", "url", "validators"]
|
|||
validators = ["regex", "once_cell"]
|
||||
|
||||
[dependencies]
|
||||
async-graphql-derive = { path = "async-graphql-derive", version = "1.4.1" }
|
||||
async-graphql-derive = { path = "async-graphql-derive", version = "1.4.2" }
|
||||
graphql-parser = "0.2.3"
|
||||
anyhow = "1.0.26"
|
||||
thiserror = "1.0.11"
|
||||
|
|
|
@ -109,10 +109,15 @@ Open `http://localhost:8000` in browser
|
|||
- [X] IntRange
|
||||
- [X] IntLessThan
|
||||
- [X] IntGreaterThan
|
||||
- [X] IntNonZero
|
||||
- [X] String
|
||||
- [X] Email
|
||||
- [X] MAC
|
||||
- [X] String
|
||||
- [X] StringMinLength
|
||||
- [X] StringMaxLength
|
||||
- [X] List
|
||||
- [X] ListMaxLength
|
||||
- [X] ListMinLength
|
||||
- [X] Subscription
|
||||
- [X] Filter
|
||||
- [X] WebSocket transport
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql-actix-web"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "async-graphql for actix-web"
|
||||
|
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
|
|||
categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
async-graphql = { path = "..", version = "1.4.1" }
|
||||
async-graphql = { path = "..", version = "1.4.2" }
|
||||
actix-web = "2.0.0"
|
||||
actix-multipart = "0.2.0"
|
||||
actix-web-actors = "2.0.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "async-graphql-derive"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
authors = ["sunli <scott_s829@163.com>"]
|
||||
edition = "2018"
|
||||
description = "Macros for async-graphql"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::{parse_validators, parse_value};
|
||||
use crate::utils::{parse_validator, parse_value};
|
||||
use graphql_parser::query::Value;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
@ -60,7 +60,7 @@ pub struct Argument {
|
|||
pub name: Option<String>,
|
||||
pub desc: Option<String>,
|
||||
pub default: Option<Value>,
|
||||
pub validators: TokenStream,
|
||||
pub validator: TokenStream,
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
|
@ -68,11 +68,11 @@ impl Argument {
|
|||
let mut name = None;
|
||||
let mut desc = None;
|
||||
let mut default = None;
|
||||
let mut validators = quote! { Default::default() };
|
||||
let mut validator = quote! { None };
|
||||
|
||||
for attr in attrs {
|
||||
match attr.parse_meta() {
|
||||
Ok(Meta::List(ls)) if ls.path.is_ident("arg") => {
|
||||
match attr.parse_meta()? {
|
||||
Meta::List(ls) if ls.path.is_ident("arg") => {
|
||||
for meta in &ls.nested {
|
||||
if let NestedMeta::Meta(Meta::NameValue(nv)) = meta {
|
||||
if nv.path.is_ident("name") {
|
||||
|
@ -120,7 +120,7 @@ impl Argument {
|
|||
}
|
||||
}
|
||||
|
||||
validators = parse_validators(crate_name, &ls)?;
|
||||
validator = parse_validator(crate_name, &ls)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ impl Argument {
|
|||
name,
|
||||
desc,
|
||||
default,
|
||||
validators,
|
||||
validator,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -150,11 +150,11 @@ impl Field {
|
|||
let mut deprecation = None;
|
||||
|
||||
for attr in attrs {
|
||||
match attr.parse_meta() {
|
||||
Ok(Meta::Path(p)) if p.is_ident("field") => {
|
||||
match attr.parse_meta()? {
|
||||
Meta::Path(p) if p.is_ident("field") => {
|
||||
is_field = true;
|
||||
}
|
||||
Ok(Meta::List(ls)) if ls.path.is_ident("field") => {
|
||||
Meta::List(ls) if ls.path.is_ident("field") => {
|
||||
is_field = true;
|
||||
for meta in &ls.nested {
|
||||
if let NestedMeta::Meta(Meta::NameValue(nv)) = meta {
|
||||
|
@ -271,7 +271,7 @@ impl EnumItem {
|
|||
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("item") {
|
||||
if let Ok(Meta::List(args)) = attr.parse_meta() {
|
||||
if let Meta::List(args) = attr.parse_meta()? {
|
||||
for meta in args.nested {
|
||||
if let NestedMeta::Meta(Meta::NameValue(nv)) = meta {
|
||||
if nv.path.is_ident("name") {
|
||||
|
@ -322,7 +322,7 @@ pub struct InputField {
|
|||
pub name: Option<String>,
|
||||
pub desc: Option<String>,
|
||||
pub default: Option<Value>,
|
||||
pub validators: TokenStream,
|
||||
pub validator: TokenStream,
|
||||
}
|
||||
|
||||
impl InputField {
|
||||
|
@ -331,11 +331,11 @@ impl InputField {
|
|||
let mut name = None;
|
||||
let mut desc = None;
|
||||
let mut default = None;
|
||||
let mut validators = quote! { Default::default() };
|
||||
let mut validator = quote! { None };
|
||||
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("field") {
|
||||
if let Ok(Meta::List(args)) = &attr.parse_meta() {
|
||||
if let Meta::List(args) = &attr.parse_meta()? {
|
||||
for meta in &args.nested {
|
||||
match meta {
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("internal") => {
|
||||
|
@ -389,7 +389,7 @@ impl InputField {
|
|||
}
|
||||
}
|
||||
|
||||
validators = parse_validators(crate_name, &args)?;
|
||||
validator = parse_validator(crate_name, &args)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ impl InputField {
|
|||
name,
|
||||
desc,
|
||||
default,
|
||||
validators,
|
||||
validator,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
|||
let field_args = args::InputField::parse(&crate_name, &field.attrs)?;
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
let ty = &field.ty;
|
||||
let validators = &field_args.validators;
|
||||
let validator = &field_args.validator;
|
||||
let name = field_args
|
||||
.name
|
||||
.unwrap_or_else(|| ident.to_string().to_camel_case());
|
||||
|
@ -95,7 +95,7 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
|||
description: #desc,
|
||||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #default,
|
||||
validators: #validators,
|
||||
validator: #validator,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
|
|||
description: #desc,
|
||||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validators: Default::default(),
|
||||
validator: None,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
name,
|
||||
desc,
|
||||
default,
|
||||
validators,
|
||||
validator,
|
||||
},
|
||||
) in args
|
||||
{
|
||||
|
@ -142,7 +142,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
description: #desc,
|
||||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validators: #validators,
|
||||
validator: #validator,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
name,
|
||||
desc,
|
||||
default,
|
||||
validators,
|
||||
validator,
|
||||
},
|
||||
) in args
|
||||
{
|
||||
|
@ -166,7 +166,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
description: #desc,
|
||||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validators: #validators,
|
||||
validator: #validator,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -97,7 +97,10 @@ pub fn check_reserved_name(name: &str, internal: bool) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_validator(crate_name: &TokenStream, nested_meta: &NestedMeta) -> Result<TokenStream> {
|
||||
pub fn parse_nested_validator(
|
||||
crate_name: &TokenStream,
|
||||
nested_meta: &NestedMeta,
|
||||
) -> Result<TokenStream> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
match nested_meta {
|
||||
|
@ -105,7 +108,7 @@ pub fn parse_validator(crate_name: &TokenStream, nested_meta: &NestedMeta) -> Re
|
|||
if ls.path.is_ident("and") {
|
||||
let mut validators = Vec::new();
|
||||
for nested_meta in &ls.nested {
|
||||
validators.push(parse_validator(crate_name, nested_meta)?);
|
||||
validators.push(parse_nested_validator(crate_name, nested_meta)?);
|
||||
}
|
||||
Ok(validators
|
||||
.into_iter()
|
||||
|
@ -117,7 +120,7 @@ pub fn parse_validator(crate_name: &TokenStream, nested_meta: &NestedMeta) -> Re
|
|||
} else if ls.path.is_ident("or") {
|
||||
let mut validators = Vec::new();
|
||||
for nested_meta in &ls.nested {
|
||||
validators.push(parse_validator(crate_name, nested_meta)?);
|
||||
validators.push(parse_nested_validator(crate_name, nested_meta)?);
|
||||
}
|
||||
Ok(validators
|
||||
.into_iter()
|
||||
|
@ -150,17 +153,24 @@ pub fn parse_validator(crate_name: &TokenStream, nested_meta: &NestedMeta) -> Re
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_validators(crate_name: &TokenStream, args: &MetaList) -> Result<TokenStream> {
|
||||
let mut validators = Vec::new();
|
||||
pub fn parse_validator(crate_name: &TokenStream, args: &MetaList) -> Result<TokenStream> {
|
||||
for arg in &args.nested {
|
||||
if let NestedMeta::Meta(Meta::List(ls)) = arg {
|
||||
if ls.path.is_ident("validators") {
|
||||
for meta in &ls.nested {
|
||||
let validator = parse_validator(crate_name, meta)?;
|
||||
validators.push(quote! { Box::new(#validator) });
|
||||
if ls.path.is_ident("validator") {
|
||||
if ls.nested.len() > 1 {
|
||||
return Err(Error::new_spanned(ls,
|
||||
"Only one validator can be defined. You can connect combine validators with `and` or `or`"));
|
||||
}
|
||||
if ls.nested.len() == 0 {
|
||||
return Err(Error::new_spanned(
|
||||
ls,
|
||||
"At least one validator must be defined",
|
||||
));
|
||||
}
|
||||
let validator = parse_nested_validator(crate_name, &ls.nested[0])?;
|
||||
return Ok(quote! { Some(std::sync::Arc::new(#validator)) });
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(quote! { std::sync::Arc::new(vec![#(#validators),*]) })
|
||||
Ok(quote! {None})
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ pub use types::{EnumItem, EnumType};
|
|||
/// | name | Argument name | string | Y |
|
||||
/// | desc | Argument description | string | Y |
|
||||
/// | default | Argument default value | string | Y |
|
||||
/// | validators | Input value validators | `InputValueValidator` | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
///
|
||||
/// # The field returns the value type
|
||||
///
|
||||
|
@ -300,7 +300,7 @@ pub use async_graphql_derive::Enum;
|
|||
/// | name | Field name | string | Y |
|
||||
/// | desc | Field description | string | Y |
|
||||
/// | default | Field default value | string | Y |
|
||||
/// | validators | Input value validators | `InputValueValidator` | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -355,7 +355,7 @@ pub use async_graphql_derive::InputObject;
|
|||
/// | desc | Field description | string | Y |
|
||||
/// | context | Method with the context | string | Y |
|
||||
/// | deprecation | Field deprecation reason | string | Y |
|
||||
/// | args | Field arguments | [Arg] | Y |
|
||||
/// | args | Field arguments | | Y |
|
||||
///
|
||||
/// # Field argument parameters
|
||||
///
|
||||
|
@ -485,7 +485,7 @@ pub use async_graphql_derive::Union;
|
|||
/// | name | Argument name | string | Y |
|
||||
/// | desc | Argument description | string | Y |
|
||||
/// | default | Argument default value | string | Y |
|
||||
/// | validators | Input value validators | `InputValueValidator` | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -60,7 +60,7 @@ pub struct InputValue {
|
|||
pub description: Option<&'static str>,
|
||||
pub ty: String,
|
||||
pub default_value: Option<&'static str>,
|
||||
pub validators: Arc<Vec<Box<dyn InputValueValidator>>>,
|
||||
pub validator: Option<Arc<dyn InputValueValidator>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -57,7 +57,7 @@ impl<Query: ObjectType, Mutation: ObjectType, Subscription: SubscriptionType>
|
|||
description: Some("Included when true."),
|
||||
ty: "Boolean!".to_string(),
|
||||
default_value: None,
|
||||
validators: Default::default(),
|
||||
validator: None,
|
||||
});
|
||||
args
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ impl<Query: ObjectType, Mutation: ObjectType, Subscription: SubscriptionType>
|
|||
description: Some("Skipped when true."),
|
||||
ty: "Boolean!".to_string(),
|
||||
default_value: None,
|
||||
validators: Default::default(),
|
||||
validator: None,
|
||||
});
|
||||
args
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ impl<T: Type> Type for QueryRoot<T> {
|
|||
description: None,
|
||||
ty: "String!".to_string(),
|
||||
default_value: None,
|
||||
validators: Default::default(),
|
||||
validator: None,
|
||||
},
|
||||
);
|
||||
args
|
||||
|
|
|
@ -36,7 +36,7 @@ impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> {
|
|||
.current_args
|
||||
.and_then(|args| args.get(name).map(|input| input))
|
||||
{
|
||||
for validator in arg.validators.iter() {
|
||||
if let Some(validator) = &arg.validator {
|
||||
if let Some(reason) = validator.is_valid(value) {
|
||||
ctx.report_error(
|
||||
vec![pos],
|
||||
|
|
|
@ -24,7 +24,7 @@ impl InputValueValidator for IntRange {
|
|||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"Int\"".to_string())
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ impl InputValueValidator for IntLessThan {
|
|||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"Int\"".to_string())
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,3 +76,23 @@ impl InputValueValidator for IntGreaterThan {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Integer nonzero validator
|
||||
pub struct IntNonZero {}
|
||||
|
||||
impl InputValueValidator for IntNonZero {
|
||||
fn is_valid(&self, value: &Value) -> Option<String> {
|
||||
if let Value::Int(n) = value {
|
||||
if n.as_i64().unwrap() == 0 {
|
||||
Some(format!(
|
||||
"the value is {}, but must be nonzero",
|
||||
n.as_i64().unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"Int\"".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
src/validators/list_validators.rs
Normal file
50
src/validators/list_validators.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::validators::InputValueValidator;
|
||||
use graphql_parser::query::Value;
|
||||
|
||||
/// List minimum length validator
|
||||
pub struct ListMinLength {
|
||||
/// Must be greater than or equal to this value.
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl InputValueValidator for ListMinLength {
|
||||
fn is_valid(&self, value: &Value) -> Option<String> {
|
||||
if let Value::List(values) = value {
|
||||
if values.len() < self.length {
|
||||
Some(format!(
|
||||
"The value length is {}, but the length must be greater than or equal to {}",
|
||||
values.len(),
|
||||
self.length
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"List\"".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// List maximum length validator
|
||||
pub struct ListMaxLength {
|
||||
/// Must be less than or equal to this value.
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl InputValueValidator for ListMaxLength {
|
||||
fn is_valid(&self, value: &Value) -> Option<String> {
|
||||
if let Value::List(values) = value {
|
||||
if values.len() > self.length {
|
||||
Some(format!(
|
||||
"The value length is {}, but the length must be less than or equal to {}",
|
||||
values.len(),
|
||||
self.length
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
mod int_validators;
|
||||
mod list_validators;
|
||||
mod string_validators;
|
||||
|
||||
use graphql_parser::schema::Value;
|
||||
|
||||
pub use int_validators::{IntGreaterThan, IntLessThan, IntRange};
|
||||
pub use string_validators::{Email, MAC};
|
||||
pub use int_validators::{IntGreaterThan, IntLessThan, IntNonZero, IntRange};
|
||||
pub use list_validators::{ListMaxLength, ListMinLength};
|
||||
pub use string_validators::{Email, StringMaxLength, StringMinLength, MAC};
|
||||
|
||||
/// Input value validator
|
||||
///
|
||||
|
@ -20,19 +22,19 @@ pub use string_validators::{Email, MAC};
|
|||
/// impl QueryRoot {
|
||||
/// // Input is email address
|
||||
/// #[field]
|
||||
/// async fn value1(&self, #[arg(validators(Email))] email: String) -> i32 {
|
||||
/// async fn value1(&self, #[arg(validator(Email))] email: String) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// // Input is email or MAC address
|
||||
/// #[field]
|
||||
/// async fn value2(&self, #[arg(validators(or(Email, MAC(colon: false))))] email_or_mac: String) -> i32 {
|
||||
/// async fn value2(&self, #[arg(validator(or(Email, MAC(colon = false))))] email_or_mac: String) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// // Input is integer between 100 and 200
|
||||
/// #[field]
|
||||
/// async fn value3(&self, #[arg(validators(IntRange(min = 100, max = 200)))] value: i32) -> i32 {
|
||||
/// async fn value3(&self, #[arg(validator(IntRange(min = 100, max = 200)))] value: i32) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
|
@ -42,6 +44,8 @@ where
|
|||
Self: Sync + Send,
|
||||
{
|
||||
/// Check value is valid, returns the reason for the error if it fails, otherwise None.
|
||||
///
|
||||
/// If the input type is different from the required type, return None directly, and other validators will find this error.
|
||||
fn is_valid(&self, value: &Value) -> Option<String>;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,54 @@ use graphql_parser::schema::Value;
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
/// String minimum length validator
|
||||
pub struct StringMinLength {
|
||||
/// Must be greater than or equal to this value.
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl InputValueValidator for StringMinLength {
|
||||
fn is_valid(&self, value: &Value) -> Option<String> {
|
||||
if let Value::String(s) = value {
|
||||
if s.len() < self.length {
|
||||
Some(format!(
|
||||
"The value length is {}, but the length must be greater than or equal to {}",
|
||||
s.len(),
|
||||
self.length
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// String maximum length validator
|
||||
pub struct StringMaxLength {
|
||||
/// Must be less than or equal to this value.
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl InputValueValidator for StringMaxLength {
|
||||
fn is_valid(&self, value: &Value) -> Option<String> {
|
||||
if let Value::String(s) = value {
|
||||
if s.len() > self.length {
|
||||
Some(format!(
|
||||
"The value length is {}, but the length must be less than or equal to {}",
|
||||
s.len(),
|
||||
self.length
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static EMAIL_RE: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new("^(([0-9A-Za-z!#$%&'*+-/=?^_`{|}~&&[^@]]+)|(\"([0-9A-Za-z!#$%&'*+-/=?^_`{|}~ \"(),:;<>@\\[\\\\\\]]+)\"))@").unwrap()
|
||||
});
|
||||
|
@ -19,7 +67,7 @@ impl InputValueValidator for Email {
|
|||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"String\"".to_string())
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +79,8 @@ static MAC_ADDRESS_NO_COLON_RE: Lazy<Regex> =
|
|||
|
||||
/// MAC address validator
|
||||
pub struct MAC {
|
||||
/// Must include colon
|
||||
colon: bool,
|
||||
/// Must include colon.
|
||||
pub colon: bool,
|
||||
}
|
||||
|
||||
impl InputValueValidator for MAC {
|
||||
|
@ -50,7 +98,7 @@ impl InputValueValidator for MAC {
|
|||
None
|
||||
}
|
||||
} else {
|
||||
Some("expected type \"String\"".to_string())
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user