graphql_starter/graphql/
pagination.rs

1use 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    /// Total number of items in this connection
14    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
29/// Trait to convert into a [Connection]
30pub trait IntoConnection<T>
31where
32    T: OutputType,
33{
34    /// Converts `self` to a [Connection]
35    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}