Skip to content

Commit 6e0d3ac

Browse files
committed
add generic update function for partial updates to entities
1 parent 39fa218 commit 6e0d3ac

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

entity_api/src/mutate.rs

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use crate::error::Error;
2+
use sea_orm::{
3+
ActiveModelBehavior, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait,
4+
IntoActiveModel, Value,
5+
};
6+
use std::collections::HashMap;
7+
8+
/// Updates an existing record in the database using a map of column names to values.
9+
///
10+
/// This function provides a flexible way to update only specific fields of an entity
11+
/// without having to provide all fields. It takes an active model and an update map,
12+
/// and only modifies the fields specified in the map.
13+
///
14+
/// # Type Parameters
15+
///
16+
/// * `A` - The ActiveModel type that implements ActiveModelTrait and ActiveModelBehavior
17+
/// * `C` - The Column type that implements ColumnTrait
18+
///
19+
/// # Arguments
20+
///
21+
/// * `db` - A reference to the database connection
22+
/// * `active_model` - The active model to update
23+
/// * `update_map` - A map of column names to their new values
24+
///
25+
/// # Returns
26+
///
27+
/// Returns a Result containing either the updated Model or an Error
28+
pub async fn update<A, C>(
29+
db: &DatabaseConnection,
30+
mut active_model: A,
31+
update_map: UpdateMap,
32+
) -> Result<<A::Entity as EntityTrait>::Model, Error>
33+
where
34+
A: ActiveModelTrait + ActiveModelBehavior + Send,
35+
C: ColumnTrait,
36+
A::Entity: EntityTrait<Column = C>,
37+
<A::Entity as EntityTrait>::Model: IntoActiveModel<A>,
38+
{
39+
for column in C::iter() {
40+
if let Some(value) = update_map.get(&column.to_string()) {
41+
active_model.set(column, value.clone());
42+
}
43+
}
44+
Ok(active_model.update(db).await?)
45+
}
46+
47+
/// A map structure that holds column names and their corresponding values for updates.
48+
///
49+
/// This structure provides a flexible way to specify which fields should be updated
50+
/// and their new values. It's designed to work with SeaORM's Value type and supports
51+
/// optional values to handle nullable fields.
52+
#[derive(Default)]
53+
pub struct UpdateMap {
54+
map: HashMap<String, Option<Value>>,
55+
}
56+
57+
impl UpdateMap {
58+
/// Creates a new empty UpdateMap.
59+
pub fn new() -> Self {
60+
Self::default()
61+
}
62+
63+
/// Retrieves a value from the map by its key.
64+
///
65+
/// Returns an Option containing a reference to the Value if it exists,
66+
/// or None if the key is not found or the value is None.
67+
pub fn get(&self, key: &str) -> Option<&Value> {
68+
self.map.get(key).and_then(|opt| opt.as_ref())
69+
}
70+
71+
/// Inserts a key-value pair into the map.
72+
///
73+
/// If the key already exists, the value will be overwritten.
74+
pub fn insert(&mut self, key: String, value: Option<Value>) {
75+
self.map.insert(key, value);
76+
}
77+
}
78+
79+
/// A trait that allows types to be converted into an UpdateMap.
80+
///
81+
/// This trait provides a way to convert various types into an UpdateMap,
82+
/// making it easier to create update maps from different data structures.
83+
pub trait IntoUpdateMap {
84+
/// Converts the implementing type into an UpdateMap.
85+
fn into_update_map(self) -> UpdateMap;
86+
}

0 commit comments

Comments
 (0)