use crate::Client;
use crate::errors::Result;
use crate::model_traits::{HasSchema, TableColumns, TableInfo, WriteToArgs};
use crate::query::clause::ParamArgs;
use crate::writers::ColumnWriter;
use crate::writers::NextParam;
use crate::writers::TableWriter;
#[maybe_async::maybe_async]
pub async fn bulk_insert_with_ids<T>(conn: &dyn Client, data: &[T]) -> Result<()>
where
T: WriteToArgs + HasSchema,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
let syntax = conn.syntax();
let parts = <<T as HasSchema>::Schema>::identifier();
let tablename: String = TableWriter::new(syntax).write2(parts);
run(conn, data, true, &tablename).await
}
#[maybe_async::maybe_async]
pub async fn bulk_insert<T>(conn: &dyn Client, data: &[T]) -> Result<()>
where
T: WriteToArgs + HasSchema,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
let syntax = conn.syntax();
let parts = <<T as HasSchema>::Schema>::identifier();
let tablename: String = TableWriter::new(syntax).write2(parts);
run(conn, data, false, &tablename).await
}
#[maybe_async::maybe_async]
pub async fn bulk_insert_with_ids_override_tablename_unsafe<T>(
conn: &dyn Client,
data: &[T],
tablename: impl Into<String>,
) -> Result<()>
where
T: WriteToArgs + HasSchema,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
let tablename: String = tablename.into();
run(conn, data, true, &tablename).await
}
#[maybe_async::maybe_async]
pub async fn bulk_insert_override_tablename_unsafe<T>(
conn: &dyn Client,
data: &[T],
tablename: impl Into<String>,
) -> Result<()>
where
T: WriteToArgs + HasSchema,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
let tablename: String = tablename.into();
run(conn, data, false, &tablename).await
}
#[maybe_async::maybe_async]
async fn run<T>(conn: &dyn Client, data: &[T], with_ids: bool, tablename: &str) -> Result<()>
where
T: WriteToArgs + HasSchema,
<T as HasSchema>::Schema: TableInfo + TableColumns,
{
if data.is_empty() {
return Ok(());
}
let syntax = conn.syntax();
let col_writer = ColumnWriter::new(syntax);
let all_columns = <<T as HasSchema>::Schema as TableColumns>::insert_columns();
let pks = <<T as HasSchema>::Schema as TableColumns>::primary_keys();
let columns: Vec<_> = all_columns
.iter()
.filter(|c| with_ids || !pks.contains(c))
.collect();
let colnames: Vec<String> = columns
.iter()
.map(|c| col_writer.excape(c.name()))
.collect();
let colnames = colnames.join(", ");
let max_params = NextParam::new(syntax).max_params();
let chunk_size = max_params as usize / colnames.len();
let param_size = chunk_size + columns.len();
for chunk in data.chunks(chunk_size) {
let next_params = NextParam::new(syntax);
let mut args: ParamArgs = Vec::with_capacity(param_size);
let mut rows: Vec<String> = Vec::with_capacity(chunk_size);
for d in chunk {
let mut row: Vec<String> = Vec::default();
for col in &columns {
d.bind(col.name(), &mut args)?;
row.push(next_params.next());
}
rows.push(format!("({})", row.join(",")));
}
let rows = rows.join(",");
let sql = format!("INSERT INTO {tablename} ({colnames}) VALUES {rows}");
conn.execute(&sql, &args).await?;
}
Ok(())
}