feat: add subclass to entity struct
This commit is contained in:
@@ -6,6 +6,7 @@ pub fn run(path: &path::Path) -> result::Result<(), FailedTo> {
|
||||
CREATE TABLE IF NOT EXISTS entity (
|
||||
id TEXT PRIMARY KEY,
|
||||
class TEXT NOT NULL,
|
||||
subclass TEXT,
|
||||
ref_date INTEGER
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS attribute (
|
||||
|
||||
@@ -38,6 +38,7 @@ mod tests {
|
||||
let mut entity = Entity {
|
||||
id: "entity1".to_string(),
|
||||
class: "class1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: Default::default(),
|
||||
ref_date: None,
|
||||
@@ -77,6 +78,7 @@ mod tests {
|
||||
let mut entity = Entity {
|
||||
id: "entity2".to_string(),
|
||||
class: "class1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: Default::default(),
|
||||
ref_date: None,
|
||||
@@ -101,6 +103,7 @@ mod tests {
|
||||
let mut entity = Entity {
|
||||
id: "entity3".to_string(),
|
||||
class: "class1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: Default::default(),
|
||||
ref_date: None,
|
||||
|
||||
@@ -3,11 +3,13 @@ use crate::*;
|
||||
pub fn run(row: &rusqlite::Row) -> rusqlite::Result<Entity> {
|
||||
let id: String = row.get(0)?;
|
||||
let class: String = row.get(1)?;
|
||||
let ref_date: Option<u64> = row.get(2)?;
|
||||
let subclass: Option<String> = row.get(2)?;
|
||||
let ref_date: Option<u64> = row.get(3)?;
|
||||
let entity = Entity {
|
||||
id,
|
||||
state: EntityState::Loaded,
|
||||
class,
|
||||
subclass,
|
||||
ref_date,
|
||||
attributes: std::collections::HashMap::new(),
|
||||
};
|
||||
@@ -26,9 +28,10 @@ mod tests {
|
||||
fn map_row_to_entity_should_correctly_map_valid_row() {
|
||||
// Verifies that a valid database row is correctly mapped to an Entity struct with all fields populated.
|
||||
let conn = Connection::open_in_memory().unwrap();
|
||||
let entity = get_entity_from_query(&conn, "SELECT 'e1', 'c1', 12345").unwrap();
|
||||
let entity = get_entity_from_query(&conn, "SELECT 'e1', 'c1', 's1', 12345").unwrap();
|
||||
assert_eq!(entity.id, "e1");
|
||||
assert_eq!(entity.class, "c1");
|
||||
assert_eq!(entity.subclass, Some("s1".to_string()));
|
||||
assert_eq!(entity.ref_date, Some(12345));
|
||||
assert_eq!(entity.state, EntityState::Loaded);
|
||||
assert!(entity.attributes.is_empty());
|
||||
@@ -37,9 +40,20 @@ mod tests {
|
||||
fn map_row_to_entity_should_handle_null_ref_date() {
|
||||
// Ensures that a row with a NULL 'ref_date' is successfully mapped to an Entity with 'ref_date' as None.
|
||||
let conn = Connection::open_in_memory().unwrap();
|
||||
let entity = get_entity_from_query(&conn, "SELECT 'e2', 'c2', NULL").unwrap();
|
||||
let entity = get_entity_from_query(&conn, "SELECT 'e2', 'c2', 's2', NULL").unwrap();
|
||||
assert_eq!(entity.id, "e2");
|
||||
assert_eq!(entity.class, "c2");
|
||||
assert_eq!(entity.subclass, Some("s2".to_string()));
|
||||
assert_eq!(entity.ref_date, None);
|
||||
}
|
||||
#[test]
|
||||
fn map_row_to_entity_should_handle_null_subclass() {
|
||||
// Ensures that a row with a NULL 'subclass' is successfully mapped to an Entity with 'subclass' as None.
|
||||
let conn = Connection::open_in_memory().unwrap();
|
||||
let entity = get_entity_from_query(&conn, "SELECT 'e2', 'c2', NULL, NULL").unwrap();
|
||||
assert_eq!(entity.id, "e2");
|
||||
assert_eq!(entity.class, "c2");
|
||||
assert_eq!(entity.subclass, None);
|
||||
assert_eq!(entity.ref_date, None);
|
||||
}
|
||||
#[test]
|
||||
|
||||
@@ -113,6 +113,7 @@ mod tests {
|
||||
let mut entity = Entity {
|
||||
id: "e1".to_string(),
|
||||
class: "c1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::New,
|
||||
ref_date: None,
|
||||
@@ -141,6 +142,7 @@ mod tests {
|
||||
let entity = Entity {
|
||||
id: "e1".to_string(),
|
||||
class: "c1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::ToDelete,
|
||||
ref_date: None,
|
||||
@@ -161,6 +163,7 @@ mod tests {
|
||||
let to_delete = Entity {
|
||||
id: "e1".to_string(),
|
||||
class: "c1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::ToDelete,
|
||||
ref_date: None,
|
||||
@@ -168,6 +171,7 @@ mod tests {
|
||||
let to_add = Entity {
|
||||
id: "e2".to_string(),
|
||||
class: "c2".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::New,
|
||||
ref_date: None,
|
||||
@@ -190,6 +194,7 @@ mod tests {
|
||||
let unmodified = Entity {
|
||||
id: "e1".to_string(),
|
||||
class: "c1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::Loaded,
|
||||
ref_date: None,
|
||||
@@ -213,6 +218,7 @@ mod tests {
|
||||
let mut new_entity = Entity {
|
||||
id: "e_new".to_string(),
|
||||
class: "c1".to_string(),
|
||||
subclass: None,
|
||||
attributes: HashMap::new(),
|
||||
state: EntityState::New,
|
||||
ref_date: None,
|
||||
|
||||
@@ -32,8 +32,9 @@
|
||||
//! and the necessary `From` and `TryFrom` conversions.
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use heave::{EAV, Catalog, Entity, Value, FailedTo, Comparison, Filter};
|
||||
//! use heave::*;
|
||||
//! use std::convert::{From, TryFrom};
|
||||
//! use std::result::Result;
|
||||
//!
|
||||
//! // Define a simple struct representing a product.
|
||||
//! #[derive(Debug, Default, PartialEq, Clone)]
|
||||
@@ -68,10 +69,10 @@
|
||||
//!
|
||||
//! fn try_from(entity: Entity) -> Result<Self, Self::Error> {
|
||||
//! Ok(Self {
|
||||
//! id: entity.id,
|
||||
//! name: entity.unwrap("name").ok_or(FailedTo::ConvertEntity)?,
|
||||
//! price: entity.unwrap("price").ok_or(FailedTo::ConvertEntity)?,
|
||||
//! in_stock: entity.unwrap("in_stock").ok_or(FailedTo::ConvertEntity)?,
|
||||
//! id: entity.id.clone(),
|
||||
//! name: entity.unwrap("name").map_err(|_| FailedTo::ConvertEntity)?,
|
||||
//! price: entity.unwrap("price").map_err(|_| FailedTo::ConvertEntity)?,
|
||||
//! in_stock: entity.unwrap("in_stock").map_err(|_| FailedTo::ConvertEntity)?,
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
|
||||
@@ -161,6 +161,24 @@ impl Catalog {
|
||||
.filter(move |item| item.class == T::class())
|
||||
.map(|item| T::try_from(item.clone()).map_err(|_| FailedTo::ConvertEntity))
|
||||
}
|
||||
/// Returns an iterator over all entities of a specific class and subclass
|
||||
/// in the in-memory catalog.
|
||||
///
|
||||
/// This is a purely in-memory operation and does not interact with the database.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// An iterator that yields items of type `T` from the in-memory cache.
|
||||
pub fn list_by_class_and_subclass<T>(&self, subclass: &str) -> impl Iterator<Item = Result<T, FailedTo>>
|
||||
where
|
||||
T: EAV,
|
||||
{
|
||||
self.items
|
||||
.values()
|
||||
.filter(move |item| item.class == T::class())
|
||||
.filter(move |item| item.subclass == Some(subclass.to_string()))
|
||||
.map(|item| T::try_from(item.clone()).map_err(|_| FailedTo::ConvertEntity))
|
||||
}
|
||||
/// Returns an iterator over entities in the in-memory catalog that match a given
|
||||
/// class, attribute, and value.
|
||||
///
|
||||
|
||||
@@ -14,6 +14,10 @@ pub struct O {
|
||||
/// A string identifying the "type" or "class" of the entity (e.g., "product", "user").
|
||||
/// This is used to group and query entities of the same kind.
|
||||
pub class: String,
|
||||
/// A string identifying the "subtype" or "subclass" of the entity (e.g.,
|
||||
/// "computer", "phone", "customer"). This is used to group and query entities
|
||||
/// of different subtype but of the same kind or inside the same domain (class)
|
||||
pub subclass: Option<String>,
|
||||
/// A map of attribute names to `Attribute` values, holding the actual data
|
||||
/// of the entity.
|
||||
pub attributes: std::collections::HashMap<String, Attribute>,
|
||||
@@ -34,6 +38,7 @@ impl Entity {
|
||||
state: EntityState::New,
|
||||
ref_date: None,
|
||||
class: T::class().to_string(),
|
||||
subclass: None,
|
||||
attributes: std::collections::HashMap::<String, Attribute>::new(),
|
||||
}
|
||||
}
|
||||
@@ -52,6 +57,11 @@ impl Entity {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_subclass(mut self, subclass: &str) -> Self {
|
||||
self.subclass = Some(subclass.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the reference date of the entity.
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
Reference in New Issue
Block a user