mik_sql/builder/
update.rs1use crate::dialect::{Dialect, Postgres, Sqlite};
4use crate::validate::assert_valid_sql_identifier;
5
6use super::filter::{build_condition_impl, build_filter_expr_impl};
7use super::types::{Filter, FilterExpr, Operator, QueryResult, Value};
8
9#[derive(Debug)]
11#[must_use = "builder does nothing until .build() is called"]
12pub struct UpdateBuilder<D: Dialect> {
13 dialect: D,
14 table: String,
15 sets: Vec<(String, Value)>,
16 filters: Vec<Filter>,
17 filter_expr: Option<FilterExpr>,
18 returning: Vec<String>,
19}
20
21impl<D: Dialect> UpdateBuilder<D> {
22 pub fn new(dialect: D, table: impl Into<String>) -> Self {
28 let table = table.into();
29 assert_valid_sql_identifier(&table, "table");
30 Self {
31 dialect,
32 table,
33 sets: Vec::new(),
34 filters: Vec::new(),
35 filter_expr: None,
36 returning: Vec::new(),
37 }
38 }
39
40 pub fn set(mut self, column: impl Into<String>, value: Value) -> Self {
46 let column = column.into();
47 assert_valid_sql_identifier(&column, "column");
48 self.sets.push((column, value));
49 self
50 }
51
52 pub fn set_many(mut self, pairs: Vec<(&str, Value)>) -> Self {
58 for (col, val) in pairs {
59 assert_valid_sql_identifier(col, "column");
60 self.sets.push((col.to_string(), val));
61 }
62 self
63 }
64
65 pub fn filter(mut self, field: impl Into<String>, op: Operator, value: Value) -> Self {
71 let field = field.into();
72 assert_valid_sql_identifier(&field, "filter field");
73 self.filters.push(Filter { field, op, value });
74 self
75 }
76
77 pub fn filter_expr(mut self, expr: FilterExpr) -> Self {
80 self.filter_expr = Some(expr);
81 self
82 }
83
84 pub fn returning(mut self, columns: &[&str]) -> Self {
90 for col in columns {
91 assert_valid_sql_identifier(col, "returning column");
92 }
93 self.returning = columns.iter().map(|s| (*s).to_string()).collect();
94 self
95 }
96
97 pub fn build(self) -> QueryResult {
99 let mut sql = String::new();
100 let mut params = Vec::new();
101 let mut param_idx = 1usize;
102
103 sql.push_str(&format!("UPDATE {} SET ", self.table));
105
106 let set_parts: Vec<String> = self
107 .sets
108 .iter()
109 .map(|(col, val)| {
110 let p = self.dialect.param(param_idx);
111 params.push(val.clone());
112 param_idx += 1;
113 format!("{col} = {p}")
114 })
115 .collect();
116 sql.push_str(&set_parts.join(", "));
117
118 let has_filter_expr = self.filter_expr.is_some();
120 let has_simple_filters = !self.filters.is_empty();
121
122 if has_filter_expr || has_simple_filters {
123 sql.push_str(" WHERE ");
124 let mut all_conditions = Vec::new();
125
126 if let Some(ref expr) = self.filter_expr {
127 let (condition, new_params, new_idx) =
128 build_filter_expr_impl(&self.dialect, expr, param_idx);
129 all_conditions.push(condition);
130 params.extend(new_params);
131 param_idx = new_idx;
132 }
133
134 for filter in &self.filters {
135 let (condition, new_params, new_idx) =
136 build_condition_impl(&self.dialect, filter, param_idx);
137 all_conditions.push(condition);
138 params.extend(new_params);
139 param_idx = new_idx;
140 }
141
142 sql.push_str(&all_conditions.join(" AND "));
143 }
144
145 if !self.returning.is_empty() {
147 sql.push_str(&format!(" RETURNING {}", self.returning.join(", ")));
148 }
149
150 QueryResult { sql, params }
151 }
152}
153
154pub fn update(table: impl Into<String>) -> UpdateBuilder<Postgres> {
156 UpdateBuilder::new(Postgres, table)
157}
158
159pub fn update_sqlite(table: impl Into<String>) -> UpdateBuilder<Sqlite> {
161 UpdateBuilder::new(Sqlite, table)
162}