use crate::SqlWriterValues;
use crate::expr::Expr;
use crate::expr::write_expr;
use crate::query::OnConflict;
use crate::query::Returning;
use crate::query::Select;
use crate::query::With;
use crate::query::write_on_conflict;
use crate::query::write_returning;
use crate::query::write_select;
use crate::query::write_with;
use crate::types::Iden;
use crate::types::IntoIden;
use crate::types::IntoTableRef;
use crate::types::TableRef;
use crate::types::write_iden;
use crate::types::write_table_ref;
use crate::writer::SqlWriter;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Insert {
table: Option<TableRef>,
columns: Vec<Iden>,
source: Option<InsertValueSource>,
on_conflict: Option<OnConflict>,
defaults: Option<u32>,
returning: Option<Returning>,
with: Option<With>,
}
impl Insert {
pub fn new() -> Self {
Self::default()
}
pub fn to_values(&self) -> SqlWriterValues {
let mut w = SqlWriterValues::new();
write_insert(&mut w, self);
w
}
pub fn to_sql(&self) -> String {
let mut sql = String::new();
write_insert(&mut sql, self);
sql
}
pub fn into_table<T>(mut self, table: T) -> Self
where
T: IntoTableRef,
{
self.table = Some(table.into());
self
}
pub fn columns<T, I>(mut self, cols: I) -> Self
where
I: IntoIterator<Item = T>,
T: IntoIden,
{
for col in cols {
self.columns.push(col.into_iden());
}
self
}
pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
self.on_conflict = Some(on_conflict);
self
}
pub fn returning(mut self, returning: Returning) -> Self {
self.returning = Some(returning);
self
}
pub fn with(mut self, with: With) -> Self {
self.with = Some(with);
self
}
pub fn values<I>(mut self, values: I) -> Self
where
I: IntoIterator<Item = Expr>,
{
let values = values.into_iter().collect::<Vec<_>>();
assert_eq!(values.len(), self.columns.len());
if !values.is_empty() {
if let Some(InsertValueSource::Values(vs)) = &mut self.source {
vs.push(values);
} else {
self.source = Some(InsertValueSource::Values(vec![values]));
}
}
self
}
pub fn select_from<S>(mut self, select: S) -> Self
where
S: Into<Select>,
{
let select = select.into();
assert_eq!(select.columns_len(), self.columns.len());
self.source = Some(InsertValueSource::Select(Box::new(select)));
self
}
pub fn or_default_values(mut self, n: u32) -> Self {
self.defaults = Some(n);
self
}
}
#[derive(Debug, Clone, PartialEq)]
enum InsertValueSource {
Values(Vec<Vec<Expr>>),
Select(Box<Select>),
}
pub(crate) fn write_insert<W: SqlWriter>(w: &mut W, insert: &Insert) {
if let Some(with) = &insert.with {
write_with(w, with);
w.push_char(' ');
}
w.push_str("INSERT ");
if let Some(table) = &insert.table {
w.push_str("INTO ");
write_table_ref(w, table);
}
if insert.defaults.unwrap_or_default() != 0
&& insert.columns.is_empty()
&& insert.source.is_none()
{
let num_rows = insert.defaults.unwrap_or_default();
w.push_str(" VALUES ");
for i in 0..num_rows {
if i > 0 {
w.push_str(", ");
}
w.push_str("(DEFAULT)");
}
} else {
w.push_str(" (");
for (i, col) in insert.columns.iter().enumerate() {
if i > 0 {
w.push_str(", ");
}
write_iden(w, col);
}
w.push_str(")");
if let Some(source) = &insert.source {
w.push_char(' ');
match source {
InsertValueSource::Values(rows) => {
w.push_str("VALUES ");
for (i, row) in rows.iter().enumerate() {
if i > 0 {
w.push_str(", ");
}
w.push_char('(');
for (j, expr) in row.iter().enumerate() {
if j > 0 {
w.push_str(", ");
}
write_expr(w, expr);
}
w.push_char(')');
}
}
InsertValueSource::Select(select) => write_select(w, select),
}
}
if let Some(on_conflict) = &insert.on_conflict {
write_on_conflict(w, on_conflict);
}
if let Some(returning) = &insert.returning {
write_returning(w, returning);
}
}
}