1#[macro_export]
7macro_rules! sqlx_query_paginated_as {
8 (
9 $page:ident,
10 $executor:expr,
11 [$($cols:ident $(. $order:ident())? : $ty:path),*],
12 $out_struct:path,
13 $query:expr
14 ) => (
15 $crate::sqlx_query_paginated_as!(
16 columns = [$($cols $(. $order())? : $ty),*],
17 page = $page,
18 executor = $executor,
19 record = $out_struct,
20 query = $query,
21 args = []
22 )
23 );
24
25 (
26 $page:ident,
27 $executor:expr,
28 [$($cols:ident $(. $order:ident())? : $ty:path),*],
29 $out_struct:path,
30 $query:expr,
31 $($args:tt)*
32 ) => (
33 $crate::sqlx_query_paginated_as!(
34 columns = [$($cols $(. $order())? : $ty),*],
35 page = $page,
36 executor = $executor,
37 record = $out_struct,
38 query = $query,
39 args = [$($args)*]
40 )
41 );
42
43 (
44 columns = [$($cols:ident $(. $order:ident())? : $ty:path),*],
45 page = $page:ident,
46 executor = $executor:expr,
47 record = $out_struct:path,
48 query = $query:expr,
49 args = [$($args:expr),*]
50 ) => ({
51 use $crate::{
52 error::{GenericErrorCode, MapToErr},
53 pagination::{IntoCursorVec, Page, PageQuery},
54 };
55 let limit;
56 let backward;
57 let mut rows = match $page {
58 PageQuery::Forward(page) => {
59 backward = false;
60 limit = page.first;
61 if let Some(after) = page.after {
62 let after: ($($ty,)*) = after.as_data()?;
63 tracing::trace!("Fetching data after: {after:#?}");
64 $crate::sqlx_expand_paginated_query!(
65 record = $out_struct,
66 query = $query,
67 args = [$($args),*],
68 extra_row = true,
69 columns = [$($cols $(. $order())?),*],
70 first = (page.first as i64),
71 after = after
72 )
73 .fetch_all($executor)
74 .await
75 } else {
76 $crate::sqlx_expand_paginated_query!(
77 record = $out_struct,
78 query = $query,
79 args = [$($args),*],
80 extra_row = true,
81 columns = [$($cols $(. $order())?),*],
82 first = (page.first as i64)
83 )
84 .fetch_all($executor)
85 .await
86 }
87 }
88 PageQuery::Backward(page) => {
89 backward = true;
90 limit = page.last;
91 if let Some(before) = page.before {
92 let before: ($($ty,)*) = before.as_data()?;
93 tracing::trace!("Fetching data before: {before:#?}");
94 $crate::sqlx_expand_paginated_query!(
95 record = $out_struct,
96 query = $query,
97 args = [$($args),*],
98 extra_row = true,
99 columns = [$($cols $(. $order())?),*],
100 last = (page.last as i64),
101 before = before
102 )
103 .fetch_all($executor)
104 .await
105 } else {
106 $crate::sqlx_expand_paginated_query!(
107 record = $out_struct,
108 query = $query,
109 args = [$($args),*],
110 extra_row = true,
111 columns = [$($cols $(. $order())?),*],
112 last = (page.last as i64)
113 )
114 .fetch_all($executor)
115 .await
116 }
117 }
118 }
119 .map_to_err_with(
120 GenericErrorCode::InternalServerError,
121 "Error fetching paginated query",
122 )?;
123
124 let mut has_previous_page = false;
125 let mut has_next_page = false;
126 if rows.len() > limit {
127 if backward {
128 has_previous_page = true;
129 rows.remove(0);
130 } else {
131 has_next_page = true;
132 rows.remove(rows.len() - 1);
133 }
134 }
135
136 Page::from_iter(
137 has_previous_page,
138 has_next_page,
139 None,
140 rows.with_cursor(|r| $crate::struct_to_tuple!(r => $($cols),*))?,
141 )
142 });
143}
144
145#[macro_export]
146macro_rules! struct_to_tuple {
148 ($struct:ident => $($field:ident),*) => {
149 ( $($struct . $field .clone()),* )
150 };
151}