es_entity/
pagination.rs

1//! Control and customize the query execution and its response.
2
3/// Controls the sorting order when listing the entities from the database
4///
5/// `ListDirection` enum is used to specify order when listing entities from the database using [`EsRepo`][crate::EsRepo]
6/// generated functions like `list_by`, `list_for` and `list_for_filter`. Has two variants: `Ascending` and `Descending`
7///
8/// # Examples
9///
10/// ```ignore
11/// // List users by ID in ascending order (oldest first)
12/// let paginated_users_asc = users.list_by_id(
13///     PaginatedQueryArgs { first: 5, after: None },
14///     ListDirection::Ascending, // or just Default::default()
15/// ).await?
16///
17/// // List users by name in descending order (Z to A)
18/// let paginated_users_desc = users.list_by_name(
19///     PaginatedQueryArgs { first: 5, after: None },
20///     ListDirection::Descending,
21/// ).await?
22/// ```
23#[derive(Default, std::fmt::Debug, Clone, Copy)]
24pub enum ListDirection {
25    /// Sets the default direction variant to `Ascending`
26    #[default]
27    Ascending,
28    Descending,
29}
30
31/// Structure to sort entities on a specific field when listing from database
32///
33/// Sort enum is used to specify the sorting order and the field to sort the entities by when listing them using `list_for_filter`
34/// generated by [`EsRepo`][crate::EsRepo]. It is generated automatically for all fields which have `list_by` option. It encapsulates two fields,
35/// first is `by` to specify the field name, second is `direction` which takes [`ListDirection`]
36///
37/// # Example
38///
39/// ```ignore
40/// let result = users.list_for_filter(
41///     // `UsersFilter::WithName` generated by `EsRepo` using `list_for` option on `name`
42///     UsersFilter::WithName("Murphy".to_string()),
43///     Sort {
44///         // `UsersSortBy::Id` and `UsersSortBy::CreatedAt` are created by default,
45///         // other columns need `list_by` to sort by
46///         by: UsersSortBy::Id,
47///         direction: ListDirection::Descending,
48///     },
49///     PaginatedQueryArgs {
50///         first: 10,
51///         after: Default::default(),
52///     },
53/// )
54/// .await?;
55/// ```
56#[derive(std::fmt::Debug, Clone, Copy)]
57pub struct Sort<T> {
58    // T parameter represents the field
59    pub by: T,
60    pub direction: ListDirection,
61}
62
63/// A cursor-based pagination structure for efficiently paginating through large datasets
64///
65/// The `PaginatedQueryArgs<T>` encapsulates a `first` field that specifies the count of entities to fetch per query, and an optional `after` field
66/// that specifies the cursor to start from for the current query. The `<T>` parameter represents cursor type, which depends on the sorting field.
67/// A field's cursor is generated by [`EsRepo`][crate::EsRepo] if it has `list_by` option.
68///
69/// # Examples
70///
71/// ```ignore
72/// // Initial query - fetch first 10 users after an existing user id
73/// let query_args = PaginatedQueryArgs {
74///     first: 10,
75///     after: Some(user_cursor::UsersByIdCursor {
76///         id: some_existing_user_id // assume this variable exists
77///     }),
78/// };
79///
80/// // Execute query using `query_args` argument of `PaginatedQueryArgs` type
81/// let result = users.list_by_id(query_args, ListDirection::Ascending).await?;
82///
83/// // Continue pagination using the updated `next_query_args` of `PaginatedQueryArgs` type
84/// if result.has_next_page {
85///     let next_query_args = PaginatedQueryArgs {
86///         first: 10,
87///         after: result.end_cursor, // Use cursor from previous result to update `after`
88///     };
89///     let next_result = users.list_by_id(next_query_args, ListDirection::Ascending).await?;
90/// }
91/// ```
92#[derive(Debug)]
93pub struct PaginatedQueryArgs<T: std::fmt::Debug> {
94    /// Specifies the number of entities to fetch per query
95    pub first: usize,
96    /// Specifies the cursor/marker to start from for current query
97    pub after: Option<T>,
98}
99
100impl<T: std::fmt::Debug> Clone for PaginatedQueryArgs<T>
101where
102    T: Clone,
103{
104    fn clone(&self) -> Self {
105        Self {
106            first: self.first,
107            after: self.after.clone(),
108        }
109    }
110}
111
112impl<T: std::fmt::Debug> Default for PaginatedQueryArgs<T> {
113    /// Default value fetches first 100 entities
114    fn default() -> Self {
115        Self {
116            first: 100,
117            after: None,
118        }
119    }
120}
121
122/// Return type for paginated queries containing entities and pagination metadata
123///
124/// `PaginatedQueryRet` contains the fetched entities and utilities for continuing pagination.
125/// Returned by the [`EsRepo`][crate::EsRepo] functions like `list_by`, `list_for`, `list_for_filter`.
126/// Used with [`PaginatedQueryArgs`] to perform consistent and efficient pagination
127///
128/// # Examples
129///
130/// ```ignore
131/// let query_args = PaginatedQueryArgs {
132///     first: 10,
133///     after: None,
134/// };
135///
136/// // Execute query and get the `result` of type `PaginatedQueryRet`
137/// let result = users.list_by_id(query_args, ListDirection::Ascending).await?;
138///
139/// // Continue pagination using the `next_query_args` argument updated using result
140/// // Will continue only if 'has_next_page` returned from `result` is true
141/// if result.has_next_page {
142///     let next_query_args = PaginatedQueryArgs {
143///         first: 10,
144///         after: result.end_cursor, // update with 'end_cursor' of previous result
145///     };
146///     let next_result = users.list_by_id(next_query_args, ListDirection::Ascending).await?;
147/// }
148///
149/// // Or use PaginatedQueryRet::into_next_query() convenience method
150/// if let Some(next_query_args) = result.into_next_query() {
151///     let next_result = users.list_by_id(next_query_args, ListDirection::Ascending).await?;
152/// }
153/// ```
154pub struct PaginatedQueryRet<T, C> {
155    /// [Vec] for the fetched `entities` by the paginated query
156    pub entities: Vec<T>,
157    /// [bool] for indicating if the list has been exhausted or more entities can be fetched
158    pub has_next_page: bool,
159    /// cursor on the last entity fetched to continue paginated queries.
160    pub end_cursor: Option<C>,
161}
162
163impl<T, C> PaginatedQueryRet<T, C> {
164    /// Convenience method to create next query args if more pages are available
165    pub fn into_next_query(self) -> Option<PaginatedQueryArgs<C>>
166    where
167        C: std::fmt::Debug,
168    {
169        if self.has_next_page {
170            Some(PaginatedQueryArgs {
171                first: self.entities.len(),
172                after: self.end_cursor,
173            })
174        } else {
175            None
176        }
177    }
178}