# Model Trait Unification Plan ## Introduction This document outlines the plan to unify the `BaseModel` and `ModelBuilder` traits in the heromodels crate into a single `Model` trait. The goal is to simplify the codebase, reduce boilerplate, and make the API more intuitive while maintaining all existing functionality. ## Current Structure Currently, the codebase has two separate traits: 1. **BaseModel** - Provides database-related functionality: - `db_prefix()` - Returns a string prefix for database operations - `db_keys()` - Returns index keys for the model - `get_id()` - Returns the model's unique ID 2. **ModelBuilder** - Provides builder pattern functionality: - `base_data_mut()` - Gets a mutable reference to the base data - `id()` - Sets the ID for the model - `build()` - Finalizes the model by updating timestamps Each model (like User and Comment) implements both traits separately, and there are two separate macros for implementing these traits: ```rust // For BaseModel impl_base_model!(User, "user"); // For ModelBuilder impl_model_builder!(User); ``` This leads to duplication and cognitive overhead when working with models. ## Proposed Structure We will create a unified `Model` trait that combines all the functionality from both existing traits: ```mermaid classDiagram class Model { <> +db_prefix() static str +db_keys() Vec~IndexKey~ +get_id() u32 +base_data_mut() &mut BaseModelData +id(u32) Self +build() Self } class User { +base_data BaseModelData +username String +email String +full_name String +is_active bool } class Comment { +base_data BaseModelData +user_id u32 +content String } Model <|-- User Model <|-- Comment ``` ## Implementation Steps ### 1. Update model.rs Create the new `Model` trait that combines all methods from both existing traits: ```rust /// Unified trait for all models pub trait Model: Debug + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static { /// Get the database prefix for this model type fn db_prefix() -> &'static str where Self: Sized; /// Returns a list of index keys for this model instance /// These keys will be used to create additional indexes in the TST fn db_keys(&self) -> Vec { Vec::new() } /// Get the unique ID for this model fn get_id(&self) -> u32; /// Get a mutable reference to the base_data field fn base_data_mut(&mut self) -> &mut BaseModelData; /// Set the ID for this model fn id(mut self, id: u32) -> Self where Self: Sized { self.base_data_mut().id = id; self } /// Build the model, updating the modified timestamp fn build(mut self) -> Self where Self: Sized { self.base_data_mut().update_modified(); self } } ``` Create a new implementation macro that implements all required methods: ```rust /// Macro to implement Model for a struct that contains a base_data field of type BaseModelData #[macro_export] macro_rules! impl_model { ($type:ty, $prefix:expr) => { impl $crate::core::model::Model for $type { fn db_prefix() -> &'static str { $prefix } fn get_id(&self) -> u32 { self.base_data.id } fn base_data_mut(&mut self) -> &mut $crate::core::model::BaseModelData { &mut self.base_data } // Other methods have default implementations } }; } ``` Mark the old traits and macros as deprecated (or remove them entirely): ```rust #[deprecated( since = "0.2.0", note = "Use the unified Model trait instead" )] pub trait BaseModel { /* ... */ } #[deprecated( since = "0.2.0", note = "Use the unified Model trait instead" )] pub trait ModelBuilder { /* ... */ } #[deprecated( since = "0.2.0", note = "Use impl_model instead" )] #[macro_export] macro_rules! impl_base_model { /* ... */ } #[deprecated( since = "0.2.0", note = "Use impl_model instead" )] #[macro_export] macro_rules! impl_model_builder { /* ... */ } ``` ### 2. Update User and Comment Implementations For User: ```rust // Implement Model for User impl_model!(User, "user"); // Custom implementation of db_keys impl Model for User { fn db_keys(&self) -> Vec { vec![ IndexKey { name: "username", value: self.username.clone(), }, IndexKey { name: "email", value: self.email.clone(), }, IndexKey { name: "is_active", value: self.is_active.to_string(), }, ] } } ``` For Comment: ```rust // Implement Model for Comment impl_model!(Comment, "comment"); // Custom implementation of db_keys impl Model for Comment { fn db_keys(&self) -> Vec { vec![ IndexKey { name: "user_id", value: self.user_id.to_string(), }, ] } } ``` ### 3. Update Imports and References Update the lib.rs file to export the new trait and macro: ```rust // Export core module pub mod core; // Export userexample module pub mod userexample; // Re-export key types for convenience pub use core::model::{Model, BaseModelData, IndexKey}; pub use core::Comment; pub use userexample::User; // Re-export macros pub use crate::impl_model; ``` Update the example code to use the new trait: ```rust use heromodels::{Model, Comment, User}; fn main() { println!("Hero Models - Basic Usage Example"); println!("================================"); // Create a new user using the fluent interface let user = User::new(1) .username("johndoe") .email("john.doe@example.com") .full_name("John Doe") .build(); println!("Created user: {:?}", user); println!("User ID: {}", user.get_id()); println!("User DB Prefix: {}", User::db_prefix()); // Create a comment for the user let comment = Comment::new(1) .user_id(2) // commenter's user ID .content("This is a comment on the user") .build(); println!("\nCreated comment: {:?}", comment); println!("Comment ID: {}", comment.get_id()); println!("Comment DB Prefix: {}", Comment::db_prefix()); } ``` ### 4. Testing Run the example to ensure it works as expected: ```bash cargo run --example basic_user_example ``` Verify that all functionality is preserved and that the output matches the expected output. ## Benefits of This Approach 1. **Simplified Code Structure**: One trait instead of two means less cognitive overhead 2. **Reduced Boilerplate**: A single macro implementation reduces repetitive code 3. **Improved Usability**: No need to import multiple traits or worry about which trait provides which method 4. **Maintained Functionality**: All existing functionality is preserved 5. **Better Encapsulation**: The model concept is more cohesive as a single trait