Changed implementation location for GraphQLBatchRequest/Response (#608)

This commit is contained in:
Jordão Rodrigues Oliveira Rosario 2020-04-10 02:35:30 -03:00 committed by GitHub
parent c12f40c0f5
commit 926d4e5738
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 97 deletions

View file

@ -217,6 +217,120 @@ where
}
}
/// Simple wrapper around GraphQLRequest to allow the handling of Batch requests
#[derive(Debug, serde_derive::Deserialize, PartialEq)]
#[serde(untagged)]
#[serde(bound = "InputValue<S>: Deserialize<'de>")]
pub enum GraphQLBatchRequest<S = DefaultScalarValue>
where
S: ScalarValue,
{
/// A single operation request.
Single(GraphQLRequest<S>),
/// A batch operation request.
Batch(Vec<GraphQLRequest<S>>),
}
impl<S> GraphQLBatchRequest<S>
where
S: ScalarValue,
{
/// 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.
pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>(
&'a self,
root_node: &'a crate::RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT,
) -> GraphQLBatchResponse<'a, S>
where
QueryT: crate::GraphQLType<S, Context = CtxT>,
MutationT: crate::GraphQLType<S, Context = CtxT>,
SubscriptionT: crate::GraphQLType<S, Context = CtxT>,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{
match *self {
GraphQLBatchRequest::Single(ref request) => {
GraphQLBatchResponse::Single(request.execute_sync(root_node, context))
}
GraphQLBatchRequest::Batch(ref requests) => GraphQLBatchResponse::Batch(
requests
.iter()
.map(|request| request.execute_sync(root_node, context))
.collect(),
),
}
}
/// Executes a GraphQL request using the specified schema and context
///
/// This is a simple wrapper around the `execute` function exposed in
/// GraphQLRequest
pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>(
&'a self,
root_node: &'a crate::RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
context: &'a CtxT,
) -> GraphQLBatchResponse<'a, S>
where
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: crate::GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
S: Send + Sync,
{
match *self {
GraphQLBatchRequest::Single(ref request) => {
let res = request.execute(root_node, context).await;
GraphQLBatchResponse::Single(res)
}
GraphQLBatchRequest::Batch(ref requests) => {
let futures = requests
.iter()
.map(|request| request.execute(root_node, context))
.collect::<Vec<_>>();
let responses = futures::future::join_all(futures).await;
GraphQLBatchResponse::Batch(responses)
}
}
}
}
/// Simple wrapper around the result (GraphQLResponse) from executing a GraphQLBatchRequest
///
/// This struct implements Serialize, so you can simply serialize this
/// to JSON and send it over the wire. use the `is_ok` to determine
/// wheter to send a 200 or 400 HTTP status code.
#[derive(serde_derive::Serialize)]
#[serde(untagged)]
pub enum GraphQLBatchResponse<'a, S = DefaultScalarValue>
where
S: ScalarValue,
{
/// Result of a single operation in a GraphQL request.
Single(GraphQLResponse<'a, S>),
/// Result of a batch operation in a GraphQL request.
Batch(Vec<GraphQLResponse<'a, S>>),
}
impl<'a, S> GraphQLBatchResponse<'a, S>
where
S: ScalarValue,
{
/// Returns if all the GraphQLResponse in this operation are ok,
/// you can use it to determine wheter to send a 200 or 400 HTTP status code.
pub fn is_ok(&self) -> bool {
match self {
GraphQLBatchResponse::Single(res) => res.is_ok(),
GraphQLBatchResponse::Batch(reses) => reses.iter().all(|res| res.is_ok()),
}
}
}
#[cfg(any(test, feature = "expose-test-schema"))]
#[allow(missing_docs)]
pub mod tests {

View file

@ -1,6 +1,8 @@
# master
- Compatibility with the latest `juniper`.
- Changed the implementation place of GraphQLBatchRequest and GraphQLBatchResponse in `juniper_warp`
to `juniper` to be reused in other http integrations, since this implementation was private.
## Breaking Changes

View file

@ -43,106 +43,10 @@ Check the LICENSE file for details.
use std::{pin::Pin, sync::Arc};
use futures::{Future, FutureExt as _, TryFutureExt};
use juniper::{DefaultScalarValue, InputValue, ScalarValue};
use serde::Deserialize;
use juniper::{http::GraphQLBatchRequest, ScalarValue};
use tokio::task;
use warp::{filters::BoxedFilter, Filter};
#[derive(Debug, serde_derive::Deserialize, PartialEq)]
#[serde(untagged)]
#[serde(bound = "InputValue<S>: Deserialize<'de>")]
enum GraphQLBatchRequest<S = DefaultScalarValue>
where
S: ScalarValue,
{
Single(juniper::http::GraphQLRequest<S>),
Batch(Vec<juniper::http::GraphQLRequest<S>>),
}
impl<S> GraphQLBatchRequest<S>
where
S: ScalarValue,
{
pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>(
&'a self,
root_node: &'a juniper::RootNode<QueryT, MutationT, SubscriptionT, S>,
context: &CtxT,
) -> GraphQLBatchResponse<'a, S>
where
QueryT: juniper::GraphQLType<S, Context = CtxT>,
MutationT: juniper::GraphQLType<S, Context = CtxT>,
SubscriptionT: juniper::GraphQLType<S, Context = CtxT>,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
{
match *self {
GraphQLBatchRequest::Single(ref request) => {
GraphQLBatchResponse::Single(request.execute_sync(root_node, context))
}
GraphQLBatchRequest::Batch(ref requests) => GraphQLBatchResponse::Batch(
requests
.iter()
.map(|request| request.execute_sync(root_node, context))
.collect(),
),
}
}
pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>(
&'a self,
root_node: &'a juniper::RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
context: &'a CtxT,
) -> GraphQLBatchResponse<'a, S>
where
QueryT: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
QueryT::TypeInfo: Send + Sync,
MutationT: juniper::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
MutationT::TypeInfo: Send + Sync,
SubscriptionT: juniper::GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
SubscriptionT::TypeInfo: Send + Sync,
CtxT: Send + Sync,
S: Send + Sync,
{
match *self {
GraphQLBatchRequest::Single(ref request) => {
let res = request.execute(root_node, context).await;
GraphQLBatchResponse::Single(res)
}
GraphQLBatchRequest::Batch(ref requests) => {
let futures = requests
.iter()
.map(|request| request.execute(root_node, context))
.collect::<Vec<_>>();
let responses = futures::future::join_all(futures).await;
GraphQLBatchResponse::Batch(responses)
}
}
}
}
#[derive(serde_derive::Serialize)]
#[serde(untagged)]
enum GraphQLBatchResponse<'a, S = DefaultScalarValue>
where
S: ScalarValue,
{
Single(juniper::http::GraphQLResponse<'a, S>),
Batch(Vec<juniper::http::GraphQLResponse<'a, S>>),
}
impl<'a, S> GraphQLBatchResponse<'a, S>
where
S: ScalarValue,
{
fn is_ok(&self) -> bool {
match self {
GraphQLBatchResponse::Single(res) => res.is_ok(),
GraphQLBatchResponse::Batch(reses) => reses.iter().all(|res| res.is_ok()),
}
}
}
/// Make a filter for graphql queries/mutations.
///
/// The `schema` argument is your juniper schema.