umbral_core/orm/queryset/
tx.rs1use sea_query::{Expr, Func, PostgresQueryBuilder, SqliteQueryBuilder};
17use sea_query_binder::SqlxBinder;
18
19use crate::orm::{HydrateRelated, Model};
20
21use super::QuerySet;
22use super::errors::GetError;
23use super::write_helpers::{build_insert_one_for, pk_field, serialize_to_map};
24
25pub struct QuerySetTx<'tx, T> {
28 pub(super) qs: QuerySet<T>,
29 pub(super) tx: &'tx mut crate::db::Transaction,
30}
31
32impl<'tx, T: Model> QuerySetTx<'tx, T> {
33 pub async fn fetch(self) -> Result<Vec<T>, sqlx::Error>
39 where
40 T: for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow>
41 + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>
42 + HydrateRelated,
43 {
44 let q = self.qs.build_query_for(self.tx.backend_name());
45 let mut rows = match self.tx.backend_name() {
46 "sqlite" => {
47 let tx = self.tx.as_sqlite_mut().unwrap();
48 let (sql, values) = q.build_sqlx(SqliteQueryBuilder);
49 sqlx::query_as_with::<sqlx::Sqlite, T, _>(&sql, values)
50 .fetch_all(&mut **tx)
51 .await?
52 }
53 _ => {
54 let tx = self.tx.as_pg_mut().unwrap();
55 let (sql, values) = q.build_sqlx(PostgresQueryBuilder);
56 sqlx::query_as_with::<sqlx::Postgres, T, _>(&sql, values)
57 .fetch_all(&mut **tx)
58 .await?
59 }
60 };
61 for r in &mut rows {
65 r.set_m2m_parent_ids();
66 }
67 Ok(rows)
68 }
69
70 pub async fn first(mut self) -> Result<Option<T>, sqlx::Error>
72 where
73 T: for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow>
74 + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>
75 + HydrateRelated,
76 {
77 self.qs.query.limit(1);
78 let q = self.qs.build_query_for(self.tx.backend_name());
79 let mut row = match self.tx.backend_name() {
80 "sqlite" => {
81 let tx = self.tx.as_sqlite_mut().unwrap();
82 let (sql, values) = q.build_sqlx(SqliteQueryBuilder);
83 sqlx::query_as_with::<sqlx::Sqlite, T, _>(&sql, values)
84 .fetch_optional(&mut **tx)
85 .await?
86 }
87 _ => {
88 let tx = self.tx.as_pg_mut().unwrap();
89 let (sql, values) = q.build_sqlx(PostgresQueryBuilder);
90 sqlx::query_as_with::<sqlx::Postgres, T, _>(&sql, values)
91 .fetch_optional(&mut **tx)
92 .await?
93 }
94 };
95 if let Some(r) = row.as_mut() {
96 r.set_m2m_parent_ids();
97 }
98 Ok(row)
99 }
100
101 pub async fn count(self) -> Result<i64, sqlx::Error> {
103 let backend = self.tx.backend_name();
104 let mut rebuilt = self.qs.build_query_for(backend);
105 rebuilt.clear_selects();
106 rebuilt.expr(Func::count(Expr::col(sea_query::Asterisk)));
110 rebuilt.reset_limit();
111 rebuilt.reset_offset();
112 match backend {
113 "sqlite" => {
114 let tx = self.tx.as_sqlite_mut().unwrap();
115 let (sql, values) = rebuilt.build_sqlx(SqliteQueryBuilder);
116 let (n,): (i64,) = sqlx::query_as_with::<sqlx::Sqlite, (i64,), _>(&sql, values)
117 .fetch_one(&mut **tx)
118 .await?;
119 Ok(n)
120 }
121 _ => {
122 let tx = self.tx.as_pg_mut().unwrap();
123 let (sql, values) = rebuilt.build_sqlx(PostgresQueryBuilder);
124 let (n,): (i64,) = sqlx::query_as_with::<sqlx::Postgres, (i64,), _>(&sql, values)
125 .fetch_one(&mut **tx)
126 .await?;
127 Ok(n)
128 }
129 }
130 }
131
132 pub async fn exists(mut self) -> Result<bool, sqlx::Error>
134 where
135 T: for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow>
136 + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
137 {
138 self.qs.query.limit(1);
139 let backend = self.tx.backend_name();
140 let q = self.qs.build_query_for(backend);
141 let row_opt: Option<T> = match backend {
142 "sqlite" => {
143 let tx = self.tx.as_sqlite_mut().unwrap();
144 let (sql, values) = q.build_sqlx(SqliteQueryBuilder);
145 sqlx::query_as_with::<sqlx::Sqlite, T, _>(&sql, values)
146 .fetch_optional(&mut **tx)
147 .await?
148 }
149 _ => {
150 let tx = self.tx.as_pg_mut().unwrap();
151 let (sql, values) = q.build_sqlx(PostgresQueryBuilder);
152 sqlx::query_as_with::<sqlx::Postgres, T, _>(&sql, values)
153 .fetch_optional(&mut **tx)
154 .await?
155 }
156 };
157 Ok(row_opt.is_some())
158 }
159
160 pub async fn get(mut self) -> Result<T, GetError>
162 where
163 T: for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow>
164 + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
165 {
166 self.qs.query.limit(2);
167 let q = self.qs.build_query_for(self.tx.backend_name());
168 let mut rows: Vec<T> = match self.tx.backend_name() {
169 "sqlite" => {
170 let tx = self.tx.as_sqlite_mut().unwrap();
171 let (sql, values) = q.build_sqlx(SqliteQueryBuilder);
172 sqlx::query_as_with::<sqlx::Sqlite, T, _>(&sql, values)
173 .fetch_all(&mut **tx)
174 .await
175 .map_err(GetError::Sqlx)?
176 }
177 _ => {
178 let tx = self.tx.as_pg_mut().unwrap();
179 let (sql, values) = q.build_sqlx(PostgresQueryBuilder);
180 sqlx::query_as_with::<sqlx::Postgres, T, _>(&sql, values)
181 .fetch_all(&mut **tx)
182 .await
183 .map_err(GetError::Sqlx)?
184 }
185 };
186 match rows.len() {
187 0 => Err(GetError::NotFound),
188 1 => Ok(rows.pop().unwrap()),
189 _ => Err(GetError::MultipleObjectsReturned),
190 }
191 }
192
193 pub async fn delete(self) -> Result<u64, sqlx::Error> {
206 if self.qs.soft_delete_active && !self.qs.hard_delete {
207 return self.soft_delete_in_tx().await;
208 }
209 let stmt = self.qs.build_delete_for(self.tx.backend_name());
210 match self.tx.backend_name() {
211 "sqlite" => {
212 let tx = self.tx.as_sqlite_mut().unwrap();
213 let (sql, values) = stmt.build_sqlx(SqliteQueryBuilder);
214 let result = sqlx::query_with::<sqlx::Sqlite, _>(&sql, values)
215 .execute(&mut **tx)
216 .await?;
217 Ok(result.rows_affected())
218 }
219 _ => {
220 let tx = self.tx.as_pg_mut().unwrap();
221 let (sql, values) = stmt.build_sqlx(PostgresQueryBuilder);
222 let result = sqlx::query_with::<sqlx::Postgres, _>(&sql, values)
223 .execute(&mut **tx)
224 .await?;
225 Ok(result.rows_affected())
226 }
227 }
228 }
229
230 async fn soft_delete_in_tx(self) -> Result<u64, sqlx::Error> {
236 use sea_query::{Alias, Query, Value};
237 let backend = self.tx.backend_name();
238 let now = chrono::Utc::now();
239 let table = crate::db::router::schema_qualified_table(T::TABLE);
240
241 if let Some(pkf) = pk_field::<T>() {
245 let mut sel = Query::select();
246 sel.column(Alias::new(pkf.name)).from(table.clone());
247 for p in &self.qs.predicates {
248 sel.and_where(p.cond_for(backend));
249 }
250 sel.and_where(Expr::col(Alias::new("deleted_at")).is_null());
251 let meta = crate::migrate::ModelMeta::for_::<T>();
252 let mut conn = crate::orm::soft_delete_cascade::CascadeConn::from_tx(self.tx);
253 crate::orm::soft_delete_cascade::cascade_soft_delete(&mut conn, &meta, sel, now)
254 .await?;
255 }
256
257 let mut stmt = Query::update();
258 stmt.table(table);
259 stmt.value(
260 Alias::new("deleted_at"),
261 Value::ChronoDateTimeUtc(Some(Box::new(now))),
262 );
263 for p in &self.qs.predicates {
264 stmt.and_where(p.cond_for(backend));
265 }
266 stmt.and_where(Expr::col(Alias::new("deleted_at")).is_null());
267
268 match backend {
269 "sqlite" => {
270 let tx = self.tx.as_sqlite_mut().unwrap();
271 let (sql, values) = stmt.build_sqlx(SqliteQueryBuilder);
272 let result = sqlx::query_with::<sqlx::Sqlite, _>(&sql, values)
273 .execute(&mut **tx)
274 .await?;
275 Ok(result.rows_affected())
276 }
277 _ => {
278 let tx = self.tx.as_pg_mut().unwrap();
279 let (sql, values) = stmt.build_sqlx(PostgresQueryBuilder);
280 let result = sqlx::query_with::<sqlx::Postgres, _>(&sql, values)
281 .execute(&mut **tx)
282 .await?;
283 Ok(result.rows_affected())
284 }
285 }
286 }
287
288 pub async fn update_values(
291 self,
292 values: serde_json::Map<String, serde_json::Value>,
293 ) -> Result<u64, crate::orm::write::WriteError> {
294 let stmt = self.qs.build_update_for(self.tx.backend_name(), &values)?;
295 match self.tx.backend_name() {
296 "sqlite" => {
297 let tx = self.tx.as_sqlite_mut().unwrap();
298 let (sql, values) = stmt.build_sqlx(SqliteQueryBuilder);
299 let result = sqlx::query_with::<sqlx::Sqlite, _>(&sql, values)
300 .execute(&mut **tx)
301 .await?;
302 Ok(result.rows_affected())
303 }
304 _ => {
305 let tx = self.tx.as_pg_mut().unwrap();
306 let (sql, values) = stmt.build_sqlx(PostgresQueryBuilder);
307 let result = sqlx::query_with::<sqlx::Postgres, _>(&sql, values)
308 .execute(&mut **tx)
309 .await?;
310 Ok(result.rows_affected())
311 }
312 }
313 }
314
315 pub async fn create(self, instance: T) -> Result<T, crate::orm::write::WriteError>
320 where
321 T: serde::Serialize
322 + for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow>
323 + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>
324 + HydrateRelated,
325 {
326 let map = serialize_to_map(&instance)?;
327 let stmt = build_insert_one_for::<T>(self.tx.backend_name(), &map)?;
328 match self.tx.backend_name() {
329 "sqlite" => {
330 let tx = self.tx.as_sqlite_mut().unwrap();
331 let (sql, values) = stmt.build_sqlx(SqliteQueryBuilder);
332 let mut row = sqlx::query_as_with::<sqlx::Sqlite, T, _>(&sql, values)
339 .fetch_one(&mut **tx)
340 .await
341 .map_err(|e| {
342 crate::orm::validation::classify_sql_error(&e, &map)
343 .unwrap_or(crate::orm::write::WriteError::Sqlx(e))
344 })?;
345 row.set_m2m_parent_ids();
346 Ok(row)
347 }
348 _ => {
349 let tx = self.tx.as_pg_mut().unwrap();
350 let (sql, values) = stmt.build_sqlx(PostgresQueryBuilder);
351 let mut row = sqlx::query_as_with::<sqlx::Postgres, T, _>(&sql, values)
352 .fetch_one(&mut **tx)
353 .await
354 .map_err(|e| {
355 crate::orm::validation::classify_sql_error(&e, &map)
356 .unwrap_or(crate::orm::write::WriteError::Sqlx(e))
357 })?;
358 row.set_m2m_parent_ids();
359 Ok(row)
360 }
361 }
362 }
363}