v1.7.6
This commit is contained in:
parent
efad20d4c4
commit
3ac07990bb
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "async-graphql"
|
name = "async-graphql"
|
||||||
version = "1.7.5"
|
version = "1.7.6"
|
||||||
authors = ["sunli <scott_s829@163.com>"]
|
authors = ["sunli <scott_s829@163.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "The GraphQL server library implemented by rust"
|
description = "The GraphQL server library implemented by rust"
|
||||||
|
@ -18,7 +18,7 @@ default = ["bson", "uuid", "url", "chrono-tz", "validators"]
|
||||||
validators = ["regex"]
|
validators = ["regex"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-graphql-derive = { path = "async-graphql-derive", version = "1.7.5" }
|
async-graphql-derive = { path = "async-graphql-derive", version = "1.7.6" }
|
||||||
graphql-parser = "=0.2.3"
|
graphql-parser = "=0.2.3"
|
||||||
anyhow = "1.0.26"
|
anyhow = "1.0.26"
|
||||||
thiserror = "1.0.11"
|
thiserror = "1.0.11"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "async-graphql-actix-web"
|
name = "async-graphql-actix-web"
|
||||||
version = "0.7.5"
|
version = "0.7.6"
|
||||||
authors = ["sunli <scott_s829@163.com>"]
|
authors = ["sunli <scott_s829@163.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "async-graphql for actix-web"
|
description = "async-graphql for actix-web"
|
||||||
|
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
|
||||||
categories = ["network-programming", "asynchronous"]
|
categories = ["network-programming", "asynchronous"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-graphql = { path = "..", version = "1.7.5" }
|
async-graphql = { path = "..", version = "1.7.6" }
|
||||||
actix-web = "2.0.0"
|
actix-web = "2.0.0"
|
||||||
actix-multipart = "0.2.0"
|
actix-multipart = "0.2.0"
|
||||||
actix-web-actors = "2.0.0"
|
actix-web-actors = "2.0.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "async-graphql-derive"
|
name = "async-graphql-derive"
|
||||||
version = "1.7.5"
|
version = "1.7.6"
|
||||||
authors = ["sunli <scott_s829@163.com>"]
|
authors = ["sunli <scott_s829@163.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Macros for async-graphql"
|
description = "Macros for async-graphql"
|
||||||
|
|
|
@ -118,6 +118,7 @@ pub use types::{
|
||||||
Connection, DataSource, EmptyEdgeFields, EmptyMutation, EmptySubscription, QueryOperation,
|
Connection, DataSource, EmptyEdgeFields, EmptyMutation, EmptySubscription, QueryOperation,
|
||||||
Upload,
|
Upload,
|
||||||
};
|
};
|
||||||
|
pub use validation::ValidationMode;
|
||||||
|
|
||||||
/// Result type, are actually `anyhow::Result<T>`
|
/// Result type, are actually `anyhow::Result<T>`
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::query::QueryBuilder;
|
||||||
use crate::registry::{Directive, InputValue, Registry};
|
use crate::registry::{Directive, InputValue, Registry};
|
||||||
use crate::subscription::{create_connection, create_subscription_stream, SubscriptionTransport};
|
use crate::subscription::{create_connection, create_subscription_stream, SubscriptionTransport};
|
||||||
use crate::types::QueryRoot;
|
use crate::types::QueryRoot;
|
||||||
use crate::validation::{check_rules, CheckResult};
|
use crate::validation::{check_rules, CheckResult, ValidationMode};
|
||||||
use crate::{
|
use crate::{
|
||||||
ContextSelectionSet, Error, ObjectType, Pos, QueryError, QueryResponse, Result,
|
ContextSelectionSet, Error, ObjectType, Pos, QueryError, QueryResponse, Result,
|
||||||
SubscriptionStream, SubscriptionType, Type, Variables,
|
SubscriptionStream, SubscriptionType, Type, Variables,
|
||||||
|
@ -22,6 +22,7 @@ use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub(crate) struct SchemaInner<Query, Mutation, Subscription> {
|
pub(crate) struct SchemaInner<Query, Mutation, Subscription> {
|
||||||
|
pub(crate) validation_mode: ValidationMode,
|
||||||
pub(crate) query: QueryRoot<Query>,
|
pub(crate) query: QueryRoot<Query>,
|
||||||
pub(crate) mutation: Mutation,
|
pub(crate) mutation: Mutation,
|
||||||
pub(crate) subscription: Subscription,
|
pub(crate) subscription: Subscription,
|
||||||
|
@ -73,6 +74,12 @@ impl<Query: ObjectType, Mutation: ObjectType, Subscription: SubscriptionType>
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the validation mode, default is `ValidationMode::Strict`.
|
||||||
|
pub fn validation_mode(mut self, validation_mode: ValidationMode) -> Self {
|
||||||
|
self.0.validation_mode = validation_mode;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Build schema.
|
/// Build schema.
|
||||||
pub fn finish(self) -> Schema<Query, Mutation, Subscription> {
|
pub fn finish(self) -> Schema<Query, Mutation, Subscription> {
|
||||||
Schema(Arc::new(self.0))
|
Schema(Arc::new(self.0))
|
||||||
|
@ -180,6 +187,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
SchemaBuilder(SchemaInner {
|
SchemaBuilder(SchemaInner {
|
||||||
|
validation_mode: ValidationMode::Strict,
|
||||||
query: QueryRoot {
|
query: QueryRoot {
|
||||||
inner: query,
|
inner: query,
|
||||||
disable_introspection: false,
|
disable_introspection: false,
|
||||||
|
@ -230,7 +238,7 @@ where
|
||||||
cache_control,
|
cache_control,
|
||||||
complexity,
|
complexity,
|
||||||
depth,
|
depth,
|
||||||
} = check_rules(&self.0.registry, &document)?;
|
} = check_rules(&self.0.registry, &document, self.0.validation_mode)?;
|
||||||
extensions.iter().for_each(|e| e.validation_end());
|
extensions.iter().for_each(|e| e.validation_end());
|
||||||
|
|
||||||
if let Some(limit_complexity) = self.0.complexity {
|
if let Some(limit_complexity) = self.0.complexity {
|
||||||
|
@ -271,7 +279,7 @@ where
|
||||||
variables: Variables,
|
variables: Variables,
|
||||||
) -> Result<impl Stream<Item = serde_json::Value>> {
|
) -> Result<impl Stream<Item = serde_json::Value>> {
|
||||||
let document = parse_query(source).map_err(Into::<Error>::into)?;
|
let document = parse_query(source).map_err(Into::<Error>::into)?;
|
||||||
check_rules(&self.0.registry, &document)?;
|
check_rules(&self.0.registry, &document, self.0.validation_mode)?;
|
||||||
|
|
||||||
let mut fragments = HashMap::new();
|
let mut fragments = HashMap::new();
|
||||||
let mut subscription = None;
|
let mut subscription = None;
|
||||||
|
|
|
@ -18,46 +18,77 @@ pub struct CheckResult {
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_rules(registry: &Registry, doc: &Document) -> Result<CheckResult> {
|
/// Validation mode
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum ValidationMode {
|
||||||
|
/// Execute all validation rules.
|
||||||
|
Strict,
|
||||||
|
|
||||||
|
/// The executor itself also has error handling, so it can improve performance, but it can lose some error messages.
|
||||||
|
Fast,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_rules(
|
||||||
|
registry: &Registry,
|
||||||
|
doc: &Document,
|
||||||
|
mode: ValidationMode,
|
||||||
|
) -> Result<CheckResult> {
|
||||||
let mut ctx = VisitorContext::new(registry, doc);
|
let mut ctx = VisitorContext::new(registry, doc);
|
||||||
let mut cache_control = CacheControl::default();
|
let mut cache_control = CacheControl::default();
|
||||||
let mut complexity = 0;
|
let mut complexity = 0;
|
||||||
let mut depth = 0;
|
let mut depth = 0;
|
||||||
|
|
||||||
let mut visitor = VisitorNil
|
match mode {
|
||||||
.with(rules::ArgumentsOfCorrectType::default())
|
ValidationMode::Strict => {
|
||||||
.with(rules::DefaultValuesOfCorrectType)
|
let mut visitor = VisitorNil
|
||||||
.with(rules::FieldsOnCorrectType)
|
.with(rules::ArgumentsOfCorrectType::default())
|
||||||
.with(rules::FragmentsOnCompositeTypes)
|
.with(rules::DefaultValuesOfCorrectType)
|
||||||
.with(rules::KnownArgumentNames::default())
|
.with(rules::FieldsOnCorrectType)
|
||||||
.with(rules::NoFragmentCycles::default())
|
.with(rules::FragmentsOnCompositeTypes)
|
||||||
.with(rules::KnownFragmentNames)
|
.with(rules::KnownArgumentNames::default())
|
||||||
.with(rules::KnownTypeNames)
|
.with(rules::NoFragmentCycles::default())
|
||||||
.with(rules::LoneAnonymousOperation::default())
|
.with(rules::KnownFragmentNames)
|
||||||
.with(rules::NoUndefinedVariables::default())
|
.with(rules::KnownTypeNames)
|
||||||
.with(rules::NoUnusedFragments::default())
|
.with(rules::LoneAnonymousOperation::default())
|
||||||
.with(rules::NoUnusedVariables::default())
|
.with(rules::NoUndefinedVariables::default())
|
||||||
.with(rules::UniqueArgumentNames::default())
|
.with(rules::NoUnusedFragments::default())
|
||||||
.with(rules::UniqueFragmentNames::default())
|
.with(rules::NoUnusedVariables::default())
|
||||||
.with(rules::UniqueOperationNames::default())
|
.with(rules::UniqueArgumentNames::default())
|
||||||
.with(rules::UniqueVariableNames::default())
|
.with(rules::UniqueFragmentNames::default())
|
||||||
.with(rules::VariablesAreInputTypes)
|
.with(rules::UniqueOperationNames::default())
|
||||||
.with(rules::VariableInAllowedPosition::default())
|
.with(rules::UniqueVariableNames::default())
|
||||||
.with(rules::ScalarLeafs)
|
.with(rules::VariablesAreInputTypes)
|
||||||
.with(rules::PossibleFragmentSpreads::default())
|
.with(rules::VariableInAllowedPosition::default())
|
||||||
.with(rules::ProvidedNonNullArguments)
|
.with(rules::ScalarLeafs)
|
||||||
.with(rules::KnownDirectives::default())
|
.with(rules::PossibleFragmentSpreads::default())
|
||||||
.with(rules::OverlappingFieldsCanBeMerged)
|
.with(rules::ProvidedNonNullArguments)
|
||||||
.with(rules::UploadFile)
|
.with(rules::KnownDirectives::default())
|
||||||
.with(visitors::CacheControlCalculate {
|
.with(rules::OverlappingFieldsCanBeMerged)
|
||||||
cache_control: &mut cache_control,
|
.with(rules::UploadFile)
|
||||||
})
|
.with(visitors::CacheControlCalculate {
|
||||||
.with(visitors::ComplexityCalculate {
|
cache_control: &mut cache_control,
|
||||||
complexity: &mut complexity,
|
})
|
||||||
})
|
.with(visitors::ComplexityCalculate {
|
||||||
.with(visitors::DepthCalculate::new(&mut depth));
|
complexity: &mut complexity,
|
||||||
|
})
|
||||||
|
.with(visitors::DepthCalculate::new(&mut depth));
|
||||||
|
visit(&mut visitor, &mut ctx, doc);
|
||||||
|
}
|
||||||
|
ValidationMode::Fast => {
|
||||||
|
let mut visitor = VisitorNil
|
||||||
|
.with(rules::NoFragmentCycles::default())
|
||||||
|
.with(rules::UploadFile)
|
||||||
|
.with(visitors::CacheControlCalculate {
|
||||||
|
cache_control: &mut cache_control,
|
||||||
|
})
|
||||||
|
.with(visitors::ComplexityCalculate {
|
||||||
|
complexity: &mut complexity,
|
||||||
|
})
|
||||||
|
.with(visitors::DepthCalculate::new(&mut depth));
|
||||||
|
visit(&mut visitor, &mut ctx, doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
visit(&mut visitor, &mut ctx, doc);
|
|
||||||
if !ctx.errors.is_empty() {
|
if !ctx.errors.is_empty() {
|
||||||
return Err(Error::Rule { errors: ctx.errors });
|
return Err(Error::Rule { errors: ctx.errors });
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user