graphql_starter/graphql/
pagination.rs1use async_graphql::{
2 connection::{Connection, CursorType, Edge},
3 OutputType, SimpleObject,
4};
5
6use crate::{
7 error::Error,
8 pagination::{OpaqueCursor, Page},
9};
10
11#[derive(SimpleObject)]
12pub struct ConnectionFields {
13 pub total_items: Option<u64>,
15}
16
17impl CursorType for OpaqueCursor {
18 type Error = Box<Error>;
19
20 fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
21 OpaqueCursor::decode(s)
22 }
23
24 fn encode_cursor(&self) -> String {
25 self.encode()
26 }
27}
28
29pub trait IntoConnection<T>
31where
32 T: OutputType,
33{
34 fn into_connection(self) -> Connection<OpaqueCursor, T, ConnectionFields>;
36}
37
38impl<T> IntoConnection<T> for Page<T>
39where
40 T: OutputType,
41{
42 fn into_connection(self) -> Connection<OpaqueCursor, T, ConnectionFields> {
43 let mut conn = Connection::with_additional_fields(
44 self.page_info.has_previous_page,
45 self.page_info.has_next_page,
46 ConnectionFields {
47 total_items: self.total_items,
48 },
49 );
50 conn.edges
51 .extend(self.edges.into_iter().map(|e| Edge::new(e.cursor, e.node)));
52 conn
53 }
54}
55
56#[cfg(test)]
57mod tests {
58
59 use serde::{Deserialize, Serialize};
60
61 use super::*;
62
63 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
64 struct CursorData {
65 content: String,
66 }
67
68 #[test]
69 fn test_cursor() {
70 let data = CursorData {
71 content: "custom-content".into(),
72 };
73 let cursor = OpaqueCursor::new(&data).unwrap();
74
75 let encoded = cursor.encode_cursor();
76 assert_eq!(&encoded, "eyJjb250ZW50IjoiY3VzdG9tLWNvbnRlbnQifQ");
77
78 let decoded = OpaqueCursor::decode_cursor(&encoded);
79 assert!(decoded.is_ok(), "Could not decode the cursor");
80 let inner: Result<CursorData, _> = decoded.unwrap().as_data();
81 assert!(inner.is_ok(), "Could not deserialize the cursor data");
82 let inner = inner.unwrap();
83 assert_eq!(inner, data);
84 }
85}