1use crate::clause::Clause;
2use crate::{wrap, Column, Final, SqlClause};
3use tokio_postgres::types::ToSql;
4
5pub struct Insert;
6pub struct End;
7pub struct OnConflictHandle<'q>(Clause<'q, End>);
8
9pub fn insert_into<'q>(
10 table: &str,
11 map: &[(&str, &'q (dyn ToSql + Sync + 'q))],
12) -> Clause<'q, Insert> {
13 let mut sql = String::from("insert into ");
14 let mut value_list = Vec::with_capacity(map.len());
15 sql.push_str(&wrap(table));
16 sql.push_str(" (");
17 let mut not_first = false;
18 for (key, value) in map {
19 if not_first {
20 sql.push(',');
21 }
22 sql.push_str(format!("\"{}\"", key).as_str());
23 not_first = true;
24 value_list.push(*value);
25 }
26 sql.push_str(") values (");
27 let mut not_first = false;
28 for _ in 0..value_list.len() {
29 if not_first {
30 sql.push(',');
31 }
32 not_first = true;
33 sql.push('$');
34 }
35 sql.push(')');
36 Clause::new(sql, value_list)
37}
38impl<'q> Clause<'q, Insert> {
39 pub fn on_conflict_do_nothing(self) -> Clause<'q, Final> {
40 let (mut sql, params) = self.get();
41 sql.push_str(" on conflict do nothing");
42 Clause::new(sql, params)
43 }
44 pub fn on_conflict(self, cols: Clause<'q, Column>) -> OnConflictHandle<'q> {
45 let (mut sql, params) = self.get();
46 let (cols_sql, _) = cols.get();
47 sql.push_str(" on conflict (");
48 sql.push_str(&cols_sql);
49 sql.push(')');
50 OnConflictHandle(Clause::new(sql, params))
51 }
52}
53
54impl<'q> OnConflictHandle<'q> {
55 pub fn do_nothing(self) -> Clause<'q, Final> {
56 let (mut sql, params) = self.0.get();
57 sql.push_str(" do nothing");
58 Clause::new(sql, params)
59 }
60
61 pub fn do_update_excluded(self, columns: &[&str]) -> Clause<'q, Final> {
68 let (mut sql, params) = self.0.get();
69 sql.push_str(" do update set ");
70 let mut not_first = false;
71 for item in columns {
72 if not_first {
73 sql.push(',');
74 }
75 not_first = true;
76 sql.push_str(&format!("\"{}\" = excluded.\"{}\"", item, item));
77 }
78 Clause::new(sql, params)
79 }
80}
81#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::cols;
118
119 #[test]
120 fn insert_test() {
121 let (sql, params) = insert_into("Table", &[("Col1", &1), ("Col2", &2)])
122 .on_conflict(cols(&["Test"]))
123 .do_update_excluded(&["Col1", "Col2"])
124 .get();
125 println!("{:}", sql);
126 println!("params: {:?}", params);
127 }
128}