use cratestack_core::CoolError;
use crate::query::support::{classify_unique_violation, push_bind_value};
use crate::{ConflictTarget, ModelDescriptor, SqlColumnValue, sqlx};
pub(super) async fn upsert_returning_record_do_nothing<'e, E, M, PK>(
executor: E,
descriptor: &'static ModelDescriptor<M, PK>,
insert_values: &[SqlColumnValue],
conflict_target: ConflictTarget,
) -> Result<Option<M>, CoolError>
where
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
{
let mut query = sqlx::QueryBuilder::<sqlx::Postgres>::new("INSERT INTO ");
query.push(descriptor.table_name).push(" (");
for (index, value) in insert_values.iter().enumerate() {
if index > 0 {
query.push(", ");
}
query.push(value.column);
}
query.push(") VALUES (");
for (index, value) in insert_values.iter().enumerate() {
if index > 0 {
query.push(", ");
}
push_bind_value(&mut query, &value.value);
}
query.push(") ON CONFLICT (");
match conflict_target {
ConflictTarget::PrimaryKey => {
query.push(descriptor.primary_key);
}
ConflictTarget::Columns(cols) => {
for (idx, column) in cols.iter().enumerate() {
if idx > 0 {
query.push(", ");
}
query.push(*column);
}
}
}
query.push(") DO NOTHING RETURNING ");
query.push(descriptor.select_projection());
query
.build_query_as::<M>()
.fetch_optional(executor)
.await
.map_err(classify_unique_violation)
}