async_graphql/types/connection/
connection_type.rs

1use std::{borrow::Cow, marker::PhantomData};
2
3use super::{DisableNodesField, EnableNodesField, NodesFieldSwitcherSealed};
4use crate::{
5    Object, ObjectType, OutputType, TypeName,
6    connection::{
7        ConnectionNameType, DefaultConnectionName, DefaultEdgeName, EdgeNameType, PageInfo,
8        edge::Edge,
9    },
10    types::connection::{CursorType, EmptyFields},
11};
12
13/// Connection type
14///
15/// Connection is the result of a query for `connection::query`.
16pub struct Connection<
17    Cursor,
18    Node,
19    ConnectionFields = EmptyFields,
20    EdgeFields = EmptyFields,
21    Name = DefaultConnectionName,
22    EdgeName = DefaultEdgeName,
23    NodesField = EnableNodesField,
24> where
25    Cursor: CursorType + Send + Sync,
26    Node: OutputType,
27    ConnectionFields: ObjectType,
28    EdgeFields: ObjectType,
29    Name: ConnectionNameType,
30    EdgeName: EdgeNameType,
31    NodesField: NodesFieldSwitcherSealed,
32{
33    _mark1: PhantomData<Name>,
34    _mark2: PhantomData<EdgeName>,
35    _mark3: PhantomData<NodesField>,
36    /// All edges of the current page.
37    pub edges: Vec<Edge<Cursor, Node, EdgeFields, EdgeName>>,
38    /// Additional fields for connection object.
39    pub additional_fields: ConnectionFields,
40    /// If `true` means has previous page.
41    pub has_previous_page: bool,
42    /// If `true` means has next page.
43    pub has_next_page: bool,
44}
45
46impl<Cursor, Node, NodesField, EdgeFields, Name, EdgeName>
47    Connection<Cursor, Node, EmptyFields, EdgeFields, Name, EdgeName, NodesField>
48where
49    Cursor: CursorType + Send + Sync,
50    Node: OutputType,
51    EdgeFields: ObjectType,
52    Name: ConnectionNameType,
53    EdgeName: EdgeNameType,
54    NodesField: NodesFieldSwitcherSealed,
55{
56    /// Create a new connection.
57    #[inline]
58    pub fn new(has_previous_page: bool, has_next_page: bool) -> Self {
59        Connection {
60            _mark1: PhantomData,
61            _mark2: PhantomData,
62            _mark3: PhantomData,
63            additional_fields: EmptyFields,
64            has_previous_page,
65            has_next_page,
66            edges: Vec::new(),
67        }
68    }
69}
70
71impl<Cursor, Node, NodesField, ConnectionFields, EdgeFields, Name, EdgeName>
72    Connection<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName, NodesField>
73where
74    Cursor: CursorType + Send + Sync,
75    Node: OutputType,
76    ConnectionFields: ObjectType,
77    EdgeFields: ObjectType,
78    Name: ConnectionNameType,
79    EdgeName: EdgeNameType,
80    NodesField: NodesFieldSwitcherSealed,
81{
82    /// Create a new connection, it can have some additional fields.
83    #[inline]
84    pub fn with_additional_fields(
85        has_previous_page: bool,
86        has_next_page: bool,
87        additional_fields: ConnectionFields,
88    ) -> Self {
89        Connection {
90            _mark1: PhantomData,
91            _mark2: PhantomData,
92            _mark3: PhantomData,
93            additional_fields,
94            has_previous_page,
95            has_next_page,
96            edges: Vec::new(),
97        }
98    }
99}
100
101#[Object(internal, name_type, shareable)]
102impl<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName>
103    Connection<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName, DisableNodesField>
104where
105    Cursor: CursorType + Send + Sync,
106    Node: OutputType,
107    ConnectionFields: ObjectType,
108    EdgeFields: ObjectType,
109    Name: ConnectionNameType,
110    EdgeName: EdgeNameType,
111{
112    /// Information to aid in pagination.
113    async fn page_info(&self) -> PageInfo {
114        PageInfo {
115            has_previous_page: self.has_previous_page,
116            has_next_page: self.has_next_page,
117            start_cursor: self.edges.first().map(|edge| edge.cursor.encode_cursor()),
118            end_cursor: self.edges.last().map(|edge| edge.cursor.encode_cursor()),
119        }
120    }
121
122    /// A list of edges.
123    #[inline]
124    async fn edges(&self) -> &[Edge<Cursor, Node, EdgeFields, EdgeName>] {
125        &self.edges
126    }
127
128    #[graphql(flatten)]
129    #[inline]
130    async fn additional_fields(&self) -> &ConnectionFields {
131        &self.additional_fields
132    }
133}
134
135#[Object(internal, name_type, shareable)]
136impl<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName>
137    Connection<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName, EnableNodesField>
138where
139    Cursor: CursorType + Send + Sync,
140    Node: OutputType,
141    ConnectionFields: ObjectType,
142    EdgeFields: ObjectType,
143    Name: ConnectionNameType,
144    EdgeName: EdgeNameType,
145{
146    /// Information to aid in pagination.
147    async fn page_info(&self) -> PageInfo {
148        PageInfo {
149            has_previous_page: self.has_previous_page,
150            has_next_page: self.has_next_page,
151            start_cursor: self.edges.first().map(|edge| edge.cursor.encode_cursor()),
152            end_cursor: self.edges.last().map(|edge| edge.cursor.encode_cursor()),
153        }
154    }
155
156    /// A list of edges.
157    #[inline]
158    async fn edges(&self) -> &[Edge<Cursor, Node, EdgeFields, EdgeName>] {
159        &self.edges
160    }
161
162    /// A list of nodes.
163    async fn nodes(&self) -> Vec<&Node> {
164        self.edges.iter().map(|e| &e.node).collect()
165    }
166
167    #[graphql(flatten)]
168    #[inline]
169    async fn additional_fields(&self) -> &ConnectionFields {
170        &self.additional_fields
171    }
172}
173
174impl<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName, NodesField> TypeName
175    for Connection<Cursor, Node, ConnectionFields, EdgeFields, Name, EdgeName, NodesField>
176where
177    Cursor: CursorType + Send + Sync,
178    Node: OutputType,
179    ConnectionFields: ObjectType,
180    EdgeFields: ObjectType,
181    Name: ConnectionNameType,
182    EdgeName: EdgeNameType,
183    NodesField: NodesFieldSwitcherSealed,
184{
185    #[inline]
186    fn type_name() -> Cow<'static, str> {
187        Name::type_name::<Node>().into()
188    }
189}