cratestack_sqlx/query/write/
update_many.rs1use cratestack_core::{BatchSummary, CoolContext, CoolError};
13
14use crate::{
15 FilterExpr, ModelDescriptor, SqlxRuntime, UpdateModelInput, cool_error_from_sqlx, sqlx,
16};
17
18use super::preview::render_update_many_preview_sql;
19use super::update_many_exec::run_update_many_in_tx;
20
21#[derive(Debug, Clone)]
22pub struct UpdateMany<'a, M: 'static, PK: 'static> {
23 pub(crate) runtime: &'a SqlxRuntime,
24 pub(crate) descriptor: &'static ModelDescriptor<M, PK>,
25 pub(crate) filters: Vec<FilterExpr>,
26}
27
28impl<'a, M: 'static, PK: 'static> UpdateMany<'a, M, PK> {
29 pub fn where_(mut self, filter: crate::Filter) -> Self {
30 self.filters.push(FilterExpr::from(filter));
31 self
32 }
33
34 pub fn where_expr(mut self, filter: FilterExpr) -> Self {
35 self.filters.push(filter);
36 self
37 }
38
39 pub fn where_any(mut self, filters: impl IntoIterator<Item = FilterExpr>) -> Self {
40 self.filters.push(FilterExpr::any(filters));
41 self
42 }
43
44 pub fn where_optional<F>(mut self, filter: Option<F>) -> Self
46 where
47 F: Into<FilterExpr>,
48 {
49 if let Some(filter) = filter {
50 self.filters.push(filter.into());
51 }
52 self
53 }
54
55 pub fn set<I>(self, input: I) -> UpdateManySet<'a, M, PK, I> {
57 UpdateManySet {
58 runtime: self.runtime,
59 descriptor: self.descriptor,
60 filters: self.filters,
61 input,
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
67pub struct UpdateManySet<'a, M: 'static, PK: 'static, I> {
68 pub(crate) runtime: &'a SqlxRuntime,
69 pub(crate) descriptor: &'static ModelDescriptor<M, PK>,
70 pub(crate) filters: Vec<FilterExpr>,
71 pub(crate) input: I,
72}
73
74impl<'a, M: 'static, PK: 'static, I> UpdateManySet<'a, M, PK, I>
75where
76 I: UpdateModelInput<M>,
77{
78 pub fn preview_sql(&self) -> String {
79 let values = self.input.sql_values();
80 let columns: Vec<&str> = values.iter().map(|v| v.column).collect();
81 render_update_many_preview_sql(
82 self.descriptor.table_name,
83 self.descriptor.soft_delete_column.is_some(),
84 self.descriptor.version_column,
85 &columns,
86 &self.descriptor.select_projection(),
87 )
88 }
89
90 pub async fn run(self, ctx: &CoolContext) -> Result<BatchSummary, CoolError>
94 where
95 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
96 {
97 let runtime = self.runtime;
98 let descriptor = self.descriptor;
99 let mut tx = runtime.pool().begin().await.map_err(cool_error_from_sqlx)?;
100 let (summary, emits_event) =
101 run_update_many_in_tx(&mut tx, runtime, descriptor, &self.filters, self.input, ctx)
102 .await?;
103 tx.commit().await.map_err(cool_error_from_sqlx)?;
104 if emits_event {
105 let _ = runtime.drain_event_outbox().await;
106 }
107 Ok(summary)
108 }
109
110 pub async fn run_in_tx<'tx>(
113 self,
114 tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
115 ctx: &CoolContext,
116 ) -> Result<BatchSummary, CoolError>
117 where
118 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
119 {
120 let (summary, _) = run_update_many_in_tx(
121 tx,
122 self.runtime,
123 self.descriptor,
124 &self.filters,
125 self.input,
126 ctx,
127 )
128 .await?;
129 Ok(summary)
130 }
131}