review: make entity fields private; expose id and subclass

This commit is contained in:
2025-10-29 14:26:26 +01:00
parent 6ef36e2068
commit f7ab450e2c
4 changed files with 39 additions and 21 deletions

View File

@@ -44,7 +44,7 @@ impl From<Entity> for Product {
// Create a new `Product` from the entity's attributes. // Create a new `Product` from the entity's attributes.
Self { Self {
// Set the product's ID from the entity's ID. // Set the product's ID from the entity's ID.
id: value.id.clone(), id: value.id(),
// Unwrap the "name" attribute to get the product's name. // Unwrap the "name" attribute to get the product's name.
name: value.unwrap("name").expect("name is always present"), name: value.unwrap("name").expect("name is always present"),
// Unwrap the optional "model" attribute to get the product's model. // Unwrap the optional "model" attribute to get the product's model.

View File

@@ -35,7 +35,7 @@ impl From<Entity> for Component {
// `from` is a function that converts an `Entity` into a `Component`. // `from` is a function that converts an `Entity` into a `Component`.
fn from(value: Entity) -> Self { fn from(value: Entity) -> Self {
Self { Self {
id: value.id.clone(), id: value.id(),
part_number: value part_number: value
.unwrap("part_number") .unwrap("part_number")
.expect("part_number is always present"), .expect("part_number is always present"),

View File

@@ -31,21 +31,21 @@ impl EAV for Product {
} }
impl From<Entity> for Product { impl From<Entity> for Product {
fn from(value: Entity) -> Self { fn from(value: Entity) -> Self {
if let Some(ref subclass) = value.subclass { if let Some(ref subclass) = value.subclass() {
match subclass.as_ref() { match subclass.as_ref() {
"laptop" => Product::Laptop(Laptop { "laptop" => Product::Laptop(Laptop {
id: value.id.clone(), id: value.id(),
model: value.unwrap("model").expect("model is mandatory"), model: value.unwrap("model").expect("model is mandatory"),
price: value.unwrap("price").expect("price is mandatory"), price: value.unwrap("price").expect("price is mandatory"),
}), }),
"display" => Product::Display(Display { "display" => Product::Display(Display {
id: value.id.clone(), id: value.id(),
model: value.unwrap("model").expect("model is mandatory"), model: value.unwrap("model").expect("model is mandatory"),
price: value.unwrap("price").expect("price is mandatory"), price: value.unwrap("price").expect("price is mandatory"),
resolution: value.unwrap("resolution").expect("resolution is mandatory"), resolution: value.unwrap("resolution").expect("resolution is mandatory"),
}), }),
"mouse" => Product::Mouse(Mouse { "mouse" => Product::Mouse(Mouse {
id: value.id.clone(), id: value.id(),
model: value.unwrap("model").expect("model is mandatory"), model: value.unwrap("model").expect("model is mandatory"),
price: value.unwrap("price").expect("price is mandatory"), price: value.unwrap("price").expect("price is mandatory"),
wireless: value.unwrap("wireless").expect("wireless is mandatory"), wireless: value.unwrap("wireless").expect("wireless is mandatory"),

View File

@@ -4,23 +4,23 @@ use crate::*;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct O { pub struct O {
/// The unique identifier for this entity. /// The unique identifier for this entity.
pub id: String, pub(crate) id: String,
/// The current state of the entity within the `Catalog`'s in-memory cache. /// The current state of the entity within the `Catalog`'s in-memory cache.
/// This tracks whether the entity is new, modified, or marked for deletion. /// This tracks whether the entity is new, modified, or marked for deletion.
pub state: EntityState, pub(crate) state: EntityState,
/// An optional timestamp or version number, typically used for optimistic /// An optional timestamp or version number, typically used for optimistic
/// locking or tracking when the entity was last referenced or modified. /// locking or tracking when the entity was last referenced or modified.
pub ref_date: Option<u64>, pub(crate) ref_date: Option<u64>,
/// A string identifying the "type" or "class" of the entity (e.g., "product", "user"). /// 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. /// This is used to group and query entities of the same kind.
pub class: String, pub(crate) class: String,
/// A string identifying the "subtype" or "subclass" of the entity (e.g., /// A string identifying the "subtype" or "subclass" of the entity (e.g.,
/// "computer", "phone", "customer"). This is used to group and query entities /// "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) /// of different subtype but of the same kind or inside the same domain (class)
pub subclass: Option<String>, pub(crate) subclass: Option<String>,
/// A map of attribute names to `Attribute` values, holding the actual data /// A map of attribute names to `Attribute` values, holding the actual data
/// of the entity. /// of the entity.
pub attributes: std::collections::HashMap<String, Attribute>, pub(crate) attributes: std::collections::HashMap<String, Attribute>,
} }
impl Entity { impl Entity {
@@ -42,7 +42,6 @@ impl Entity {
attributes: std::collections::HashMap::<String, Attribute>::new(), attributes: std::collections::HashMap::<String, Attribute>::new(),
} }
} }
/// Sets the ID of the entity. /// Sets the ID of the entity.
/// ///
/// # Arguments /// # Arguments
@@ -56,12 +55,19 @@ impl Entity {
self.id = id.to_string(); self.id = id.to_string();
self self
} }
/// Sets the subclass of the entity.
///
/// # Arguments
///
/// * `subclass` - The subclass to set for the entity.
///
/// # Returns
///
/// The entity with the updated subclass.
pub fn with_subclass(mut self, subclass: &str) -> Self { pub fn with_subclass(mut self, subclass: &str) -> Self {
self.subclass = Some(subclass.to_string()); self.subclass = Some(subclass.to_string());
self self
} }
/// Sets the reference date of the entity. /// Sets the reference date of the entity.
/// ///
/// # Arguments /// # Arguments
@@ -75,7 +81,6 @@ impl Entity {
self.ref_date = Some(ref_date); self.ref_date = Some(ref_date);
self self
} }
/// Adds or updates an attribute for the entity. /// Adds or updates an attribute for the entity.
/// ///
/// # Arguments /// # Arguments
@@ -91,7 +96,6 @@ impl Entity {
self.attributes.insert(attribute.id.clone(), attribute); self.attributes.insert(attribute.id.clone(), attribute);
self self
} }
/// Adds or updates an attribute if the value is `Some`. /// Adds or updates an attribute if the value is `Some`.
/// ///
/// # Arguments /// # Arguments
@@ -109,7 +113,16 @@ impl Entity {
} }
self self
} }
/// Returns a reference to the `Value` of an attribute.
///
/// # Arguments
///
/// * `id` - The ID of the attribute to get the value of.
///
/// # Returns
///
/// An `Option<&Value>` which is `Some(&Value)` if the attribute exists,
/// or `None` if it does not.
pub(crate) fn value_of(&self, id: &str) -> Option<&Value> { pub(crate) fn value_of(&self, id: &str) -> Option<&Value> {
let attribute = self.attributes.get(id); let attribute = self.attributes.get(id);
match attribute { match attribute {
@@ -117,7 +130,6 @@ impl Entity {
Some(attribute) => Some(&attribute.value), Some(attribute) => Some(&attribute.value),
} }
} }
/// Unwraps an attribute's value into a specified type `T`. /// Unwraps an attribute's value into a specified type `T`.
/// ///
/// This function requires `T` to implement `TryFrom<Value>`. /// This function requires `T` to implement `TryFrom<Value>`.
@@ -138,7 +150,6 @@ impl Entity {
.map(|value| T::try_from(value.clone()).map_err(|_| FailedTo::ConvertValue)) .map(|value| T::try_from(value.clone()).map_err(|_| FailedTo::ConvertValue))
.unwrap() .unwrap()
} }
/// Unwraps an attribute's value into an `Option<T>`. /// Unwraps an attribute's value into an `Option<T>`.
/// ///
/// This function requires `T` to implement `TryFrom<Value>`. /// This function requires `T` to implement `TryFrom<Value>`.
@@ -161,7 +172,6 @@ impl Entity {
.map(|value| T::try_from(value.clone()).map_err(|_| FailedTo::ConvertValue)) .map(|value| T::try_from(value.clone()).map_err(|_| FailedTo::ConvertValue))
.transpose() .transpose()
} }
/// Unwraps an attribute's value, returning a default value if it doesn't exist or fails to convert. /// Unwraps an attribute's value, returning a default value if it doesn't exist or fails to convert.
/// ///
/// This function requires `T` to implement `TryFrom<Value>`. /// This function requires `T` to implement `TryFrom<Value>`.
@@ -183,4 +193,12 @@ impl Entity {
.transpose() .transpose()
.map(|value| value.unwrap_or(default)) .map(|value| value.unwrap_or(default))
} }
/// Returns the ID of the entity.
pub fn id(&self) -> String {
self.id.clone()
}
/// Returns the subclass of the entity, if it has one.
pub fn subclass(&self) -> Option<String> {
self.subclass.clone()
}
} }