//! Types for Relay-compliant server mod connection_type; mod cursor; mod edge; mod page_info; use std::fmt::Display; use std::future::Future; use crate::{Result, SimpleObject}; pub use connection_type::Connection; pub use cursor::CursorType; pub use edge::Edge; pub use page_info::PageInfo; /// Empty additional fields #[derive(SimpleObject)] #[graphql(internal, dummy)] pub struct EmptyFields; /// Parses the parameters and executes the query. /// /// # Examples /// /// ```rust /// use async_graphql::*; /// use async_graphql::connection::*; /// /// struct QueryRoot; /// /// struct Numbers; /// /// #[derive(SimpleObject)] /// struct Diff { /// diff: i32, /// } /// /// #[Object] /// impl QueryRoot { /// async fn numbers(&self, /// after: Option, /// before: Option, /// first: Option, /// last: Option /// ) -> Result> { /// 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::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) /// }).await /// } /// } /// /// tokio::runtime::Runtime::new().unwrap().block_on(async { /// 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( 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>>, { if first.is_some() && last.is_some() { return Err("The \"first\" and \"last\" parameters cannot exist at the same time".into()); } let first = match first { Some(first) if first < 0 => { return Err("The \"first\" parameter must be a non-negative number".into()); } Some(first) => Some(first as usize), None => None, }; let last = match last { Some(last) if last < 0 => { return Err("The \"last\" parameter must be a non-negative number".into()); } Some(last) => Some(last as usize), None => None, }; let before = match before { Some(before) => Some(Cursor::decode_cursor(&before)?), None => None, }; let after = match after { Some(after) => Some(Cursor::decode_cursor(&after)?), None => None, }; f(after, before, first, last).await }