sqlx_model/curd/
update.rs

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}
20//得到需要更改的设置数据集
21pub 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
29/// 更新操作
30pub 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    // execute_by_sql!(Update<DB,T,CT>);
146    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}