Remove connection::DataSource

This commit is contained in:
Sunli 2020-06-15 12:06:15 +08:00
parent 1124124099
commit c05127bb3e
3 changed files with 34 additions and 382 deletions

View File

@ -4,7 +4,6 @@ mod connection_type;
mod cursor;
mod edge;
mod page_info;
mod slice;
use crate::FieldResult;
pub use connection_type::Connection;
@ -18,158 +17,6 @@ use std::fmt::Display;
#[async_graphql_derive::SimpleObject(internal)]
pub struct EmptyFields;
/// Data source of GraphQL Cursor Connections type
///
/// `Edge` is an extension object type that extends the edge fields, If you don't need it, you can use `EmptyEdgeFields`.
///
/// # References
/// (GraphQL Cursor Connections Specification)[https://facebook.github.io/relay/graphql/connections.htm]
///
/// # Examples
///
/// ```rust
/// use async_graphql::*;
/// use async_graphql::connection::*;
///
/// struct QueryRoot;
///
/// struct Numbers;
///
/// #[SimpleObject]
/// struct Diff {
/// diff: i32,
/// }
///
/// #[DataSource]
/// impl DataSource for Numbers {
/// type CursorType = usize;
/// type NodeType = i32;
/// type ConnectionFieldsType = EmptyFields;
/// type EdgeFieldsType = Diff;
///
/// async fn execute_query(&self,
/// after: Option<usize>,
/// before: Option<usize>,
/// first: Option<usize>,
/// last: Option<usize>,
/// ) -> FieldResult<Connection<Self::CursorType, Self::NodeType, Self::ConnectionFieldsType, Self::EdgeFieldsType>> {
/// let mut start = after.map(|after| after + 1).unwrap_or(0);
/// let mut end = before.unwrap_or(10000);
/// if let Some(first) = first {
/// end = (start + first).min(end);
/// }
/// if let Some(last) = last {
/// start = if last > end - start {
/// end
/// } else {
/// end - last
/// };
/// }
/// let mut connection = Connection::new(start > 0, end < 10000);
/// connection.append(
/// (start..end).into_iter().map(|n|
/// Edge::with_additional_fields(n, n as i32, Diff{ diff: (10000 - n) as i32 })),
/// );
/// Ok(connection)
/// }
/// }
///
/// #[Object]
/// impl QueryRoot {
/// async fn numbers(&self,
/// after: Option<String>,
/// before: Option<String>,
/// first: Option<i32>,
/// last: Option<i32>
/// ) -> FieldResult<Connection<usize, i32, EmptyFields, Diff>> {
/// Numbers.query(after, before, first, last).await
/// }
/// }
///
/// #[async_std::main]
/// async fn main() {
/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
///
/// assert_eq!(schema.execute("{ numbers(first: 2) { edges { node diff } } }").await.unwrap().data, serde_json::json!({
/// "numbers": {
/// "edges": [
/// {"node": 0, "diff": 10000},
/// {"node": 1, "diff": 9999},
/// ]
/// },
/// }));
///
/// assert_eq!(schema.execute("{ numbers(last: 2) { edges { node diff } } }").await.unwrap().data, serde_json::json!({
/// "numbers": {
/// "edges": [
/// {"node": 9998, "diff": 2},
/// {"node": 9999, "diff": 1},
/// ]
/// },
/// }));
/// }
/// ```
#[async_trait::async_trait]
pub trait DataSource {
/// Cursor type
type CursorType: CursorType + Send + Sync;
/// Record type
type NodeType;
/// Additional fields for connection
///
/// Is a type that implements `ObjectType` and can be defined by the procedure macro `#[Object]` or `#[SimpleObject]`.
///
type ConnectionFieldsType;
/// Additional fields for edge
///
/// Is a type that implements `ObjectType` and can be defined by the procedure macro `#[Object]` or `#[SimpleObject]`.
///
type EdgeFieldsType;
/// Parses the parameters and executes the query.
async fn query(
&self,
after: Option<String>,
before: Option<String>,
first: Option<i32>,
last: Option<i32>,
) -> FieldResult<
Connection<
Self::CursorType,
Self::NodeType,
Self::ConnectionFieldsType,
Self::EdgeFieldsType,
>,
>
where
<Self::CursorType as CursorType>::Error: Display + Send + Sync + 'static,
{
query(after, before, first, last, |after, before, first, last| {
self.execute_query(after, before, first, last)
})
.await
}
/// Execute query
async fn execute_query(
&self,
after: Option<Self::CursorType>,
before: Option<Self::CursorType>,
first: Option<usize>,
last: Option<usize>,
) -> FieldResult<
Connection<
Self::CursorType,
Self::NodeType,
Self::ConnectionFieldsType,
Self::EdgeFieldsType,
>,
>;
}
/// Parses the parameters and executes the query.
///
/// If you don't want to implement `DataSource`, you can also use this function to query data directly.
@ -262,7 +109,7 @@ where
let first = match first {
Some(first) if first < 0 => {
return Err("The \"first\" parameter must be a non-negative number".into())
return Err("The \"first\" parameter must be a non-negative number".into());
}
Some(first) => Some(first as usize),
None => None,
@ -270,7 +117,7 @@ where
let last = match last {
Some(last) if last < 0 => {
return Err("The \"last\" parameter must be a non-negative number".into())
return Err("The \"last\" parameter must be a non-negative number".into());
}
Some(last) => Some(last as usize),
None => None,

View File

@ -1,63 +0,0 @@
use crate::connection::{Connection, DataSource, Edge, EmptyFields};
use crate::FieldResult;
use async_graphql_derive::DataSource;
#[DataSource(internal)]
impl<'a, T: Send + Sync> DataSource for &'a [T] {
type CursorType = usize;
type NodeType = &'a T;
type ConnectionFieldsType = EmptyFields;
type EdgeFieldsType = EmptyFields;
#[allow(clippy::suspicious_else_formatting)]
async fn execute_query(
&self,
after: Option<usize>,
before: Option<usize>,
first: Option<usize>,
last: Option<usize>,
) -> FieldResult<
Connection<
Self::CursorType,
Self::NodeType,
Self::ConnectionFieldsType,
Self::EdgeFieldsType,
>,
> {
let mut start = 0usize;
let mut end = self.len();
if let Some(after) = after {
if after >= self.len() {
return Ok(Connection::new(false, false));
}
start = after + 1;
}
if let Some(before) = before {
if before == 0 {
return Ok(Connection::new(false, false));
}
end = before;
}
let mut slice = &self[start..end];
if let Some(first) = first {
slice = &slice[..first.min(slice.len())];
end -= first.min(slice.len());
} else if let Some(last) = last {
slice = &slice[slice.len() - last.min(slice.len())..];
start = end - last.min(slice.len());
}
let mut connection = Connection::new(start > 0, end < self.len());
connection.append(
slice
.iter()
.enumerate()
.map(|(idx, item)| Edge::new(start + idx, item)),
);
Ok(connection)
}
}

View File

@ -1,126 +1,10 @@
use async_graphql::connection::*;
use async_graphql::*;
use serde_json::json;
#[async_std::test]
pub async fn test_slice_datasource() {
struct Query;
#[Object]
impl Query {
async fn values(
&self,
after: Option<String>,
before: Option<String>,
first: Option<i32>,
last: Option<i32>,
) -> FieldResult<Connection<usize, &&str>> {
const ROWS: &[&str] = &[
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
];
ROWS.query(after, before, first, last).await
}
}
static QUERY: &str = r#"
query(
$after: String
$before: String
$first: Int
$last: Int
) {
values(
after: $after
before: $before
first: $first
last: $last
) {
pageInfo {
hasPreviousPage
hasNextPage
}
edges {
node
}
}
}
"#;
async fn do_test(
vars: serde_json::Value,
(has_prev_page, has_next_page, nodes): (bool, bool, &[&str]),
) {
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
let query = QueryBuilder::new(QUERY).variables(Variables::parse_from_json(vars).unwrap());
let edges = nodes
.iter()
.map(|s| json!({ "node": s.to_owned() }))
.collect::<Vec<_>>();
assert_eq!(
query.execute(&schema).await.unwrap().data,
serde_json::json!({
"values": {
"pageInfo": {
"hasPreviousPage": has_prev_page,
"hasNextPage": has_next_page,
},
"edges": edges,
},
})
);
}
do_test(
json!({ "after": null, "before": null, "first": 2, "last": null }),
(false, true, &["a", "b"]),
)
.await;
do_test(
json!({ "after": 1usize.encode_cursor().unwrap(), "before": null, "first": 2, "last": null }),
(true, true, &["c", "d"]),
)
.await;
do_test(
json!({ "after": 1usize.encode_cursor().unwrap(), "before": null, "first": 6, "last": null }),
(true, true, &["c", "d", "e", "f", "g", "h"]),
)
.await;
do_test(
json!({ "after": null, "before": null, "first": 3, "last": null }),
(false, true, &["a", "b", "c"]),
)
.await;
do_test(
json!({ "after": null, "before": null, "first": null, "last": 3 }),
(true, false, &["x", "y", "z"]),
)
.await;
do_test(
json!({ "after": null, "before": 1usize.encode_cursor().unwrap(), "first": 10, "last": null }),
(false, true, &["a"]),
)
.await;
do_test(
json!({ "after": null, "before": 1usize.encode_cursor().unwrap(), "first": null, "last": 10 }),
(false, true, &["a"]),
)
.await;
}
#[async_std::test]
pub async fn test_datasource_additional_fields() {
struct QueryRoot;
struct Numbers;
#[SimpleObject]
struct ConnectionFields {
total_count: i32,
@ -131,53 +15,6 @@ pub async fn test_datasource_additional_fields() {
diff: i32,
}
#[DataSource]
impl DataSource for Numbers {
type CursorType = usize;
type NodeType = i32;
type ConnectionFieldsType = ConnectionFields;
type EdgeFieldsType = Diff;
async fn execute_query(
&self,
after: Option<usize>,
before: Option<usize>,
first: Option<usize>,
last: Option<usize>,
) -> FieldResult<
Connection<
Self::CursorType,
Self::NodeType,
Self::ConnectionFieldsType,
Self::EdgeFieldsType,
>,
> {
let mut start = after.map(|after| after + 1).unwrap_or(0);
let mut end = before.unwrap_or(10000);
if let Some(first) = first {
end = (start + first).min(end);
}
if let Some(last) = last {
start = if last > end - start { end } else { end - last };
}
let mut connection = Connection::with_additional_fields(
start > 0,
end < 10000,
ConnectionFields { total_count: 10000 },
);
connection.append((start..end).into_iter().map(|n| {
Edge::with_additional_fields(
n,
n as i32,
Diff {
diff: (10000 - n) as i32,
},
)
}));
Ok(connection)
}
}
#[Object]
impl QueryRoot {
async fn numbers(
@ -187,7 +24,38 @@ pub async fn test_datasource_additional_fields() {
first: Option<i32>,
last: Option<i32>,
) -> FieldResult<Connection<usize, i32, ConnectionFields, Diff>> {
Numbers.query(after, before, first, last).await
connection::query(
after,
before,
first,
last,
|after, before, first, last| async move {
let mut start = after.map(|after| after + 1).unwrap_or(0);
let mut end = before.unwrap_or(10000);
if let Some(first) = first {
end = (start + first).min(end);
}
if let Some(last) = last {
start = if last > end - start { end } else { end - last };
}
let mut connection = Connection::with_additional_fields(
start > 0,
end < 10000,
ConnectionFields { total_count: 10000 },
);
connection.append((start..end).into_iter().map(|n| {
Edge::with_additional_fields(
n,
n as i32,
Diff {
diff: (10000 - n) as i32,
},
)
}));
Ok(connection)
},
)
.await
}
}