use crate::Row;
use crate::errors::Result;
use crate::errors::WeldsError::InsertFailed;
use crate::model_traits::hooks::{AfterCreate, BeforeCreate};
use crate::model_traits::{ColumnDefaultCheck, UpdateFromRow};
use crate::model_traits::{HasSchema, TableColumns, TableInfo, WriteToArgs};
use crate::query::clause::ParamArgs;
use crate::writers::NextParam;
use crate::writers::TableWriter;
use crate::writers::column::ColumnWriter;
use crate::writers::insert::{ColArg, InsertWriter};
use welds_connections::Client;
use welds_connections::Fetch;
#[maybe_async::maybe_async]
pub async fn insert_one<T>(obj: &mut T, client: &dyn Client) -> Result<()>
where
T: WriteToArgs + HasSchema + ColumnDefaultCheck,
<T as HasSchema>::Schema: TableInfo + TableColumns,
T: UpdateFromRow,
T: BeforeCreate + AfterCreate,
{
BeforeCreate::before(obj).await?;
let syntax = client.syntax();
let mut args: ParamArgs = Vec::default();
let args2: ParamArgs = Vec::default();
let col_writer = ColumnWriter::new(syntax);
let next_params = NextParam::new(syntax);
let writer = InsertWriter::new(syntax);
let parts = <<T as HasSchema>::Schema>::identifier();
let identifier = TableWriter::new(syntax).write2(parts);
let columns = <<T as HasSchema>::Schema as TableColumns>::insert_columns();
let pks = <<T as HasSchema>::Schema as TableColumns>::primary_keys();
let mut colargs = Vec::default();
let mut id_return_required = true;
for col in &columns {
let pk = pks.iter().find(|p| p == &col);
match pk {
None => {
obj.bind(col.name(), &mut args)?;
let col = col_writer.excape(col.name());
colargs.push(ColArg(col, next_params.next()));
}
Some(_) => {
if !obj.col_is_default(col.name())? {
log::trace!("col: {} is not default, using in insert", col.name());
id_return_required = false;
obj.bind(col.name(), &mut args)?;
let col = col_writer.excape(col.name());
colargs.push(ColArg(col, next_params.next()));
} else {
log::trace!("col: {} is default, not used for insert", col.name());
}
}
}
}
let (insert, select) = writer.write(&identifier, &colargs, &columns, &pks);
let mut statements = vec![Fetch {
sql: &insert,
params: &args,
}];
let sql2: String;
if id_return_required {
if pks.len() >= 2 {
return Err(crate::errors::WeldsError::InsertFailed("Unable to insert record with multiple PKs where IDs are expected to be returned from database. To insert a record with multiple PKs they must both be provided.".to_owned()));
}
if let Some(select) = select {
sql2 = select.to_owned();
statements.push(Fetch {
sql: &sql2,
params: &args2,
})
}
}
let mut datasets = client.fetch_many(&statements).await?;
let mut rows: Vec<Row> = datasets.drain(..).flatten().collect();
if !id_return_required {
AfterCreate::after(obj).await.ok();
return Ok(());
}
let row = rows.pop();
let mut row =
row.ok_or_else(|| InsertFailed("Insert didn't return inserted ID/Row".to_owned()))?;
UpdateFromRow::update_from_row(obj, &mut row)?;
AfterCreate::after(obj).await.ok();
Ok(())
}
#[cfg(test)]
mod tests;