1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use async_graphql::{
    connection::{Connection, CursorType, Edge},
    OutputType, SimpleObject,
};

use crate::{
    error::Error,
    pagination::{OpaqueCursor, Page},
};

#[derive(SimpleObject)]
pub struct ConnectionFields {
    /// Total number of items in this connection
    pub total_items: Option<u64>,
}

impl CursorType for OpaqueCursor {
    type Error = Box<Error>;

    fn decode_cursor(s: &str) -> Result<Self, Self::Error> {
        OpaqueCursor::decode(s)
    }

    fn encode_cursor(&self) -> String {
        self.encode()
    }
}

/// Trait to convert into a [Connection]
pub trait IntoConnection<T>
where
    T: OutputType,
{
    /// Converts `self` to a [Connection]
    fn into_connection(self) -> Connection<OpaqueCursor, T, ConnectionFields>;
}

impl<T> IntoConnection<T> for Page<T>
where
    T: OutputType,
{
    fn into_connection(self) -> Connection<OpaqueCursor, T, ConnectionFields> {
        let mut conn = Connection::with_additional_fields(
            self.page_info.has_previous_page,
            self.page_info.has_next_page,
            ConnectionFields {
                total_items: self.total_items,
            },
        );
        conn.edges
            .extend(self.edges.into_iter().map(|e| Edge::new(e.cursor, e.node)));
        conn
    }
}

#[cfg(test)]
mod tests {

    use serde::{Deserialize, Serialize};

    use super::*;

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    struct CursorData {
        content: String,
    }

    #[test]
    fn test_cursor() {
        let data = CursorData {
            content: "custom-content".into(),
        };
        let cursor = OpaqueCursor::new(&data).unwrap();

        let encoded = cursor.encode_cursor();
        assert_eq!(&encoded, "eyJjb250ZW50IjoiY3VzdG9tLWNvbnRlbnQifQ");

        let decoded = OpaqueCursor::decode_cursor(&encoded);
        assert!(decoded.is_ok(), "Could not decode the cursor");
        let inner: Result<CursorData, _> = decoded.unwrap().as_data();
        assert!(inner.is_ok(), "Could not deserialize the cursor data");
        let inner = inner.unwrap();
        assert_eq!(inner, data);
    }
}