Strip redundant Send/Sync bounds (#688)

Additionally:
- strip redundant type parameters for juniper::Context in some core definitions and reuse associated type
This commit is contained in:
Kai Ren 2020-06-30 18:13:15 +03:00 committed by GitHub
parent 7578175baf
commit 4d77a1a9b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 556 additions and 554 deletions

View file

@ -1,11 +1,14 @@
#![deny(warnings)] #![deny(warnings)]
use futures::{Stream, StreamExt};
use juniper::http::GraphQLRequest;
use juniper::{DefaultScalarValue, EmptyMutation, FieldError, RootNode, SubscriptionCoordinator};
use juniper_subscriptions::Coordinator;
use std::pin::Pin; use std::pin::Pin;
use futures::{Stream, StreamExt};
use juniper::{
http::GraphQLRequest, DefaultScalarValue, EmptyMutation, FieldError, RootNode,
SubscriptionCoordinator,
};
use juniper_subscriptions::Coordinator;
#[derive(Clone)] #[derive(Clone)]
pub struct Database; pub struct Database;
@ -50,13 +53,11 @@ async fn main() {
let schema = schema(); let schema = schema();
let coordinator = Coordinator::new(schema); let coordinator = Coordinator::new(schema);
let req: GraphQLRequest<DefaultScalarValue> = serde_json::from_str( let req: GraphQLRequest<DefaultScalarValue> = serde_json::from_str(
r#" r#"{
{
"query": "subscription { helloWorld }" "query": "subscription { helloWorld }"
} }"#,
"#,
) )
.unwrap(); .unwrap();
let ctx = Database::new(); let ctx = Database::new();
let mut conn = coordinator.subscribe(&req, &ctx).await.unwrap(); let mut conn = coordinator.subscribe(&req, &ctx).await.unwrap();
while let Some(result) = conn.next().await { while let Some(result) = conn.next().await {

View file

@ -7,7 +7,7 @@ edition = "2018"
[dependencies] [dependencies]
env_logger = "0.6.2" env_logger = "0.6.2"
futures = { version = "=0.3.1" } futures = "0.3.1"
log = "0.4.8" log = "0.4.8"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"

View file

@ -1,6 +1,6 @@
//! This example demonstrates asynchronous subscriptions with warp and tokio 0.2 //! This example demonstrates asynchronous subscriptions with warp and tokio 0.2
use std::{pin::Pin, sync::Arc, time::Duration}; use std::{env, pin::Pin, sync::Arc, time::Duration};
use futures::{Future, FutureExt as _, Stream}; use futures::{Future, FutureExt as _, Stream};
use juniper::{DefaultScalarValue, EmptyMutation, FieldError, RootNode}; use juniper::{DefaultScalarValue, EmptyMutation, FieldError, RootNode};
@ -136,10 +136,10 @@ fn schema() -> Schema {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
::std::env::set_var("RUST_LOG", "warp_subscriptions"); env::set_var("RUST_LOG", "warp_subscriptions");
env_logger::init(); env_logger::init();
let log = warp::log("warp_server"); let log = warp::log("warp_subscriptions");
let homepage = warp::path::end().map(|| { let homepage = warp::path::end().map(|| {
Response::builder() Response::builder()

View file

@ -43,6 +43,7 @@ bson = { version = "1.0.0", optional = true }
chrono = { version = "0.4.0", optional = true } chrono = { version = "0.4.0", optional = true }
fnv = "1.0.3" fnv = "1.0.3"
futures = "0.3.1" futures = "0.3.1"
futures-enum = "0.1.12"
indexmap = { version = "1.0.0", features = ["serde-1"] } indexmap = { version = "1.0.0", features = ["serde-1"] }
serde = { version = "1.0.8", features = ["derive"] } serde = { version = "1.0.8", features = ["derive"] }
serde_json = { version="1.0.2", optional = true } serde_json = { version="1.0.2", optional = true }

View file

@ -7,6 +7,7 @@ use std::{
}; };
use fnv::FnvHashMap; use fnv::FnvHashMap;
use futures::Stream;
use crate::{ use crate::{
ast::{ ast::{
@ -224,9 +225,9 @@ pub type FieldResult<T, S = DefaultScalarValue> = Result<T, FieldError<S>>;
/// The result of resolving an unspecified field /// The result of resolving an unspecified field
pub type ExecutionResult<S = DefaultScalarValue> = Result<Value<S>, FieldError<S>>; pub type ExecutionResult<S = DefaultScalarValue> = Result<Value<S>, FieldError<S>>;
/// Boxed `futures::Stream` yielding `Result<Value<S>, ExecutionError<S>>` /// Boxed `Stream` yielding `Result<Value<S>, ExecutionError<S>>`
pub type ValuesStream<'a, S = DefaultScalarValue> = pub type ValuesStream<'a, S = DefaultScalarValue> =
std::pin::Pin<Box<dyn futures::Stream<Item = Result<Value<S>, ExecutionError<S>>> + Send + 'a>>; std::pin::Pin<Box<dyn Stream<Item = Result<Value<S>, ExecutionError<S>>> + Send + 'a>>;
/// The map of variables used for substitution during query execution /// The map of variables used for substitution during query execution
pub type Variables<S = DefaultScalarValue> = HashMap<String, InputValue<S>>; pub type Variables<S = DefaultScalarValue> = HashMap<String, InputValue<S>>;
@ -374,18 +375,15 @@ where
'i: 'res, 'i: 'res,
'v: 'res, 'v: 'res,
'a: 'res, 'a: 'res,
T: GraphQLSubscriptionValue<S, Context = CtxT> + Send + Sync, T: GraphQLSubscriptionValue<S, Context = CtxT> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
CtxT: Send + Sync, CtxT: Sync,
S: Send + Sync, S: Send + Sync,
{ {
match self.subscribe(info, value).await { self.subscribe(info, value).await.unwrap_or_else(|e| {
Ok(v) => v, self.push_error(e);
Err(e) => { Value::Null
self.push_error(e); })
Value::Null
}
}
} }
/// Resolve a single arbitrary value into a stream of [`Value`]s. /// Resolve a single arbitrary value into a stream of [`Value`]s.
@ -398,9 +396,9 @@ where
where where
't: 'res, 't: 'res,
'a: 'res, 'a: 'res,
T: GraphQLSubscriptionValue<S, Context = CtxT>, T: GraphQLSubscriptionValue<S, Context = CtxT> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
CtxT: Send + Sync, CtxT: Sync,
S: Send + Sync, S: Send + Sync,
{ {
value.resolve_into_stream(info, self).await value.resolve_into_stream(info, self).await
@ -427,9 +425,9 @@ where
/// Resolve a single arbitrary value into an `ExecutionResult` /// Resolve a single arbitrary value into an `ExecutionResult`
pub async fn resolve_async<T>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult<S> pub async fn resolve_async<T>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult<S>
where where
T: GraphQLValueAsync<S, Context = CtxT> + Send + Sync + ?Sized, T: GraphQLValueAsync<S, Context = CtxT> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
CtxT: Send + Sync, CtxT: Sync,
S: Send + Sync, S: Send + Sync,
{ {
value value
@ -444,10 +442,10 @@ where
value: &T, value: &T,
) -> ExecutionResult<S> ) -> ExecutionResult<S>
where where
T: GraphQLValueAsync<S, Context = NewCtxT> + Send + Sync, T: GraphQLValueAsync<S, Context = NewCtxT> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
NewCtxT: FromContext<CtxT> + Sync,
S: Send + Sync, S: Send + Sync,
NewCtxT: FromContext<CtxT> + Send + Sync,
{ {
let e = self.replaced_context(<NewCtxT as FromContext<CtxT>>::from(self.context)); let e = self.replaced_context(<NewCtxT as FromContext<CtxT>>::from(self.context));
e.resolve_async(info, value).await e.resolve_async(info, value).await
@ -471,9 +469,9 @@ where
/// If the field fails to resolve, `null` will be returned. /// If the field fails to resolve, `null` will be returned.
pub async fn resolve_into_value_async<T>(&self, info: &T::TypeInfo, value: &T) -> Value<S> pub async fn resolve_into_value_async<T>(&self, info: &T::TypeInfo, value: &T) -> Value<S>
where where
T: GraphQLValueAsync<S, Context = CtxT> + Send + Sync + ?Sized, T: GraphQLValueAsync<S, Context = CtxT> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
CtxT: Send + Sync, CtxT: Sync,
S: Send + Sync, S: Send + Sync,
{ {
self.resolve_async(info, value).await.unwrap_or_else(|e| { self.resolve_async(info, value).await.unwrap_or_else(|e| {
@ -750,18 +748,18 @@ impl<S> ExecutionError<S> {
/// Create new `Executor` and start query/mutation execution. /// Create new `Executor` and start query/mutation execution.
/// Returns `IsSubscription` error if subscription is passed. /// Returns `IsSubscription` error if subscription is passed.
pub fn execute_validated_query<'a, 'b, QueryT, MutationT, SubscriptionT, CtxT, S>( pub fn execute_validated_query<'a, 'b, QueryT, MutationT, SubscriptionT, S>(
document: &'b Document<S>, document: &'b Document<S>,
operation: &'b Spanning<Operation<S>>, operation: &'b Spanning<Operation<S>>,
root_node: &RootNode<QueryT, MutationT, SubscriptionT, S>, root_node: &RootNode<QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &CtxT, context: &QueryT::Context,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
if operation.item.operation_type == OperationType::Subscription { if operation.item.operation_type == OperationType::Subscription {
return Err(GraphQLError::IsSubscription); return Err(GraphQLError::IsSubscription);
@ -844,22 +842,22 @@ where
/// Create new `Executor` and start asynchronous query execution. /// Create new `Executor` and start asynchronous query execution.
/// Returns `IsSubscription` error if subscription is passed. /// Returns `IsSubscription` error if subscription is passed.
pub async fn execute_validated_query_async<'a, 'b, QueryT, MutationT, SubscriptionT, CtxT, S>( pub async fn execute_validated_query_async<'a, 'b, QueryT, MutationT, SubscriptionT, S>(
document: &'b Document<'a, S>, document: &'b Document<'a, S>,
operation: &'b Spanning<Operation<'_, S>>, operation: &'b Spanning<Operation<'_, S>>,
root_node: &RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &CtxT, context: &QueryT::Context,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = QueryT::Context> + Sync,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{ {
if operation.item.operation_type == OperationType::Subscription { if operation.item.operation_type == OperationType::Subscription {
return Err(GraphQLError::IsSubscription); return Err(GraphQLError::IsSubscription);
@ -986,27 +984,26 @@ pub async fn resolve_validated_subscription<
QueryT, QueryT,
MutationT, MutationT,
SubscriptionT, SubscriptionT,
CtxT,
S, S,
>( >(
document: &Document<'d, S>, document: &Document<'d, S>,
operation: &Spanning<Operation<'op, S>>, operation: &Spanning<Operation<'op, S>>,
root_node: &'r RootNode<'r, QueryT, MutationT, SubscriptionT, S>, root_node: &'r RootNode<'r, QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &'r CtxT, context: &'r QueryT::Context,
) -> Result<(Value<ValuesStream<'r, S>>, Vec<ExecutionError<S>>), GraphQLError<'r>> ) -> Result<(Value<ValuesStream<'r, S>>, Vec<ExecutionError<S>>), GraphQLError<'r>>
where where
'r: 'exec_ref, 'r: 'exec_ref,
'd: 'r, 'd: 'r,
'op: 'd, 'op: 'd,
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync + 'r,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = QueryT::Context>,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync + 'r,
{ {
if operation.item.operation_type != OperationType::Subscription { if operation.item.operation_type != OperationType::Subscription {
return Err(GraphQLError::NotSubscription); return Err(GraphQLError::NotSubscription);

View file

@ -75,16 +75,16 @@ where
/// ///
/// This is a simple wrapper around the `execute_sync` function exposed at the /// This is a simple wrapper around the `execute_sync` function exposed at the
/// top level of this crate. /// top level of this crate.
pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>( pub fn execute_sync<'a, QueryT, MutationT, SubscriptionT>(
&'a self, &'a self,
root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT, context: &QueryT::Context,
) -> GraphQLResponse<'a, S> ) -> GraphQLResponse<'a, S>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
GraphQLResponse(crate::execute_sync( GraphQLResponse(crate::execute_sync(
&self.query, &self.query,
@ -99,20 +99,20 @@ where
/// ///
/// This is a simple wrapper around the `execute` function exposed at the /// This is a simple wrapper around the `execute` function exposed at the
/// top level of this crate. /// top level of this crate.
pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>( pub async fn execute<'a, QueryT, MutationT, SubscriptionT>(
&'a self, &'a self,
root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
context: &'a CtxT, context: &'a QueryT::Context,
) -> GraphQLResponse<'a, S> ) -> GraphQLResponse<'a, S>
where where
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = QueryT::Context> + Sync,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{ {
let op = self.operation_name(); let op = self.operation_name();
let vars = &self.variables(); let vars = &self.variables();
@ -125,23 +125,23 @@ where
/// specified schema and context. /// specified schema and context.
/// This is a wrapper around the `resolve_into_stream` function exposed at the top /// This is a wrapper around the `resolve_into_stream` function exposed at the top
/// level of this crate. /// level of this crate.
pub async fn resolve_into_stream<'req, 'rn, 'ctx, 'a, CtxT, QueryT, MutationT, SubscriptionT, S>( pub async fn resolve_into_stream<'req, 'rn, 'ctx, 'a, QueryT, MutationT, SubscriptionT, S>(
req: &'req GraphQLRequest<S>, req: &'req GraphQLRequest<S>,
root_node: &'rn RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &'rn RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
context: &'ctx CtxT, context: &'ctx QueryT::Context,
) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
'req: 'a, 'req: 'a,
'rn: 'a, 'rn: 'a,
'ctx: 'a, 'ctx: 'a,
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = QueryT::Context>,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{ {
let op = req.operation_name(); let op = req.operation_name();
let vars = req.variables(); let vars = req.variables();
@ -257,15 +257,15 @@ where
/// Execute a GraphQL batch request synchronously using the specified schema and context /// Execute a GraphQL batch request synchronously using the specified schema and context
/// ///
/// This is a simple wrapper around the `execute_sync` function exposed in GraphQLRequest. /// This is a simple wrapper around the `execute_sync` function exposed in GraphQLRequest.
pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>( pub fn execute_sync<'a, QueryT, MutationT, SubscriptionT>(
&'a self, &'a self,
root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT, context: &QueryT::Context,
) -> GraphQLBatchResponse<'a, S> ) -> GraphQLBatchResponse<'a, S>
where where
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
match *self { match *self {
Self::Single(ref req) => { Self::Single(ref req) => {
@ -283,27 +283,27 @@ where
/// ///
/// This is a simple wrapper around the `execute` function exposed in /// This is a simple wrapper around the `execute` function exposed in
/// GraphQLRequest /// GraphQLRequest
pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>( pub async fn execute<'a, QueryT, MutationT, SubscriptionT>(
&'a self, &'a self,
root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
context: &'a CtxT, context: &'a QueryT::Context,
) -> GraphQLBatchResponse<'a, S> ) -> GraphQLBatchResponse<'a, S>
where where
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Send + Sync, QueryT::TypeInfo: Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, QueryT::Context: Sync,
MutationT::TypeInfo: Send + Sync, MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, MutationT::TypeInfo: Sync,
SubscriptionT::TypeInfo: Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = QueryT::Context>,
CtxT: Send + Sync, SubscriptionT::TypeInfo: Sync,
S: Send + Sync, S: Send + Sync,
{ {
match *self { match self {
Self::Single(ref req) => { Self::Single(req) => {
let resp = req.execute(root_node, context).await; let resp = req.execute(root_node, context).await;
GraphQLBatchResponse::Single(resp) GraphQLBatchResponse::Single(resp)
} }
Self::Batch(ref reqs) => { Self::Batch(reqs) => {
let resps = futures::future::join_all( let resps = futures::future::join_all(
reqs.iter().map(|req| req.execute(root_node, context)), reqs.iter().map(|req| req.execute(root_node, context)),
) )

View file

@ -229,18 +229,18 @@ impl<'a> fmt::Display for GraphQLError<'a> {
impl<'a> std::error::Error for GraphQLError<'a> {} impl<'a> std::error::Error for GraphQLError<'a> {}
/// Execute a query synchronously in a provided schema /// Execute a query synchronously in a provided schema
pub fn execute_sync<'a, S, CtxT, QueryT, MutationT, SubscriptionT>( pub fn execute_sync<'a, S, QueryT, MutationT, SubscriptionT>(
document_source: &'a str, document_source: &'a str,
operation_name: Option<&str>, operation_name: Option<&str>,
root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &CtxT, context: &QueryT::Context,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
let document = parse_document_source(document_source, &root_node.schema)?; let document = parse_document_source(document_source, &root_node.schema)?;
@ -268,22 +268,22 @@ where
} }
/// Execute a query in a provided schema /// Execute a query in a provided schema
pub async fn execute<'a, S, CtxT, QueryT, MutationT, SubscriptionT>( pub async fn execute<'a, S, QueryT, MutationT, SubscriptionT>(
document_source: &'a str, document_source: &'a str,
operation_name: Option<&str>, operation_name: Option<&str>,
root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &CtxT, context: &QueryT::Context,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = QueryT::Context> + Sync,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{ {
let document = parse_document_source(document_source, &root_node.schema)?; let document = parse_document_source(document_source, &root_node.schema)?;
@ -312,22 +312,22 @@ where
} }
/// Resolve subscription into `ValuesStream` /// Resolve subscription into `ValuesStream`
pub async fn resolve_into_stream<'a, S, CtxT, QueryT, MutationT, SubscriptionT>( pub async fn resolve_into_stream<'a, S, QueryT, MutationT, SubscriptionT>(
document_source: &'a str, document_source: &'a str,
operation_name: Option<&str>, operation_name: Option<&str>,
root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
variables: &Variables<S>, variables: &Variables<S>,
context: &'a CtxT, context: &'a QueryT::Context,
) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = QueryT::Context>,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{ {
let document: crate::ast::Document<'a, S> = let document: crate::ast::Document<'a, S> =
parse_document_source(document_source, &root_node.schema)?; parse_document_source(document_source, &root_node.schema)?;
@ -357,16 +357,16 @@ where
} }
/// Execute the reference introspection query in the provided schema /// Execute the reference introspection query in the provided schema
pub fn introspect<'a, S, CtxT, QueryT, MutationT, SubscriptionT>( pub fn introspect<'a, S, QueryT, MutationT, SubscriptionT>(
root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>, root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT, context: &QueryT::Context,
format: IntrospectionFormat, format: IntrospectionFormat,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
execute_sync( execute_sync(
match format { match format {

View file

@ -134,7 +134,7 @@ impl Subscription {
#[tokio::test] #[tokio::test]
async fn object_introspect() { async fn object_introspect() {
let res = util::run_info_query::<Query, Mutation, Subscription, Context>("Query").await; let res = util::run_info_query::<Query, Mutation, Subscription>("Query").await;
assert_eq!( assert_eq!(
res, res,
crate::graphql_value!({ crate::graphql_value!({

View file

@ -149,7 +149,7 @@ impl Subscription {
#[tokio::test] #[tokio::test]
async fn object_introspect() { async fn object_introspect() {
let res = util::run_info_query::<Query, Mutation, Subscription, Context>("Subscription").await; let res = util::run_info_query::<Query, Mutation, Subscription>("Subscription").await;
assert_eq!( assert_eq!(
res, res,
crate::graphql_value!({ crate::graphql_value!({

View file

@ -1,34 +1,41 @@
use crate::{DefaultScalarValue, GraphQLType, GraphQLTypeAsync, RootNode, Value, Variables}; use crate::{DefaultScalarValue, GraphQLType, GraphQLTypeAsync, RootNode, Value, Variables};
pub async fn run_query<Query, Mutation, Subscription, Context>(query: &str) -> Value pub async fn run_query<Query, Mutation, Subscription>(query: &str) -> Value
where where
Query: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Context> + Default, Query: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = ()> + Default,
Mutation: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Context> + Default, Query::Context: Default + Sync,
Mutation:
GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Query::Context> + Default,
Subscription: Subscription:
GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default + Sync + Send, GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Query::Context> + Default + Sync,
Context: Default + Send + Sync,
{ {
let schema = RootNode::new( let schema = RootNode::new(
Query::default(), Query::default(),
Mutation::default(), Mutation::default(),
Subscription::default(), Subscription::default(),
); );
let (result, errs) = let (result, errs) = crate::execute(
crate::execute(query, None, &schema, &Variables::new(), &Context::default()) query,
.await None,
.expect("Execution failed"); &schema,
&Variables::new(),
&Query::Context::default(),
)
.await
.expect("Execution failed");
assert_eq!(errs, []); assert_eq!(errs, []);
result result
} }
pub async fn run_info_query<Query, Mutation, Subscription, Context>(type_name: &str) -> Value pub async fn run_info_query<Query, Mutation, Subscription>(type_name: &str) -> Value
where where
Query: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Context> + Default, Query: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = ()> + Default,
Mutation: GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Context> + Default, Query::Context: Default + Sync,
Mutation:
GraphQLTypeAsync<DefaultScalarValue, TypeInfo = (), Context = Query::Context> + Default,
Subscription: Subscription:
GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default + Sync + Send, GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Query::Context> + Default + Sync,
Context: Default + Send + Sync,
{ {
let query = format!( let query = format!(
r#" r#"
@ -52,7 +59,7 @@ where
"#, "#,
type_name type_name
); );
let result = run_query::<Query, Mutation, Subscription, Context>(&query).await; let result = run_query::<Query, Mutation, Subscription>(&query).await;
result result
.as_object_value() .as_object_value()
.expect("Result is not an object") .expect("Result is not an object")

View file

@ -16,19 +16,19 @@ use crate::schema::{
model::{DirectiveLocation, DirectiveType, RootNode, SchemaType, TypeType}, model::{DirectiveLocation, DirectiveType, RootNode, SchemaType, TypeType},
}; };
impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> GraphQLType<S> impl<'a, S, QueryT, MutationT, SubscriptionT> GraphQLType<S>
for RootNode<'a, QueryT, MutationT, SubscriptionT, S> for RootNode<'a, QueryT, MutationT, SubscriptionT, S>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
fn name(info: &QueryT::TypeInfo) -> Option<&str> { fn name(info: &Self::TypeInfo) -> Option<&str> {
QueryT::name(info) QueryT::name(info)
} }
fn meta<'r>(info: &QueryT::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -36,27 +36,27 @@ where
} }
} }
impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> GraphQLValue<S> impl<'a, S, QueryT, MutationT, SubscriptionT> GraphQLValue<S>
for RootNode<'a, QueryT, MutationT, SubscriptionT, S> for RootNode<'a, QueryT, MutationT, SubscriptionT, S>
where where
S: ScalarValue, S: ScalarValue,
QueryT: GraphQLType<S, Context = CtxT>, QueryT: GraphQLType<S>,
MutationT: GraphQLType<S, Context = CtxT>, MutationT: GraphQLType<S, Context = QueryT::Context>,
SubscriptionT: GraphQLType<S, Context = CtxT>, SubscriptionT: GraphQLType<S, Context = QueryT::Context>,
{ {
type Context = CtxT; type Context = QueryT::Context;
type TypeInfo = QueryT::TypeInfo; type TypeInfo = QueryT::TypeInfo;
fn type_name<'i>(&self, info: &'i QueryT::TypeInfo) -> Option<&'i str> { fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
QueryT::name(info) QueryT::name(info)
} }
fn resolve_field( fn resolve_field(
&self, &self,
info: &QueryT::TypeInfo, info: &Self::TypeInfo,
field: &str, field: &str,
args: &Arguments<S>, args: &Arguments<S>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
match field { match field {
"__schema" => executor "__schema" => executor
@ -93,17 +93,17 @@ where
} }
} }
impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> GraphQLValueAsync<S> impl<'a, S, QueryT, MutationT, SubscriptionT> GraphQLValueAsync<S>
for RootNode<'a, QueryT, MutationT, SubscriptionT, S> for RootNode<'a, QueryT, MutationT, SubscriptionT, S>
where where
QueryT: GraphQLTypeAsync<S>,
QueryT::TypeInfo: Sync,
QueryT::Context: Sync + 'a,
MutationT: GraphQLTypeAsync<S, Context = QueryT::Context>,
MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = QueryT::Context> + Sync,
SubscriptionT::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT>,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync + 'a,
{ {
fn resolve_field_async<'b>( fn resolve_field_async<'b>(
&'b self, &'b self,

View file

@ -13,10 +13,10 @@ use super::base::{is_excluded, merge_key_into, Arguments, GraphQLType, GraphQLVa
/// ///
/// Convenience macros related to asynchronous queries/mutations expand into an implementation of /// Convenience macros related to asynchronous queries/mutations expand into an implementation of
/// this trait and [`GraphQLValue`] for the given type. /// this trait and [`GraphQLValue`] for the given type.
pub trait GraphQLValueAsync<S = DefaultScalarValue>: GraphQLValue<S> + Send + Sync pub trait GraphQLValueAsync<S = DefaultScalarValue>: GraphQLValue<S> + Sync
where where
Self::Context: Send + Sync, Self::TypeInfo: Sync,
Self::TypeInfo: Send + Sync, Self::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
/// Resolves the value of a single field on this [`GraphQLValueAsync`]. /// Resolves the value of a single field on this [`GraphQLValueAsync`].
@ -119,34 +119,34 @@ crate::sa::assert_obj_safe!(GraphQLValueAsync<Context = (), TypeInfo = ()>);
/// doesn't require manual or code-generated implementation. /// doesn't require manual or code-generated implementation.
pub trait GraphQLTypeAsync<S = DefaultScalarValue>: GraphQLValueAsync<S> + GraphQLType<S> pub trait GraphQLTypeAsync<S = DefaultScalarValue>: GraphQLValueAsync<S> + GraphQLType<S>
where where
Self::Context: Send + Sync, Self::Context: Sync,
Self::TypeInfo: Send + Sync, Self::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
} }
impl<S, T> GraphQLTypeAsync<S> for T impl<S, T> GraphQLTypeAsync<S> for T
where where
T: GraphQLValueAsync<S> + GraphQLType<S>, T: GraphQLValueAsync<S> + GraphQLType<S> + ?Sized,
T::Context: Send + Sync, T::Context: Sync,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
} }
// Wrapper function around resolve_selection_set_into_async_recursive. // Wrapper function around resolve_selection_set_into_async_recursive.
// This wrapper is necessary because async fns can not be recursive. // This wrapper is necessary because async fns can not be recursive.
fn resolve_selection_set_into_async<'a, 'e, T, CtxT, S>( fn resolve_selection_set_into_async<'a, 'e, T, S>(
instance: &'a T, instance: &'a T,
info: &'a T::TypeInfo, info: &'a T::TypeInfo,
selection_set: &'e [Selection<'e, S>], selection_set: &'e [Selection<'e, S>],
executor: &'e Executor<'e, 'e, CtxT, S>, executor: &'e Executor<'e, 'e, T::Context, S>,
) -> BoxFuture<'a, Value<S>> ) -> BoxFuture<'a, Value<S>>
where where
T: GraphQLValueAsync<S, Context = CtxT> + ?Sized, T: GraphQLValueAsync<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
'e: 'a, 'e: 'a,
{ {
Box::pin(resolve_selection_set_into_async_recursive( Box::pin(resolve_selection_set_into_async_recursive(
@ -167,23 +167,31 @@ enum AsyncValue<S> {
Nested(Value<S>), Nested(Value<S>),
} }
pub(crate) async fn resolve_selection_set_into_async_recursive<'a, T, CtxT, S>( pub(crate) async fn resolve_selection_set_into_async_recursive<'a, T, S>(
instance: &'a T, instance: &'a T,
info: &'a T::TypeInfo, info: &'a T::TypeInfo,
selection_set: &'a [Selection<'a, S>], selection_set: &'a [Selection<'a, S>],
executor: &'a Executor<'a, 'a, CtxT, S>, executor: &'a Executor<'a, 'a, T::Context, S>,
) -> Value<S> ) -> Value<S>
where where
T: GraphQLValueAsync<S, Context = CtxT> + Send + Sync + ?Sized, T: GraphQLValueAsync<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
use futures::stream::{FuturesOrdered, StreamExt as _}; use futures::stream::{FuturesOrdered, StreamExt as _};
#[derive(futures_enum::Future)]
enum AsyncValueFuture<A, B, C, D> {
Field(A),
FragmentSpread(B),
InlineFragment1(C),
InlineFragment2(D),
}
let mut object = Object::with_capacity(selection_set.len()); let mut object = Object::with_capacity(selection_set.len());
let mut async_values = FuturesOrdered::<BoxFuture<'a, AsyncValue<S>>>::new(); let mut async_values = FuturesOrdered::<AsyncValueFuture<_, _, _, _>>::new();
let meta_type = executor let meta_type = executor
.schema() .schema()
@ -246,7 +254,7 @@ where
let is_non_null = meta_field.field_type.is_non_null(); let is_non_null = meta_field.field_type.is_non_null();
let response_name = response_name.to_string(); let response_name = response_name.to_string();
let field_future = async move { async_values.push(AsyncValueFuture::Field(async move {
// TODO: implement custom future type instead of // TODO: implement custom future type instead of
// two-level boxing. // two-level boxing.
let res = instance let res = instance
@ -270,18 +278,16 @@ where
name: response_name, name: response_name,
value, value,
}) })
}; }));
async_values.push(Box::pin(field_future));
} }
Selection::FragmentSpread(Spanning { Selection::FragmentSpread(Spanning {
item: ref spread, .. item: ref spread, ..
}) => { }) => {
if is_excluded(&spread.directives, executor.variables()) { if is_excluded(&spread.directives, executor.variables()) {
continue; continue;
} }
async_values.push(AsyncValueFuture::FragmentSpread(async move {
// TODO: prevent duplicate boxing.
let f = async move {
let fragment = &executor let fragment = &executor
.fragment_by_name(spread.name.item) .fragment_by_name(spread.name.item)
.expect("Fragment could not be found"); .expect("Fragment could not be found");
@ -293,9 +299,9 @@ where
) )
.await; .await;
AsyncValue::Nested(value) AsyncValue::Nested(value)
}; }));
async_values.push(Box::pin(f));
} }
Selection::InlineFragment(Spanning { Selection::InlineFragment(Spanning {
item: ref fragment, item: ref fragment,
start: ref start_pos, start: ref start_pos,
@ -322,20 +328,18 @@ where
if let Ok(Value::Object(obj)) = sub_result { if let Ok(Value::Object(obj)) = sub_result {
for (k, v) in obj { for (k, v) in obj {
// TODO: prevent duplicate boxing. async_values.push(AsyncValueFuture::InlineFragment1(async move {
let f = async move {
AsyncValue::Field(AsyncField { AsyncValue::Field(AsyncField {
name: k, name: k,
value: Some(v), value: Some(v),
}) })
}; }));
async_values.push(Box::pin(f));
} }
} else if let Err(e) = sub_result { } else if let Err(e) = sub_result {
sub_exec.push_error_at(e, start_pos.clone()); sub_exec.push_error_at(e, start_pos.clone());
} }
} else { } else {
let f = async move { async_values.push(AsyncValueFuture::InlineFragment2(async move {
let value = resolve_selection_set_into_async( let value = resolve_selection_set_into_async(
instance, instance,
info, info,
@ -344,8 +348,7 @@ where
) )
.await; .await;
AsyncValue::Nested(value) AsyncValue::Nested(value)
}; }));
async_values.push(Box::pin(f));
} }
} }
} }

View file

@ -401,16 +401,16 @@ where
/// and then merges returned values into `result` or pushes errors to /// and then merges returned values into `result` or pushes errors to
/// field's/fragment's sub executor. /// field's/fragment's sub executor.
/// ///
/// Returns false if any errors occured and true otherwise. /// Returns false if any errors occurred and true otherwise.
pub(crate) fn resolve_selection_set_into<T, CtxT, S>( pub(crate) fn resolve_selection_set_into<T, S>(
instance: &T, instance: &T,
info: &T::TypeInfo, info: &T::TypeInfo,
selection_set: &[Selection<S>], selection_set: &[Selection<S>],
executor: &Executor<CtxT, S>, executor: &Executor<T::Context, S>,
result: &mut Object<S>, result: &mut Object<S>,
) -> bool ) -> bool
where where
T: GraphQLValue<S, Context = CtxT> + ?Sized, T: GraphQLValue<S> + ?Sized,
S: ScalarValue, S: ScalarValue,
{ {
let meta_type = executor let meta_type = executor

View file

@ -9,16 +9,16 @@ use crate::{
value::{ScalarValue, Value}, value::{ScalarValue, Value},
}; };
impl<S, T, CtxT> GraphQLType<S> for Option<T> impl<S, T> GraphQLType<S> for Option<T>
where where
T: GraphQLType<S>,
S: ScalarValue, S: ScalarValue,
T: GraphQLType<S, Context = CtxT>,
{ {
fn name(_: &T::TypeInfo) -> Option<&'static str> { fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -26,23 +26,23 @@ where
} }
} }
impl<S, T, CtxT> GraphQLValue<S> for Option<T> impl<S, T> GraphQLValue<S> for Option<T>
where where
S: ScalarValue, S: ScalarValue,
T: GraphQLValue<S, Context = CtxT>, T: GraphQLValue<S>,
{ {
type Context = CtxT; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
_: Option<&[Selection<S>]>, _: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
match *self { match *self {
Some(ref obj) => executor.resolve(info, obj), Some(ref obj) => executor.resolve(info, obj),
@ -51,12 +51,12 @@ where
} }
} }
impl<S, T, CtxT> GraphQLValueAsync<S> for Option<T> impl<S, T> GraphQLValueAsync<S> for Option<T>
where where
T: GraphQLValueAsync<S, Context = CtxT>, T: GraphQLValueAsync<S>,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,
@ -65,8 +65,8 @@ where
executor: &'a Executor<Self::Context, S>, executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> { ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
let f = async move { let f = async move {
let value = match *self { let value = match self {
Some(ref obj) => executor.resolve_into_value_async(info, obj).await, Some(obj) => executor.resolve_into_value_async(info, obj).await,
None => Value::null(), None => Value::null(),
}; };
Ok(value) Ok(value)
@ -101,16 +101,16 @@ where
} }
} }
impl<S, T, CtxT> GraphQLType<S> for Vec<T> impl<S, T> GraphQLType<S> for Vec<T>
where where
T: GraphQLType<S, Context = CtxT>, T: GraphQLType<S>,
S: ScalarValue, S: ScalarValue,
{ {
fn name(_: &T::TypeInfo) -> Option<&'static str> { fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -118,34 +118,34 @@ where
} }
} }
impl<S, T, CtxT> GraphQLValue<S> for Vec<T> impl<S, T> GraphQLValue<S> for Vec<T>
where where
T: GraphQLValue<S, Context = CtxT>, T: GraphQLValue<S>,
S: ScalarValue, S: ScalarValue,
{ {
type Context = CtxT; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
_: Option<&[Selection<S>]>, _: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
resolve_into_list(executor, info, self.iter()) resolve_into_list(executor, info, self.iter())
} }
} }
impl<S, T, CtxT> GraphQLValueAsync<S> for Vec<T> impl<S, T> GraphQLValueAsync<S> for Vec<T>
where where
T: GraphQLValueAsync<S, Context = CtxT>, T: GraphQLValueAsync<S>,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,
@ -190,16 +190,16 @@ where
} }
} }
impl<S, T, CtxT> GraphQLType<S> for [T] impl<S, T> GraphQLType<S> for [T]
where where
S: ScalarValue, S: ScalarValue,
T: GraphQLType<S, Context = CtxT>, T: GraphQLType<S>,
{ {
fn name(_: &T::TypeInfo) -> Option<&'static str> { fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -207,34 +207,34 @@ where
} }
} }
impl<S, T, CtxT> GraphQLValue<S> for [T] impl<S, T> GraphQLValue<S> for [T]
where where
S: ScalarValue, S: ScalarValue,
T: GraphQLValue<S, Context = CtxT>, T: GraphQLValue<S>,
{ {
type Context = CtxT; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None None
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
_: Option<&[Selection<S>]>, _: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
resolve_into_list(executor, info, self.iter()) resolve_into_list(executor, info, self.iter())
} }
} }
impl<S, T, CtxT> GraphQLValueAsync<S> for [T] impl<S, T> GraphQLValueAsync<S> for [T]
where where
T: GraphQLValueAsync<S, Context = CtxT>, T: GraphQLValueAsync<S>,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,
@ -292,11 +292,11 @@ async fn resolve_into_list_async<'a, 't, S, T, I>(
items: I, items: I,
) -> ExecutionResult<S> ) -> ExecutionResult<S>
where where
S: ScalarValue + Send + Sync,
I: Iterator<Item = &'t T> + ExactSizeIterator, I: Iterator<Item = &'t T> + ExactSizeIterator,
T: GraphQLValueAsync<S> + ?Sized + 't, T: GraphQLValueAsync<S> + ?Sized + 't,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Send + Sync, T::Context: Sync,
S: ScalarValue + Send + Sync,
{ {
use futures::stream::{FuturesOrdered, StreamExt as _}; use futures::stream::{FuturesOrdered, StreamExt as _};
use std::iter::FromIterator; use std::iter::FromIterator;
@ -307,7 +307,7 @@ where
.expect("Current type is not a list type") .expect("Current type is not a list type")
.is_non_null(); .is_non_null();
let iter = items.map(|item| async move { executor.resolve_into_value_async(info, item).await }); let iter = items.map(|it| async move { executor.resolve_into_value_async(info, it).await });
let mut futures = FuturesOrdered::from_iter(iter); let mut futures = FuturesOrdered::from_iter(iter);
let mut values = Vec::with_capacity(futures.len()); let mut values = Vec::with_capacity(futures.len());

View file

@ -12,16 +12,16 @@ use crate::{
BoxFuture, BoxFuture,
}; };
impl<S, T, CtxT> GraphQLType<S> for Box<T> impl<S, T> GraphQLType<S> for Box<T>
where where
T: GraphQLType<S> + ?Sized,
S: ScalarValue, S: ScalarValue,
T: GraphQLType<S, Context = CtxT> + ?Sized,
{ {
fn name(info: &T::TypeInfo) -> Option<&str> { fn name(info: &Self::TypeInfo) -> Option<&str> {
T::name(info) T::name(info)
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -29,54 +29,54 @@ where
} }
} }
impl<S, T, CtxT> GraphQLValue<S> for Box<T> impl<S, T> GraphQLValue<S> for Box<T>
where where
T: GraphQLValue<S> + ?Sized,
S: ScalarValue, S: ScalarValue,
T: GraphQLValue<S, Context = CtxT> + ?Sized,
{ {
type Context = CtxT; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
(**self).type_name(info) (**self).type_name(info)
} }
fn resolve_into_type( fn resolve_into_type(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
name: &str, name: &str,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_into_type(info, name, selection_set, executor) (**self).resolve_into_type(info, name, selection_set, executor)
} }
fn resolve_field( fn resolve_field(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
field: &str, field: &str,
args: &Arguments<S>, args: &Arguments<S>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_field(info, field, args, executor) (**self).resolve_field(info, field, args, executor)
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve(info, selection_set, executor) (**self).resolve(info, selection_set, executor)
} }
} }
impl<S, T, CtxT> GraphQLValueAsync<S> for Box<T> impl<S, T> GraphQLValueAsync<S> for Box<T>
where where
T: GraphQLValueAsync<S, Context = CtxT> + ?Sized, T: GraphQLValueAsync<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,
@ -111,16 +111,16 @@ where
} }
} }
impl<'e, S, T, CtxT> GraphQLType<S> for &'e T impl<'e, S, T> GraphQLType<S> for &'e T
where where
T: GraphQLType<S> + ?Sized,
S: ScalarValue, S: ScalarValue,
T: GraphQLType<S, Context = CtxT> + ?Sized,
{ {
fn name(info: &T::TypeInfo) -> Option<&str> { fn name(info: &Self::TypeInfo) -> Option<&str> {
T::name(info) T::name(info)
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -128,43 +128,43 @@ where
} }
} }
impl<'e, S, T, CtxT> GraphQLValue<S> for &'e T impl<'e, S, T> GraphQLValue<S> for &'e T
where where
S: ScalarValue, S: ScalarValue,
T: GraphQLValue<S, Context = CtxT> + ?Sized, T: GraphQLValue<S> + ?Sized,
{ {
type Context = CtxT; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
(**self).type_name(info) (**self).type_name(info)
} }
fn resolve_into_type( fn resolve_into_type(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
name: &str, name: &str,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_into_type(info, name, selection_set, executor) (**self).resolve_into_type(info, name, selection_set, executor)
} }
fn resolve_field( fn resolve_field(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
field: &str, field: &str,
args: &Arguments<S>, args: &Arguments<S>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_field(info, field, args, executor) (**self).resolve_field(info, field, args, executor)
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<CtxT, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve(info, selection_set, executor) (**self).resolve(info, selection_set, executor)
} }
@ -172,10 +172,10 @@ where
impl<'e, S, T> GraphQLValueAsync<S> for &'e T impl<'e, S, T> GraphQLValueAsync<S> for &'e T
where where
S: ScalarValue + Send + Sync,
T: GraphQLValueAsync<S> + ?Sized, T: GraphQLValueAsync<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Send + Sync, T::Context: Sync,
S: ScalarValue + Send + Sync,
{ {
fn resolve_field_async<'b>( fn resolve_field_async<'b>(
&'b self, &'b self,
@ -212,11 +212,11 @@ where
S: ScalarValue, S: ScalarValue,
T: GraphQLType<S> + ?Sized, T: GraphQLType<S> + ?Sized,
{ {
fn name(info: &T::TypeInfo) -> Option<&str> { fn name(info: &Self::TypeInfo) -> Option<&str> {
T::name(info) T::name(info)
} }
fn meta<'r>(info: &T::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where where
S: 'r, S: 'r,
{ {
@ -232,35 +232,35 @@ where
type Context = T::Context; type Context = T::Context;
type TypeInfo = T::TypeInfo; type TypeInfo = T::TypeInfo;
fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
(**self).type_name(info) (**self).type_name(info)
} }
fn resolve_into_type( fn resolve_into_type(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
name: &str, name: &str,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<T::Context, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_into_type(info, name, selection_set, executor) (**self).resolve_into_type(info, name, selection_set, executor)
} }
fn resolve_field( fn resolve_field(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
field: &str, field: &str,
args: &Arguments<S>, args: &Arguments<S>,
executor: &Executor<T::Context, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve_field(info, field, args, executor) (**self).resolve_field(info, field, args, executor)
} }
fn resolve( fn resolve(
&self, &self,
info: &T::TypeInfo, info: &Self::TypeInfo,
selection_set: Option<&[Selection<S>]>, selection_set: Option<&[Selection<S>]>,
executor: &Executor<T::Context, S>, executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> { ) -> ExecutionResult<S> {
(**self).resolve(info, selection_set, executor) (**self).resolve(info, selection_set, executor)
} }
@ -268,10 +268,10 @@ where
impl<'e, S, T> GraphQLValueAsync<S> for Arc<T> impl<'e, S, T> GraphQLValueAsync<S> for Arc<T>
where where
T: GraphQLValueAsync<S> + Send + ?Sized,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
T: GraphQLValueAsync<S> + ?Sized,
<T as GraphQLValue<S>>::TypeInfo: Send + Sync,
<T as GraphQLValue<S>>::Context: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,

View file

@ -382,9 +382,9 @@ where
impl<S, T> GraphQLValueAsync<S> for EmptyMutation<T> impl<S, T> GraphQLValueAsync<S> for EmptyMutation<T>
where where
Self::TypeInfo: Sync,
Self::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
Self::TypeInfo: Send + Sync,
Self::Context: Send + Sync,
{ {
} }
@ -442,9 +442,9 @@ where
impl<T, S> GraphQLSubscriptionValue<S> for EmptySubscription<T> impl<T, S> GraphQLSubscriptionValue<S> for EmptySubscription<T>
where where
Self::TypeInfo: Sync,
Self::Context: Sync,
S: ScalarValue + Send + Sync + 'static, S: ScalarValue + Send + Sync + 'static,
Self::TypeInfo: Send + Sync,
Self::Context: Send + Sync,
{ {
} }

View file

@ -1,3 +1,5 @@
use futures::{future, stream};
use crate::{ use crate::{
http::{GraphQLRequest, GraphQLResponse}, http::{GraphQLRequest, GraphQLResponse},
parser::Spanning, parser::Spanning,
@ -69,10 +71,10 @@ pub trait SubscriptionConnection<'a, S>: futures::Stream<Item = GraphQLResponse<
/// ///
/// [1]: https://spec.graphql.org/June2018/#sec-Subscription /// [1]: https://spec.graphql.org/June2018/#sec-Subscription
/// [2]: https://spec.graphql.org/June2018/#sec-Objects /// [2]: https://spec.graphql.org/June2018/#sec-Objects
pub trait GraphQLSubscriptionValue<S = DefaultScalarValue>: GraphQLValue<S> + Send + Sync pub trait GraphQLSubscriptionValue<S = DefaultScalarValue>: GraphQLValue<S> + Sync
where where
Self::Context: Send + Sync, Self::TypeInfo: Sync,
Self::TypeInfo: Send + Sync, Self::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
/// Resolves into `Value<ValuesStream>`. /// Resolves into `Value<ValuesStream>`.
@ -181,17 +183,17 @@ crate::sa::assert_obj_safe!(GraphQLSubscriptionValue<Context = (), TypeInfo = ()
pub trait GraphQLSubscriptionType<S = DefaultScalarValue>: pub trait GraphQLSubscriptionType<S = DefaultScalarValue>:
GraphQLSubscriptionValue<S> + GraphQLType<S> GraphQLSubscriptionValue<S> + GraphQLType<S>
where where
Self::Context: Send + Sync, Self::Context: Sync,
Self::TypeInfo: Send + Sync, Self::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
} }
impl<S, T> GraphQLSubscriptionType<S> for T impl<S, T> GraphQLSubscriptionType<S> for T
where where
T: GraphQLSubscriptionValue<S> + GraphQLType<S>, T: GraphQLSubscriptionValue<S> + GraphQLType<S> + ?Sized,
T::Context: Send + Sync, T::Context: Sync,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
{ {
} }
@ -199,10 +201,10 @@ where
/// Wrapper function around `resolve_selection_set_into_stream_recursive`. /// Wrapper function around `resolve_selection_set_into_stream_recursive`.
/// This wrapper is necessary because async fns can not be recursive. /// This wrapper is necessary because async fns can not be recursive.
/// Panics if executor's current selection set is None. /// Panics if executor's current selection set is None.
pub(crate) fn resolve_selection_set_into_stream<'i, 'inf, 'ref_e, 'e, 'res, 'fut, T, CtxT, S>( pub(crate) fn resolve_selection_set_into_stream<'i, 'inf, 'ref_e, 'e, 'res, 'fut, T, S>(
instance: &'i T, instance: &'i T,
info: &'inf T::TypeInfo, info: &'inf T::TypeInfo,
executor: &'ref_e Executor<'ref_e, 'e, CtxT, S>, executor: &'ref_e Executor<'ref_e, 'e, T::Context, S>,
) -> BoxFuture<'fut, Value<ValuesStream<'res, S>>> ) -> BoxFuture<'fut, Value<ValuesStream<'res, S>>>
where where
'inf: 'res, 'inf: 'res,
@ -211,10 +213,10 @@ where
'e: 'fut, 'e: 'fut,
'ref_e: 'fut, 'ref_e: 'fut,
'res: 'fut, 'res: 'fut,
T: GraphQLSubscriptionValue<S, Context = CtxT> + ?Sized, T: GraphQLSubscriptionValue<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
{ {
Box::pin(resolve_selection_set_into_stream_recursive( Box::pin(resolve_selection_set_into_stream_recursive(
instance, info, executor, instance, info, executor,
@ -224,16 +226,16 @@ where
/// Selection set default resolver logic. /// Selection set default resolver logic.
/// Returns `Value::Null` if cannot keep resolving. Otherwise pushes errors to /// Returns `Value::Null` if cannot keep resolving. Otherwise pushes errors to
/// `Executor`. /// `Executor`.
async fn resolve_selection_set_into_stream_recursive<'i, 'inf, 'ref_e, 'e, 'res, T, CtxT, S>( async fn resolve_selection_set_into_stream_recursive<'i, 'inf, 'ref_e, 'e, 'res, T, S>(
instance: &'i T, instance: &'i T,
info: &'inf T::TypeInfo, info: &'inf T::TypeInfo,
executor: &'ref_e Executor<'ref_e, 'e, CtxT, S>, executor: &'ref_e Executor<'ref_e, 'e, T::Context, S>,
) -> Value<ValuesStream<'res, S>> ) -> Value<ValuesStream<'res, S>>
where where
T: GraphQLSubscriptionValue<S, Context = CtxT> + Send + Sync + ?Sized, T: GraphQLSubscriptionValue<S> + ?Sized,
T::TypeInfo: Send + Sync, T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync, S: ScalarValue + Send + Sync,
CtxT: Send + Sync,
'inf: 'res, 'inf: 'res,
'e: 'res, 'e: 'res,
{ {
@ -270,7 +272,7 @@ where
Value::scalar(instance.concrete_type_name(executor.context(), info)); Value::scalar(instance.concrete_type_name(executor.context(), info));
object.add_field( object.add_field(
response_name, response_name,
Value::Scalar(Box::pin(futures::stream::once(async { Ok(typename) }))), Value::Scalar(Box::pin(stream::once(future::ok(typename)))),
); );
continue; continue;
} }
@ -278,11 +280,11 @@ where
let meta_field = meta_type let meta_field = meta_type
.field_by_name(f.name.item) .field_by_name(f.name.item)
.unwrap_or_else(|| { .unwrap_or_else(|| {
panic!(format!( panic!(
"Field {} not found on type {:?}", "Field {} not found on type {:?}",
f.name.item, f.name.item,
meta_type.name() meta_type.name(),
)) )
}) })
.clone(); .clone();
@ -366,6 +368,7 @@ where
Err(e) => sub_exec.push_error_at(e, start_pos.clone()), Err(e) => sub_exec.push_error_at(e, start_pos.clone()),
} }
} }
Selection::InlineFragment(Spanning { Selection::InlineFragment(Spanning {
item: ref fragment, item: ref fragment,
start: ref start_pos, start: ref start_pos,

View file

@ -1,6 +1,7 @@
#![deny(warnings)] #![deny(warnings)]
extern crate log; use std::env;
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer};
use juniper::{ use juniper::{
@ -38,8 +39,9 @@ async fn graphql(
#[actix_rt::main] #[actix_rt::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
::std::env::set_var("RUST_LOG", "actix_web=info"); env::set_var("RUST_LOG", "info");
env_logger::init(); env_logger::init();
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
App::new() App::new()
.data(schema()) .data(schema())

View file

@ -83,21 +83,21 @@ where
} }
/// Actix Web GraphQL Handler for GET and POST requests /// Actix Web GraphQL Handler for GET and POST requests
pub async fn graphql_handler<Query, Mutation, Subscription, Context, S>( pub async fn graphql_handler<Query, Mutation, Subscription, CtxT, S>(
schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>, schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>,
context: &Context, context: &CtxT,
req: HttpRequest, req: HttpRequest,
payload: actix_web::web::Payload, payload: actix_web::web::Payload,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse, Error>
where where
S: ScalarValue + Send + Sync + 'static, Query: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Context: Send + Sync + 'static, Query::TypeInfo: Sync,
Query: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Mutation: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Query::TypeInfo: Send + Sync, Mutation::TypeInfo: Sync,
Mutation: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Subscription: juniper::GraphQLSubscriptionType<S, Context = CtxT>,
Mutation::TypeInfo: Send + Sync, Subscription::TypeInfo: Sync,
Subscription: juniper::GraphQLSubscriptionType<S, Context = Context> + Send + Sync + 'static, CtxT: Sync,
Subscription::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
match *req.method() { match *req.method() {
Method::POST => post_graphql_handler(schema, context, req, payload).await, Method::POST => post_graphql_handler(schema, context, req, payload).await,
@ -108,20 +108,20 @@ where
} }
} }
/// Actix GraphQL Handler for GET requests /// Actix GraphQL Handler for GET requests
pub async fn get_graphql_handler<Query, Mutation, Subscription, Context, S>( pub async fn get_graphql_handler<Query, Mutation, Subscription, CtxT, S>(
schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>, schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>,
context: &Context, context: &CtxT,
req: HttpRequest, req: HttpRequest,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse, Error>
where where
S: ScalarValue + Send + Sync + 'static, Query: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Context: Send + Sync + 'static, Query::TypeInfo: Sync,
Query: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Mutation: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Query::TypeInfo: Send + Sync, Mutation::TypeInfo: Sync,
Mutation: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Subscription: juniper::GraphQLSubscriptionType<S, Context = CtxT>,
Mutation::TypeInfo: Send + Sync, Subscription::TypeInfo: Sync,
Subscription: juniper::GraphQLSubscriptionType<S, Context = Context> + Send + Sync + 'static, CtxT: Sync,
Subscription::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
let get_req = web::Query::<GetGraphQLRequest>::from_query(req.query_string())?; let get_req = web::Query::<GetGraphQLRequest>::from_query(req.query_string())?;
let req = GraphQLRequest::from(get_req.into_inner()); let req = GraphQLRequest::from(get_req.into_inner());
@ -137,21 +137,21 @@ where
} }
/// Actix GraphQL Handler for POST requests /// Actix GraphQL Handler for POST requests
pub async fn post_graphql_handler<Query, Mutation, Subscription, Context, S>( pub async fn post_graphql_handler<Query, Mutation, Subscription, CtxT, S>(
schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>, schema: &juniper::RootNode<'static, Query, Mutation, Subscription, S>,
context: &Context, context: &CtxT,
req: HttpRequest, req: HttpRequest,
payload: actix_web::web::Payload, payload: actix_web::web::Payload,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse, Error>
where where
S: ScalarValue + Send + Sync + 'static, Query: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Context: Send + Sync + 'static, Query::TypeInfo: Sync,
Query: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Mutation: juniper::GraphQLTypeAsync<S, Context = CtxT>,
Query::TypeInfo: Send + Sync, Mutation::TypeInfo: Sync,
Mutation: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Subscription: juniper::GraphQLSubscriptionType<S, Context = CtxT>,
Mutation::TypeInfo: Send + Sync, Subscription::TypeInfo: Sync,
Subscription: juniper::GraphQLSubscriptionType<S, Context = Context> + Send + Sync + 'static, CtxT: Sync,
Subscription::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
let content_type_header = req let content_type_header = req
.headers() .headers()

View file

@ -101,12 +101,12 @@ fn impl_scalar_struct(
}; };
let _async = quote!( let _async = quote!(
impl <__S> ::juniper::GraphQLValueAsync<__S> for #ident impl<__S> ::juniper::GraphQLValueAsync<__S> for #ident
where where
Self: Sync,
Self::TypeInfo: Sync,
Self::Context: Sync,
__S: ::juniper::ScalarValue + Send + Sync, __S: ::juniper::ScalarValue + Send + Sync,
Self: Send + Sync,
Self::Context: Send + Sync,
Self::TypeInfo: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,

View file

@ -504,9 +504,7 @@ impl ToTokens for UnionDefinition {
let mut where_async = where_clause let mut where_async = where_clause
.cloned() .cloned()
.unwrap_or_else(|| parse_quote! { where }); .unwrap_or_else(|| parse_quote! { where });
where_async where_async.predicates.push(parse_quote! { Self: Sync });
.predicates
.push(parse_quote! { Self: Send + Sync });
if self.scalar.is_none() { if self.scalar.is_none() {
where_async where_async
.predicates .predicates

View file

@ -247,10 +247,10 @@ pub fn build_scalar(
let _async = quote!( let _async = quote!(
impl#async_generic_type_decl ::juniper::GraphQLValueAsync<#async_generic_type> for #impl_for_type impl#async_generic_type_decl ::juniper::GraphQLValueAsync<#async_generic_type> for #impl_for_type
where where
Self: Sync,
Self::TypeInfo: Sync,
Self::Context: Sync,
#async_generic_type: ::juniper::ScalarValue + Send + Sync, #async_generic_type: ::juniper::ScalarValue + Send + Sync,
Self: Send + Sync,
Self::Context: Send + Sync,
Self::TypeInfo: Send + Sync,
{ {
fn resolve_async<'a>( fn resolve_async<'a>(
&'a self, &'a self,

View file

@ -930,7 +930,7 @@ impl GraphQLTypeDefiniton {
where_async where_async
.predicates .predicates
.push(parse_quote!( #scalar: Send + Sync )); .push(parse_quote!( #scalar: Send + Sync ));
where_async.predicates.push(parse_quote!(Self: Send + Sync)); where_async.predicates.push(parse_quote!(Self: Sync));
// FIXME: add where clause for interfaces. // FIXME: add where clause for interfaces.
@ -1431,7 +1431,7 @@ impl GraphQLTypeDefiniton {
where_async where_async
.predicates .predicates
.push(parse_quote!( #scalar: Send + Sync )); .push(parse_quote!( #scalar: Send + Sync ));
where_async.predicates.push(parse_quote!(Self: Send + Sync)); where_async.predicates.push(parse_quote!(Self: Sync));
let _async = quote!( let _async = quote!(
impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty
@ -1683,7 +1683,7 @@ impl GraphQLTypeDefiniton {
where_async where_async
.predicates .predicates
.push(parse_quote!( #scalar: Send + Sync )); .push(parse_quote!( #scalar: Send + Sync ));
where_async.predicates.push(parse_quote!(Self: Send + Sync)); where_async.predicates.push(parse_quote!(Self: Sync));
let async_type = quote!( let async_type = quote!(
impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #type_generics_tokens impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #type_generics_tokens

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use hyper::{ use hyper::{
service::{make_service_fn, service_fn}, service::{make_service_fn, service_fn},
Body, Method, Response, Server, StatusCode, Body, Method, Response, Server, StatusCode,
@ -6,7 +8,6 @@ use juniper::{
tests::{model::Database, schema::Query}, tests::{model::Database, schema::Query},
EmptyMutation, EmptySubscription, RootNode, EmptyMutation, EmptySubscription, RootNode,
}; };
use std::sync::Arc;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {

View file

@ -21,14 +21,14 @@ pub async fn graphql_sync<CtxT, QueryT, MutationT, SubscriptionT, S>(
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>, hyper::Error> ) -> Result<Response<Body>, hyper::Error>
where where
S: ScalarValue + Send + Sync + 'static, QueryT: GraphQLType<S, Context = CtxT>,
CtxT: Send + Sync + 'static, QueryT::TypeInfo: Sync,
QueryT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, MutationT: GraphQLType<S, Context = CtxT>,
MutationT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, SubscriptionT: GraphQLType<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Sync,
MutationT::TypeInfo: Send + Sync, CtxT: Sync,
SubscriptionT::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
Ok(match parse_req(req).await { Ok(match parse_req(req).await {
Ok(req) => execute_request_sync(root_node, context, req).await, Ok(req) => execute_request_sync(root_node, context, req).await,
@ -42,14 +42,14 @@ pub async fn graphql<CtxT, QueryT, MutationT, SubscriptionT, S>(
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>, hyper::Error> ) -> Result<Response<Body>, hyper::Error>
where where
S: ScalarValue + Send + Sync + 'static, QueryT: GraphQLTypeAsync<S, Context = CtxT>,
CtxT: Send + Sync + 'static, QueryT::TypeInfo: Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + 'static, MutationT: GraphQLTypeAsync<S, Context = CtxT>,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + 'static, MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Sync,
MutationT::TypeInfo: Send + Sync, CtxT: Sync,
SubscriptionT::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
Ok(match parse_req(req).await { Ok(match parse_req(req).await {
Ok(req) => execute_request(root_node, context, req).await, Ok(req) => execute_request(root_node, context, req).await,
@ -158,14 +158,14 @@ async fn execute_request_sync<CtxT, QueryT, MutationT, SubscriptionT, S>(
request: GraphQLBatchRequest<S>, request: GraphQLBatchRequest<S>,
) -> Response<Body> ) -> Response<Body>
where where
S: ScalarValue + Send + Sync + 'static, QueryT: GraphQLType<S, Context = CtxT>,
CtxT: Send + Sync + 'static, QueryT::TypeInfo: Sync,
QueryT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, MutationT: GraphQLType<S, Context = CtxT>,
MutationT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync + 'static, SubscriptionT: GraphQLType<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Sync,
MutationT::TypeInfo: Send + Sync, CtxT: Sync,
SubscriptionT::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
let res = request.execute_sync(&*root_node, &context); let res = request.execute_sync(&*root_node, &context);
let body = Body::from(serde_json::to_string_pretty(&res).unwrap()); let body = Body::from(serde_json::to_string_pretty(&res).unwrap());
@ -189,14 +189,14 @@ async fn execute_request<CtxT, QueryT, MutationT, SubscriptionT, S>(
request: GraphQLBatchRequest<S>, request: GraphQLBatchRequest<S>,
) -> Response<Body> ) -> Response<Body>
where where
S: ScalarValue + Send + Sync + 'static, QueryT: GraphQLTypeAsync<S, Context = CtxT>,
CtxT: Send + Sync + 'static, QueryT::TypeInfo: Sync,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + 'static, MutationT: GraphQLTypeAsync<S, Context = CtxT>,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + 'static, MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Sync,
MutationT::TypeInfo: Send + Sync, CtxT: Sync,
SubscriptionT::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync,
{ {
let res = request.execute(&*root_node, &context).await; let res = request.execute(&*root_node, &context).await;
let body = Body::from(serde_json::to_string_pretty(&res).unwrap()); let body = Body::from(serde_json::to_string_pretty(&res).unwrap());

View file

@ -41,6 +41,10 @@ Check the LICENSE file for details.
use std::io::{Cursor, Read}; use std::io::{Cursor, Read};
use juniper::{
http::{self, GraphQLBatchRequest},
DefaultScalarValue, FieldError, GraphQLType, InputValue, RootNode, ScalarValue,
};
use rocket::{ use rocket::{
data::{FromDataSimple, Outcome as FromDataOutcome}, data::{FromDataSimple, Outcome as FromDataOutcome},
http::{ContentType, RawStr, Status}, http::{ContentType, RawStr, Status},
@ -51,12 +55,6 @@ use rocket::{
Request, Request,
}; };
use juniper::{http, InputValue};
use juniper::{
http::GraphQLBatchRequest, DefaultScalarValue, FieldError, GraphQLType, RootNode, ScalarValue,
};
/// Simple wrapper around an incoming GraphQL request /// Simple wrapper around an incoming GraphQL request
/// ///
/// See the `http` module for more information. This type can be constructed /// See the `http` module for more information. This type can be constructed
@ -422,7 +420,11 @@ mod fromform_tests {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use juniper::{
http::tests as http_tests,
tests::{model::Database, schema::Query},
EmptyMutation, EmptySubscription, RootNode,
};
use rocket::{ use rocket::{
self, get, self, get,
http::ContentType, http::ContentType,
@ -432,12 +434,6 @@ mod tests {
routes, Rocket, State, routes, Rocket, State,
}; };
use juniper::{
http::tests as http_tests,
tests::{model::Database, schema::Query},
EmptyMutation, EmptySubscription, RootNode,
};
type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>; type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
#[get("/?<request..>")] #[get("/?<request..>")]

View file

@ -1,11 +1,10 @@
#![feature(decl_macro, proc_macro_hygiene)] #![feature(decl_macro, proc_macro_hygiene)]
use rocket::{response::content, State};
use juniper::{ use juniper::{
tests::{model::Database, schema::Query}, tests::{model::Database, schema::Query},
EmptyMutation, EmptySubscription, RootNode, EmptyMutation, EmptySubscription, RootNode,
}; };
use rocket::{response::content, State};
type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>; type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;

View file

@ -119,13 +119,13 @@ where
context: &CtxT, context: &CtxT,
) -> GraphQLResponse ) -> GraphQLResponse
where where
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, QueryT: GraphQLTypeAsync<S, Context = CtxT>,
QueryT::TypeInfo: Send + Sync, QueryT::TypeInfo: Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, MutationT: GraphQLTypeAsync<S, Context = CtxT>,
MutationT::TypeInfo: Send + Sync, MutationT::TypeInfo: Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT>,
SubscriptionT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Sync,
CtxT: Send + Sync, CtxT: Sync,
S: Send + Sync, S: Send + Sync,
{ {
let response = self.0.execute(root_node, context).await; let response = self.0.execute(root_node, context).await;
@ -204,7 +204,7 @@ impl GraphQLResponse {
impl<'f, S> FromForm<'f> for GraphQLRequest<S> impl<'f, S> FromForm<'f> for GraphQLRequest<S>
where where
S: ScalarValue + Send + Sync, S: ScalarValue,
{ {
type Error = String; type Error = String;
@ -275,7 +275,7 @@ where
impl<'v, S> FromFormValue<'v> for GraphQLRequest<S> impl<'v, S> FromFormValue<'v> for GraphQLRequest<S>
where where
S: ScalarValue + Send + Sync, S: ScalarValue,
{ {
type Error = String; type Error = String;
@ -290,7 +290,7 @@ const BODY_LIMIT: u64 = 1024 * 100;
impl<S> FromDataSimple for GraphQLRequest<S> impl<S> FromDataSimple for GraphQLRequest<S>
where where
S: ScalarValue + Send + Sync, S: ScalarValue,
{ {
type Error = String; type Error = String;

View file

@ -11,9 +11,13 @@
#![deny(warnings)] #![deny(warnings)]
#![doc(html_root_url = "https://docs.rs/juniper_subscriptions/0.14.2")] #![doc(html_root_url = "https://docs.rs/juniper_subscriptions/0.14.2")]
use std::{iter::FromIterator, pin::Pin}; use std::{
iter::FromIterator,
pin::Pin,
task::{self, Poll},
};
use futures::{task::Poll, Stream}; use futures::{future, stream, FutureExt as _, Stream, StreamExt as _, TryFutureExt as _};
use juniper::{ use juniper::{
http::{GraphQLRequest, GraphQLResponse}, http::{GraphQLRequest, GraphQLResponse},
BoxFuture, ExecutionError, GraphQLError, GraphQLSubscriptionType, GraphQLTypeAsync, Object, BoxFuture, ExecutionError, GraphQLError, GraphQLSubscriptionType, GraphQLTypeAsync, Object,
@ -25,14 +29,14 @@ use juniper::{
/// - handles subscription start /// - handles subscription start
pub struct Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S> pub struct Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S>
where where
S: ScalarValue + Send + Sync, QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync, QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send,
MutationT::TypeInfo: Send + Sync, MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send,
SubscriptionT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync, CtxT: Sync,
S: ScalarValue + Send + Sync,
{ {
root_node: juniper::RootNode<'a, QueryT, MutationT, SubscriptionT, S>, root_node: juniper::RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
} }
@ -40,14 +44,14 @@ where
impl<'a, QueryT, MutationT, SubscriptionT, CtxT, S> impl<'a, QueryT, MutationT, SubscriptionT, CtxT, S>
Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S> Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S>
where where
S: ScalarValue + Send + Sync, QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync, QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send,
MutationT::TypeInfo: Send + Sync, MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send,
SubscriptionT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync, CtxT: Sync,
S: ScalarValue + Send + Sync,
{ {
/// Builds new [`Coordinator`] with specified `root_node` /// Builds new [`Coordinator`] with specified `root_node`
pub fn new(root_node: juniper::RootNode<'a, QueryT, MutationT, SubscriptionT, S>) -> Self { pub fn new(root_node: juniper::RootNode<'a, QueryT, MutationT, SubscriptionT, S>) -> Self {
@ -58,14 +62,14 @@ where
impl<'a, QueryT, MutationT, SubscriptionT, CtxT, S> SubscriptionCoordinator<'a, CtxT, S> impl<'a, QueryT, MutationT, SubscriptionT, CtxT, S> SubscriptionCoordinator<'a, CtxT, S>
for Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S> for Coordinator<'a, QueryT, MutationT, SubscriptionT, CtxT, S>
where where
S: ScalarValue + Send + Sync + 'a, QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send,
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync, QueryT::TypeInfo: Send + Sync,
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync, MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send,
MutationT::TypeInfo: Send + Sync, MutationT::TypeInfo: Send + Sync,
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync, SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send,
SubscriptionT::TypeInfo: Send + Sync, SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync, CtxT: Sync,
S: ScalarValue + Send + Sync + 'a,
{ {
type Connection = Connection<'a, S>; type Connection = Connection<'a, S>;
@ -76,13 +80,9 @@ where
req: &'a GraphQLRequest<S>, req: &'a GraphQLRequest<S>,
context: &'a CtxT, context: &'a CtxT,
) -> BoxFuture<'a, Result<Self::Connection, Self::Error>> { ) -> BoxFuture<'a, Result<Self::Connection, Self::Error>> {
let rn = &self.root_node; juniper::http::resolve_into_stream(req, &self.root_node, context)
.map_ok(|(stream, errors)| Connection::from_stream(stream, errors))
Box::pin(async move { .boxed()
let (stream, errors) = juniper::http::resolve_into_stream(req, rn, context).await?;
Ok(Connection::from_stream(stream, errors))
})
} }
} }
@ -98,7 +98,7 @@ where
/// [`Value::Object`] - waits while each field of the [`Object`] is returned, then yields the whole object /// [`Value::Object`] - waits while each field of the [`Object`] is returned, then yields the whole object
/// `Value::Object<Value::Object<_>>` - returns [`Value::Null`] if [`Value::Object`] consists of sub-objects /// `Value::Object<Value::Object<_>>` - returns [`Value::Null`] if [`Value::Object`] consists of sub-objects
pub struct Connection<'a, S> { pub struct Connection<'a, S> {
stream: Pin<Box<dyn futures::Stream<Item = GraphQLResponse<'a, S>> + Send + 'a>>, stream: Pin<Box<dyn Stream<Item = GraphQLResponse<'a, S>> + Send + 'a>>,
} }
impl<'a, S> Connection<'a, S> impl<'a, S> Connection<'a, S>
@ -118,16 +118,13 @@ impl<'a, S> SubscriptionConnection<'a, S> for Connection<'a, S> where
{ {
} }
impl<'a, S> futures::Stream for Connection<'a, S> impl<'a, S> Stream for Connection<'a, S>
where where
S: ScalarValue + Send + Sync + 'a, S: ScalarValue + Send + Sync + 'a,
{ {
type Item = GraphQLResponse<'a, S>; type Item = GraphQLResponse<'a, S>;
fn poll_next( fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
self: Pin<&mut Self>,
cx: &mut futures::task::Context<'_>,
) -> Poll<Option<Self::Item>> {
// this is safe as stream is only mutated here and is not moved anywhere // this is safe as stream is only mutated here and is not moved anywhere
let Connection { stream } = unsafe { self.get_unchecked_mut() }; let Connection { stream } = unsafe { self.get_unchecked_mut() };
let stream = unsafe { Pin::new_unchecked(stream) }; let stream = unsafe { Pin::new_unchecked(stream) };
@ -146,22 +143,20 @@ where
fn whole_responses_stream<'a, S>( fn whole_responses_stream<'a, S>(
stream: Value<ValuesStream<'a, S>>, stream: Value<ValuesStream<'a, S>>,
errors: Vec<ExecutionError<S>>, errors: Vec<ExecutionError<S>>,
) -> Pin<Box<dyn futures::Stream<Item = GraphQLResponse<'a, S>> + Send + 'a>> ) -> Pin<Box<dyn Stream<Item = GraphQLResponse<'a, S>> + Send + 'a>>
where where
S: ScalarValue + Send + Sync + 'a, S: ScalarValue + Send + Sync + 'a,
{ {
use futures::stream::{self, StreamExt as _};
if !errors.is_empty() { if !errors.is_empty() {
return Box::pin(stream::once(async move { return Box::pin(stream::once(future::ready(GraphQLResponse::from_result(
GraphQLResponse::from_result(Ok((Value::Null, errors))) Ok((Value::Null, errors)),
})); ))));
} }
match stream { match stream {
Value::Null => Box::pin(stream::once(async move { Value::Null => Box::pin(stream::once(future::ready(GraphQLResponse::from_result(
GraphQLResponse::from_result(Ok((Value::Null, vec![]))) Ok((Value::Null, vec![])),
})), )))),
Value::Scalar(s) => Box::pin(s.map(|res| match res { Value::Scalar(s) => Box::pin(s.map(|res| match res {
Ok(val) => GraphQLResponse::from_result(Ok((val, vec![]))), Ok(val) => GraphQLResponse::from_result(Ok((val, vec![]))),
Err(err) => GraphQLResponse::from_result(Ok((Value::Null, vec![err]))), Err(err) => GraphQLResponse::from_result(Ok((Value::Null, vec![err]))),
@ -176,9 +171,9 @@ where
Value::Object(mut object) => { Value::Object(mut object) => {
let obj_len = object.field_count(); let obj_len = object.field_count();
if obj_len == 0 { if obj_len == 0 {
return Box::pin(stream::once(async move { return Box::pin(stream::once(future::ready(GraphQLResponse::from_result(
GraphQLResponse::from_result(Ok((Value::Null, vec![]))) Ok((Value::Null, vec![])),
})); ))));
} }
let mut filled_count = 0; let mut filled_count = 0;
@ -187,66 +182,65 @@ where
ready_vec.push(None); ready_vec.push(None);
} }
let stream = let stream = stream::poll_fn(move |mut ctx| -> Poll<Option<GraphQLResponse<'a, S>>> {
futures::stream::poll_fn(move |mut ctx| -> Poll<Option<GraphQLResponse<'a, S>>> { let mut obj_iterator = object.iter_mut();
let mut obj_iterator = object.iter_mut();
// Due to having to modify `ready_vec` contents (by-move pattern) // Due to having to modify `ready_vec` contents (by-move pattern)
// and only being able to iterate over `object`'s mutable references (by-ref pattern) // and only being able to iterate over `object`'s mutable references (by-ref pattern)
// `ready_vec` and `object` cannot be iterated simultaneously. // `ready_vec` and `object` cannot be iterated simultaneously.
// TODO: iterate over i and (ref field_name, ref val) once // TODO: iterate over i and (ref field_name, ref val) once
// [this RFC](https://github.com/rust-lang/rust/issues/68354) // [this RFC](https://github.com/rust-lang/rust/issues/68354)
// is implemented // is implemented
for ready in ready_vec.iter_mut().take(obj_len) { for ready in ready_vec.iter_mut().take(obj_len) {
let (field_name, val) = match obj_iterator.next() { let (field_name, val) = match obj_iterator.next() {
Some(v) => v, Some(v) => v,
None => break, None => break,
}; };
if ready.is_some() { if ready.is_some() {
continue; continue;
} }
match val { match val {
Value::Scalar(stream) => { Value::Scalar(stream) => {
match Pin::new(stream).poll_next(&mut ctx) { match Pin::new(stream).poll_next(&mut ctx) {
Poll::Ready(None) => return Poll::Ready(None), Poll::Ready(None) => return Poll::Ready(None),
Poll::Ready(Some(value)) => { Poll::Ready(Some(value)) => {
*ready = Some((field_name.clone(), value)); *ready = Some((field_name.clone(), value));
filled_count += 1; filled_count += 1;
}
Poll::Pending => { /* check back later */ }
} }
} Poll::Pending => { /* check back later */ }
_ => {
// For now only `Object<Value::Scalar>` is supported
*ready = Some((field_name.clone(), Ok(Value::Null)));
filled_count += 1;
} }
} }
_ => {
// For now only `Object<Value::Scalar>` is supported
*ready = Some((field_name.clone(), Ok(Value::Null)));
filled_count += 1;
}
} }
}
if filled_count == obj_len { if filled_count == obj_len {
filled_count = 0; filled_count = 0;
let new_vec = (0..obj_len).map(|_| None).collect::<Vec<_>>(); let new_vec = (0..obj_len).map(|_| None).collect::<Vec<_>>();
let ready_vec = std::mem::replace(&mut ready_vec, new_vec); let ready_vec = std::mem::replace(&mut ready_vec, new_vec);
let ready_vec_iterator = ready_vec.into_iter().map(|el| { let ready_vec_iterator = ready_vec.into_iter().map(|el| {
let (name, val) = el.unwrap(); let (name, val) = el.unwrap();
if let Ok(value) = val { if let Ok(value) = val {
(name, value) (name, value)
} else { } else {
(name, Value::Null) (name, Value::Null)
} }
}); });
let obj = Object::from_iter(ready_vec_iterator); let obj = Object::from_iter(ready_vec_iterator);
Poll::Ready(Some(GraphQLResponse::from_result(Ok(( Poll::Ready(Some(GraphQLResponse::from_result(Ok((
Value::Object(obj), Value::Object(obj),
vec![], vec![],
))))) )))))
} else { } else {
Poll::Pending Poll::Pending
} }
}); });
Box::pin(stream) Box::pin(stream)
} }
@ -255,10 +249,11 @@ where
#[cfg(test)] #[cfg(test)]
mod whole_responses_stream { mod whole_responses_stream {
use super::*;
use futures::{stream, StreamExt as _}; use futures::{stream, StreamExt as _};
use juniper::{DefaultScalarValue, ExecutionError, FieldError}; use juniper::{DefaultScalarValue, ExecutionError, FieldError};
use super::*;
#[tokio::test] #[tokio::test]
async fn with_error() { async fn with_error() {
let expected = vec![GraphQLResponse::<DefaultScalarValue>::error( let expected = vec![GraphQLResponse::<DefaultScalarValue>::error(

View file

@ -1,6 +1,6 @@
#![deny(warnings)] #![deny(warnings)]
extern crate log; use std::env;
use juniper::{ use juniper::{
tests::{model::Database, schema::Query}, tests::{model::Database, schema::Query},
@ -20,7 +20,7 @@ fn schema() -> Schema {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
::std::env::set_var("RUST_LOG", "warp_server"); env::set_var("RUST_LOG", "warp_server");
env_logger::init(); env_logger::init();
let log = warp::log("warp_server"); let log = warp::log("warp_server");

View file

@ -111,25 +111,25 @@ use warp::{body, filters::BoxedFilter, header, http, query, Filter};
/// .and(warp::post()) /// .and(warp::post())
/// .and(graphql_filter); /// .and(graphql_filter);
/// ``` /// ```
pub fn make_graphql_filter<Query, Mutation, Subscription, Context, S>( pub fn make_graphql_filter<Query, Mutation, Subscription, CtxT, S>(
schema: juniper::RootNode<'static, Query, Mutation, Subscription, S>, schema: juniper::RootNode<'static, Query, Mutation, Subscription, S>,
context_extractor: BoxedFilter<(Context,)>, context_extractor: BoxedFilter<(CtxT,)>,
) -> BoxedFilter<(http::Response<Vec<u8>>,)> ) -> BoxedFilter<(http::Response<Vec<u8>>,)>
where where
S: ScalarValue + Send + Sync + 'static, Query: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + 'static,
Context: Send + Sync + 'static,
Query: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static,
Query::TypeInfo: Send + Sync, Query::TypeInfo: Send + Sync,
Mutation: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Mutation: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + 'static,
Mutation::TypeInfo: Send + Sync, Mutation::TypeInfo: Send + Sync,
Subscription: juniper::GraphQLSubscriptionType<S, Context = Context> + Send + Sync + 'static, Subscription: juniper::GraphQLSubscriptionType<S, Context = CtxT> + Send + 'static,
Subscription::TypeInfo: Send + Sync, Subscription::TypeInfo: Send + Sync,
CtxT: Send + Sync + 'static,
S: ScalarValue + Send + Sync + 'static,
{ {
let schema = Arc::new(schema); let schema = Arc::new(schema);
let post_json_schema = schema.clone(); let post_json_schema = schema.clone();
let post_graphql_schema = schema.clone(); let post_graphql_schema = schema.clone();
let handle_post_json_request = move |context: Context, req: GraphQLBatchRequest<S>| { let handle_post_json_request = move |context: CtxT, req: GraphQLBatchRequest<S>| {
let schema = post_json_schema.clone(); let schema = post_json_schema.clone();
async move { async move {
let resp = req.execute(&schema, &context).await; let resp = req.execute(&schema, &context).await;
@ -150,7 +150,7 @@ where
.and(body::json()) .and(body::json())
.and_then(handle_post_json_request); .and_then(handle_post_json_request);
let handle_post_graphql_request = move |context: Context, body: Bytes| { let handle_post_graphql_request = move |context: CtxT, body: Bytes| {
let schema = post_graphql_schema.clone(); let schema = post_graphql_schema.clone();
async move { async move {
let query = str::from_utf8(body.as_ref()).map_err(|e| { let query = str::from_utf8(body.as_ref()).map_err(|e| {
@ -173,7 +173,7 @@ where
.and(body::bytes()) .and(body::bytes())
.and_then(handle_post_graphql_request); .and_then(handle_post_graphql_request);
let handle_get_request = move |context: Context, mut qry: HashMap<String, String>| { let handle_get_request = move |context: CtxT, mut qry: HashMap<String, String>| {
let schema = schema.clone(); let schema = schema.clone();
async move { async move {
let req = GraphQLRequest::new( let req = GraphQLRequest::new(
@ -206,22 +206,22 @@ where
} }
/// Make a synchronous filter for graphql endpoint. /// Make a synchronous filter for graphql endpoint.
pub fn make_graphql_filter_sync<Query, Mutation, Subscription, Context, S>( pub fn make_graphql_filter_sync<Query, Mutation, Subscription, CtxT, S>(
schema: juniper::RootNode<'static, Query, Mutation, Subscription, S>, schema: juniper::RootNode<'static, Query, Mutation, Subscription, S>,
context_extractor: BoxedFilter<(Context,)>, context_extractor: BoxedFilter<(CtxT,)>,
) -> BoxedFilter<(http::Response<Vec<u8>>,)> ) -> BoxedFilter<(http::Response<Vec<u8>>,)>
where where
Query: juniper::GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
Mutation: juniper::GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
Subscription: juniper::GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
CtxT: Send + Sync + 'static,
S: ScalarValue + Send + Sync + 'static, S: ScalarValue + Send + Sync + 'static,
Context: Send + Sync + 'static,
Query: juniper::GraphQLType<S, Context = Context, TypeInfo = ()> + Send + Sync + 'static,
Mutation: juniper::GraphQLType<S, Context = Context, TypeInfo = ()> + Send + Sync + 'static,
Subscription: juniper::GraphQLType<S, Context = Context, TypeInfo = ()> + Send + Sync + 'static,
{ {
let schema = Arc::new(schema); let schema = Arc::new(schema);
let post_json_schema = schema.clone(); let post_json_schema = schema.clone();
let post_graphql_schema = schema.clone(); let post_graphql_schema = schema.clone();
let handle_post_json_request = move |context: Context, req: GraphQLBatchRequest<S>| { let handle_post_json_request = move |context: CtxT, req: GraphQLBatchRequest<S>| {
let schema = post_json_schema.clone(); let schema = post_json_schema.clone();
async move { async move {
let res = task::spawn_blocking(move || { let res = task::spawn_blocking(move || {
@ -243,7 +243,7 @@ where
.and(body::json()) .and(body::json())
.and_then(handle_post_json_request); .and_then(handle_post_json_request);
let handle_post_graphql_request = move |context: Context, body: Bytes| { let handle_post_graphql_request = move |context: CtxT, body: Bytes| {
let schema = post_graphql_schema.clone(); let schema = post_graphql_schema.clone();
async move { async move {
let res = task::spawn_blocking(move || { let res = task::spawn_blocking(move || {
@ -270,7 +270,7 @@ where
.and(body::bytes()) .and(body::bytes())
.and_then(handle_post_graphql_request); .and_then(handle_post_graphql_request);
let handle_get_request = move |context: Context, mut qry: HashMap<String, String>| { let handle_get_request = move |context: CtxT, mut qry: HashMap<String, String>| {
let schema = schema.clone(); let schema = schema.clone();
async move { async move {
let res = task::spawn_blocking(move || { let res = task::spawn_blocking(move || {
@ -430,21 +430,20 @@ pub mod subscriptions {
/// - execute subscription and return values from stream /// - execute subscription and return values from stream
/// - stop stream and close ws connection /// - stop stream and close ws connection
#[allow(dead_code)] #[allow(dead_code)]
pub fn graphql_subscriptions<Query, Mutation, Subscription, Context, S>( pub fn graphql_subscriptions<Query, Mutation, Subscription, CtxT, S>(
websocket: warp::ws::WebSocket, websocket: warp::ws::WebSocket,
coordinator: Arc<Coordinator<'static, Query, Mutation, Subscription, Context, S>>, coordinator: Arc<Coordinator<'static, Query, Mutation, Subscription, CtxT, S>>,
context: Context, context: CtxT,
) -> impl Future<Output = Result<(), failure::Error>> + Send ) -> impl Future<Output = Result<(), failure::Error>> + Send
where where
S: ScalarValue + Send + Sync + 'static, Query: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + 'static,
Context: Clone + Send + Sync + 'static,
Query: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static,
Query::TypeInfo: Send + Sync, Query::TypeInfo: Send + Sync,
Mutation: juniper::GraphQLTypeAsync<S, Context = Context> + Send + Sync + 'static, Mutation: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + 'static,
Mutation::TypeInfo: Send + Sync, Mutation::TypeInfo: Send + Sync,
Subscription: Subscription: juniper::GraphQLSubscriptionType<S, Context = CtxT> + Send + 'static,
juniper::GraphQLSubscriptionType<S, Context = Context> + Send + Sync + 'static,
Subscription::TypeInfo: Send + Sync, Subscription::TypeInfo: Send + Sync,
CtxT: Clone + Send + Sync + 'static,
S: ScalarValue + Send + Sync + 'static,
{ {
let (sink_tx, sink_rx) = websocket.split(); let (sink_tx, sink_rx) = websocket.split();
let (ws_tx, ws_rx) = mpsc::unbounded(); let (ws_tx, ws_rx) = mpsc::unbounded();