use std::rc::Rc;
#[cfg(feature="with-json")]
use serde_json::Value as JsonValue;
use crate::{backend::QueryBuilder, Query, SelectExpr, SelectStatement, types::*, value::*, prepare::*, error::*};
#[derive(Debug, Default, Clone)]
pub struct InsertStatement {
pub(crate) table: Option<Box<TableRef>>,
pub(crate) columns: Vec<Rc<dyn Iden>>,
pub(crate) values: Vec<Vec<Value>>,
pub(crate) returning: Vec<SelectExpr>,
}
impl InsertStatement {
pub fn new() -> Self {
Self::default()
}
#[allow(clippy::wrong_self_convention)]
pub fn into_table<T>(&mut self, tbl_ref: T) -> &mut Self
where T: IntoTableRef {
self.table = Some(Box::new(tbl_ref.into_table_ref()));
self
}
pub fn columns<C, I>(&mut self, columns: I) -> &mut Self
where
C: IntoIden,
I: IntoIterator<Item = C>,
{
self.columns = columns.into_iter().map(|c| c.into_iden()).collect();
self
}
pub fn values<I>(&mut self, values: I) -> Result<&mut Self>
where
I: IntoIterator<Item = Value>,
{
let values = values.into_iter().collect::<Vec<_>>();
if self.columns.len() != values.len() {
return Err(Error::ColValNumMismatch {
col_len: self.columns.len(),
val_len: values.len(),
});
}
self.values.push(values);
Ok(self)
}
pub fn values_panic<I>(&mut self, values: I) -> &mut Self
where
I: IntoIterator<Item = Value>,
{
self.values(values).unwrap()
}
pub fn returning(&mut self, select: SelectStatement) -> &mut Self {
self.returning = select.selects;
self
}
pub fn returning_col<C>(&mut self, col: C) -> &mut Self
where C: IntoIden {
self.returning(Query::select().column(col.into_iden()).take())
}
#[cfg(feature="with-json")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-json")))]
pub fn json(&mut self, object: JsonValue) -> &mut Self {
match object {
JsonValue::Object(_) => (),
_ => panic!("object must be JsonValue::Object"),
}
let mut values = Vec::new();
if self.columns.is_empty() {
let map = object.as_object().unwrap();
let mut keys: Vec<String> = map.keys().cloned().collect();
keys.sort();
for k in keys.iter() {
self.columns.push(Rc::new(Alias::new(k)));
}
}
for col in self.columns.iter() {
values.push(
match object.get(col.to_string()) {
Some(value) => json_value_to_sea_value(value),
None => Value::Null,
}
);
}
self.values.push(values);
self
}
pub fn build_collect<T: QueryBuilder>(&self, query_builder: T, collector: &mut dyn FnMut(Value)) -> String {
let mut sql = SqlWriter::new();
query_builder.prepare_insert_statement(self, &mut sql, collector);
sql.result()
}
pub fn build_collect_any(&self, query_builder: &dyn QueryBuilder, collector: &mut dyn FnMut(Value)) -> String {
let mut sql = SqlWriter::new();
query_builder.prepare_insert_statement(self, &mut sql, collector);
sql.result()
}
pub fn build<T: QueryBuilder>(&self, query_builder: T) -> (String, Values) {
let mut values = Vec::new();
let mut collector = |v| values.push(v);
let sql = self.build_collect(query_builder, &mut collector);
(sql, Values(values))
}
pub fn build_any(&self, query_builder: &dyn QueryBuilder) -> (String, Values) {
let mut values = Vec::new();
let mut collector = |v| values.push(v);
let sql = self.build_collect_any(query_builder, &mut collector);
(sql, Values(values))
}
pub fn to_string<T: QueryBuilder>(&self, query_builder: T) -> String {
let (sql, values) = self.build_any(&query_builder);
inject_parameters(&sql, values.0, &query_builder)
}
}