diff --git a/src/types/connection/mod.rs b/src/types/connection/mod.rs index 4f3188b9..51afd1d5 100644 --- a/src/types/connection/mod.rs +++ b/src/types/connection/mod.rs @@ -103,6 +103,112 @@ where F: FnOnce(Option, Option, Option, Option) -> R, R: Future, E>>, E: Into, +{ + query_with(after, before, first, last, f).await +} + +/// Parses the parameters and executes the query and return a custom `Connection` type. +/// +/// `Connection` and `Edge` have certain limitations. For example, you cannot customize +/// the name of the type, so you can use this function to execute the query and return a customized `Connection` type. +/// +/// # Examples +/// +/// ```rust +/// use async_graphql::*; +/// use async_graphql::connection::*; +/// +/// #[derive(SimpleObject)] +/// struct MyEdge { +/// cursor: usize, +/// node: i32, +/// diff: i32, +/// } +/// +/// #[derive(SimpleObject)] +/// struct MyConnection { +/// edges: Vec, +/// page_info: PageInfo, +/// } +/// +/// struct QueryRoot; +/// +/// #[Object] +/// impl QueryRoot { +/// async fn numbers(&self, +/// after: Option, +/// before: Option, +/// first: Option, +/// last: Option +/// ) -> Result { +/// query_with(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 connection = MyConnection { +/// edges: (start..end).into_iter().map(|n| MyEdge { +/// cursor: n, +/// node: n as i32, +/// diff: (10000 - n) as i32, +/// }).collect(), +/// page_info: PageInfo { +/// has_previous_page: start > 0, +/// has_next_page: end < 10000, +/// start_cursor: Some(start.encode_cursor()), +/// end_cursor: Some(end.encode_cursor()), +/// }, +/// }; +/// Ok::<_, Error>(connection) +/// }).await +/// } +/// } +/// +/// #[tokio::main] +/// async fn main() { +/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription); +/// +/// assert_eq!(schema.execute("{ numbers(first: 2) { edges { node diff } } }").await.into_result().unwrap().data, value!({ +/// "numbers": { +/// "edges": [ +/// {"node": 0, "diff": 10000}, +/// {"node": 1, "diff": 9999}, +/// ] +/// }, +/// })); +/// +/// assert_eq!(schema.execute("{ numbers(last: 2) { edges { node diff } } }").await.into_result().unwrap().data, value!({ +/// "numbers": { +/// "edges": [ +/// {"node": 9998, "diff": 2}, +/// {"node": 9999, "diff": 1}, +/// ] +/// }, +/// })); +/// } +/// +/// ``` +pub async fn query_with( + after: Option, + before: Option, + first: Option, + last: Option, + f: F, +) -> Result +where + Cursor: CursorType + Send + Sync, + ::Error: Display + Send + Sync + 'static, + F: FnOnce(Option, Option, Option, Option) -> R, + R: Future>, + E: Into, { if first.is_some() && last.is_some() { return Err("The \"first\" and \"last\" parameters cannot exist at the same time".into());