From cad285fd5970575a713a3bb35457b5357b5e02a6 Mon Sep 17 00:00:00 2001 From: despiegk Date: Tue, 22 Apr 2025 08:24:17 +0400 Subject: [PATCH] ... --- heromodels/Cargo.lock | 329 ++++++++++++++++++++++ heromodels/Cargo.toml | 2 +- heromodels/README.md | 133 +++++++++ heromodels/examples/basic_user_example.rs | 28 ++ heromodels/src/comment.rs | 63 ----- heromodels/src/core/comment.rs | 56 ++++ heromodels/src/core/lib.rs | 10 + heromodels/src/core/mod.rs | 7 + heromodels/src/{ => core}/model.rs | 34 ++- heromodels/src/lib.rs | 51 +--- heromodels/src/userexample/lib.rs | 6 + heromodels/src/userexample/mod.rs | 5 + heromodels/src/{ => userexample}/user.rs | 64 +++-- 13 files changed, 659 insertions(+), 129 deletions(-) create mode 100644 heromodels/Cargo.lock create mode 100644 heromodels/README.md create mode 100644 heromodels/examples/basic_user_example.rs delete mode 100644 heromodels/src/comment.rs create mode 100644 heromodels/src/core/comment.rs create mode 100644 heromodels/src/core/lib.rs create mode 100644 heromodels/src/core/mod.rs rename heromodels/src/{ => core}/model.rs (82%) create mode 100644 heromodels/src/userexample/lib.rs create mode 100644 heromodels/src/userexample/mod.rs rename heromodels/src/{ => userexample}/user.rs (56%) diff --git a/heromodels/Cargo.lock b/heromodels/Cargo.lock new file mode 100644 index 0000000..b60e503 --- /dev/null +++ b/heromodels/Cargo.lock @@ -0,0 +1,329 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "heromodels" +version = "0.1.0" +dependencies = [ + "bincode", + "chrono", + "serde", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] diff --git a/heromodels/Cargo.toml b/heromodels/Cargo.toml index eb9fc22..7258a64 100644 --- a/heromodels/Cargo.toml +++ b/heromodels/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "heromodels" version = "0.1.0" -edition = "2021" +edition = "2024" description = "A library for hero models with base model trait implementation" authors = ["Your Name "] diff --git a/heromodels/README.md b/heromodels/README.md new file mode 100644 index 0000000..6ffd5d9 --- /dev/null +++ b/heromodels/README.md @@ -0,0 +1,133 @@ +# Hero Models + +A Rust library for model management with a base model trait implementation and builder pattern support. + +## Features + +- **Base Model Trait**: Common interface for all models with standard methods +- **Builder Pattern**: All models use the builder pattern for flexible and clear construction +- **Indexing Support**: Built-in support for model indexing with customizable keys +- **Comment System**: Integrated comment system that can be attached to any model +- **Timestamps**: Automatic creation and modification timestamps + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +heromodels = "0.1.0" +``` + +### Basic Example + +```rust +use heromodels::{BaseModel, User, Comment}; + +fn main() { + // Create a new user using the builder pattern + let user_result = User::builder(1) + .username("johndoe") + .email("john.doe@example.com") + .full_name("John Doe") + .build(); + + let mut user = user_result.expect("Failed to build user"); + + // Create a comment for the user using the builder pattern + let comment_result = Comment::builder(1) + .user_id(2) // commenter's user ID + .model_id(user.get_id()) + .model_type(User::db_prefix()) + .content("This is a comment on the user") + .build(); + + let comment = comment_result.expect("Failed to build comment"); + + // Add the comment to the user + user.base_data.add_comment(comment.get_id()); + + // Get the database keys for the user + let keys = user.db_keys(); + for key in keys { + println!("{}: {}", key.name, key.value); + } +} +``` + +### Creating Custom Models + +To create your own model that inherits from the base model: + +```rust +use serde::{Deserialize, Serialize}; +use heromodels::model::{BaseModel, BaseModelData, IndexKey}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Product { + pub base_data: BaseModelData, + pub name: String, + pub price: f64, + pub sku: String, +} + +impl BaseModel for Product { + fn db_prefix() -> &'static str { + "product" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "name", + value: self.name.clone(), + }, + IndexKey { + name: "sku", + value: self.sku.clone(), + }, + ] + } +} + +// Implement a builder for your custom model +pub struct ProductBuilder { + id: u32, + base_data_builder: Option, + name: Option, + price: Option, + sku: Option, +} + +impl ProductBuilder { + pub fn new(id: u32) -> Self { + Self { + id, + base_data_builder: Some(BaseModelData::builder(id)), + name: None, + price: None, + sku: None, + } + } + + // Add builder methods... + + pub fn build(self) -> Result { + // Implementation... + } +} + +impl Product { + pub fn builder(id: u32) -> ProductBuilder { + ProductBuilder::new(id) + } +} +``` + +## License + +MIT \ No newline at end of file diff --git a/heromodels/examples/basic_user_example.rs b/heromodels/examples/basic_user_example.rs new file mode 100644 index 0000000..4b8f8e4 --- /dev/null +++ b/heromodels/examples/basic_user_example.rs @@ -0,0 +1,28 @@ +use heromodels::{BaseModel, Comment, User, ModelBuilder}; + +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()); + +} \ No newline at end of file diff --git a/heromodels/src/comment.rs b/heromodels/src/comment.rs deleted file mode 100644 index 50b0add..0000000 --- a/heromodels/src/comment.rs +++ /dev/null @@ -1,63 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::model::{BaseModel, BaseModelData, IndexKey}; - -/// Represents a comment on a model -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Comment { - /// Base model data - pub base_data: BaseModelData, - - /// The ID of the user who created the comment - pub user_id: u32, - - /// The ID of the model this comment is attached to - pub model_id: u32, - - /// The type of model this comment is attached to - pub model_type: String, - - /// The content of the comment - pub content: String, -} - -impl Comment { - /// Create a new comment - pub fn new(id: u32, user_id: u32, model_id: u32, model_type: String, content: String) -> Self { - Self { - base_data: BaseModelData::new(id), - user_id, - model_id, - model_type, - content, - } - } - - /// Update the comment content - pub fn update_content(&mut self, content: String) { - self.content = content; - self.base_data.update_modified(); - } -} - -impl BaseModel for Comment { - fn db_prefix() -> &'static str { - "comment" - } - - fn get_id(&self) -> u32 { - self.base_data.id - } - - fn db_keys(&self) -> Vec { - vec![ - IndexKey { - name: "user_id", - value: self.user_id.to_string(), - }, - IndexKey { - name: "model_id", - value: format!("{}:{}", self.model_type, self.model_id), - }, - ] - } -} \ No newline at end of file diff --git a/heromodels/src/core/comment.rs b/heromodels/src/core/comment.rs new file mode 100644 index 0000000..0ae61a3 --- /dev/null +++ b/heromodels/src/core/comment.rs @@ -0,0 +1,56 @@ +use serde::{Deserialize, Serialize}; +use crate::core::model::{BaseModel, BaseModelData, IndexKey, ModelBuilder}; +use crate::impl_model_builder; + +/// Represents a comment on a model +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Comment { + pub base_data: BaseModelData, + pub user_id: u32, + pub content: String, +} + +impl Comment { + /// Create a new comment + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + user_id: 0, + content: String::new(), + } + } + + /// Set the user ID + pub fn user_id(mut self, id: u32) -> Self { + self.user_id = id; + self + } + + /// Set the content + pub fn content(mut self, content: impl ToString) -> Self { + self.content = content.to_string(); + self + } +} + +impl BaseModel for Comment { + fn db_prefix() -> &'static str { + "comment" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "user_id", + value: self.user_id.to_string(), + }, + ] + } +} + +// Implement ModelBuilder for Comment +impl_model_builder!(Comment); \ No newline at end of file diff --git a/heromodels/src/core/lib.rs b/heromodels/src/core/lib.rs new file mode 100644 index 0000000..fcafca8 --- /dev/null +++ b/heromodels/src/core/lib.rs @@ -0,0 +1,10 @@ + +pub mod model; +pub mod comment; + + + +// Re-export key types for convenience +pub use model::{BaseModel, BaseModelData, IndexKey, IndexKeyBuilder, ModelBuilder}; +pub use comment::Comment; +pub use crate::impl_model_builder; diff --git a/heromodels/src/core/mod.rs b/heromodels/src/core/mod.rs new file mode 100644 index 0000000..180b3d4 --- /dev/null +++ b/heromodels/src/core/mod.rs @@ -0,0 +1,7 @@ +// Export submodules +pub mod model; +pub mod comment; + +// Re-export key types for convenience +pub use model::{BaseModel, BaseModelData, IndexKey, IndexKeyBuilder, ModelBuilder}; +pub use comment::Comment; \ No newline at end of file diff --git a/heromodels/src/model.rs b/heromodels/src/core/model.rs similarity index 82% rename from heromodels/src/model.rs rename to heromodels/src/core/model.rs index a45a804..4c59588 100644 --- a/heromodels/src/model.rs +++ b/heromodels/src/core/model.rs @@ -100,7 +100,7 @@ impl BaseModelData { /// Remove a comment from this model pub fn remove_comment(&mut self, comment_id: u32) { self.comments.retain(|&id| id != comment_id); - self.modified_at = chrono::Utc::now().timestamp(); + self.update_modified(); } /// Update the modified timestamp @@ -164,11 +164,29 @@ impl BaseModelDataBuilder { } } +/// Trait for model builders that have a base_data field +pub trait ModelBuilder: Sized { + /// 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 { + self.base_data_mut().id = id; + self + } + + /// Build the model, updating the modified timestamp + fn build(mut self) -> Self { + self.base_data_mut().update_modified(); + self + } +} + /// Macro to implement BaseModel for a struct that contains a base_data field of type BaseModelData #[macro_export] macro_rules! impl_base_model { ($type:ty, $prefix:expr) => { - impl BaseModel for $type { + impl $crate::core::model::BaseModel for $type { fn db_prefix() -> &'static str { $prefix } @@ -178,4 +196,16 @@ macro_rules! impl_base_model { } } }; +} + +/// Macro to implement ModelBuilder for a struct that contains a base_data field of type BaseModelData +#[macro_export] +macro_rules! impl_model_builder { + ($type:ty) => { + impl $crate::core::model::ModelBuilder for $type { + fn base_data_mut(&mut self) -> &mut $crate::core::model::BaseModelData { + &mut self.base_data + } + } + }; } \ No newline at end of file diff --git a/heromodels/src/lib.rs b/heromodels/src/lib.rs index bb59b4c..ada23e2 100644 --- a/heromodels/src/lib.rs +++ b/heromodels/src/lib.rs @@ -1,47 +1,12 @@ -//! # Hero Models -//! -//! A library for hero models with base model trait implementation. -//! -//! This crate provides a base model trait and implementation that other models can inherit from. -//! It also provides a Comment model that can be used to add comments to any model. +// Export core module +pub mod core; -pub mod model; -pub mod comment; -pub mod user; +// Export userexample module +pub mod userexample; // Re-export key types for convenience -pub use model::{BaseModel, BaseModelData, IndexKey, impl_base_model}; -pub use comment::Comment; -pub use user::User; +pub use core::{BaseModel, BaseModelData, IndexKey, ModelBuilder}; +pub use core::Comment; +pub use userexample::User; -/// Example of how to use the heromodels crate -/// -/// ```rust -/// use heromodels::{BaseModel, User, Comment}; -/// -/// // Create a new user -/// let mut user = User::new( -/// 1, -/// "johndoe".to_string(), -/// "john.doe@example.com".to_string(), -/// "John Doe".to_string() -/// ); -/// -/// // Create a comment for the user -/// let comment = Comment::new( -/// 1, -/// 2, // commenter's user ID -/// user.get_id(), -/// User::db_prefix().to_string(), -/// "This is a comment on the user".to_string() -/// ); -/// -/// // Add the comment to the user -/// user.base_data.add_comment(comment.get_id()); -/// -/// // Get the database prefix for the User model -/// assert_eq!(User::db_prefix(), "user"); -/// -/// // Get the database keys for the user -/// let keys = user.db_keys(); -/// assert!(keys.iter().any(|k| k.name == "username" && k.value == "johndoe")); \ No newline at end of file +// No need to re-export macros as they are already exported at the crate root \ No newline at end of file diff --git a/heromodels/src/userexample/lib.rs b/heromodels/src/userexample/lib.rs new file mode 100644 index 0000000..e7538ce --- /dev/null +++ b/heromodels/src/userexample/lib.rs @@ -0,0 +1,6 @@ + +// Export user module +pub mod user; + +// Re-export User for convenience +pub use user::User; \ No newline at end of file diff --git a/heromodels/src/userexample/mod.rs b/heromodels/src/userexample/mod.rs new file mode 100644 index 0000000..66a4c00 --- /dev/null +++ b/heromodels/src/userexample/mod.rs @@ -0,0 +1,5 @@ +// Export user module +pub mod user; + +// Re-export User for convenience +pub use user::User; \ No newline at end of file diff --git a/heromodels/src/user.rs b/heromodels/src/userexample/user.rs similarity index 56% rename from heromodels/src/user.rs rename to heromodels/src/userexample/user.rs index 664d403..0f071c5 100644 --- a/heromodels/src/user.rs +++ b/heromodels/src/userexample/user.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::model::{BaseModel, BaseModelData, IndexKey}; +use crate::core::model::{BaseModel, BaseModelData, IndexKey, ModelBuilder}; +use crate::impl_model_builder; /// Represents a user in the system #[derive(Debug, Clone, Serialize, Deserialize)] @@ -22,38 +23,58 @@ pub struct User { impl User { /// Create a new user - pub fn new(id: u32, username: String, email: String, full_name: String) -> Self { + pub fn new(id: u32) -> Self { Self { base_data: BaseModelData::new(id), - username, - email, - full_name, + username: String::new(), + email: String::new(), + full_name: String::new(), is_active: true, } } + /// Set the username + pub fn username(mut self, username: impl ToString) -> Self { + self.username = username.to_string(); + + self + } + + /// Set the email + pub fn email(mut self, email: impl ToString) -> Self { + self.email = email.to_string(); + + self + } + + /// Set the full name + pub fn full_name(mut self, full_name: impl ToString) -> Self { + self.full_name = full_name.to_string(); + + self + } + + /// Set whether the user is active + pub fn is_active(mut self, is_active: bool) -> Self { + self.is_active = is_active; + + self + } + + /// Add a comment ID + pub fn add_comment(mut self, comment_id: u32) -> Self { + self.base_data.add_comment(comment_id); + self + } + /// Deactivate the user pub fn deactivate(&mut self) { self.is_active = false; - self.base_data.update_modified(); } /// Activate the user pub fn activate(&mut self) { self.is_active = true; - self.base_data.update_modified(); - } - - /// Update user's email - pub fn update_email(&mut self, email: String) { - self.email = email; - self.base_data.update_modified(); - } - - /// Update user's full name - pub fn update_full_name(&mut self, full_name: String) { - self.full_name = full_name; - self.base_data.update_modified(); } } @@ -83,4 +104,7 @@ impl BaseModel for User { }, ] } -} \ No newline at end of file +} + +// Implement ModelBuilder for User +impl_model_builder!(User); \ No newline at end of file