use super::builder::QueryBuilder;
use super::types::*;
use serde_json::Value;
#[derive(Debug)]
pub struct UpsertBuilder<M = ()> {
pub(crate) query_builder: QueryBuilder<M>,
pub(crate) conflict_columns: Vec<String>,
pub(crate) update_clauses: Vec<SetClause>,
}
impl<M> UpsertBuilder<M> {
pub fn update_set<T: Into<Value>>(mut self, column: &str, value: T) -> Self {
self.update_clauses.push(SetClause {
column: column.to_string(),
value: Some(value.into()),
});
self
}
pub fn update_set_null(mut self, column: &str) -> Self {
self.update_clauses.push(SetClause {
column: column.to_string(),
value: None,
});
self
}
pub fn build(self) -> QueryBuilder<M> {
self.query_builder
}
pub fn to_sql_with_params(&self) -> (String, Vec<String>) {
let mut sql = String::new();
let mut params = Vec::new();
let mut param_counter = 1;
if let Some(table) = &self.query_builder.insert_table {
sql.push_str(&format!("INSERT INTO {}", table));
if !self.query_builder.set_clauses.is_empty() {
sql.push_str(" (");
let columns: Vec<String> = self
.query_builder
.set_clauses
.iter()
.map(|clause| clause.column.clone())
.collect();
sql.push_str(&columns.join(", "));
sql.push_str(") VALUES (");
for (i, clause) in self.query_builder.set_clauses.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
}
if let Some(ref value) = clause.value {
sql.push_str(&format!("${}", param_counter));
params.push(value.to_string());
param_counter += 1;
} else {
sql.push_str("NULL");
}
}
sql.push(')');
}
}
if !self.conflict_columns.is_empty() {
sql.push_str(&format!(
" ON CONFLICT ({}) DO UPDATE SET ",
self.conflict_columns.join(", ")
));
for (i, clause) in self.update_clauses.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
}
sql.push_str(&format!("{} = ", clause.column));
if let Some(ref value) = clause.value {
sql.push_str(&format!("${}", param_counter));
params.push(value.to_string());
param_counter += 1;
} else {
sql.push_str("NULL");
}
}
}
(sql, params)
}
}