1use super::builder::QueryBuilder;
4use super::types::*;
5use serde_json::Value;
6
7#[derive(Debug)]
9pub struct UpsertBuilder<M = ()> {
10 pub(crate) query_builder: QueryBuilder<M>,
11 pub(crate) conflict_columns: Vec<String>,
12 pub(crate) update_clauses: Vec<SetClause>,
13}
14
15impl<M> UpsertBuilder<M> {
16 pub fn update_set<T: Into<Value>>(mut self, column: &str, value: T) -> Self {
18 self.update_clauses.push(SetClause {
19 column: column.to_string(),
20 value: Some(value.into()),
21 });
22 self
23 }
24
25 pub fn update_set_null(mut self, column: &str) -> Self {
27 self.update_clauses.push(SetClause {
28 column: column.to_string(),
29 value: None,
30 });
31 self
32 }
33
34 pub fn build(self) -> QueryBuilder<M> {
36 self.query_builder
39 }
40
41 pub fn to_sql_with_params(&self) -> (String, Vec<String>) {
43 let mut sql = String::new();
44 let mut params = Vec::new();
45 let mut param_counter = 1;
46
47 if let Some(table) = &self.query_builder.insert_table {
49 sql.push_str(&format!("INSERT INTO {}", table));
50
51 if !self.query_builder.set_clauses.is_empty() {
52 sql.push_str(" (");
53 let columns: Vec<String> = self
54 .query_builder
55 .set_clauses
56 .iter()
57 .map(|clause| clause.column.clone())
58 .collect();
59 sql.push_str(&columns.join(", "));
60 sql.push_str(") VALUES (");
61
62 for (i, clause) in self.query_builder.set_clauses.iter().enumerate() {
63 if i > 0 {
64 sql.push_str(", ");
65 }
66 if let Some(ref value) = clause.value {
67 sql.push_str(&format!("${}", param_counter));
68 params.push(value.to_string());
69 param_counter += 1;
70 } else {
71 sql.push_str("NULL");
72 }
73 }
74 sql.push(')');
75 }
76 }
77
78 if !self.conflict_columns.is_empty() {
80 sql.push_str(&format!(
81 " ON CONFLICT ({}) DO UPDATE SET ",
82 self.conflict_columns.join(", ")
83 ));
84
85 for (i, clause) in self.update_clauses.iter().enumerate() {
86 if i > 0 {
87 sql.push_str(", ");
88 }
89 sql.push_str(&format!("{} = ", clause.column));
90 if let Some(ref value) = clause.value {
91 sql.push_str(&format!("${}", param_counter));
92 params.push(value.to_string());
93 param_counter += 1;
94 } else {
95 sql.push_str("NULL");
96 }
97 }
98 }
99
100 (sql, params)
101 }
102}