use d1_orm_query::Set;
use crate::{convert::to_js_vec, error::OrmError, model::D1Model, table::Table};
impl<'db, M: D1Model> Table<'db, M> {
pub async fn upsert(&self, model: &M, on_conflict: &[&str], set: Set) -> Result<M, OrmError> {
let cols = M::COLUMNS.join(", ");
let phs = (1..=M::COLUMNS.len()).map(|i| format!("?{}", i)).collect::<Vec<_>>().join(", ");
let conflict_cols = on_conflict.join(", ");
let next_n = M::COLUMNS.len() + 1;
let (set_sql, extra_values, _) = set.build(next_n);
let sql = format!(
"INSERT INTO {} ({}) VALUES ({}) ON CONFLICT({}) DO UPDATE SET {} RETURNING *",
M::TABLE, cols, phs, conflict_cols, set_sql
);
let all: Vec<_> = model.values().into_iter().chain(extra_values).collect();
let js = to_js_vec(&all);
self.db.prepare(&sql)
.bind(&js).map_err(|_| OrmError::Bind)?
.first::<M>(None).await.map_err(|_| OrmError::Execute)?
.ok_or(OrmError::Execute)
}
pub async fn upsert_ignore(&self, model: &M, on_conflict: &[&str]) -> Result<(), OrmError> {
let cols = M::COLUMNS.join(", ");
let phs = (1..=M::COLUMNS.len()).map(|i| format!("?{}", i)).collect::<Vec<_>>().join(", ");
let conflict_cols = on_conflict.join(", ");
let sql = format!(
"INSERT INTO {} ({}) VALUES ({}) ON CONFLICT({}) DO NOTHING",
M::TABLE, cols, phs, conflict_cols
);
let js = to_js_vec(&model.values());
self.db.prepare(&sql)
.bind(&js).map_err(|_| OrmError::Bind)?
.run().await.map_err(|_| OrmError::Execute)?;
Ok(())
}
}