cratestack_sqlx/query/read/
find_many.rs1use cratestack_core::{CoolContext, CoolError};
6
7use crate::query::support::{ReadPolicyKind, push_order_and_paging, push_scoped_conditions};
8use crate::{FilterExpr, ModelDescriptor, OrderClause, SqlxRuntime, sqlx};
9
10#[derive(Debug, Clone)]
11pub struct FindMany<'a, M: 'static, PK: 'static> {
12 pub(crate) runtime: &'a SqlxRuntime,
13 pub(crate) descriptor: &'static ModelDescriptor<M, PK>,
14 pub(crate) filters: Vec<FilterExpr>,
15 pub(crate) order_by: Vec<OrderClause>,
16 pub(crate) limit: Option<i64>,
17 pub(crate) offset: Option<i64>,
18 pub(crate) for_update: bool,
19}
20
21impl<'a, M: 'static, PK: 'static> FindMany<'a, M, PK> {
22 pub fn where_(mut self, filter: crate::Filter) -> Self {
23 self.filters.push(FilterExpr::from(filter));
24 self
25 }
26
27 pub fn where_expr(mut self, filter: FilterExpr) -> Self {
28 self.filters.push(filter);
29 self
30 }
31
32 pub fn where_any(mut self, filters: impl IntoIterator<Item = FilterExpr>) -> Self {
33 self.filters.push(FilterExpr::any(filters));
34 self
35 }
36
37 pub fn where_optional<F>(mut self, filter: Option<F>) -> Self
41 where
42 F: Into<FilterExpr>,
43 {
44 if let Some(filter) = filter {
45 self.filters.push(filter.into());
46 }
47 self
48 }
49
50 pub fn order_by(mut self, clause: OrderClause) -> Self {
51 self.order_by.push(clause);
52 self
53 }
54
55 pub fn limit(mut self, limit: i64) -> Self {
56 self.limit = Some(limit);
57 self
58 }
59
60 pub fn offset(mut self, offset: i64) -> Self {
61 self.offset = Some(offset);
62 self
63 }
64
65 pub fn for_update(mut self) -> Self {
69 self.for_update = true;
70 self
71 }
72
73 pub fn preview_sql(&self) -> String {
74 super::find_many_preview::preview_sql(self)
75 }
76
77 pub fn preview_scoped_sql(&self, ctx: &CoolContext) -> String {
78 super::find_many_preview::preview_scoped_sql(self, ctx)
79 }
80
81 pub async fn run(self, ctx: &CoolContext) -> Result<Vec<M>, CoolError>
82 where
83 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
84 {
85 let order_by = self.effective_order_by();
86 let mut query = sqlx::QueryBuilder::<sqlx::Postgres>::new("SELECT ");
87 query
88 .push(self.descriptor.select_projection())
89 .push(" FROM ")
90 .push(self.descriptor.table_name);
91
92 push_scoped_conditions(
93 &mut query,
94 self.descriptor,
95 &self.filters,
96 None::<(&'static str, i64)>,
97 ctx,
98 ReadPolicyKind::List,
99 );
100 push_order_and_paging(&mut query, &order_by, self.limit, self.offset);
101 if self.for_update {
102 query.push(" FOR UPDATE");
103 }
104
105 query
106 .build_query_as::<M>()
107 .fetch_all(self.runtime.pool())
108 .await
109 .map_err(|error| CoolError::Database(error.to_string()))
110 }
111
112 pub async fn run_in_tx<'tx>(
115 self,
116 tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
117 ctx: &CoolContext,
118 ) -> Result<Vec<M>, CoolError>
119 where
120 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
121 {
122 let order_by = self.effective_order_by();
123 let mut query = sqlx::QueryBuilder::<sqlx::Postgres>::new("SELECT ");
124 query
125 .push(self.descriptor.select_projection())
126 .push(" FROM ")
127 .push(self.descriptor.table_name);
128
129 push_scoped_conditions(
130 &mut query,
131 self.descriptor,
132 &self.filters,
133 None::<(&'static str, i64)>,
134 ctx,
135 ReadPolicyKind::List,
136 );
137 push_order_and_paging(&mut query, &order_by, self.limit, self.offset);
138 if self.for_update {
139 query.push(" FOR UPDATE");
140 }
141
142 query
143 .build_query_as::<M>()
144 .fetch_all(&mut **tx)
145 .await
146 .map_err(|error| CoolError::Database(error.to_string()))
147 }
148
149 pub(super) fn effective_order_by(&self) -> Vec<OrderClause> {
150 let mut order_by = self.order_by.clone();
151 let Some(direction) = order_by
152 .iter()
153 .find(|clause| clause.is_relation_scalar())
154 .map(OrderClause::direction)
155 else {
156 return order_by;
157 };
158
159 if order_by
160 .iter()
161 .any(|clause| clause.targets_column(self.descriptor.primary_key))
162 {
163 return order_by;
164 }
165
166 order_by.push(OrderClause::column(self.descriptor.primary_key, direction));
167 order_by
168 }
169
170 pub fn include<Rel, RelPK>(
174 self,
175 relation: cratestack_sql::RelationInclude<M, Rel, RelPK>,
176 ) -> super::find_many_with::FindManyWith<'a, M, PK, Rel, RelPK>
177 where
178 Rel: 'static,
179 RelPK: 'static,
180 {
181 super::find_many_with::FindManyWith::new(self, relation)
182 }
183}