Some checks failed
CI / tests (push) Failing after 31s
Replace the existing two-query create_or_update implementation with a single atomic PostgreSQL upsert using ON CONFLICT clause to eliminate race conditions and improve performance. Race condition fix: The previous implementation had a critical race condition where multiple concurrent requests could: 1. Both call find() and get None (record doesn't exist) 2. Both call create() and the second one fails with duplicate key error 3. Or between find() and create(), another transaction inserts the record This created unreliable behavior in high-concurrency scenarios. Changes: - Add generate_upsert_query function in trait_implementation.rs - Generate SQL with INSERT ... ON CONFLICT ... DO UPDATE SET pattern - Remove default trait implementation that used separate find/create/update calls - Update derive_trait to include upsert query generation - Convert create_or_update from default implementation to required trait method The new implementation eliminates race conditions while reducing database round trips from 2-3 queries down to 1, significantly improving both reliability and performance.
84 lines
2.3 KiB
Rust
84 lines
2.3 KiB
Rust
pub trait Georm<Id> {
|
|
/// Find all the entities in the database.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn find_all(
|
|
pool: &sqlx::PgPool,
|
|
) -> impl ::std::future::Future<Output = ::sqlx::Result<Vec<Self>>> + Send
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Find the entiy in the database based on its identifier.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn find(
|
|
pool: &sqlx::PgPool,
|
|
id: &Id,
|
|
) -> impl std::future::Future<Output = sqlx::Result<Option<Self>>> + Send
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Create the entity in the database.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn create(
|
|
&self,
|
|
pool: &sqlx::PgPool,
|
|
) -> impl std::future::Future<Output = sqlx::Result<Self>> + Send
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Update an entity with a matching identifier in the database.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn update(
|
|
&self,
|
|
pool: &sqlx::PgPool,
|
|
) -> impl std::future::Future<Output = sqlx::Result<Self>> + Send
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Update an entity with a matching identifier in the database if
|
|
/// it exists, create it otherwise.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn create_or_update(
|
|
&self,
|
|
pool: &sqlx::PgPool,
|
|
) -> impl std::future::Future<Output = sqlx::Result<Self>> + Send
|
|
where
|
|
Self: Sized;
|
|
|
|
/// Delete the entity from the database if it exists.
|
|
///
|
|
/// # Returns
|
|
/// Returns the amount of rows affected by the deletion.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn delete(
|
|
&self,
|
|
pool: &sqlx::PgPool,
|
|
) -> impl std::future::Future<Output = sqlx::Result<u64>> + Send;
|
|
|
|
/// Delete any entity with the identifier `id`.
|
|
///
|
|
/// # Returns
|
|
/// Returns the amount of rows affected by the deletion.
|
|
///
|
|
/// # Errors
|
|
/// Returns any error Postgres may have encountered
|
|
fn delete_by_id(
|
|
pool: &sqlx::PgPool,
|
|
id: &Id,
|
|
) -> impl std::future::Future<Output = sqlx::Result<u64>> + Send;
|
|
|
|
/// Returns the identifier of the entity.
|
|
fn get_id(&self) -> &Id;
|
|
}
|