mirror of
https://github.com/Phundrak/georm.git
synced 2025-08-30 22:25:35 +00:00
feat: deprecate create_or_update
in favour of upsert
The `create_or_update` method has been deprecated and replaced by `upsert` for clarity and consistency with common database terminology. This commit also removes the file `src/entity.rs` which has been forgotten in earlier commits and was no longer part of Georm.
This commit is contained in:
parent
49c7d86102
commit
5d8a1b1917
@ -557,7 +557,7 @@ Post::find(executor, &post_id).await?;
|
|||||||
// Mutation operations
|
// Mutation operations
|
||||||
post.create(executor).await?;
|
post.create(executor).await?;
|
||||||
post.update(executor).await?;
|
post.update(executor).await?;
|
||||||
post.create_or_update(executor).await?;
|
post.upsert(executor).await?;
|
||||||
post.delete(executor).await?;
|
post.delete(executor).await?;
|
||||||
Post::delete_by_id(executor, &post_id).await?;
|
Post::delete_by_id(executor, &post_id).await?;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ impl Profile {
|
|||||||
&mut self,
|
&mut self,
|
||||||
display_name: Option<String>,
|
display_name: Option<String>,
|
||||||
bio: Option<String>,
|
bio: Option<String>,
|
||||||
executor: E
|
executor: E,
|
||||||
) -> Result<Self>
|
) -> Result<Self>
|
||||||
where
|
where
|
||||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||||
|
@ -69,7 +69,7 @@ impl User {
|
|||||||
pub async fn get_user_by_id_or_select<'e, E>(
|
pub async fn get_user_by_id_or_select<'e, E>(
|
||||||
id: Option<i32>,
|
id: Option<i32>,
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
executor: E
|
executor: E,
|
||||||
) -> Result<Self>
|
) -> Result<Self>
|
||||||
where
|
where
|
||||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||||
@ -128,8 +128,7 @@ impl User {
|
|||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_profile(id: Option<i32>, pool: &sqlx::PgPool) -> Result<(User, Profile)>
|
pub async fn update_profile(id: Option<i32>, pool: &sqlx::PgPool) -> Result<(User, Profile)> {
|
||||||
{
|
|
||||||
let prompt = "Select the user whose profile you want to update";
|
let prompt = "Select the user whose profile you want to update";
|
||||||
let user = Self::get_user_by_id_or_select(id, prompt, pool).await?;
|
let user = Self::get_user_by_id_or_select(id, prompt, pool).await?;
|
||||||
let profile = match user.get_profile(pool).await? {
|
let profile = match user.get_profile(pool).await? {
|
||||||
|
@ -44,7 +44,7 @@ pub fn generate_upsert_query(
|
|||||||
let field_idents: Vec<syn::Ident> = fields.iter().map(|f| f.ident.clone()).collect();
|
let field_idents: Vec<syn::Ident> = fields.iter().map(|f| f.ident.clone()).collect();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
async fn create_or_update<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Self>
|
async fn upsert<'e, E>(&self, mut executor: E) -> ::sqlx::Result<Self>
|
||||||
where
|
where
|
||||||
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
E: ::sqlx::Executor<'e, Database = ::sqlx::Postgres>
|
||||||
{
|
{
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
17
src/georm.rs
17
src/georm.rs
@ -26,7 +26,7 @@ use sqlx::{Executor, Postgres};
|
|||||||
/// ### Instance Methods (Mutation Operations)
|
/// ### Instance Methods (Mutation Operations)
|
||||||
/// - [`create`] - Insert a new entity into the database
|
/// - [`create`] - Insert a new entity into the database
|
||||||
/// - [`update`] - Update an existing entity in the database
|
/// - [`update`] - Update an existing entity in the database
|
||||||
/// - [`create_or_update`] - Upsert (insert or update) an entity
|
/// - [`upsert`] - Upsert (insert or update) an entity
|
||||||
/// - [`delete`] - Delete this entity from the database
|
/// - [`delete`] - Delete this entity from the database
|
||||||
/// - [`get_id`] - Get the primary key of this entity
|
/// - [`get_id`] - Get the primary key of this entity
|
||||||
///
|
///
|
||||||
@ -92,7 +92,7 @@ use sqlx::{Executor, Postgres};
|
|||||||
/// [`find`]: Georm::find
|
/// [`find`]: Georm::find
|
||||||
/// [`create`]: Georm::create
|
/// [`create`]: Georm::create
|
||||||
/// [`update`]: Georm::update
|
/// [`update`]: Georm::update
|
||||||
/// [`create_or_update`]: Georm::create_or_update
|
/// [`upsert`]: Georm::upsert
|
||||||
/// [`delete`]: Georm::delete
|
/// [`delete`]: Georm::delete
|
||||||
/// [`delete_by_id`]: Georm::delete_by_id
|
/// [`delete_by_id`]: Georm::delete_by_id
|
||||||
/// [`get_id`]: Georm::get_id
|
/// [`get_id`]: Georm::get_id
|
||||||
@ -264,7 +264,7 @@ pub trait Georm<Id> {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// let user = User { id: 1, username: "alice".into(), email: "alice@example.com".into() };
|
/// let user = User { id: 1, username: "alice".into(), email: "alice@example.com".into() };
|
||||||
/// let final_user = user.create_or_update(&pool).await?;
|
/// let final_user = user.upsert(&pool).await?;
|
||||||
/// // Will insert if ID 1 doesn't exist, update if it does
|
/// // Will insert if ID 1 doesn't exist, update if it does
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -273,13 +273,22 @@ pub trait Georm<Id> {
|
|||||||
/// - Non-primary-key constraint violations
|
/// - Non-primary-key constraint violations
|
||||||
/// - Database connection issues
|
/// - Database connection issues
|
||||||
/// - Permission problems
|
/// - Permission problems
|
||||||
|
fn upsert<'e, E>(&self, executor: E) -> impl ::std::future::Future<Output = sqlx::Result<Self>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
E: Executor<'e, Database = Postgres>;
|
||||||
|
|
||||||
|
#[deprecated(since = "0.3.0", note = "Please use `upsert` instead")]
|
||||||
fn create_or_update<'e, E>(
|
fn create_or_update<'e, E>(
|
||||||
&self,
|
&self,
|
||||||
executor: E,
|
executor: E,
|
||||||
) -> impl ::std::future::Future<Output = sqlx::Result<Self>>
|
) -> impl ::std::future::Future<Output = sqlx::Result<Self>>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
E: Executor<'e, Database = Postgres>;
|
E: Executor<'e, Database = Postgres>,
|
||||||
|
{
|
||||||
|
self.upsert(executor)
|
||||||
|
}
|
||||||
|
|
||||||
/// Delete this entity from the database.
|
/// Delete this entity from the database.
|
||||||
///
|
///
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
//! ### Instance Methods (called on entity objects)
|
//! ### Instance Methods (called on entity objects)
|
||||||
//! - `entity.create(pool)` - Insert new record, returns created entity with database-generated values
|
//! - `entity.create(pool)` - Insert new record, returns created entity with database-generated values
|
||||||
//! - `entity.update(pool)` - Update existing record, returns updated entity with fresh database state
|
//! - `entity.update(pool)` - Update existing record, returns updated entity with fresh database state
|
||||||
//! - `entity.create_or_update(pool)` - True PostgreSQL upsert using `ON CONFLICT`, returns final entity
|
//! - `entity.upsert(pool)` - True PostgreSQL upsert using `ON CONFLICT`, returns final entity
|
||||||
//! - `entity.delete(pool)` - Delete this record, returns affected row count
|
//! - `entity.delete(pool)` - Delete this record, returns affected row count
|
||||||
//! - `entity.get_id()` - Get reference to the entity's ID (`&Id` for simple keys, owned for composite)
|
//! - `entity.get_id()` - Get reference to the entity's ID (`&Id` for simple keys, owned for composite)
|
||||||
//!
|
//!
|
||||||
@ -55,7 +55,7 @@
|
|||||||
//! Georm leverages PostgreSQL-specific features for performance and reliability:
|
//! Georm leverages PostgreSQL-specific features for performance and reliability:
|
||||||
//!
|
//!
|
||||||
//! - **RETURNING clause**: All `INSERT` and `UPDATE` operations use `RETURNING *` to capture database-generated values (sequences, defaults, triggers)
|
//! - **RETURNING clause**: All `INSERT` and `UPDATE` operations use `RETURNING *` to capture database-generated values (sequences, defaults, triggers)
|
||||||
//! - **True upserts**: `create_or_update()` uses `INSERT ... ON CONFLICT ... DO UPDATE` for atomic upsert operations
|
//! - **True upserts**: `upsert()` uses `INSERT ... ON CONFLICT ... DO UPDATE` for atomic upsert operations
|
||||||
//! - **Prepared statements**: All queries use parameter binding for security and performance
|
//! - **Prepared statements**: All queries use parameter binding for security and performance
|
||||||
//! - **Compile-time verification**: SQLx macros verify all generated SQL against your database schema at compile time
|
//! - **Compile-time verification**: SQLx macros verify all generated SQL against your database schema at compile time
|
||||||
//!
|
//!
|
||||||
|
@ -36,7 +36,7 @@ fn composite_key_get_id() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[sqlx::test(fixtures("composite_key"))]
|
#[sqlx::test(fixtures("composite_key"))]
|
||||||
async fn composite_key_create_or_update(pool: sqlx::PgPool) -> sqlx::Result<()> {
|
async fn composite_key_upsert(pool: sqlx::PgPool) -> sqlx::Result<()> {
|
||||||
let new_user_role = UserRole {
|
let new_user_role = UserRole {
|
||||||
user_id: 5,
|
user_id: 5,
|
||||||
role_id: 2,
|
role_id: 2,
|
||||||
@ -44,7 +44,7 @@ async fn composite_key_create_or_update(pool: sqlx::PgPool) -> sqlx::Result<()>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This will test the upsert query generation bug
|
// This will test the upsert query generation bug
|
||||||
let result = new_user_role.create_or_update(&pool).await?;
|
let result = new_user_role.upsert(&pool).await?;
|
||||||
assert_eq!(5, result.user_id);
|
assert_eq!(5, result.user_id);
|
||||||
assert_eq!(2, result.role_id);
|
assert_eq!(2, result.role_id);
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ async fn upsert_handles_generated_fields(pool: sqlx::PgPool) -> sqlx::Result<()>
|
|||||||
let mut modified_product = product.clone();
|
let mut modified_product = product.clone();
|
||||||
modified_product.price = BigDecimal::from(1200);
|
modified_product.price = BigDecimal::from(1200);
|
||||||
|
|
||||||
let upserted = modified_product.create_or_update(&pool).await?;
|
let upserted = modified_product.upsert(&pool).await?;
|
||||||
|
|
||||||
// price is updated
|
// price is updated
|
||||||
assert_eq!(upserted.price, BigDecimal::from(1200));
|
assert_eq!(upserted.price, BigDecimal::from(1200));
|
||||||
|
@ -115,7 +115,7 @@ async fn should_create_if_does_not_exist(pool: sqlx::PgPool) -> sqlx::Result<()>
|
|||||||
name: "Miura Kentaro".into(),
|
name: "Miura Kentaro".into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
author.create_or_update(&pool).await?;
|
author.upsert(&pool).await?;
|
||||||
let all_authors = Author::find_all(&pool).await?;
|
let all_authors = Author::find_all(&pool).await?;
|
||||||
assert_eq!(1, all_authors.len());
|
assert_eq!(1, all_authors.len());
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -130,7 +130,7 @@ async fn should_update_if_exist(pool: sqlx::PgPool) -> sqlx::Result<()> {
|
|||||||
name: "Miura Kentaro".into(),
|
name: "Miura Kentaro".into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
author.create_or_update(&pool).await?;
|
author.upsert(&pool).await?;
|
||||||
let mut all_authors = Author::find_all(&pool).await?;
|
let mut all_authors = Author::find_all(&pool).await?;
|
||||||
all_authors.sort();
|
all_authors.sort();
|
||||||
assert_eq!(3, all_authors.len());
|
assert_eq!(3, all_authors.len());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user