1use std::marker::PhantomData;
2
3use sea_orm::sea_query::IntoCondition;
4use sea_orm::sea_query::IntoValueTuple;
5use sea_orm::{
6 ColumnTrait, ConnectionTrait, EntityTrait, FromQueryResult, IntoIdentity, PaginatorTrait,
7 QueryFilter, QueryOrder, QuerySelect, Select,
8};
9
10use crate::error::db_err_to_error;
11use crate::pagination::{
12 CursorParams, CursorResult, PageParams, PageResult, paginate, paginate_cursor,
13};
14
15pub struct EntityQuery<T, E: EntityTrait> {
35 select: Select<E>,
36 _phantom: PhantomData<T>,
37}
38
39impl<T, E> EntityQuery<T, E>
40where
41 E: EntityTrait,
42 T: From<E::Model> + Send + Sync,
43 E::Model: FromQueryResult + Send + Sync,
44{
45 pub fn new(select: Select<E>) -> Self {
47 Self {
48 select,
49 _phantom: PhantomData,
50 }
51 }
52
53 pub fn filter(self, f: impl IntoCondition) -> Self {
57 Self {
58 select: QueryFilter::filter(self.select, f),
59 _phantom: PhantomData,
60 }
61 }
62
63 pub fn order_by_asc<C: ColumnTrait>(self, col: C) -> Self {
65 Self {
66 select: QueryOrder::order_by_asc(self.select, col),
67 _phantom: PhantomData,
68 }
69 }
70
71 pub fn order_by_desc<C: ColumnTrait>(self, col: C) -> Self {
73 Self {
74 select: QueryOrder::order_by_desc(self.select, col),
75 _phantom: PhantomData,
76 }
77 }
78
79 pub fn limit(self, n: u64) -> Self {
81 Self {
82 select: QuerySelect::limit(self.select, Some(n)),
83 _phantom: PhantomData,
84 }
85 }
86
87 pub fn offset(self, n: u64) -> Self {
89 Self {
90 select: QuerySelect::offset(self.select, Some(n)),
91 _phantom: PhantomData,
92 }
93 }
94
95 pub async fn all(self, db: &impl ConnectionTrait) -> Result<Vec<T>, modo::Error> {
99 let rows = self.select.all(db).await.map_err(db_err_to_error)?;
100 Ok(rows.into_iter().map(T::from).collect())
101 }
102
103 pub async fn one(self, db: &impl ConnectionTrait) -> Result<Option<T>, modo::Error> {
105 let row = self.select.one(db).await.map_err(db_err_to_error)?;
106 Ok(row.map(T::from))
107 }
108
109 pub async fn count(self, db: &impl ConnectionTrait) -> Result<u64, modo::Error> {
111 self.select.count(db).await.map_err(db_err_to_error)
112 }
113
114 pub async fn paginate(
116 self,
117 db: &impl ConnectionTrait,
118 params: &PageParams,
119 ) -> Result<PageResult<T>, modo::Error> {
120 paginate(self.select, db, params)
121 .await
122 .map_err(db_err_to_error)
123 .map(|r| r.map(T::from))
124 }
125
126 pub async fn paginate_cursor<C, V, F>(
131 self,
132 col: C,
133 cursor_fn: F,
134 db: &impl ConnectionTrait,
135 params: &CursorParams<V>,
136 ) -> Result<CursorResult<T>, modo::Error>
137 where
138 C: IntoIdentity,
139 V: IntoValueTuple + Clone,
140 F: Fn(&E::Model) -> String,
141 {
142 paginate_cursor(self.select, col, cursor_fn, db, params)
143 .await
144 .map_err(db_err_to_error)
145 .map(|r| r.map(T::from))
146 }
147
148 pub fn find_also_related<U, F>(self) -> JoinedQuery<T, U, E, F>
154 where
155 F: EntityTrait,
156 U: From<F::Model> + Send + Sync,
157 F::Model: FromQueryResult + Send + Sync,
158 E: sea_orm::Related<F>,
159 {
160 JoinedQuery {
161 select: self.select.find_also_related(F::default()),
162 _phantom: PhantomData,
163 }
164 }
165
166 pub fn find_with_related<U, F>(self) -> JoinedManyQuery<T, U, E, F>
170 where
171 F: EntityTrait,
172 U: From<F::Model> + Send + Sync,
173 F::Model: FromQueryResult + Send + Sync,
174 E: sea_orm::Related<F>,
175 {
176 JoinedManyQuery {
177 select: self.select.find_with_related(F::default()),
178 _phantom: PhantomData,
179 }
180 }
181
182 pub fn into_select(self) -> Select<E> {
186 self.select
187 }
188}
189
190pub struct JoinedQuery<T, U, E: EntityTrait, F: EntityTrait> {
196 select: sea_orm::SelectTwo<E, F>,
197 _phantom: PhantomData<(T, U)>,
198}
199
200impl<T, U, E, F> JoinedQuery<T, U, E, F>
201where
202 E: EntityTrait,
203 F: EntityTrait,
204 T: From<E::Model> + Send + Sync,
205 U: From<F::Model> + Send + Sync,
206 E::Model: FromQueryResult + Send + Sync,
207 F::Model: FromQueryResult + Send + Sync,
208{
209 pub fn filter(self, f: impl IntoCondition) -> Self {
211 Self {
212 select: QueryFilter::filter(self.select, f),
213 _phantom: PhantomData,
214 }
215 }
216
217 pub fn order_by_asc<C: ColumnTrait>(self, col: C) -> Self {
219 Self {
220 select: QueryOrder::order_by_asc(self.select, col),
221 _phantom: PhantomData,
222 }
223 }
224
225 pub fn order_by_desc<C: ColumnTrait>(self, col: C) -> Self {
227 Self {
228 select: QueryOrder::order_by_desc(self.select, col),
229 _phantom: PhantomData,
230 }
231 }
232
233 pub fn limit(self, n: u64) -> Self {
235 Self {
236 select: QuerySelect::limit(self.select, Some(n)),
237 _phantom: PhantomData,
238 }
239 }
240
241 pub fn offset(self, n: u64) -> Self {
243 Self {
244 select: QuerySelect::offset(self.select, Some(n)),
245 _phantom: PhantomData,
246 }
247 }
248
249 pub async fn all(self, db: &impl ConnectionTrait) -> Result<Vec<(T, Option<U>)>, modo::Error> {
251 let rows = self.select.all(db).await.map_err(db_err_to_error)?;
252 Ok(rows
253 .into_iter()
254 .map(|(a, b)| (T::from(a), b.map(U::from)))
255 .collect())
256 }
257
258 pub async fn one(
260 self,
261 db: &impl ConnectionTrait,
262 ) -> Result<Option<(T, Option<U>)>, modo::Error> {
263 let row = self.select.one(db).await.map_err(db_err_to_error)?;
264 Ok(row.map(|(a, b)| (T::from(a), b.map(U::from))))
265 }
266
267 pub fn into_select(self) -> sea_orm::SelectTwo<E, F> {
269 self.select
270 }
271}
272
273pub struct JoinedManyQuery<T, U, E: EntityTrait, F: EntityTrait> {
279 select: sea_orm::SelectTwoMany<E, F>,
280 _phantom: PhantomData<(T, U)>,
281}
282
283impl<T, U, E, F> JoinedManyQuery<T, U, E, F>
284where
285 E: EntityTrait,
286 F: EntityTrait,
287 T: From<E::Model> + Send + Sync,
288 U: From<F::Model> + Send + Sync,
289 E::Model: FromQueryResult + Send + Sync,
290 F::Model: FromQueryResult + Send + Sync,
291{
292 pub fn filter(self, f: impl IntoCondition) -> Self {
294 Self {
295 select: QueryFilter::filter(self.select, f),
296 _phantom: PhantomData,
297 }
298 }
299
300 pub fn order_by_asc<C: ColumnTrait>(self, col: C) -> Self {
302 Self {
303 select: QueryOrder::order_by_asc(self.select, col),
304 _phantom: PhantomData,
305 }
306 }
307
308 pub fn order_by_desc<C: ColumnTrait>(self, col: C) -> Self {
310 Self {
311 select: QueryOrder::order_by_desc(self.select, col),
312 _phantom: PhantomData,
313 }
314 }
315
316 pub fn limit(self, n: u64) -> Self {
318 Self {
319 select: QuerySelect::limit(self.select, Some(n)),
320 _phantom: PhantomData,
321 }
322 }
323
324 pub fn offset(self, n: u64) -> Self {
326 Self {
327 select: QuerySelect::offset(self.select, Some(n)),
328 _phantom: PhantomData,
329 }
330 }
331
332 pub async fn all(self, db: &impl ConnectionTrait) -> Result<Vec<(T, Vec<U>)>, modo::Error> {
334 let rows = self.select.all(db).await.map_err(db_err_to_error)?;
335 Ok(rows
336 .into_iter()
337 .map(|(a, bs)| (T::from(a), bs.into_iter().map(U::from).collect()))
338 .collect())
339 }
340
341 pub fn into_select(self) -> sea_orm::SelectTwoMany<E, F> {
343 self.select
344 }
345}
346
347pub struct EntityUpdateMany<E: EntityTrait> {
366 update: sea_orm::UpdateMany<E>,
367}
368
369impl<E: EntityTrait> EntityUpdateMany<E> {
370 pub fn new(update: sea_orm::UpdateMany<E>) -> Self {
372 Self { update }
373 }
374
375 pub fn filter(self, f: impl IntoCondition) -> Self {
377 Self {
378 update: QueryFilter::filter(self.update, f),
379 }
380 }
381
382 pub fn col_expr<C: sea_orm::sea_query::IntoIden>(
386 self,
387 col: C,
388 expr: sea_orm::sea_query::SimpleExpr,
389 ) -> Self {
390 Self {
391 update: self.update.col_expr(col, expr),
392 }
393 }
394
395 pub async fn exec(self, db: &impl ConnectionTrait) -> Result<u64, modo::Error> {
397 self.update
398 .exec(db)
399 .await
400 .map(|r| r.rows_affected)
401 .map_err(db_err_to_error)
402 }
403}
404
405pub struct EntityDeleteMany<E: EntityTrait> {
423 delete: sea_orm::DeleteMany<E>,
424}
425
426impl<E: EntityTrait> EntityDeleteMany<E> {
427 pub fn new(delete: sea_orm::DeleteMany<E>) -> Self {
429 Self { delete }
430 }
431
432 pub fn filter(self, f: impl IntoCondition) -> Self {
434 Self {
435 delete: QueryFilter::filter(self.delete, f),
436 }
437 }
438
439 pub async fn exec(self, db: &impl ConnectionTrait) -> Result<u64, modo::Error> {
441 self.delete
442 .exec(db)
443 .await
444 .map(|r| r.rows_affected)
445 .map_err(db_err_to_error)
446 }
447}