use std::borrow::Cow;
use crate::ast::{Column, Expression, Query, Row, Table, Update, Values};
#[derive(Clone, Debug, PartialEq)]
pub struct Insert<'a> {
pub(crate) table: Option<Table<'a>>,
pub(crate) columns: Vec<Column<'a>>,
pub(crate) values: Expression<'a>,
pub(crate) on_conflict: Option<OnConflict<'a>>,
pub(crate) returning: Option<Vec<Column<'a>>>,
pub(crate) comment: Option<Cow<'a, str>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SingleRowInsert<'a> {
pub(crate) table: Option<Table<'a>>,
pub(crate) columns: Vec<Column<'a>>,
pub(crate) values: Row<'a>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MultiRowInsert<'a> {
pub(crate) table: Option<Table<'a>>,
pub(crate) columns: Vec<Column<'a>>,
pub(crate) values: Vec<Row<'a>>,
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq)]
pub enum OnConflict<'a> {
DoNothing,
Update(Update<'a>, Vec<Column<'a>>),
}
impl<'a> From<Insert<'a>> for Query<'a> {
fn from(insert: Insert<'a>) -> Self {
Query::Insert(Box::new(insert))
}
}
impl<'a> From<SingleRowInsert<'a>> for Insert<'a> {
fn from(insert: SingleRowInsert<'a>) -> Self {
let values = if insert.values.is_empty() {
Expression::from(Row::new())
} else {
Expression::from(insert.values)
};
Insert {
table: insert.table,
columns: insert.columns,
values,
on_conflict: None,
returning: None,
comment: None,
}
}
}
impl<'a> From<MultiRowInsert<'a>> for Insert<'a> {
fn from(insert: MultiRowInsert<'a>) -> Self {
let values = Expression::from(Values::new(insert.values));
Insert {
table: insert.table,
columns: insert.columns,
values,
on_conflict: None,
returning: None,
comment: None,
}
}
}
impl<'a> From<SingleRowInsert<'a>> for Query<'a> {
fn from(insert: SingleRowInsert<'a>) -> Query<'a> {
Query::from(Insert::from(insert))
}
}
impl<'a> From<MultiRowInsert<'a>> for Query<'a> {
fn from(insert: MultiRowInsert<'a>) -> Query<'a> {
Query::from(Insert::from(insert))
}
}
impl<'a> Insert<'a> {
pub fn single_into<T>(table: T) -> SingleRowInsert<'a>
where
T: Into<Table<'a>>,
{
SingleRowInsert {
table: Some(table.into()),
columns: Vec::new(),
values: Row::new(),
}
}
pub fn single() -> SingleRowInsert<'a> {
SingleRowInsert {
table: None,
columns: Vec::new(),
values: Row::new(),
}
}
pub fn multi_into<T, K, I>(table: T, columns: I) -> MultiRowInsert<'a>
where
T: Into<Table<'a>>,
K: Into<Column<'a>>,
I: IntoIterator<Item = K>,
{
MultiRowInsert {
table: Some(table.into()),
columns: columns.into_iter().map(|c| c.into()).collect(),
values: Vec::new(),
}
}
pub fn multi<K, I>(columns: I) -> MultiRowInsert<'a>
where
K: Into<Column<'a>>,
I: IntoIterator<Item = K>,
{
MultiRowInsert {
table: None,
columns: columns.into_iter().map(|c| c.into()).collect(),
values: Vec::new(),
}
}
pub fn expression_into<T, I, K, E>(table: T, columns: I, expression: E) -> Self
where
T: Into<Table<'a>>,
I: IntoIterator<Item = K>,
K: Into<Column<'a>>,
E: Into<Expression<'a>>,
{
Insert {
table: Some(table.into()),
columns: columns.into_iter().map(|c| c.into()).collect(),
values: expression.into(),
on_conflict: None,
returning: None,
comment: None,
}
}
pub fn on_conflict(mut self, on_conflict: OnConflict<'a>) -> Self {
self.on_conflict = Some(on_conflict);
self
}
pub fn comment<C: Into<Cow<'a, str>>>(mut self, comment: C) -> Self {
self.comment = Some(comment.into());
self
}
#[cfg(any(feature = "postgresql", feature = "mssql", feature = "sqlite"))]
#[cfg_attr(
feature = "docs",
doc(cfg(any(feature = "postgresql", feature = "mssql", feature = "sqlite")))
)]
pub fn returning<K, I>(mut self, columns: I) -> Self
where
K: Into<Column<'a>>,
I: IntoIterator<Item = K>,
{
self.returning = Some(columns.into_iter().map(|k| k.into()).collect());
self
}
}
impl<'a> SingleRowInsert<'a> {
pub fn value<K, V>(mut self, key: K, val: V) -> SingleRowInsert<'a>
where
K: Into<Column<'a>>,
V: Into<Expression<'a>>,
{
self.columns.push(key.into());
self.values.push(val.into());
self
}
pub fn build(self) -> Insert<'a> {
Insert::from(self)
}
}
impl<'a> MultiRowInsert<'a> {
pub fn values<V>(mut self, values: V) -> Self
where
V: Into<Row<'a>>,
{
self.values.push(values.into());
self
}
pub fn build(self) -> Insert<'a> {
Insert::from(self)
}
}