1use crate::error::DbError;
36use crate::model::Model;
37use crate::pool::Connection;
38use crate::value::Value;
39use std::collections::HashMap;
40
41#[derive(Debug, Clone, PartialEq, Default)]
74pub enum ActiveValue<T> {
75 Set(T),
77 Unchanged,
79 #[default]
81 NotSet,
82}
83
84impl<T> ActiveValue<T> {
85 pub fn is_set(&self) -> bool {
87 matches!(self, ActiveValue::Set(_))
88 }
89
90 pub fn is_unchanged(&self) -> bool {
92 matches!(self, ActiveValue::Unchanged)
93 }
94
95 pub fn is_not_set(&self) -> bool {
97 matches!(self, ActiveValue::NotSet)
98 }
99
100 pub fn into_value(self) -> Option<T> {
102 match self {
103 ActiveValue::Set(v) => Some(v),
104 _ => None,
105 }
106 }
107
108 pub fn as_value(&self) -> Option<&T> {
110 match self {
111 ActiveValue::Set(v) => Some(v),
112 _ => None,
113 }
114 }
115}
116
117impl<T: Into<Value>> From<T> for ActiveValue<Value> {
121 fn from(value: T) -> Self {
122 ActiveValue::Set(value.into())
123 }
124}
125
126pub trait ActiveModelTrait: Send + Sync {
143 fn table_name(&self) -> &str;
145
146 fn pk_value(&self) -> Option<Value>;
148
149 fn for_each_changed<F>(&self, f: F)
154 where
155 F: FnMut(&str, &ActiveValue<Value>);
156}
157
158#[derive(Debug, Clone)]
180pub struct ActiveModel<M: Model> {
181 model: M,
182 changes: HashMap<String, ActiveValue<Value>>,
184}
185
186impl<M: Model> ActiveModel<M> {
187 pub fn from_model(model: M) -> Self {
191 Self {
192 model,
193 changes: HashMap::new(),
194 }
195 }
196
197 pub fn set(&mut self, field: impl Into<String>, value: ActiveValue<Value>) {
207 self.changes.insert(field.into(), value);
208 }
209
210 pub fn unset(&mut self, field: &str) {
212 self.changes.remove(field);
213 }
214
215 pub fn get(&self, field: &str) -> Option<&ActiveValue<Value>> {
217 self.changes.get(field)
218 }
219
220 pub fn changed_fields(&self) -> Vec<(&str, &Value)> {
222 self.changes
223 .iter()
224 .filter_map(|(k, v)| match v {
225 ActiveValue::Set(val) => Some((k.as_str(), val)),
226 _ => None,
227 })
228 .collect()
229 }
230
231 pub fn as_mut_model(&mut self) -> &mut M {
233 &mut self.model
234 }
235
236 pub fn as_model(&self) -> &M {
238 &self.model
239 }
240
241 pub fn into_model(self) -> M {
243 self.model
244 }
245}
246
247impl<M: Model> ActiveModelTrait for ActiveModel<M>
248where
249 M::PrimaryKey: Into<Value>,
250{
251 fn table_name(&self) -> &str {
252 M::table_name()
253 }
254
255 fn pk_value(&self) -> Option<Value> {
256 let v = self.model.pk_as_value();
257 if v.is_null() {
258 None
259 } else {
260 Some(v)
261 }
262 }
263
264 fn for_each_changed<F>(&self, mut f: F)
265 where
266 F: FnMut(&str, &ActiveValue<Value>),
267 {
268 for (key, av) in self.changes.iter() {
269 f(key, av);
270 }
271 }
272}
273
274pub async fn update<A, C>(conn: &mut C, active: A) -> Result<u64, DbError>
294where
295 A: ActiveModelTrait,
296 C: Connection + ?Sized,
297{
298 let table = active.table_name().to_string();
299 let pk_value = active
300 .pk_value()
301 .ok_or_else(|| DbError::QueryError("ActiveModel: primary key is not set".to_string()))?;
302
303 let mut set_clauses: Vec<String> = Vec::new();
305 let mut params: Vec<Value> = Vec::new();
306
307 active.for_each_changed(|field, av| {
308 if let ActiveValue::Set(val) = av {
309 set_clauses.push(format!("{} = {}", field, val.to_param()));
310 params.push(val.clone());
311 }
312 });
313
314 if set_clauses.is_empty() {
315 return Ok(0);
316 }
317
318 let sql = format!(
319 "UPDATE {} SET {} WHERE {} = {}",
320 table,
321 set_clauses.join(", "),
322 active.pk_name_for_update(),
324 pk_value.to_param()
325 );
326
327 conn.execute(&sql).await
330}
331
332pub async fn save<A, C>(conn: &mut C, active: A) -> Result<u64, DbError>
339where
340 A: ActiveModelTrait,
341 C: Connection + ?Sized,
342{
343 if active.pk_value().is_some() {
344 update(conn, active).await
345 } else {
346 insert(conn, active).await
347 }
348}
349
350async fn insert<A, C>(conn: &mut C, active: A) -> Result<u64, DbError>
352where
353 A: ActiveModelTrait,
354 C: Connection + ?Sized,
355{
356 let table = active.table_name().to_string();
357 let mut columns: Vec<String> = Vec::new();
358 let mut values: Vec<String> = Vec::new();
359
360 active.for_each_changed(|field, av| {
361 if let ActiveValue::Set(val) = av {
362 columns.push(field.to_string());
363 values.push(val.to_param().into_owned());
364 }
365 });
366
367 if columns.is_empty() {
368 return Err(DbError::QueryError(
369 "ActiveModel: no fields set for insert".to_string(),
370 ));
371 }
372
373 let sql = format!(
374 "INSERT INTO {} ({}) VALUES ({})",
375 table,
376 columns.join(", "),
377 values.join(", ")
378 );
379
380 conn.execute(&sql).await
381}
382
383pub trait ActiveModelExt: ActiveModelTrait {
392 fn pk_name_for_update(&self) -> &str {
394 "id"
395 }
396}
397
398impl<A: ActiveModelTrait> ActiveModelExt for A {}
399
400#[cfg(test)]
405mod tests {
406 use super::*;
407
408 #[derive(Debug, Clone, Default)]
411 #[allow(dead_code)]
412 struct User {
413 id: i64,
414 name: String,
415 email: String,
416 }
417
418 impl Model for User {
419 type PrimaryKey = i64;
420
421 fn table_name() -> &'static str {
422 "users"
423 }
424
425 fn pk_name() -> &'static str {
426 "id"
427 }
428
429 fn pk(&self) -> Self::PrimaryKey {
430 self.id
431 }
432
433 fn set_pk(&mut self, pk: Self::PrimaryKey) {
434 self.id = pk;
435 }
436
437 fn pk_as_value(&self) -> Value {
438 Value::I64(self.id)
439 }
440 }
441
442 #[test]
445 fn test_active_value_set() {
446 let av: ActiveValue<Value> = ActiveValue::Set(Value::String("Alice".into()));
447 assert!(av.is_set());
448 assert!(!av.is_unchanged());
449 assert!(!av.is_not_set());
450 assert_eq!(av.into_value(), Some(Value::String("Alice".into())));
451 }
452
453 #[test]
454 fn test_active_value_unchanged() {
455 let av: ActiveValue<Value> = ActiveValue::Unchanged;
456 assert!(!av.is_set());
457 assert!(av.is_unchanged());
458 assert!(!av.is_not_set());
459 assert_eq!(av.into_value(), None);
460 }
461
462 #[test]
463 fn test_active_value_not_set() {
464 let av: ActiveValue<Value> = ActiveValue::NotSet;
465 assert!(!av.is_set());
466 assert!(!av.is_unchanged());
467 assert!(av.is_not_set());
468 assert_eq!(av.into_value(), None);
469 }
470
471 #[test]
472 fn test_active_value_default_is_not_set() {
473 let av: ActiveValue<Value> = ActiveValue::default();
474 assert!(av.is_not_set());
475 }
476
477 #[test]
478 fn test_active_value_from_str() {
479 let av: ActiveValue<Value> = "hello".into();
481 assert!(av.is_set());
482 assert_eq!(av.into_value(), Some(Value::String("hello".into())));
483 }
484
485 #[test]
486 fn test_active_value_from_i64() {
487 let av: ActiveValue<Value> = 42i64.into();
488 assert!(av.is_set());
489 assert_eq!(av.into_value(), Some(Value::I64(42)));
490 }
491
492 #[test]
493 fn test_active_value_as_value() {
494 let av = ActiveValue::Set(Value::I64(99));
495 assert_eq!(av.as_value(), Some(&Value::I64(99)));
496
497 let unchanged: ActiveValue<Value> = ActiveValue::Unchanged;
498 assert_eq!(unchanged.as_value(), None);
499 }
500
501 #[test]
504 fn test_active_model_from_model() {
505 let user = User {
506 id: 1,
507 name: "Alice".into(),
508 email: "alice@example.com".into(),
509 };
510 let active = ActiveModel::from_model(user.clone());
511 assert_eq!(active.table_name(), "users");
512 assert_eq!(active.pk_value(), Some(Value::I64(1)));
513 assert!(active.changed_fields().is_empty());
515 }
516
517 #[test]
518 fn test_active_model_set_and_changed_fields() {
519 let user = User {
520 id: 1,
521 name: "Alice".into(),
522 email: "alice@example.com".into(),
523 };
524 let mut active = ActiveModel::from_model(user);
525 active.set(
526 "email",
527 ActiveValue::Set(Value::String("new@example.com".into())),
528 );
529 active.set("name", ActiveValue::Unchanged); let changed = active.changed_fields();
532 assert_eq!(changed.len(), 1);
533 assert_eq!(changed[0].0, "email");
534 assert_eq!(changed[0].1, &Value::String("new@example.com".into()));
535 }
536
537 #[test]
538 fn test_active_model_for_each_changed() {
539 let user = User {
540 id: 1,
541 name: "Alice".into(),
542 email: "alice@example.com".into(),
543 };
544 let mut active = ActiveModel::from_model(user);
545 active.set("name", ActiveValue::Set(Value::String("Bob".into())));
546 active.set(
547 "email",
548 ActiveValue::Set(Value::String("bob@example.com".into())),
549 );
550 active.set("extra", ActiveValue::NotSet); let mut count = 0;
553 let mut names: Vec<String> = Vec::new();
554 active.for_each_changed(|field, av| {
555 count += 1;
556 names.push(field.to_string());
557 let _ = av;
560 });
561 assert_eq!(count, 3); assert!(names.contains(&"name".to_string()));
563 assert!(names.contains(&"email".to_string()));
564 assert!(names.contains(&"extra".to_string()));
565 }
566
567 #[test]
568 fn test_active_model_unset() {
569 let user = User::default();
570 let mut active = ActiveModel::from_model(user);
571 active.set("name", ActiveValue::Set(Value::String("Alice".into())));
572 assert_eq!(active.changed_fields().len(), 1);
573
574 active.unset("name");
575 assert!(active.changed_fields().is_empty());
576 }
577
578 #[test]
579 fn test_active_model_get() {
580 let user = User::default();
581 let mut active = ActiveModel::from_model(user);
582 active.set("name", ActiveValue::Set(Value::String("Alice".into())));
583
584 assert!(active.get("name").is_some());
585 assert!(active.get("email").is_none());
586 }
587
588 #[test]
589 fn test_active_model_into_model() {
590 let user = User {
591 id: 42,
592 name: "Original".into(),
593 email: "orig@example.com".into(),
594 };
595 let active = ActiveModel::from_model(user.clone());
596 let restored = active.into_model();
597 assert_eq!(restored.id, user.id);
598 assert_eq!(restored.name, user.name);
599 }
600
601 #[test]
602 fn test_active_model_as_mut_model() {
603 let user = User::default();
604 let mut active = ActiveModel::from_model(user);
605 active.as_mut_model().name = "Modified".into();
606 assert_eq!(active.as_model().name, "Modified");
607 }
608
609 #[test]
612 fn test_three_state_semantics() {
613 let user = User {
615 id: 1,
616 name: "Alice".into(),
617 email: "alice@example.com".into(),
618 };
619
620 let mut active = ActiveModel::from_model(user);
621
622 active.set(
624 "email",
625 ActiveValue::Set(Value::String("new@example.com".into())),
626 );
627
628 let changed = active.changed_fields();
630 assert_eq!(changed.len(), 1);
631 assert_eq!(changed[0].0, "email");
632
633 }
636
637 #[test]
638 fn test_new_record_all_not_set() {
639 let user = User::default();
641 let mut active = ActiveModel::from_model(user);
642
643 assert!(active.changed_fields().is_empty());
645
646 active.set("name", ActiveValue::Set(Value::String("Bob".into())));
648 active.set(
649 "email",
650 ActiveValue::Set(Value::String("bob@example.com".into())),
651 );
652
653 let changed = active.changed_fields();
654 assert_eq!(changed.len(), 2);
655 }
656
657 #[test]
658 fn test_active_value_clone_and_debug() {
659 let av = ActiveValue::Set(Value::I64(100));
660 let av2 = av.clone();
661 assert_eq!(av, av2);
662
663 let debug_str = format!("{:?}", av);
665 assert!(debug_str.contains("Set"));
666 }
667}