feat: add EntityState::Updated, change name from insert to upsert in catalog

This commit is contained in:
2025-10-14 13:01:16 +02:00
parent c01cfaf027
commit 827ac20e87
4 changed files with 32 additions and 26 deletions

View File

@@ -70,7 +70,7 @@ fn main() {
price: 125000,
};
// Insert the new laptop into the catalog. Note that at this time the product is in memory.
catalog.insert(new_laptop);
catalog.upsert(new_laptop);
// Persist the changes in the catalog to the database.
catalog.persist().unwrap();
// Remove the SQLite database file.

View File

@@ -33,14 +33,18 @@ impl Catalog {
Ok(())
}
/// Inserts a single object that implements the `EAV` trait into the catalog.
/// Inserts or updates a single object that implements the `EAV` trait into the catalog.
///
/// # Arguments
///
/// * `object` - The object to insert.
pub fn insert(&mut self, object: impl EAV) {
pub fn upsert(&mut self, object: impl EAV) {
let mut entity = object.into();
entity.state = EntityState::New;
if self.items.contains_key(&entity.id) {
entity.state = EntityState::Updated;
} else {
entity.state = EntityState::New;
}
self.items.insert(entity.id.clone(), entity);
}
@@ -51,7 +55,7 @@ impl Catalog {
/// * `objects` - A vector of objects to insert.
pub fn insert_many(&mut self, objects: Vec<impl EAV>) {
for object in objects {
self.insert(object);
self.upsert(object);
}
}
@@ -300,7 +304,7 @@ mod tests {
in_stock: true,
};
let item_id = item.id.clone();
catalog.insert(item);
catalog.upsert(item);
let entity = catalog.items.get(&item_id).unwrap();
assert_eq!(entity.id, item_id);
assert_eq!(entity.state, EntityState::New);
@@ -321,14 +325,14 @@ mod tests {
in_stock: true,
};
let item_id = item1.id.clone();
catalog.insert(item1);
catalog.upsert(item1);
let item2 = Item {
id: "item-123".to_string(),
name: "Second Item".to_string(),
price: 200,
in_stock: false,
};
catalog.insert(item2);
catalog.upsert(item2);
assert_eq!(catalog.items.len(), 1);
let entity = catalog.items.get(&item_id).unwrap();
assert_eq!(entity.value_of("name"), Some(&Value::from("Second Item")));
@@ -376,7 +380,7 @@ mod tests {
price: 100,
in_stock: true,
};
catalog.insert(item.clone());
catalog.upsert(item.clone());
let retrieved_item: Option<Item> = catalog.get("item-123");
assert_eq!(retrieved_item, Some(item));
}
@@ -391,7 +395,7 @@ mod tests {
price: 100,
in_stock: true,
};
catalog.insert(item.clone());
catalog.upsert(item.clone());
let retrieved_item: Option<Item> = catalog.get("nonexistent-id");
assert!(retrieved_item.is_none());
}
@@ -413,8 +417,8 @@ mod tests {
price: 200,
in_stock: false,
};
catalog.insert(item1.clone());
catalog.insert(item2.clone());
catalog.upsert(item1.clone());
catalog.upsert(item2.clone());
let retrieved_item: Option<Item> =
catalog.get_by_class_and_attribute("name", "Unique Item");
assert_eq!(retrieved_item, Some(item2));
@@ -436,8 +440,8 @@ mod tests {
price: 250,
in_stock: false,
};
catalog.insert(item1.clone());
catalog.insert(item2.clone());
catalog.upsert(item1.clone());
catalog.upsert(item2.clone());
// Test with &str for String attribute
let retrieved_by_name: Option<Item> =
catalog.get_by_class_and_attribute("name", "Item One");
@@ -460,7 +464,7 @@ mod tests {
price: 100,
in_stock: true,
};
catalog.insert(item.clone());
catalog.upsert(item.clone());
// Test with a value that doesn't exist
let retrieved_item: Option<Item> =
catalog.get_by_class_and_attribute("name", "Non-existent Name");
@@ -488,8 +492,8 @@ mod tests {
price: 200,
in_stock: false,
};
catalog.insert(item1.clone());
catalog.insert(item2.clone());
catalog.upsert(item1.clone());
catalog.upsert(item2.clone());
let results: Vec<Item> = catalog.list_by_class::<Item>().collect();
assert_eq!(results.len(), 2);
assert!(results.contains(&item1));
@@ -527,9 +531,9 @@ mod tests {
price: 300,
in_stock: true,
};
catalog.insert(item1.clone());
catalog.insert(item2.clone());
catalog.insert(item3.clone());
catalog.upsert(item1.clone());
catalog.upsert(item2.clone());
catalog.upsert(item3.clone());
let results: Vec<Item> = catalog
.list_by_class_and_attribute("in_stock", true)
.collect();
@@ -549,7 +553,7 @@ mod tests {
price: 100,
in_stock: true,
};
catalog.insert(item);
catalog.upsert(item);
// Search for a value that doesn't exist
let results: Vec<Item> = catalog
.list_by_class_and_attribute("in_stock", false)
@@ -580,7 +584,7 @@ mod tests {
in_stock: true,
};
let item_id = item.id.clone();
catalog.insert(item);
catalog.upsert(item);
catalog.delete(&item_id);
let entity = catalog.items.get(&item_id).unwrap();
assert_eq!(entity.state, EntityState::ToDelete);
@@ -596,7 +600,7 @@ mod tests {
price: 100,
in_stock: true,
};
catalog.insert(item);
catalog.upsert(item);
let original_items = catalog.items.clone();
// Attempt to delete a non-existent entity, which should not panic or change anything.
catalog.delete("nonexistent-id");
@@ -622,7 +626,7 @@ mod tests {
price: 123,
in_stock: true,
};
catalog1.insert(item1.clone());
catalog1.upsert(item1.clone());
assert!(catalog1.persist().is_ok());
// 2. Create a new catalog and load the item to verify it was persisted
let mut catalog2 = Catalog::new(db_path);
@@ -652,7 +656,7 @@ mod tests {
price: 123,
in_stock: true,
};
catalog1.insert(item1.clone());
catalog1.upsert(item1.clone());
assert!(catalog1.persist().is_ok());
// 2. Mark the item for deletion and persist again.
catalog1.delete(&item1.id);

View File

@@ -4,6 +4,8 @@ pub enum EntityState {
/// The entity is newly created and has not been persisted.
#[default]
New,
/// The entity has been updated and changes have not been persisted,
Updated,
/// The state of the entity is unknown.
Unknown,
/// The entity has been loaded from the database.

View File

@@ -59,7 +59,7 @@ mod tests {
// save some info for late comparison
let original_product = product.clone();
// insert the new object into catalog consuming it
catalog.insert(product);
catalog.upsert(product);
// read value from catalog using the original key
let read_product = catalog.get::<Product>(&original_product.id).unwrap();
// assert equality between original and read