1use d1_orm_query::Set;
2use crate::{convert::to_js_vec, error::OrmError, model::D1Model, table::Table};
3
4impl<'db, M: D1Model> Table<'db, M> {
5 pub async fn upsert(&self, model: &M, on_conflict: &[&str], set: Set) -> Result<M, OrmError> {
6 let cols = M::COLUMNS.join(", ");
7 let phs = (1..=M::COLUMNS.len()).map(|i| format!("?{}", i)).collect::<Vec<_>>().join(", ");
8 let conflict_cols = on_conflict.join(", ");
9 let next_n = M::COLUMNS.len() + 1;
10 let (set_sql, extra_values, _) = set.build(next_n);
11 let sql = format!(
12 "INSERT INTO {} ({}) VALUES ({}) ON CONFLICT({}) DO UPDATE SET {} RETURNING *",
13 M::TABLE, cols, phs, conflict_cols, set_sql
14 );
15 let all: Vec<_> = model.values().into_iter().chain(extra_values).collect();
16 let js = to_js_vec(&all);
17 self.db.prepare(&sql)
18 .bind(&js).map_err(|_| OrmError::Bind)?
19 .first::<M>(None).await.map_err(|_| OrmError::Execute)?
20 .ok_or(OrmError::Execute)
21 }
22
23 pub async fn upsert_ignore(&self, model: &M, on_conflict: &[&str]) -> Result<(), OrmError> {
24 let cols = M::COLUMNS.join(", ");
25 let phs = (1..=M::COLUMNS.len()).map(|i| format!("?{}", i)).collect::<Vec<_>>().join(", ");
26 let conflict_cols = on_conflict.join(", ");
27 let sql = format!(
28 "INSERT INTO {} ({}) VALUES ({}) ON CONFLICT({}) DO NOTHING",
29 M::TABLE, cols, phs, conflict_cols
30 );
31 let js = to_js_vec(&model.values());
32 self.db.prepare(&sql)
33 .bind(&js).map_err(|_| OrmError::Bind)?
34 .run().await.map_err(|_| OrmError::Execute)?;
35 Ok(())
36 }
37}