Skip to main content

d1_orm_engine/
upsert.rs

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}