From c62fb7ba64eea7f1ca3fa44ebf908b5e1b5840ed Mon Sep 17 00:00:00 2001 From: Kurt Wolf Date: Wed, 20 Nov 2024 13:57:37 -0800 Subject: [PATCH] fix insert on conflict do nothing --- core/src/insert.rs | 34 +++++++++++++++++++++++++++++++--- core/src/model.rs | 4 ++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/core/src/insert.rs b/core/src/insert.rs index 7fda7e8..5d32a7b 100644 --- a/core/src/insert.rs +++ b/core/src/insert.rs @@ -1,8 +1,7 @@ use crate::Result; use futures::future::BoxFuture; pub use sqlmo::query::OnConflict; -#[allow(unused_imports)] -use sqlmo::{Dialect, Insert, ToSql}; +use sqlmo::{Dialect, Insert, ToSql, Union, Select, Cte, SelectColumn}; /// Represents an insert query. /// We had to turn this into a model because we need to pass in the on_conflict configuration. @@ -28,7 +27,36 @@ impl<'a, Acquire, Model: crate::model::Model, DB: sqlx::Database> std::futur type IntoFuture = BoxFuture<'a, Self::Output>; fn into_future(self) -> Self::IntoFuture { - let q = self.insert.to_sql(Dialect::Postgres); + // hack to get around the fact that postgres drops the return + // value in ON CONFLICT DO NOTHING case + let q = if matches!(self.insert.on_conflict, OnConflict::Ignore) { + let insert_as_select = Select { + ctes: vec![ + Cte::new("inserted", self.insert) + ], + columns: vec![SelectColumn::raw("*")], + from: Some("inserted".into()), + ..Select::default() + }; + let pkey = Model::primary_key().unwrap(); + let plc_idx = Model::primary_key_placeholder_idx().unwrap(); + let select_existing = Select { + from: Some(Model::table_name().into()), + columns: Model::table_columns().iter().map(|&c| c.into()).collect(), + where_: format!("{pkey} = ${plc_idx}").into(), + ..Select::default() + }; + let union = Union { + all: true, + queries: vec![ + insert_as_select, + select_existing + ] + }; + union.to_sql(Dialect::Postgres) + } else { + self.insert.to_sql(Dialect::Postgres) + }; (self.closure)(self.acquire, self.model, q) } } diff --git a/core/src/model.rs b/core/src/model.rs index 75ff6aa..abc1c51 100644 --- a/core/src/model.rs +++ b/core/src/model.rs @@ -109,4 +109,8 @@ pub trait TableMeta { fn table_name() -> &'static str; fn table_columns() -> &'static [&'static str]; fn primary_key() -> Option<&'static str>; + fn primary_key_placeholder_idx() -> Option { + let col = Self::primary_key()?; + Self::table_columns().iter().position(|&c| c == col).map(|i| i + 1) + } }