use keelson_core::clause::{HasSet, HasTableRef, HasValues, Set, TableRef, Values};
use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
use keelson_core::{Dialect, Error, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
use super::write_hints_and_modifiers;
use crate::Mysql;
use crate::extras::{
HasDuplicateKeyUpdate, HasHints, HasModifiers, HasRowAlias, Hints, Modifiers, RowAlias,
};
#[derive(Debug, Clone, Default)]
pub struct InsertQuery {
pub hints: Hints,
pub modifiers: Modifiers,
pub table: TableRef,
pub values: Values,
pub set: Set,
pub row_alias: RowAlias,
pub duplicate_key_update: Set,
}
impl InsertQuery {
pub fn new() -> InsertQuery {
InsertQuery::default()
}
pub fn apply(&mut self, mods: impl Mod<InsertQuery>) {
mods.apply(self);
}
}
impl Expression for InsertQuery {
fn write_sql(&self, w: &mut SqlWriter<'_>) {
if self.table.is_empty() {
w.record_error(Error::Incomplete("the target table of an INSERT"));
return;
}
w.push_str("INSERT ");
write_hints_and_modifiers(w, &self.hints, &self.modifiers);
w.push_str("INTO ");
write_target_and_row_source(w, &self.table, &self.set, &self.values);
w.write_if(!self.row_alias.is_empty(), " ", &self.row_alias, "");
w.write_if(
!self.duplicate_key_update.is_empty(),
" ON DUPLICATE KEY UPDATE ",
&self.duplicate_key_update,
"",
);
}
}
pub(super) fn write_target_and_row_source(
w: &mut SqlWriter<'_>,
table: &TableRef,
set: &Set,
values: &Values,
) {
if set.is_empty() {
w.write_expr(table);
if values.is_empty() {
w.push_str(" VALUES ()");
} else {
w.push_str(" ");
w.write_expr(values);
}
return;
}
if table.columns.is_empty() {
w.write_expr(table);
} else {
w.write_expr(&TableRef {
columns: Vec::new(),
..table.clone()
});
}
w.push_str(" SET ");
w.write_expr(set);
}
impl Query for InsertQuery {
fn query_type(&self) -> QueryType {
QueryType::Insert
}
fn dialect(&self) -> &dyn Dialect {
&Mysql
}
}
impl<H, L, M> QueryExtensions<H, L, M> for InsertQuery {}
impl IntoExpr for InsertQuery {
fn into_expr(self) -> Expr {
crate::query(self)
}
}
impl IntoExprList for InsertQuery {
fn into_expr_list(self) -> Vec<Expr> {
vec![self.into_expr()]
}
}
impl HasHints for InsertQuery {
fn hints_mut(&mut self) -> &mut Hints {
&mut self.hints
}
}
impl HasModifiers for InsertQuery {
fn modifiers_mut(&mut self) -> &mut Modifiers {
&mut self.modifiers
}
}
impl HasTableRef for InsertQuery {
fn table_ref_mut(&mut self) -> &mut TableRef {
&mut self.table
}
}
impl HasValues for InsertQuery {
fn values_mut(&mut self) -> &mut Values {
&mut self.values
}
}
impl HasSet for InsertQuery {
fn set_mut(&mut self) -> &mut Set {
&mut self.set
}
}
impl HasRowAlias for InsertQuery {
fn row_alias_mut(&mut self) -> &mut RowAlias {
&mut self.row_alias
}
}
impl HasDuplicateKeyUpdate for InsertQuery {
fn duplicate_key_update_mut(&mut self) -> &mut Set {
&mut self.duplicate_key_update
}
}