1use crate::WhereOption;
2
3use super::{DbType, FieldItem, ModelTableField, ModelTableName};
4use sqlx::database::HasArguments;
5use sqlx::query::Query;
6use sqlx::{Arguments, Executor, IntoArguments};
7use sqlx::{Database, Error};
8
9pub trait UpdateData<'t, DB>
10where
11 DB: Database,
12{
13 fn diff_columns(&self) -> Vec<FieldItem>;
14 fn sqlx_bind<'q>(
15 &'q self,
16 res: Query<'q, DB, <DB as HasArguments>::Arguments>,
17 ) -> Query<'q, DB, <DB as HasArguments>::Arguments>;
18 fn sqlx_string(&self, field: &FieldItem) -> Option<String>;
19}
20pub trait ModelUpdateData<'t, DB, CT>: ModelTableField<DB> + ModelTableName
22where
23 CT: UpdateData<'t, DB>,
24 DB: Database,
25{
26 fn diff(&'t self, source: &Option<&Self>) -> CT;
27}
28
29pub struct Update<'t, DB, T, CT>
31where
32 T: ModelUpdateData<'t, DB, CT>,
33 CT: UpdateData<'t, DB>,
34 DB: Database,
35{
36 pub change: CT,
37 _marker: (
38 std::marker::PhantomData<&'t CT>,
39 std::marker::PhantomData<&'t T>,
40 std::marker::PhantomData<DB>,
41 ),
42}
43impl<'t, DB, T, CT> Update<'t, DB, T, CT>
44where
45 T: ModelUpdateData<'t, DB, CT>,
46 CT: UpdateData<'t, DB>,
47 DB: Database,
48{
49 pub fn new(val: CT) -> Update<'t, DB, T, CT> {
50 Update {
51 change: val,
52 _marker: Default::default(),
53 }
54 }
55 pub fn model<'q: 't>(val: &'q T, source: &Option<&T>) -> Update<'t, DB, T, CT> {
56 Update {
57 change: val.diff(source),
58 _marker: Default::default(),
59 }
60 }
61 pub fn empty_change(&self) -> bool {
62 self.change.diff_columns().is_empty()
63 }
64 pub fn sql_sets(&self) -> String {
65 let diff = self.change.diff_columns();
66 let mut values = Vec::<String>::with_capacity(diff.len());
67 for (pos, val) in diff.iter().enumerate() {
68 let bst = DbType::type_new::<DB>().mark(pos);
69 values.push(format!("{}={}", val.name, bst));
70 }
71 values.join(",")
72 }
73 pub fn sql_values_sets(&self) -> String {
74 let diff = self.change.diff_columns();
75 let mut values = Vec::<String>::with_capacity(diff.len());
76 for val in diff.iter() {
77 if let Some(setval) = self.change.sqlx_string(val) {
78 values.push(format!("{}={}", val.name, setval));
79 }
80 }
81 values.join(",")
82 }
83 pub fn bind_values<'q>(
84 &'q self,
85 res: Query<'q, DB, <DB as HasArguments>::Arguments>,
86 ) -> Query<'q, DB, <DB as HasArguments>::Arguments> {
87 self.change.sqlx_bind(res)
88 }
89 pub async fn execute_by_scalar_pk<'c, PT, E>(
90 &self,
91 pk_scalar: PT,
92 executor: E,
93 ) -> Result<<DB as Database>::QueryResult, Error>
94 where
95 for<'q> PT: 'q + Send + sqlx::Encode<'q, DB> + sqlx::Type<DB>,
96 for<'n> <DB as HasArguments<'n>>::Arguments: Arguments<'n> + IntoArguments<'n, DB>,
97 E: Executor<'c, Database = DB>,
98 {
99 if self.empty_change() {
100 return Ok(<DB as Database>::QueryResult::default());
101 }
102 let table = T::table_name();
103 let values = self.sql_sets();
104 let sql = format!(
105 "UPDATE {} SET {} WHERE {}",
106 table.full_name(),
107 values,
108 scalar_pk_where!(DB, T::table_pk(), self.change.diff_columns().len())
109 );
110
111 let mut res = sqlx::query(sql.as_str());
112 res = self.bind_values(res);
113 res = res.bind(pk_scalar);
114 executor.execute(res).await
115 }
116 pub async fn execute_by_where<'c, E>(
117 &self,
118 where_sql: &WhereOption,
119 executor: E,
120 ) -> Result<<DB as Database>::QueryResult, Error>
121 where
122 for<'n> <DB as HasArguments<'n>>::Arguments: Arguments<'n> + IntoArguments<'n, DB>,
123 E: Executor<'c, Database = DB>,
124 {
125 if self.empty_change() {
126 return Ok(<DB as Database>::QueryResult::default());
127 }
128 let table = T::table_name();
129 let values = self.sql_sets();
130 let sql = match where_sql {
131 WhereOption::Where(wsql) => {
132 format!("UPDATE {} SET {} WHERE {}", table.full_name(), values, wsql)
133 }
134 WhereOption::None => {
135 format!("UPDATE {} SET {}", table.full_name(), values)
136 }
137 WhereOption::NoWhere(other) => {
138 format!("UPDATE {} SET {} {}", table.full_name(), values, other)
139 }
140 };
141 let mut res = sqlx::query(sql.as_str());
142 res = self.bind_values(res);
143 executor.execute(res).await
144 }
145 pub async fn execute_by_pk<'c, E>(
147 &self,
148 source: &T,
149 executor: E,
150 ) -> Result<<DB as Database>::QueryResult, Error>
151 where
152 for<'n> <DB as HasArguments<'n>>::Arguments: Arguments<'n> + IntoArguments<'n, DB>,
153 E: Executor<'c, Database = DB>,
154 {
155 if self.empty_change() {
156 return Ok(<DB as Database>::QueryResult::default());
157 }
158 let table = T::table_name();
159 let pkf = T::table_pk();
160 let mut where_sql = vec![];
161 let values = self.sql_sets();
162 for (pos, val) in pkf.0.iter().enumerate() {
163 let bst = DbType::type_new::<DB>().mark(pos + self.change.diff_columns().len());
164 where_sql.push(format!("{}={}", val.name, bst));
165 }
166 let sql = format!(
167 "UPDATE {} SET {} WHERE {}",
168 table.full_name(),
169 values,
170 where_sql.join(" and ")
171 );
172 let mut res = sqlx::query(sql.as_str());
173 res = self.bind_values(res);
174 for val in pkf.0.iter() {
175 res = source.query_sqlx_bind(val, res);
176 }
177 executor.execute(res).await
178 }
179}