Restructure crates for correct proc macro usage
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
parent
96a1ecd974
commit
b8e1449ddb
@ -96,7 +96,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
// Generate Model trait implementation
|
||||
let db_keys_impl = if indexed_fields.is_empty() {
|
||||
quote! {
|
||||
fn db_keys(&self) -> Vec<crate::models::IndexKey> {
|
||||
fn db_keys(&self) -> Vec<heromodels_core::IndexKey> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
@ -107,7 +107,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
.cloned()
|
||||
.unwrap_or(field_name.to_string());
|
||||
quote! {
|
||||
crate::models::IndexKey {
|
||||
heromodels_core::IndexKey {
|
||||
name: #name_str,
|
||||
value: self.#field_name.to_string(),
|
||||
}
|
||||
@ -115,7 +115,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
});
|
||||
|
||||
quote! {
|
||||
fn db_keys(&self) -> Vec<crate::models::IndexKey> {
|
||||
fn db_keys(&self) -> Vec<heromodels_core::IndexKey> {
|
||||
vec![
|
||||
#(#field_keys),*
|
||||
]
|
||||
@ -124,7 +124,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
let model_impl = quote! {
|
||||
impl crate::models::Model for #struct_name {
|
||||
impl heromodels_core::Model for #struct_name {
|
||||
fn db_prefix() -> &'static str {
|
||||
#db_prefix
|
||||
}
|
||||
@ -133,7 +133,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut crate::models::BaseModelData {
|
||||
fn base_data_mut(&mut self) -> &mut heromodels_core::BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let index_impl = quote! {
|
||||
pub struct #index_struct_name;
|
||||
|
||||
impl crate::models::Index for #index_struct_name {
|
||||
impl heromodels_core::Index for #index_struct_name {
|
||||
type Model = super::#struct_name;
|
||||
type Key = #field_type;
|
||||
|
||||
@ -176,8 +176,9 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
if !index_impls.is_empty() {
|
||||
let index_mod_name = format_ident!("{}_index", db_prefix);
|
||||
index_impls = quote! {
|
||||
pub mod index {
|
||||
pub mod #index_mod_name {
|
||||
#index_impls
|
||||
}
|
||||
}
|
9
heromodels/Cargo.lock
generated
9
heromodels/Cargo.lock
generated
@ -263,6 +263,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"fjall",
|
||||
"heromodels-derive",
|
||||
"heromodels_core",
|
||||
"ourdb",
|
||||
"serde",
|
||||
"tst",
|
||||
@ -277,6 +278,14 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heromodels_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
|
@ -12,4 +12,5 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||
fjall = "2.9.0"
|
||||
ourdb = { path = "../ourdb" }
|
||||
tst = { path = "../tst" }
|
||||
heromodels-derive = { path = "./heromodels-derive" }
|
||||
heromodels-derive = { path = "../heromodels-derive" }
|
||||
heromodels_core = { path = "../heromodels_core" }
|
||||
|
@ -1,6 +1,7 @@
|
||||
use heromodels::db::{Collection, Db};
|
||||
use heromodels::models::userexample::user::index::{is_active, username};
|
||||
use heromodels::models::{Comment, Model, User};
|
||||
use heromodels::models::userexample::user::user_index::{is_active, username};
|
||||
use heromodels::models::{Comment, User};
|
||||
use heromodels_core::Model;
|
||||
|
||||
fn main() {
|
||||
let index_db = tst::TST::new("/tmp/ourdb/tst", true).expect("can create index DB");
|
||||
|
@ -1,5 +1,5 @@
|
||||
use heromodels::model;
|
||||
use heromodels::models::core::model::{BaseModelData, Model};
|
||||
use heromodels_core::{BaseModelData, Model};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Define a custom attribute for indexing
|
||||
|
@ -1,58 +1,58 @@
|
||||
use heromodels::model;
|
||||
use heromodels::models::core::model::{BaseModelData, Model, Index, IndexKey};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use heromodels_core::{BaseModelData, Model};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Basic usage
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[model]
|
||||
pub struct SimpleUser {
|
||||
pub base_data: BaseModelData,
|
||||
|
||||
|
||||
#[index]
|
||||
pub login: String,
|
||||
|
||||
|
||||
pub full_name: String,
|
||||
}
|
||||
|
||||
// With customization options
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[model(prefix = "custom_user")]
|
||||
#[model]
|
||||
pub struct CustomUser {
|
||||
pub base_data: BaseModelData,
|
||||
|
||||
|
||||
#[index(name = "user_name")]
|
||||
pub login_name: String,
|
||||
|
||||
|
||||
#[index]
|
||||
pub is_active: bool,
|
||||
|
||||
|
||||
pub full_name: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hero Models - Model Macro Example");
|
||||
println!("=================================");
|
||||
|
||||
|
||||
// Example usage of the generated implementations
|
||||
println!("SimpleUser DB Prefix: {}", SimpleUser::db_prefix());
|
||||
println!("CustomUser DB Prefix: {}", CustomUser::db_prefix());
|
||||
|
||||
|
||||
let user = SimpleUser {
|
||||
base_data: BaseModelData::new(1),
|
||||
login: "johndoe".to_string(),
|
||||
full_name: "John Doe".to_string(),
|
||||
};
|
||||
|
||||
|
||||
let custom_user = CustomUser {
|
||||
base_data: BaseModelData::new(2),
|
||||
login_name: "janesmith".to_string(),
|
||||
is_active: true,
|
||||
full_name: "Jane Smith".to_string(),
|
||||
};
|
||||
|
||||
|
||||
println!("\nSimpleUser ID: {}", user.get_id());
|
||||
println!("SimpleUser DB Keys: {:?}", user.db_keys());
|
||||
|
||||
|
||||
println!("\nCustomUser ID: {}", custom_user.get_id());
|
||||
println!("CustomUser DB Keys: {:?}", custom_user.db_keys());
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use heromodels::model;
|
||||
use heromodels::models::core::model::{BaseModelData, Model, IndexKey};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use heromodels_core::{BaseModelData, Model};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Basic usage
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@ -14,16 +14,17 @@ pub struct SimpleUser {
|
||||
fn main() {
|
||||
println!("Hero Models - Simple Model Example");
|
||||
println!("==================================");
|
||||
|
||||
|
||||
// Example usage of the generated implementation
|
||||
println!("SimpleUser DB Prefix: {}", SimpleUser::db_prefix());
|
||||
|
||||
|
||||
let user = SimpleUser {
|
||||
base_data: BaseModelData::new(1),
|
||||
login: "johndoe".to_string(),
|
||||
full_name: "John Doe".to_string(),
|
||||
};
|
||||
|
||||
|
||||
println!("\nSimpleUser ID: {}", user.get_id());
|
||||
println!("SimpleUser DB Keys: {:?}", user.db_keys());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use crate::models::{Index, Model};
|
||||
use heromodels_core::{Index, Model};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod fjall;
|
||||
|
@ -1,8 +1,7 @@
|
||||
use heromodels_core::{Index, Model};
|
||||
use ourdb::OurDBSetArgs;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::models::{Index, Model};
|
||||
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::HashSet,
|
||||
@ -30,7 +29,7 @@ impl OurDB {
|
||||
impl super::Db for OurDB {
|
||||
type Error = tst::Error;
|
||||
|
||||
fn collection<M: crate::models::Model>(
|
||||
fn collection<M: Model>(
|
||||
&self,
|
||||
) -> Result<impl super::Collection<&str, M>, super::Error<Self::Error>> {
|
||||
Ok(self.clone())
|
||||
|
@ -1,10 +1,13 @@
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::models::core::model::{Model, BaseModelData, IndexKey};
|
||||
|
||||
/// Represents a comment on a model
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[model]
|
||||
pub struct Comment {
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub user_id: u32,
|
||||
pub content: String,
|
||||
}
|
||||
@ -24,34 +27,10 @@ impl Comment {
|
||||
self.user_id = id;
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
/// Set the content
|
||||
pub fn content(mut self, content: impl ToString) -> Self {
|
||||
self.content = content.to_string();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Implement the Model trait for Comment
|
||||
impl Model for Comment {
|
||||
fn db_prefix() -> &'static str {
|
||||
"comment"
|
||||
}
|
||||
|
||||
fn get_id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
|
||||
fn db_keys(&self) -> Vec<IndexKey> {
|
||||
vec![
|
||||
IndexKey {
|
||||
name: "user_id",
|
||||
value: self.user_id.to_string(),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Export submodules
|
||||
pub mod model;
|
||||
pub mod comment;
|
||||
pub mod model;
|
||||
|
||||
// Re-export key types for convenience
|
||||
pub use model::{Model, BaseModelData, IndexKey, IndexKeyBuilder, Index};
|
||||
pub use comment::Comment;
|
||||
pub use comment::Comment;
|
||||
|
||||
|
@ -1,223 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Represents an index key for a model
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IndexKey {
|
||||
/// The name of the index key
|
||||
pub name: &'static str,
|
||||
|
||||
/// The value of the index key for a specific model instance
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Builder for IndexKey
|
||||
pub struct IndexKeyBuilder {
|
||||
name: &'static str,
|
||||
value: String,
|
||||
}
|
||||
|
||||
impl IndexKeyBuilder {
|
||||
/// Create a new IndexKeyBuilder
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
value: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the value for this index key
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the IndexKey
|
||||
pub fn build(self) -> IndexKey {
|
||||
IndexKey {
|
||||
name: self.name,
|
||||
value: self.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// The default implementation returns an empty vector
|
||||
/// Override this method to provide custom indexes
|
||||
fn db_keys(&self) -> Vec<IndexKey> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for an index in the DB
|
||||
pub trait Index {
|
||||
/// The model for which this is an index in the database
|
||||
type Model: Model;
|
||||
|
||||
type Key: ToString + ?Sized;
|
||||
|
||||
/// The key of this index
|
||||
fn key() -> &'static str;
|
||||
}
|
||||
|
||||
/// Base struct that all models should include
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BaseModelData {
|
||||
/// Unique incremental ID per circle
|
||||
pub id: u32,
|
||||
|
||||
/// Unix epoch timestamp for creation time
|
||||
pub created_at: i64,
|
||||
|
||||
/// Unix epoch timestamp for last modification time
|
||||
pub modified_at: i64,
|
||||
|
||||
/// List of comment IDs referencing Comment objects
|
||||
pub comments: Vec<u32>,
|
||||
}
|
||||
|
||||
impl BaseModelData {
|
||||
/// Create a new BaseModelData instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
Self {
|
||||
id,
|
||||
created_at: now,
|
||||
modified_at: now,
|
||||
comments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new BaseModelDataBuilder
|
||||
pub fn builder(id: u32) -> BaseModelDataBuilder {
|
||||
BaseModelDataBuilder::new(id)
|
||||
}
|
||||
|
||||
/// Add a comment to this model
|
||||
pub fn add_comment(&mut self, comment_id: u32) {
|
||||
self.comments.push(comment_id);
|
||||
self.modified_at = chrono::Utc::now().timestamp();
|
||||
}
|
||||
|
||||
/// Remove a comment from this model
|
||||
pub fn remove_comment(&mut self, comment_id: u32) {
|
||||
self.comments.retain(|&id| id != comment_id);
|
||||
self.update_modified();
|
||||
}
|
||||
|
||||
/// Update the modified timestamp
|
||||
pub fn update_modified(&mut self) {
|
||||
self.modified_at = chrono::Utc::now().timestamp();
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for BaseModelData
|
||||
pub struct BaseModelDataBuilder {
|
||||
id: u32,
|
||||
created_at: Option<i64>,
|
||||
modified_at: Option<i64>,
|
||||
comments: Vec<u32>,
|
||||
}
|
||||
|
||||
impl BaseModelDataBuilder {
|
||||
/// Create a new BaseModelDataBuilder
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self {
|
||||
id,
|
||||
created_at: None,
|
||||
modified_at: None,
|
||||
comments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the created_at timestamp
|
||||
pub fn created_at(mut self, timestamp: i64) -> Self {
|
||||
self.created_at = Some(timestamp);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the modified_at timestamp
|
||||
pub fn modified_at(mut self, timestamp: i64) -> Self {
|
||||
self.modified_at = Some(timestamp);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a comment ID
|
||||
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
||||
self.comments.push(comment_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add multiple comment IDs
|
||||
pub fn add_comments(mut self, comment_ids: Vec<u32>) -> Self {
|
||||
self.comments.extend(comment_ids);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the BaseModelData
|
||||
pub fn build(self) -> BaseModelData {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
BaseModelData {
|
||||
id: self.id,
|
||||
created_at: self.created_at.unwrap_or(now),
|
||||
modified_at: self.modified_at.unwrap_or(now),
|
||||
comments: self.comments,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to implement Model for a struct that contains a base_data field of type BaseModelData
|
||||
#[macro_export]
|
||||
macro_rules! impl_model {
|
||||
// Basic implementation with default db_keys
|
||||
($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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,6 +3,6 @@ pub mod core;
|
||||
pub mod userexample;
|
||||
|
||||
// Re-export key types for convenience
|
||||
pub use core::model::{Model, BaseModelData, IndexKey, Index};
|
||||
pub use core::Comment;
|
||||
pub use userexample::User;
|
||||
pub use userexample::User;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::models::core::model::BaseModelData;
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -81,72 +81,3 @@ impl User {
|
||||
self.is_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Implement the Model trait for User
|
||||
// impl Model for User {
|
||||
// fn db_prefix() -> &'static str {
|
||||
// "user"
|
||||
// }
|
||||
//
|
||||
// fn get_id(&self) -> u32 {
|
||||
// self.base_data.id
|
||||
// }
|
||||
//
|
||||
// //WHY?
|
||||
// fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
// &mut self.base_data
|
||||
// }
|
||||
//
|
||||
// fn db_keys(&self) -> Vec<IndexKey> {
|
||||
// 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(),
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Marker structs for indexed fields
|
||||
//
|
||||
// pub struct UserName;
|
||||
// pub struct Email;
|
||||
// pub struct IsActive;
|
||||
//
|
||||
// impl Index for UserName {
|
||||
// type Model = User;
|
||||
//
|
||||
// type Key = str;
|
||||
//
|
||||
// fn key() -> &'static str {
|
||||
// "username"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Index for Email {
|
||||
// type Model = User;
|
||||
//
|
||||
// type Key = str;
|
||||
//
|
||||
// fn key() -> &'static str {
|
||||
// "email"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Index for IsActive {
|
||||
// type Model = User;
|
||||
//
|
||||
// type Key = bool;
|
||||
//
|
||||
// fn key() -> &'static str {
|
||||
// "is_active"
|
||||
// }
|
||||
// }
|
||||
|
318
heromodels_core/Cargo.lock
generated
Normal file
318
heromodels_core/Cargo.lock
generated
Normal file
@ -0,0 +1,318 @@
|
||||
# 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 = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
||||
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",
|
||||
"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_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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",
|
||||
]
|
8
heromodels_core/Cargo.toml
Normal file
8
heromodels_core/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "heromodels_core"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.40"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
201
heromodels_core/src/lib.rs
Normal file
201
heromodels_core/src/lib.rs
Normal file
@ -0,0 +1,201 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// Represents an index key for a model
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IndexKey {
|
||||
/// The name of the index key
|
||||
pub name: &'static str,
|
||||
|
||||
/// The value of the index key for a specific model instance
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Builder for IndexKey
|
||||
pub struct IndexKeyBuilder {
|
||||
name: &'static str,
|
||||
value: String,
|
||||
}
|
||||
|
||||
impl IndexKeyBuilder {
|
||||
/// Create a new IndexKeyBuilder
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
value: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the value for this index key
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the IndexKey
|
||||
pub fn build(self) -> IndexKey {
|
||||
IndexKey {
|
||||
name: self.name,
|
||||
value: self.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// The default implementation returns an empty vector
|
||||
/// Override this method to provide custom indexes
|
||||
fn db_keys(&self) -> Vec<IndexKey> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for an index in the DB
|
||||
pub trait Index {
|
||||
/// The model for which this is an index in the database
|
||||
type Model: Model;
|
||||
|
||||
type Key: ToString + ?Sized;
|
||||
|
||||
/// The key of this index
|
||||
fn key() -> &'static str;
|
||||
}
|
||||
|
||||
/// Base struct that all models should include
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BaseModelData {
|
||||
/// Unique incremental ID per circle
|
||||
pub id: u32,
|
||||
|
||||
/// Unix epoch timestamp for creation time
|
||||
pub created_at: i64,
|
||||
|
||||
/// Unix epoch timestamp for last modification time
|
||||
pub modified_at: i64,
|
||||
|
||||
/// List of comment IDs referencing Comment objects
|
||||
pub comments: Vec<u32>,
|
||||
}
|
||||
|
||||
impl BaseModelData {
|
||||
/// Create a new BaseModelData instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
Self {
|
||||
id,
|
||||
created_at: now,
|
||||
modified_at: now,
|
||||
comments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new BaseModelDataBuilder
|
||||
pub fn builder(id: u32) -> BaseModelDataBuilder {
|
||||
BaseModelDataBuilder::new(id)
|
||||
}
|
||||
|
||||
/// Add a comment to this model
|
||||
pub fn add_comment(&mut self, comment_id: u32) {
|
||||
self.comments.push(comment_id);
|
||||
self.modified_at = chrono::Utc::now().timestamp();
|
||||
}
|
||||
|
||||
/// Remove a comment from this model
|
||||
pub fn remove_comment(&mut self, comment_id: u32) {
|
||||
self.comments.retain(|&id| id != comment_id);
|
||||
self.update_modified();
|
||||
}
|
||||
|
||||
/// Update the modified timestamp
|
||||
pub fn update_modified(&mut self) {
|
||||
self.modified_at = chrono::Utc::now().timestamp();
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for BaseModelData
|
||||
pub struct BaseModelDataBuilder {
|
||||
id: u32,
|
||||
created_at: Option<i64>,
|
||||
modified_at: Option<i64>,
|
||||
comments: Vec<u32>,
|
||||
}
|
||||
|
||||
impl BaseModelDataBuilder {
|
||||
/// Create a new BaseModelDataBuilder
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self {
|
||||
id,
|
||||
created_at: None,
|
||||
modified_at: None,
|
||||
comments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the created_at timestamp
|
||||
pub fn created_at(mut self, timestamp: i64) -> Self {
|
||||
self.created_at = Some(timestamp);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the modified_at timestamp
|
||||
pub fn modified_at(mut self, timestamp: i64) -> Self {
|
||||
self.modified_at = Some(timestamp);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a comment ID
|
||||
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
||||
self.comments.push(comment_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add multiple comment IDs
|
||||
pub fn add_comments(mut self, comment_ids: Vec<u32>) -> Self {
|
||||
self.comments.extend(comment_ids);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the BaseModelData
|
||||
pub fn build(self) -> BaseModelData {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
BaseModelData {
|
||||
id: self.id,
|
||||
created_at: self.created_at.unwrap_or(now),
|
||||
modified_at: self.modified_at.unwrap_or(now),
|
||||
comments: self.comments,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user