final db models wip
This commit is contained in:
parent
2a2d69dafb
commit
abbed9a1a1
BIN
heromodels/.DS_Store
vendored
Normal file
BIN
heromodels/.DS_Store
vendored
Normal file
Binary file not shown.
60
heromodels/Cargo.lock
generated
60
heromodels/Cargo.lock
generated
@ -2,14 +2,6 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adapter_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"rhai",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
@ -177,12 +169,6 @@ dependencies = [
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -193,21 +179,19 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
name = "heromodels"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"adapter_macros",
|
||||
"bincode",
|
||||
"chrono",
|
||||
"heromodels-derive",
|
||||
"heromodels_core",
|
||||
"ourdb",
|
||||
"rhai",
|
||||
"rhai_autobind_macros",
|
||||
"rhai_client_macros",
|
||||
"rhai_wrapper",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tst",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -419,16 +403,6 @@ dependencies = [
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai_autobind_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai_client_macros"
|
||||
version = "0.1.0"
|
||||
@ -450,25 +424,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai_macros_derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai_wrapper"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"rhai",
|
||||
"rhai_macros_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.37.1"
|
||||
@ -570,7 +525,7 @@ version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
@ -643,6 +598,17 @@ version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
@ -14,13 +14,11 @@ ourdb = { path = "../ourdb" }
|
||||
tst = { path = "../tst" }
|
||||
heromodels-derive = { path = "../heromodels-derive" }
|
||||
heromodels_core = { path = "../heromodels_core" }
|
||||
rhai_autobind_macros = { path = "../../rhaj/rhai_autobind_macros" }
|
||||
rhai_wrapper = { path = "../../rhaj/rhai_wrapper" }
|
||||
rhai = { version = "1.21.0", features = ["std", "sync", "decimal", "internals"] } # Added "decimal" feature, sync for Arc<Mutex<>>
|
||||
adapter_macros = { path = "../adapter_macros" }
|
||||
rhai_client_macros = { path = "../rhai_client_macros" }
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
uuid = { version = "1.17.0", features = ["v4"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
Binary file not shown.
Binary file not shown.
@ -3,7 +3,7 @@ let db = get_db();
|
||||
|
||||
// Create a new calendar using the constructor and builder methods
|
||||
print("Creating a new calendar (ID will be DB-assigned) via registered constructor...");
|
||||
let calendar = new_calendar(). // ID removed
|
||||
let calendar = new_calendar("My first calendar"). // ID removed
|
||||
name("My First Calendar").
|
||||
description("A calendar for testing Rhai integration");
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
use heromodels::db::hero::OurDB;
|
||||
use heromodels::models::calendar::{Attendee, AttendanceStatus, Calendar, Event};
|
||||
use heromodels::models::calendar::rhai::register_rhai_engine_functions;
|
||||
use rhai::Engine;
|
||||
use std::sync::Arc;
|
||||
use std::{fs, path::Path};
|
||||
use rhai_wrapper::wrap_vec_return;
|
||||
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize Rhai engine
|
||||
@ -14,6 +17,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Register the Calendar type with Rhai
|
||||
// This function is generated by the #[rhai_model_export] attribute
|
||||
Calendar::register_rhai_bindings_for_calendar(&mut engine, db.clone());
|
||||
register_rhai_engine_functions(&mut engine, db.clone());
|
||||
|
||||
// Register a function to get the database instance
|
||||
engine.register_fn("get_db", move || db.clone());
|
||||
|
Binary file not shown.
Binary file not shown.
@ -9,6 +9,15 @@ use crate::models::gov::{
|
||||
// ComplianceRequirement, ComplianceDocument, ComplianceAudit - These don't exist
|
||||
};
|
||||
use crate::models::circle::{Circle, Member, Name, Wallet}; // Remove Asset
|
||||
use crate::models::calendar::{Event, Calendar};
|
||||
|
||||
// Implement model-specific methods for Event
|
||||
impl_model_methods!(Event, event, events);
|
||||
|
||||
// Implement model-specific methods for Calendar
|
||||
impl_model_methods!(Calendar, calendar, calendars);
|
||||
|
||||
impl_model_methods!(Attendee, attendee, attendees);
|
||||
|
||||
// Implement model-specific methods for Product
|
||||
impl_model_methods!(Product, product, products);
|
||||
|
@ -6,3 +6,6 @@ pub mod db;
|
||||
|
||||
// Re-export the procedural macro
|
||||
pub use heromodels_derive::model;
|
||||
|
||||
// Re-export BaseModelData from heromodels_core
|
||||
pub use heromodels_core::BaseModelData;
|
||||
|
@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use heromodels_core::{BaseModelData, Model, IndexKey, IndexKeyBuilder, Index};
|
||||
use rhai::{CustomType, TypeBuilder}; // For #[derive(CustomType)]
|
||||
use heromodels_core::BaseModelDataOps;
|
||||
use heromodels_derive::model;
|
||||
|
||||
// --- Enums ---
|
||||
|
||||
@ -34,7 +36,8 @@ impl Default for BusinessType {
|
||||
|
||||
// --- Company Struct ---
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, CustomType)] // Added CustomType
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, CustomType, Default)] // Added CustomType
|
||||
#[model]
|
||||
pub struct Company {
|
||||
pub base_data: BaseModelData,
|
||||
pub name: String,
|
||||
@ -51,31 +54,6 @@ pub struct Company {
|
||||
pub status: CompanyStatus,
|
||||
}
|
||||
|
||||
// --- Model Trait Implementation ---
|
||||
|
||||
impl Model for Company {
|
||||
fn db_prefix() -> &'static str {
|
||||
"company"
|
||||
}
|
||||
|
||||
fn get_id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
|
||||
// Override db_keys to provide custom indexes if needed
|
||||
fn db_keys(&self) -> Vec<IndexKey> {
|
||||
vec![
|
||||
IndexKeyBuilder::new("name").value(self.name.clone()).build(),
|
||||
IndexKeyBuilder::new("registration_number").value(self.registration_number.clone()).build(),
|
||||
// Add other relevant keys, e.g., by status or type if frequently queried
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// --- Index Implementations (Example) ---
|
||||
|
||||
pub struct CompanyNameIndex;
|
||||
@ -98,13 +76,19 @@ impl Index for CompanyRegistrationNumberIndex {
|
||||
|
||||
// --- Builder Pattern ---
|
||||
|
||||
impl BaseModelDataOps for Company {
|
||||
fn get_base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
}
|
||||
|
||||
impl Company {
|
||||
pub fn new(name: String, registration_number: String, incorporation_date: i64) -> Self { // incorporation_date to i64
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name,
|
||||
registration_number,
|
||||
incorporation_date, // This is i64 now
|
||||
name: String::new(),
|
||||
registration_number: String::new(),
|
||||
incorporation_date: 0,
|
||||
fiscal_year_end: String::new(),
|
||||
email: String::new(),
|
||||
phone: String::new(),
|
||||
@ -116,29 +100,44 @@ impl Company {
|
||||
status: CompanyStatus::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fiscal_year_end(mut self, fiscal_year_end: String) -> Self {
|
||||
self.fiscal_year_end = fiscal_year_end;
|
||||
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn registration_number(mut self, registration_number: impl ToString) -> Self {
|
||||
self.registration_number = registration_number.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn incorporation_date(mut self, incorporation_date: i64) -> Self {
|
||||
self.incorporation_date = incorporation_date;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn email(mut self, email: String) -> Self {
|
||||
self.email = email;
|
||||
pub fn fiscal_year_end(mut self, fiscal_year_end: impl ToString) -> Self {
|
||||
self.fiscal_year_end = fiscal_year_end.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn phone(mut self, phone: String) -> Self {
|
||||
self.phone = phone;
|
||||
pub fn email(mut self, email: impl ToString) -> Self {
|
||||
self.email = email.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn website(mut self, website: String) -> Self {
|
||||
self.website = website;
|
||||
pub fn phone(mut self, phone: impl ToString) -> Self {
|
||||
self.phone = phone.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn address(mut self, address: String) -> Self {
|
||||
self.address = address;
|
||||
pub fn website(mut self, website: impl ToString) -> Self {
|
||||
self.website = website.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -147,13 +146,13 @@ impl Company {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn industry(mut self, industry: String) -> Self {
|
||||
self.industry = industry;
|
||||
pub fn industry(mut self, industry: impl ToString) -> Self {
|
||||
self.industry = industry.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = description;
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -162,17 +161,5 @@ impl Company {
|
||||
self
|
||||
}
|
||||
|
||||
// Setter for base_data fields if needed directly, though usually handled by Model trait or new()
|
||||
// Builder methods for created_at and modified_at can be more specific if needed,
|
||||
// but Model::build() updates modified_at, and BaseModelData::new() sets created_at.
|
||||
// If direct setting is required for tests or specific scenarios:
|
||||
pub fn set_base_created_at(mut self, created_at: i64) -> Self {
|
||||
self.base_data.created_at = created_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_modified_at(mut self, modified_at: i64) -> Self {
|
||||
self.base_data.modified_at = modified_at;
|
||||
self
|
||||
}
|
||||
// Base data operations are now handled by BaseModelDataOps trait
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_core::Model;
|
||||
use heromodels_core::BaseModelDataOps;
|
||||
use heromodels_derive::model;
|
||||
|
||||
// ProductType represents the type of a product
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
|
||||
@ -27,18 +29,18 @@ pub struct ProductComponent {
|
||||
}
|
||||
|
||||
impl ProductComponent {
|
||||
// Minimal constructor
|
||||
pub fn new(name: String) -> Self {
|
||||
// Minimal constructor with no parameters
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name,
|
||||
name: String::new(),
|
||||
description: String::new(),
|
||||
quantity: 1, // Default quantity to 1
|
||||
}
|
||||
}
|
||||
|
||||
// Builder methods
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = description;
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -47,14 +49,15 @@ impl ProductComponent {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Product represents a product or service offered
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[model]
|
||||
pub struct Product {
|
||||
pub base_data: BaseModelData,
|
||||
pub name: String,
|
||||
@ -69,20 +72,6 @@ pub struct Product {
|
||||
pub components: Vec<ProductComponent>,
|
||||
}
|
||||
|
||||
impl Model for Product {
|
||||
fn get_id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn db_prefix() -> &'static str {
|
||||
"prod"
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
}
|
||||
|
||||
impl Product {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@ -101,13 +90,13 @@ impl Product {
|
||||
}
|
||||
|
||||
// Builder methods
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = description;
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -121,8 +110,8 @@ impl Product {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn category(mut self, category: String) -> Self {
|
||||
self.category = category;
|
||||
pub fn category(mut self, category: impl ToString) -> Self {
|
||||
self.category = category.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -156,24 +145,5 @@ impl Product {
|
||||
self
|
||||
}
|
||||
|
||||
// BaseModelData field setters
|
||||
pub fn set_base_created_at(mut self, time: i64) -> Self {
|
||||
self.base_data.created_at = time;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_modified_at(mut self, time: i64) -> Self {
|
||||
self.base_data.modified_at = time;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_base_comment_id(mut self, comment_id: u32) -> Self {
|
||||
self.base_data.comments.push(comment_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_comment_ids(mut self, comment_ids: Vec<u32>) -> Self {
|
||||
self.base_data.comments = comment_ids;
|
||||
self
|
||||
}
|
||||
// BaseModelData field operations are now handled by BaseModelDataOps trait
|
||||
}
|
||||
|
@ -1,332 +1,628 @@
|
||||
use rhai::{Engine, Module, Dynamic, EvalAltResult, Position};
|
||||
use rhai::plugin::*;
|
||||
use rhai::{Engine, Module, Dynamic, EvalAltResult, Position, INT};
|
||||
use std::sync::Arc;
|
||||
use std::mem;
|
||||
use crate::db::Collection; // For db.set and db.get_by_id
|
||||
use crate::db::hero::OurDB;
|
||||
use crate::db::Db;
|
||||
|
||||
use super::company::{Company, CompanyStatus, BusinessType};
|
||||
use crate::models::biz::shareholder::{Shareholder, ShareholderType};
|
||||
use crate::models::biz::product::{Product, ProductType, ProductStatus, ProductComponent};
|
||||
use crate::models::biz::sale::{Sale, SaleItem, SaleStatus};
|
||||
use heromodels_core::Model;
|
||||
|
||||
// Helper function to convert i64 to u32, returning a Rhai error if conversion fails
|
||||
fn id_from_i64(id_val: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(id_val).map_err(|_| {
|
||||
type RhaiCompany = Company;
|
||||
type RhaiShareholder = Shareholder;
|
||||
type RhaiProduct = Product;
|
||||
type RhaiProductComponent = ProductComponent;
|
||||
type RhaiSale = Sale;
|
||||
type RhaiSaleItem = SaleItem;
|
||||
|
||||
// Helper to convert i64 from Rhai to u32 for IDs
|
||||
fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(id_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Failed to convert i64 '{}' to u32 for ID", id_val),
|
||||
Position::NONE,
|
||||
format!("Failed to convert ID '{}' to u32", id_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[export_module]
|
||||
mod rhai_biz_module {
|
||||
// --- Company Functions ---
|
||||
#[rhai_fn(name = "new_company")]
|
||||
pub fn new_company() -> RhaiCompany {
|
||||
Company::new()
|
||||
}
|
||||
|
||||
// Company builder methods
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn company_name(company: &mut RhaiCompany, name: String) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.name(name);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "fiscal_year_end", return_raw, global, pure)]
|
||||
pub fn company_fiscal_year_end(company: &mut RhaiCompany, fiscal_year_end: String) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.fiscal_year_end(fiscal_year_end);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "registration_number", return_raw, global, pure)]
|
||||
pub fn company_registration_number(company: &mut RhaiCompany, reg_num: String) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.registration_number(reg_num);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "incorporation_date", return_raw, global, pure)]
|
||||
pub fn company_incorporation_date(company: &mut RhaiCompany, date: i64) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.incorporation_date(date);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn company_status(company: &mut RhaiCompany, status: CompanyStatus) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.status(status);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "business_type", return_raw, global, pure)]
|
||||
pub fn company_business_type(company: &mut RhaiCompany, business_type: BusinessType) -> Result<RhaiCompany, Box<EvalAltResult>> {
|
||||
let owned_company = mem::take(company);
|
||||
*company = owned_company.business_type(business_type);
|
||||
Ok(company.clone())
|
||||
}
|
||||
|
||||
// Company getters
|
||||
#[rhai_fn(name = "get_company_id")]
|
||||
pub fn get_company_id(company: &mut RhaiCompany) -> i64 {
|
||||
company.get_id() as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_name")]
|
||||
pub fn get_company_name(company: &mut RhaiCompany) -> String {
|
||||
company.name.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_created_at")]
|
||||
pub fn get_company_created_at(company: &mut RhaiCompany) -> i64 {
|
||||
company.base_data.created_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_modified_at")]
|
||||
pub fn get_company_modified_at(company: &mut RhaiCompany) -> i64 {
|
||||
company.base_data.modified_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_registration_number")]
|
||||
pub fn get_company_registration_number(company: &mut RhaiCompany) -> String {
|
||||
company.registration_number.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_fiscal_year_end")]
|
||||
pub fn get_company_fiscal_year_end(company: &mut RhaiCompany) -> String {
|
||||
company.fiscal_year_end.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_incorporation_date")]
|
||||
pub fn get_company_incorporation_date(company: &mut RhaiCompany) -> i64 {
|
||||
company.incorporation_date
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_status")]
|
||||
pub fn get_company_status(company: &mut RhaiCompany) -> CompanyStatus {
|
||||
company.status.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_company_business_type")]
|
||||
pub fn get_company_business_type(company: &mut RhaiCompany) -> BusinessType {
|
||||
company.business_type.clone()
|
||||
}
|
||||
|
||||
// --- Shareholder Functions ---
|
||||
#[rhai_fn(name = "new_shareholder")]
|
||||
pub fn new_shareholder() -> RhaiShareholder {
|
||||
Shareholder::new()
|
||||
}
|
||||
|
||||
// Shareholder builder methods
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn shareholder_name(shareholder: &mut RhaiShareholder, name: String) -> Result<RhaiShareholder, Box<EvalAltResult>> {
|
||||
let owned_shareholder = mem::take(shareholder);
|
||||
*shareholder = owned_shareholder.name(name);
|
||||
Ok(shareholder.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "company_id", return_raw, global, pure)]
|
||||
pub fn shareholder_company_id(shareholder: &mut RhaiShareholder, company_id: i64) -> Result<RhaiShareholder, Box<EvalAltResult>> {
|
||||
let company_id_u32 = id_from_i64_to_u32(company_id)?;
|
||||
let owned_shareholder = mem::take(shareholder);
|
||||
*shareholder = owned_shareholder.company_id(company_id_u32);
|
||||
Ok(shareholder.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "share_count", return_raw, global, pure)]
|
||||
pub fn shareholder_share_count(shareholder: &mut RhaiShareholder, share_count: f64) -> Result<RhaiShareholder, Box<EvalAltResult>> {
|
||||
let owned_shareholder = mem::take(shareholder);
|
||||
shareholder.shares = share_count;
|
||||
Ok(shareholder.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "type_", return_raw, global, pure)]
|
||||
pub fn shareholder_type(shareholder: &mut RhaiShareholder, type_: ShareholderType) -> Result<RhaiShareholder, Box<EvalAltResult>> {
|
||||
let owned_shareholder = mem::take(shareholder);
|
||||
*shareholder = owned_shareholder.type_(type_);
|
||||
Ok(shareholder.clone())
|
||||
}
|
||||
|
||||
// Shareholder getters
|
||||
#[rhai_fn(name = "get_shareholder_id")]
|
||||
pub fn get_shareholder_id(shareholder: &mut RhaiShareholder) -> i64 {
|
||||
shareholder.get_id() as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_shareholder_name")]
|
||||
pub fn get_shareholder_name(shareholder: &mut RhaiShareholder) -> String {
|
||||
shareholder.name.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_shareholder_company_id")]
|
||||
pub fn get_shareholder_company_id(shareholder: &mut RhaiShareholder) -> i64 {
|
||||
shareholder.company_id as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_shareholder_share_count")]
|
||||
pub fn get_shareholder_share_count(shareholder: &mut RhaiShareholder) -> i64 {
|
||||
shareholder.shares as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_shareholder_type")]
|
||||
pub fn get_shareholder_type(shareholder: &mut RhaiShareholder) -> ShareholderType {
|
||||
shareholder.type_.clone()
|
||||
}
|
||||
|
||||
// --- ProductComponent Functions ---
|
||||
#[rhai_fn(name = "new_product_component")]
|
||||
pub fn new_product_component() -> RhaiProductComponent {
|
||||
ProductComponent::new()
|
||||
}
|
||||
|
||||
// ProductComponent builder methods
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn product_component_name(component: &mut RhaiProductComponent, name: String) -> Result<RhaiProductComponent, Box<EvalAltResult>> {
|
||||
let owned_component = mem::take(component);
|
||||
*component = owned_component.name(name);
|
||||
Ok(component.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn product_component_description(component: &mut RhaiProductComponent, description: String) -> Result<RhaiProductComponent, Box<EvalAltResult>> {
|
||||
let owned_component = mem::take(component);
|
||||
*component = owned_component.description(description);
|
||||
Ok(component.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "quantity", return_raw, global, pure)]
|
||||
pub fn product_component_quantity(component: &mut RhaiProductComponent, quantity: i64) -> Result<RhaiProductComponent, Box<EvalAltResult>> {
|
||||
let owned_component = mem::take(component);
|
||||
*component = owned_component.quantity(quantity as u32);
|
||||
Ok(component.clone())
|
||||
}
|
||||
|
||||
// ProductComponent getters
|
||||
#[rhai_fn(name = "get_product_component_name")]
|
||||
pub fn get_product_component_name(component: &mut RhaiProductComponent) -> String {
|
||||
component.name.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_component_description")]
|
||||
pub fn get_product_component_description(component: &mut RhaiProductComponent) -> String {
|
||||
component.description.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_component_quantity")]
|
||||
pub fn get_product_component_quantity(component: &mut RhaiProductComponent) -> i64 {
|
||||
component.quantity as i64
|
||||
}
|
||||
|
||||
// --- Product Functions ---
|
||||
#[rhai_fn(name = "new_product")]
|
||||
pub fn new_product() -> RhaiProduct {
|
||||
Product::new()
|
||||
}
|
||||
|
||||
// Product builder methods
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn product_name(product: &mut RhaiProduct, name: String) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.name(name);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn product_description(product: &mut RhaiProduct, description: String) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.description(description);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "price", return_raw, global, pure)]
|
||||
pub fn product_price(product: &mut RhaiProduct, price: f64) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.price(price);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "type_", return_raw, global, pure)]
|
||||
pub fn product_type(product: &mut RhaiProduct, type_: ProductType) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.type_(type_);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "category", return_raw, global, pure)]
|
||||
pub fn product_category(product: &mut RhaiProduct, category: String) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.category(category);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn product_status(product: &mut RhaiProduct, status: ProductStatus) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.status(status);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "max_amount", return_raw, global, pure)]
|
||||
pub fn product_max_amount(product: &mut RhaiProduct, max_amount: i64) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.max_amount(max_amount as u16);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "purchase_till", return_raw, global, pure)]
|
||||
pub fn product_purchase_till(product: &mut RhaiProduct, purchase_till: i64) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.purchase_till(purchase_till);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "active_till", return_raw, global, pure)]
|
||||
pub fn product_active_till(product: &mut RhaiProduct, active_till: i64) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.active_till(active_till);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "add_component", return_raw, global, pure)]
|
||||
pub fn product_add_component(product: &mut RhaiProduct, component: RhaiProductComponent) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.add_component(component);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "components", return_raw, global, pure)]
|
||||
pub fn product_components(product: &mut RhaiProduct, components: Vec<RhaiProductComponent>) -> Result<RhaiProduct, Box<EvalAltResult>> {
|
||||
let owned_product = mem::take(product);
|
||||
*product = owned_product.components(components);
|
||||
Ok(product.clone())
|
||||
}
|
||||
|
||||
// Product getters
|
||||
#[rhai_fn(name = "get_product_id")]
|
||||
pub fn get_product_id(product: &mut RhaiProduct) -> i64 {
|
||||
product.get_id() as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_name")]
|
||||
pub fn get_product_name(product: &mut RhaiProduct) -> String {
|
||||
product.name.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_description")]
|
||||
pub fn get_product_description(product: &mut RhaiProduct) -> String {
|
||||
product.description.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_price")]
|
||||
pub fn get_product_price(product: &mut RhaiProduct) -> f64 {
|
||||
product.price
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_type")]
|
||||
pub fn get_product_type(product: &mut RhaiProduct) -> ProductType {
|
||||
product.type_.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_category")]
|
||||
pub fn get_product_category(product: &mut RhaiProduct) -> String {
|
||||
product.category.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_status")]
|
||||
pub fn get_product_status(product: &mut RhaiProduct) -> ProductStatus {
|
||||
product.status.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_max_amount")]
|
||||
pub fn get_product_max_amount(product: &mut RhaiProduct) -> i64 {
|
||||
product.max_amount as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_purchase_till")]
|
||||
pub fn get_product_purchase_till(product: &mut RhaiProduct) -> i64 {
|
||||
product.purchase_till
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_active_till")]
|
||||
pub fn get_product_active_till(product: &mut RhaiProduct) -> i64 {
|
||||
product.active_till
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_components")]
|
||||
pub fn get_product_components(product: &mut RhaiProduct) -> Vec<RhaiProductComponent> {
|
||||
product.components.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_created_at")]
|
||||
pub fn get_product_created_at(product: &mut RhaiProduct) -> i64 {
|
||||
product.base_data.created_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_modified_at")]
|
||||
pub fn get_product_modified_at(product: &mut RhaiProduct) -> i64 {
|
||||
product.base_data.modified_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_product_comments")]
|
||||
pub fn get_product_comments(product: &mut RhaiProduct) -> Vec<i64> {
|
||||
product.base_data.comments.iter().map(|&id| id as i64).collect()
|
||||
}
|
||||
|
||||
// --- SaleItem Functions ---
|
||||
#[rhai_fn(name = "new_sale_item")]
|
||||
pub fn new_sale_item() -> RhaiSaleItem {
|
||||
SaleItem::new()
|
||||
}
|
||||
|
||||
// SaleItem builder methods
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn sale_item_name(item: &mut RhaiSaleItem, name: String) -> Result<RhaiSaleItem, Box<EvalAltResult>> {
|
||||
let owned_item = mem::take(item);
|
||||
*item = owned_item.name(name);
|
||||
Ok(item.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "price", return_raw, global, pure)]
|
||||
pub fn sale_item_price(item: &mut RhaiSaleItem, price: f64) -> Result<RhaiSaleItem, Box<EvalAltResult>> {
|
||||
let owned_item = mem::take(item);
|
||||
item.unit_price = price;
|
||||
Ok(item.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "quantity", return_raw, global, pure)]
|
||||
pub fn sale_item_quantity(item: &mut RhaiSaleItem, quantity: i64) -> Result<RhaiSaleItem, Box<EvalAltResult>> {
|
||||
let owned_item = mem::take(item);
|
||||
*item = owned_item.quantity(quantity.try_into().unwrap());
|
||||
Ok(item.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "product_id", return_raw, global, pure)]
|
||||
pub fn sale_item_product_id(item: &mut RhaiSaleItem, product_id: i64) -> Result<RhaiSaleItem, Box<EvalAltResult>> {
|
||||
let product_id_u32 = id_from_i64_to_u32(product_id)?;
|
||||
let owned_item = mem::take(item);
|
||||
*item = owned_item.product_id(product_id_u32);
|
||||
Ok(item.clone())
|
||||
}
|
||||
|
||||
// SaleItem getters
|
||||
#[rhai_fn(name = "get_sale_item_name")]
|
||||
pub fn get_sale_item_name(item: &mut RhaiSaleItem) -> String {
|
||||
item.name.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_item_price")]
|
||||
pub fn get_sale_item_price(item: &mut RhaiSaleItem) -> f64 {
|
||||
item.unit_price
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_item_quantity")]
|
||||
pub fn get_sale_item_quantity(item: &mut RhaiSaleItem) -> i64 {
|
||||
item.quantity as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_item_product_id")]
|
||||
pub fn get_sale_item_product_id(item: &mut RhaiSaleItem) -> i64 {
|
||||
item.product_id as i64
|
||||
}
|
||||
|
||||
// --- Sale Functions ---
|
||||
#[rhai_fn(name = "new_sale")]
|
||||
pub fn new_sale() -> RhaiSale {
|
||||
Sale::new()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "transaction_id", return_raw, global, pure)]
|
||||
pub fn sale_transaction_id(sale: &mut RhaiSale, transaction_id: u32) -> Result<RhaiSale, Box<EvalAltResult>> {
|
||||
let owned_sale = mem::take(sale);
|
||||
sale.transaction_id = transaction_id;
|
||||
Ok(sale.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn sale_status(sale: &mut RhaiSale, status: SaleStatus) -> Result<RhaiSale, Box<EvalAltResult>> {
|
||||
let owned_sale = mem::take(sale);
|
||||
*sale = owned_sale.status(status);
|
||||
Ok(sale.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "add_item", return_raw, global, pure)]
|
||||
pub fn sale_add_item(sale: &mut RhaiSale, item: RhaiSaleItem) -> Result<RhaiSale, Box<EvalAltResult>> {
|
||||
let owned_sale = mem::take(sale);
|
||||
*sale = owned_sale.add_item(item);
|
||||
Ok(sale.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "items", return_raw, global, pure)]
|
||||
pub fn sale_items(sale: &mut RhaiSale, items: Vec<RhaiSaleItem>) -> Result<RhaiSale, Box<EvalAltResult>> {
|
||||
let owned_sale = mem::take(sale);
|
||||
*sale = owned_sale.items(items);
|
||||
Ok(sale.clone())
|
||||
}
|
||||
|
||||
// Sale getters
|
||||
#[rhai_fn(name = "get_sale_id")]
|
||||
pub fn get_sale_id(sale: &mut RhaiSale) -> i64 {
|
||||
sale.get_id() as i64
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_transaction_id")]
|
||||
pub fn get_sale_transaction_id(sale: &mut RhaiSale) -> u32 {
|
||||
sale.transaction_id
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_status")]
|
||||
pub fn get_sale_status(sale: &mut RhaiSale) -> SaleStatus {
|
||||
sale.status.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_items")]
|
||||
pub fn get_sale_items(sale: &mut RhaiSale) -> Vec<RhaiSaleItem> {
|
||||
sale.items.clone()
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_created_at")]
|
||||
pub fn get_sale_created_at(sale: &mut RhaiSale) -> i64 {
|
||||
sale.base_data.created_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_modified_at")]
|
||||
pub fn get_sale_modified_at(sale: &mut RhaiSale) -> i64 {
|
||||
sale.base_data.modified_at
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "get_sale_comments")]
|
||||
pub fn get_sale_comments(sale: &mut RhaiSale) -> Vec<i64> {
|
||||
sale.base_data.comments.iter().map(|&id| id as i64).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_biz_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
let module = Module::new();
|
||||
|
||||
// --- Enum Constants: CompanyStatus ---
|
||||
let mut status_constants_module = Module::new();
|
||||
status_constants_module.set_var("Active", Dynamic::from(CompanyStatus::Active.clone()));
|
||||
status_constants_module.set_var("Inactive", Dynamic::from(CompanyStatus::Inactive.clone()));
|
||||
status_constants_module.set_var("Suspended", Dynamic::from(CompanyStatus::Suspended.clone()));
|
||||
engine.register_static_module("CompanyStatusConstants", status_constants_module.into());
|
||||
engine.register_type_with_name::<CompanyStatus>("CompanyStatus");
|
||||
|
||||
// --- Enum Constants: BusinessType ---
|
||||
let mut business_type_constants_module = Module::new();
|
||||
business_type_constants_module.set_var("Coop", Dynamic::from(BusinessType::Coop.clone()));
|
||||
business_type_constants_module.set_var("Single", Dynamic::from(BusinessType::Single.clone()));
|
||||
business_type_constants_module.set_var("Twin", Dynamic::from(BusinessType::Twin.clone()));
|
||||
business_type_constants_module.set_var("Starter", Dynamic::from(BusinessType::Starter.clone()));
|
||||
business_type_constants_module.set_var("Global", Dynamic::from(BusinessType::Global.clone()));
|
||||
engine.register_static_module("BusinessTypeConstants", business_type_constants_module.into());
|
||||
engine.register_type_with_name::<BusinessType>("BusinessType");
|
||||
|
||||
// --- Company ---
|
||||
engine.register_type_with_name::<Company>("Company");
|
||||
|
||||
// Constructor
|
||||
engine.register_fn("new_company", |name: String, registration_number: String, incorporation_date: i64| -> Result<Company, Box<EvalAltResult>> { Ok(Company::new(name, registration_number, incorporation_date)) });
|
||||
|
||||
// Getters for Company
|
||||
engine.register_get("id", |company: &mut Company| -> Result<i64, Box<EvalAltResult>> { Ok(company.get_id() as i64) });
|
||||
engine.register_get("created_at", |company: &mut Company| -> Result<i64, Box<EvalAltResult>> { Ok(company.base_data.created_at) });
|
||||
engine.register_get("modified_at", |company: &mut Company| -> Result<i64, Box<EvalAltResult>> { Ok(company.base_data.modified_at) });
|
||||
engine.register_get("name", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.name.clone()) });
|
||||
engine.register_get("registration_number", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.registration_number.clone()) });
|
||||
engine.register_get("incorporation_date", |company: &mut Company| -> Result<i64, Box<EvalAltResult>> { Ok(company.incorporation_date as i64) });
|
||||
engine.register_get("fiscal_year_end", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.fiscal_year_end.clone()) });
|
||||
engine.register_get("email", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.email.clone()) });
|
||||
engine.register_get("phone", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.phone.clone()) });
|
||||
engine.register_get("website", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.website.clone()) });
|
||||
engine.register_get("address", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.address.clone()) });
|
||||
engine.register_get("business_type", |company: &mut Company| -> Result<BusinessType, Box<EvalAltResult>> { Ok(company.business_type.clone()) });
|
||||
engine.register_get("industry", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.industry.clone()) });
|
||||
engine.register_get("description", |company: &mut Company| -> Result<String, Box<EvalAltResult>> { Ok(company.description.clone()) });
|
||||
engine.register_get("status", |company: &mut Company| -> Result<CompanyStatus, Box<EvalAltResult>> { Ok(company.status.clone()) });
|
||||
// Builder methods for Company
|
||||
engine.register_fn("fiscal_year_end", |company: Company, fiscal_year_end: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.fiscal_year_end(fiscal_year_end)) });
|
||||
engine.register_fn("email", |company: Company, email: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.email(email)) });
|
||||
engine.register_fn("phone", |company: Company, phone: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.phone(phone)) });
|
||||
engine.register_fn("website", |company: Company, website: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.website(website)) });
|
||||
engine.register_fn("address", |company: Company, address: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.address(address)) });
|
||||
engine.register_fn("business_type", |company: Company, business_type: BusinessType| -> Result<Company, Box<EvalAltResult>> { Ok(company.business_type(business_type)) });
|
||||
engine.register_fn("industry", |company: Company, industry: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.industry(industry)) });
|
||||
engine.register_fn("description", |company: Company, description: String| -> Result<Company, Box<EvalAltResult>> { Ok(company.description(description)) });
|
||||
engine.register_fn("status", |company: Company, status: CompanyStatus| -> Result<Company, Box<EvalAltResult>> { Ok(company.status(status)) });
|
||||
engine.register_fn("set_base_created_at", |company: Company, created_at: i64| -> Result<Company, Box<EvalAltResult>> { Ok(company.set_base_created_at(created_at)) });
|
||||
engine.register_fn("set_base_modified_at", |company: Company, modified_at: i64| -> Result<Company, Box<EvalAltResult>> { Ok(company.set_base_modified_at(modified_at)) });
|
||||
|
||||
// --- Enum Constants: ShareholderType ---
|
||||
let mut shareholder_type_constants_module = Module::new();
|
||||
shareholder_type_constants_module.set_var("Individual", Dynamic::from(ShareholderType::Individual.clone()));
|
||||
shareholder_type_constants_module.set_var("Corporate", Dynamic::from(ShareholderType::Corporate.clone()));
|
||||
engine.register_static_module("ShareholderTypeConstants", shareholder_type_constants_module.into());
|
||||
engine.register_type_with_name::<ShareholderType>("ShareholderType");
|
||||
|
||||
// --- Shareholder ---
|
||||
engine.register_type_with_name::<Shareholder>("Shareholder");
|
||||
|
||||
// Constructor for Shareholder (minimal, takes only ID)
|
||||
engine.register_fn("new_shareholder", || -> Result<Shareholder, Box<EvalAltResult>> { Ok(Shareholder::new()) });
|
||||
|
||||
// Getters for Shareholder
|
||||
engine.register_get("id", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.get_id() as i64) });
|
||||
engine.register_get("created_at", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.base_data.created_at) });
|
||||
engine.register_get("modified_at", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.base_data.modified_at) });
|
||||
engine.register_get("company_id", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.company_id as i64) });
|
||||
engine.register_get("user_id", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.user_id as i64) });
|
||||
engine.register_get("name", |shareholder: &mut Shareholder| -> Result<String, Box<EvalAltResult>> { Ok(shareholder.name.clone()) });
|
||||
engine.register_get("shares", |shareholder: &mut Shareholder| -> Result<f64, Box<EvalAltResult>> { Ok(shareholder.shares) });
|
||||
engine.register_get("percentage", |shareholder: &mut Shareholder| -> Result<f64, Box<EvalAltResult>> { Ok(shareholder.percentage) });
|
||||
engine.register_get("type_", |shareholder: &mut Shareholder| -> Result<ShareholderType, Box<EvalAltResult>> { Ok(shareholder.type_.clone()) });
|
||||
engine.register_get("since", |shareholder: &mut Shareholder| -> Result<i64, Box<EvalAltResult>> { Ok(shareholder.since) });
|
||||
|
||||
// Builder methods for Shareholder
|
||||
engine.register_fn("company_id", |shareholder: Shareholder, company_id: i64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.company_id(company_id as u32)) });
|
||||
engine.register_fn("user_id", |shareholder: Shareholder, user_id: i64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.user_id(user_id as u32)) });
|
||||
engine.register_fn("name", |shareholder: Shareholder, name: String| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.name(name)) });
|
||||
engine.register_fn("shares", |shareholder: Shareholder, shares: f64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.shares(shares)) });
|
||||
engine.register_fn("percentage", |shareholder: Shareholder, percentage: f64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.percentage(percentage)) });
|
||||
engine.register_fn("type_", |shareholder: Shareholder, type_: ShareholderType| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.type_(type_)) });
|
||||
engine.register_fn("since", |shareholder: Shareholder, since: i64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.since(since)) });
|
||||
engine.register_fn("set_base_created_at", |shareholder: Shareholder, created_at: i64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.set_base_created_at(created_at)) });
|
||||
engine.register_fn("set_base_modified_at", |shareholder: Shareholder, modified_at: i64| -> Result<Shareholder, Box<EvalAltResult>> { Ok(shareholder.set_base_modified_at(modified_at)) });
|
||||
|
||||
|
||||
// --- Enum Constants: ProductType ---
|
||||
let mut product_type_constants_module = Module::new();
|
||||
product_type_constants_module.set_var("Product", Dynamic::from(ProductType::Product.clone()));
|
||||
product_type_constants_module.set_var("Service", Dynamic::from(ProductType::Service.clone()));
|
||||
engine.register_static_module("ProductTypeConstants", product_type_constants_module.into());
|
||||
engine.register_type_with_name::<ProductType>("ProductType");
|
||||
|
||||
// --- Enum Constants: ProductStatus ---
|
||||
let mut product_status_constants_module = Module::new();
|
||||
product_status_constants_module.set_var("Available", Dynamic::from(ProductStatus::Available.clone()));
|
||||
product_status_constants_module.set_var("Unavailable", Dynamic::from(ProductStatus::Unavailable.clone()));
|
||||
engine.register_static_module("ProductStatusConstants", product_status_constants_module.into());
|
||||
engine.register_type_with_name::<ProductStatus>("ProductStatus");
|
||||
|
||||
// --- Enum Constants: SaleStatus ---
|
||||
let mut sale_status_module = Module::new();
|
||||
sale_status_module.set_var("Pending", Dynamic::from(SaleStatus::Pending.clone()));
|
||||
sale_status_module.set_var("Completed", Dynamic::from(SaleStatus::Completed.clone()));
|
||||
sale_status_module.set_var("Cancelled", Dynamic::from(SaleStatus::Cancelled.clone()));
|
||||
engine.register_static_module("SaleStatusConstants", sale_status_module.into());
|
||||
engine.register_type_with_name::<SaleStatus>("SaleStatus");
|
||||
|
||||
// --- ProductComponent ---
|
||||
engine.register_type_with_name::<ProductComponent>("ProductComponent")
|
||||
.register_fn("new_product_component", |name: String| -> Result<ProductComponent, Box<EvalAltResult>> { Ok(ProductComponent::new(name)) })
|
||||
.register_get("name", |pc: &mut ProductComponent| -> Result<String, Box<EvalAltResult>> { Ok(pc.name.clone()) })
|
||||
.register_fn("name", |pc: ProductComponent, name: String| -> Result<ProductComponent, Box<EvalAltResult>> { Ok(pc.name(name)) })
|
||||
.register_get("description", |pc: &mut ProductComponent| -> Result<String, Box<EvalAltResult>> { Ok(pc.description.clone()) })
|
||||
.register_fn("description", |pc: ProductComponent, description: String| -> Result<ProductComponent, Box<EvalAltResult>> { Ok(pc.description(description)) })
|
||||
.register_get("quantity", |pc: &mut ProductComponent| -> Result<i64, Box<EvalAltResult>> { Ok(pc.quantity as i64) })
|
||||
.register_fn("quantity", |pc: ProductComponent, quantity: i64| -> Result<ProductComponent, Box<EvalAltResult>> { Ok(pc.quantity(quantity as u32)) });
|
||||
|
||||
// --- Product ---
|
||||
engine.register_type_with_name::<Product>("Product")
|
||||
.register_fn("new_product", || -> Result<Product, Box<EvalAltResult>> { Ok(Product::new()) })
|
||||
// Getters for Product
|
||||
.register_get("id", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.base_data.id as i64) })
|
||||
.register_get("name", |p: &mut Product| -> Result<String, Box<EvalAltResult>> { Ok(p.name.clone()) })
|
||||
.register_get("description", |p: &mut Product| -> Result<String, Box<EvalAltResult>> { Ok(p.description.clone()) })
|
||||
.register_get("price", |p: &mut Product| -> Result<f64, Box<EvalAltResult>> { Ok(p.price) })
|
||||
.register_get("type_", |p: &mut Product| -> Result<ProductType, Box<EvalAltResult>> { Ok(p.type_.clone()) })
|
||||
.register_get("category", |p: &mut Product| -> Result<String, Box<EvalAltResult>> { Ok(p.category.clone()) })
|
||||
.register_get("status", |p: &mut Product| -> Result<ProductStatus, Box<EvalAltResult>> { Ok(p.status.clone()) })
|
||||
.register_get("max_amount", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.max_amount as i64) })
|
||||
.register_get("purchase_till", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.purchase_till) })
|
||||
.register_get("active_till", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.active_till) })
|
||||
.register_get("components", |p: &mut Product| -> Result<rhai::Array, Box<EvalAltResult>> {
|
||||
let rhai_array = p.components.iter().cloned().map(Dynamic::from).collect::<rhai::Array>();
|
||||
Ok(rhai_array)
|
||||
})
|
||||
// Getters for BaseModelData fields
|
||||
.register_get("created_at", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.base_data.created_at) })
|
||||
.register_get("modified_at", |p: &mut Product| -> Result<i64, Box<EvalAltResult>> { Ok(p.base_data.modified_at) })
|
||||
.register_get("comments", |p: &mut Product| -> Result<Vec<i64>, Box<EvalAltResult>> { Ok(p.base_data.comments.iter().map(|&id| id as i64).collect()) })
|
||||
// Builder methods for Product
|
||||
.register_fn("name", |p: Product, name: String| -> Result<Product, Box<EvalAltResult>> { Ok(p.name(name)) })
|
||||
.register_fn("description", |p: Product, description: String| -> Result<Product, Box<EvalAltResult>> { Ok(p.description(description)) })
|
||||
.register_fn("price", |p: Product, price: f64| -> Result<Product, Box<EvalAltResult>> { Ok(p.price(price)) })
|
||||
.register_fn("type_", |p: Product, type_: ProductType| -> Result<Product, Box<EvalAltResult>> { Ok(p.type_(type_)) })
|
||||
.register_fn("category", |p: Product, category: String| -> Result<Product, Box<EvalAltResult>> { Ok(p.category(category)) })
|
||||
.register_fn("status", |p: Product, status: ProductStatus| -> Result<Product, Box<EvalAltResult>> { Ok(p.status(status)) })
|
||||
.register_fn("max_amount", |p: Product, max_amount: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.max_amount(max_amount as u16)) })
|
||||
.register_fn("purchase_till", |p: Product, purchase_till: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.purchase_till(purchase_till)) })
|
||||
.register_fn("active_till", |p: Product, active_till: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.active_till(active_till)) })
|
||||
.register_fn("add_component", |p: Product, component: ProductComponent| -> Result<Product, Box<EvalAltResult>> { Ok(p.add_component(component)) })
|
||||
.register_fn("components", |p: Product, components: Vec<ProductComponent>| -> Result<Product, Box<EvalAltResult>> { Ok(p.components(components)) })
|
||||
.register_fn("set_base_created_at", |p: Product, time: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.set_base_created_at(time)) })
|
||||
.register_fn("set_base_modified_at", |p: Product, time: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.set_base_modified_at(time)) })
|
||||
.register_fn("add_base_comment_id", |p: Product, comment_id: i64| -> Result<Product, Box<EvalAltResult>> { Ok(p.add_base_comment_id(id_from_i64(comment_id)?)) })
|
||||
.register_fn("set_base_comment_ids", |p: Product, comment_ids: Vec<i64>| -> Result<Product, Box<EvalAltResult>> {
|
||||
let u32_ids = comment_ids.into_iter().map(id_from_i64).collect::<Result<Vec<u32>, _>>()?;
|
||||
Ok(p.set_base_comment_ids(u32_ids))
|
||||
});
|
||||
|
||||
// --- SaleItem ---
|
||||
engine.register_type_with_name::<SaleItem>("SaleItem");
|
||||
engine.register_fn("new_sale_item", |product_id_i64: i64, name: String, quantity_i64: i64, unit_price: f64, subtotal: f64| -> Result<SaleItem, Box<EvalAltResult>> {
|
||||
Ok(SaleItem::new(id_from_i64(product_id_i64)?, name, quantity_i64 as i32, unit_price, subtotal))
|
||||
});
|
||||
|
||||
// Getters for SaleItem
|
||||
engine.register_get("product_id", |si: &mut SaleItem| -> Result<i64, Box<EvalAltResult>> { Ok(si.product_id as i64) });
|
||||
engine.register_get("name", |si: &mut SaleItem| -> Result<String, Box<EvalAltResult>> { Ok(si.name.clone()) });
|
||||
engine.register_get("quantity", |si: &mut SaleItem| -> Result<i64, Box<EvalAltResult>> { Ok(si.quantity as i64) });
|
||||
engine.register_get("unit_price", |si: &mut SaleItem| -> Result<f64, Box<EvalAltResult>> { Ok(si.unit_price) });
|
||||
engine.register_get("subtotal", |si: &mut SaleItem| -> Result<f64, Box<EvalAltResult>> { Ok(si.subtotal) });
|
||||
engine.register_get("service_active_until", |si: &mut SaleItem| -> Result<Option<i64>, Box<EvalAltResult>> { Ok(si.service_active_until) });
|
||||
|
||||
// Builder-style methods for SaleItem
|
||||
engine.register_type_with_name::<SaleItem>("SaleItem")
|
||||
.register_fn("product_id", |item: SaleItem, product_id_i64: i64| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.product_id(id_from_i64(product_id_i64)?)) })
|
||||
.register_fn("name", |item: SaleItem, name: String| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.name(name)) })
|
||||
.register_fn("quantity", |item: SaleItem, quantity_i64: i64| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.quantity(quantity_i64 as i32)) })
|
||||
.register_fn("unit_price", |item: SaleItem, unit_price: f64| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.unit_price(unit_price)) })
|
||||
.register_fn("subtotal", |item: SaleItem, subtotal: f64| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.subtotal(subtotal)) })
|
||||
.register_fn("service_active_until", |item: SaleItem, until: Option<i64>| -> Result<SaleItem, Box<EvalAltResult>> { Ok(item.service_active_until(until)) });
|
||||
|
||||
// --- Sale ---
|
||||
engine.register_type_with_name::<Sale>("Sale");
|
||||
engine.register_fn("new_sale", |company_id_i64: i64, buyer_name: String, buyer_email: String, total_amount: f64, status: SaleStatus, sale_date: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(Sale::new(id_from_i64(company_id_i64)?, buyer_name, buyer_email, total_amount, status, sale_date)) });
|
||||
|
||||
// Getters for Sale
|
||||
engine.register_get("id", |s: &mut Sale| -> Result<i64, Box<EvalAltResult>> { Ok(s.get_id() as i64) });
|
||||
engine.register_get("customer_id", |s: &mut Sale| -> Result<i64, Box<EvalAltResult>> { Ok(s.company_id as i64) });
|
||||
engine.register_get("buyer_name", |s: &mut Sale| -> Result<String, Box<EvalAltResult>> { Ok(s.buyer_name.clone()) });
|
||||
engine.register_get("buyer_email", |s: &mut Sale| -> Result<String, Box<EvalAltResult>> { Ok(s.buyer_email.clone()) });
|
||||
engine.register_get("total_amount", |s: &mut Sale| -> Result<f64, Box<EvalAltResult>> { Ok(s.total_amount) });
|
||||
engine.register_get("status", |s: &mut Sale| -> Result<SaleStatus, Box<EvalAltResult>> { Ok(s.status.clone()) });
|
||||
engine.register_get("sale_date", |s: &mut Sale| -> Result<i64, Box<EvalAltResult>> { Ok(s.sale_date) });
|
||||
engine.register_get("items", |s: &mut Sale| -> Result<rhai::Array, Box<EvalAltResult>> {
|
||||
Ok(s.items.iter().cloned().map(Dynamic::from).collect::<rhai::Array>())
|
||||
});
|
||||
engine.register_get("notes", |s: &mut Sale| -> Result<String, Box<EvalAltResult>> { Ok(s.notes.clone()) });
|
||||
engine.register_get("created_at", |s: &mut Sale| -> Result<i64, Box<EvalAltResult>> { Ok(s.base_data.created_at) });
|
||||
engine.register_get("modified_at", |s: &mut Sale| -> Result<i64, Box<EvalAltResult>> { Ok(s.base_data.modified_at) });
|
||||
// engine.register_get("uuid", |s: &mut Sale| -> Result<Option<String>, Box<EvalAltResult>> { Ok(s.base_data().uuid.clone()) }); // UUID not in BaseModelData
|
||||
engine.register_get("comments", |s: &mut Sale| -> Result<rhai::Array, Box<EvalAltResult>> {
|
||||
Ok(s.base_data.comments.iter().map(|&id| Dynamic::from(id as i64)).collect::<rhai::Array>())
|
||||
});
|
||||
|
||||
// Builder-style methods for Sale
|
||||
engine.register_type_with_name::<Sale>("Sale")
|
||||
.register_fn("customer_id", |s: Sale, customer_id_i64: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.company_id(id_from_i64(customer_id_i64)?)) })
|
||||
.register_fn("buyer_name", |s: Sale, buyer_name: String| -> Result<Sale, Box<EvalAltResult>> { Ok(s.buyer_name(buyer_name)) })
|
||||
.register_fn("buyer_email", |s: Sale, buyer_email: String| -> Result<Sale, Box<EvalAltResult>> { Ok(s.buyer_email(buyer_email)) })
|
||||
.register_fn("total_amount", |s: Sale, total_amount: f64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.total_amount(total_amount)) })
|
||||
.register_fn("status", |s: Sale, status: SaleStatus| -> Result<Sale, Box<EvalAltResult>> { Ok(s.status(status)) })
|
||||
.register_fn("sale_date", |s: Sale, sale_date: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.sale_date(sale_date)) })
|
||||
.register_fn("add_item", |s: Sale, item: SaleItem| -> Result<Sale, Box<EvalAltResult>> { Ok(s.add_item(item)) })
|
||||
.register_fn("items", |s: Sale, items: Vec<SaleItem>| -> Result<Sale, Box<EvalAltResult>> { Ok(s.items(items)) })
|
||||
.register_fn("notes", |s: Sale, notes: String| -> Result<Sale, Box<EvalAltResult>> { Ok(s.notes(notes)) })
|
||||
.register_fn("set_base_id", |s: Sale, id_i64: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.set_base_id(id_from_i64(id_i64)?)) })
|
||||
// .register_fn("set_base_uuid", |s: Sale, uuid: Option<String>| -> Result<Sale, Box<EvalAltResult>> { Ok(s.set_base_uuid(uuid)) }) // UUID not in BaseModelData
|
||||
.register_fn("set_base_created_at", |s: Sale, time: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.set_base_created_at(time)) })
|
||||
.register_fn("set_base_modified_at", |s: Sale, time: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.set_base_modified_at(time)) })
|
||||
.register_fn("add_base_comment", |s: Sale, comment_id_i64: i64| -> Result<Sale, Box<EvalAltResult>> { Ok(s.add_base_comment(id_from_i64(comment_id_i64)?)) })
|
||||
.register_fn("set_base_comments", |s: Sale, comment_ids: Vec<i64>| -> Result<Sale, Box<EvalAltResult>> {
|
||||
let u32_ids = comment_ids.into_iter().map(id_from_i64).collect::<Result<Vec<u32>, _>>()?;
|
||||
Ok(s.set_base_comments(u32_ids))
|
||||
});
|
||||
|
||||
// DB functions for Product
|
||||
let captured_db_for_set_product = Arc::clone(&db);
|
||||
engine.register_fn("set_product", move |product: Product| -> Result<Product, Box<EvalAltResult>> {
|
||||
let original_id_for_error = product.get_id();
|
||||
captured_db_for_set_product.set(&product)
|
||||
.map(|(_id, updated_product)| updated_product)
|
||||
.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Product (Original ID: {}): {}", original_id_for_error, e).into(), Position::NONE))
|
||||
})
|
||||
});
|
||||
|
||||
let captured_db_for_get_prod = Arc::clone(&db);
|
||||
engine.register_fn("get_product_by_id", move |id_i64: i64| -> Result<Product, Box<EvalAltResult>> {
|
||||
let id_u32 = id_i64 as u32;
|
||||
captured_db_for_get_prod.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Product (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Product with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// DB functions for Sale
|
||||
let captured_db_for_set_sale = Arc::clone(&db);
|
||||
engine.register_fn("set_sale", move |sale: Sale| -> Result<Sale, Box<EvalAltResult>> {
|
||||
let original_id_for_error = sale.get_id();
|
||||
captured_db_for_set_sale.set(&sale)
|
||||
.map(|(_id, updated_sale)| updated_sale)
|
||||
.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Sale (Original ID: {}): {}", original_id_for_error, e).into(), Position::NONE))
|
||||
})
|
||||
});
|
||||
|
||||
let captured_db_for_get_sale = Arc::clone(&db);
|
||||
engine.register_fn("get_sale_by_id", move |id_i64: i64| -> Result<Sale, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64(id_i64)?;
|
||||
captured_db_for_get_sale.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Sale (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Sale with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// Mock DB functions for Shareholder
|
||||
let captured_db_for_set_shareholder = Arc::clone(&db);
|
||||
engine.register_fn("set_shareholder", move |shareholder: Shareholder| -> Result<Shareholder, Box<EvalAltResult>> {
|
||||
let original_id_for_error = shareholder.get_id();
|
||||
captured_db_for_set_shareholder.set(&shareholder)
|
||||
.map(|(_id, updated_shareholder)| updated_shareholder)
|
||||
.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Shareholder (Original ID: {}): {}", original_id_for_error, e).into(), Position::NONE))
|
||||
})
|
||||
});
|
||||
|
||||
let captured_db_for_get_sh = Arc::clone(&db);
|
||||
engine.register_fn("get_shareholder_by_id", move |id_i64: i64| -> Result<Shareholder, Box<EvalAltResult>> {
|
||||
let id_u32 = id_i64 as u32;
|
||||
captured_db_for_get_sh.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Shareholder (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Shareholder with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// Mock DB functions for Company
|
||||
let captured_db_for_set_company = Arc::clone(&db);
|
||||
engine.register_fn("set_company", move |company: Company| -> Result<Company, Box<EvalAltResult>> {
|
||||
let original_id_for_error = company.get_id(); // Capture ID before it's potentially changed by DB
|
||||
captured_db_for_set_company.set(&company)
|
||||
.map(|(_id, updated_company)| updated_company) // Use the model returned by db.set()
|
||||
.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Company (Original ID: {}): {}", original_id_for_error, e).into(), Position::NONE))
|
||||
})
|
||||
});
|
||||
|
||||
let captured_db_for_get = Arc::clone(&db);
|
||||
engine.register_fn("get_company_by_id", move |id_i64: i64| -> Result<Company, Box<EvalAltResult>> {
|
||||
let id_u32 = id_i64 as u32; // Assuming direct conversion is fine, or use a helper like in flow
|
||||
captured_db_for_get.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Company (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Company with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// Register the exported module globally
|
||||
let module = exported_module!(rhai_biz_module);
|
||||
engine.register_global_module(module.into());
|
||||
|
||||
// Create a new module for database operations
|
||||
let mut db_module = Module::new();
|
||||
|
||||
// Database operations will obtain fresh collection handles directly.
|
||||
|
||||
// Add database functions for Company
|
||||
let db_for_set_company = Arc::clone(&db);
|
||||
db_module.set_native_fn("set_company", move |company: Company| -> Result<INT, Box<EvalAltResult>> {
|
||||
let company_collection_set = db_for_set_company.collection::<Company>().expect("Failed to get company collection for set in closure");
|
||||
company_collection_set.set(&company)
|
||||
.map(|(id_val, _)| id_val as INT)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to save company: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_for_get_company = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_company_by_id", move |id: INT| -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let company_collection_get = db_for_get_company.collection::<Company>().expect("Failed to get company collection for get in closure");
|
||||
let id_u32 = id_from_i64_to_u32(id)?;
|
||||
company_collection_get.get_by_id(id_u32)
|
||||
.map(Dynamic::from)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get company with id {}: {:?}", id, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
// Add database functions for Shareholder
|
||||
let db_for_set_shareholder = Arc::clone(&db);
|
||||
db_module.set_native_fn("set_shareholder", move |shareholder: Shareholder| -> Result<INT, Box<EvalAltResult>> {
|
||||
let shareholder_collection_set = db_for_set_shareholder.collection::<Shareholder>().expect("Failed to get shareholder collection for set in closure");
|
||||
shareholder_collection_set.set(&shareholder)
|
||||
.map(|(id_val, _)| id_val as INT)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to save shareholder: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_for_get_shareholder = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_shareholder_by_id", move |id: INT| -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let shareholder_collection_get = db_for_get_shareholder.collection::<Shareholder>().expect("Failed to get shareholder collection for get in closure");
|
||||
let id_u32 = id_from_i64_to_u32(id)?;
|
||||
shareholder_collection_get.get_by_id(id_u32)
|
||||
.map(Dynamic::from)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get shareholder with id {}: {:?}", id, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
// Add database functions for Product
|
||||
let db_for_set_product = Arc::clone(&db);
|
||||
db_module.set_native_fn("set_product", move |product: Product| -> Result<INT, Box<EvalAltResult>> {
|
||||
let product_collection_set = db_for_set_product.collection::<Product>().expect("Failed to get product collection for set in closure");
|
||||
product_collection_set.set(&product)
|
||||
.map(|(id_val, _)| id_val as INT)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to save product: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_for_get_product = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_product_by_id", move |id: INT| -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let product_collection_get = db_for_get_product.collection::<Product>().expect("Failed to get product collection for get in closure");
|
||||
let id_u32 = id_from_i64_to_u32(id)?;
|
||||
product_collection_get.get_by_id(id_u32)
|
||||
.map(Dynamic::from)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get product with id {}: {:?}", id, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
// Add database functions for Sale
|
||||
let db_for_set_sale = Arc::clone(&db);
|
||||
db_module.set_native_fn("set_sale", move |sale: Sale| -> Result<INT, Box<EvalAltResult>> {
|
||||
let sale_collection_set = db_for_set_sale.collection::<Sale>().expect("Failed to get sale collection for set in closure");
|
||||
sale_collection_set.set(&sale)
|
||||
.map(|(id_val, _)| id_val as INT)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to save sale: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_for_get_sale = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_sale_by_id", move |id: INT| -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let sale_collection_get = db_for_get_sale.collection::<Sale>().expect("Failed to get sale collection for get in closure");
|
||||
let id_u32 = id_from_i64_to_u32(id)?;
|
||||
sale_collection_get.get_by_id(id_u32)
|
||||
.map(Dynamic::from)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get sale with id {}: {:?}", id, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
// Register the database module globally
|
||||
engine.register_global_module(db_module.into());
|
||||
|
||||
println!("Successfully registered biz Rhai module using export_module approach.");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use heromodels_core::{BaseModelData, Model};
|
||||
use heromodels_core::{BaseModelData, Model, BaseModelDataOps};
|
||||
|
||||
/// Represents the status of a sale.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@ -16,7 +16,7 @@ impl Default for SaleStatus {
|
||||
}
|
||||
|
||||
/// Represents an individual item within a Sale.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct SaleItem {
|
||||
pub product_id: u32,
|
||||
pub name: String, // Denormalized product name at time of sale
|
||||
@ -27,14 +27,14 @@ pub struct SaleItem {
|
||||
}
|
||||
|
||||
impl SaleItem {
|
||||
/// Creates a new `SaleItem`.
|
||||
pub fn new(product_id: u32, name: String, quantity: i32, unit_price: f64, subtotal: f64) -> Self {
|
||||
/// Creates a new `SaleItem` with default values.
|
||||
pub fn new() -> Self {
|
||||
SaleItem {
|
||||
product_id,
|
||||
name,
|
||||
quantity,
|
||||
unit_price,
|
||||
subtotal,
|
||||
product_id: 0,
|
||||
name: String::new(),
|
||||
quantity: 0,
|
||||
unit_price: 0.0,
|
||||
subtotal: 0.0,
|
||||
service_active_until: None,
|
||||
}
|
||||
}
|
||||
@ -45,8 +45,8 @@ impl SaleItem {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -72,12 +72,12 @@ impl SaleItem {
|
||||
}
|
||||
|
||||
/// Represents a sale of products or services.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct Sale {
|
||||
pub base_data: BaseModelData,
|
||||
pub company_id: u32,
|
||||
pub buyer_name: String,
|
||||
pub buyer_email: String,
|
||||
pub buyer_id: u32,
|
||||
pub transaction_id: u32,
|
||||
pub total_amount: f64,
|
||||
pub status: SaleStatus,
|
||||
pub sale_date: i64,
|
||||
@ -99,24 +99,23 @@ impl Model for Sale {
|
||||
}
|
||||
}
|
||||
|
||||
impl BaseModelDataOps for Sale {
|
||||
fn get_base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
}
|
||||
|
||||
impl Sale {
|
||||
/// Creates a new `Sale`.
|
||||
pub fn new(
|
||||
company_id: u32,
|
||||
buyer_name: String,
|
||||
buyer_email: String,
|
||||
total_amount: f64,
|
||||
status: SaleStatus,
|
||||
sale_date: i64,
|
||||
) -> Self {
|
||||
/// Creates a new `Sale` with default values.
|
||||
pub fn new() -> Self {
|
||||
Sale {
|
||||
base_data: BaseModelData::new(),
|
||||
company_id,
|
||||
buyer_name,
|
||||
buyer_email,
|
||||
total_amount,
|
||||
status,
|
||||
sale_date,
|
||||
company_id: 0,
|
||||
buyer_id: 0,
|
||||
transaction_id: 0,
|
||||
total_amount: 0.0,
|
||||
status: SaleStatus::default(),
|
||||
sale_date: 0,
|
||||
items: Vec::new(),
|
||||
notes: String::new(),
|
||||
}
|
||||
@ -128,13 +127,13 @@ impl Sale {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn buyer_name(mut self, buyer_name: String) -> Self {
|
||||
self.buyer_name = buyer_name;
|
||||
pub fn buyer_id(mut self, buyer_id: u32) -> Self {
|
||||
self.buyer_id = buyer_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn buyer_email(mut self, buyer_email: String) -> Self {
|
||||
self.buyer_email = buyer_email;
|
||||
pub fn transaction_id(mut self, transaction_id: u32) -> Self {
|
||||
self.transaction_id = transaction_id;
|
||||
self
|
||||
}
|
||||
|
||||
@ -163,40 +162,10 @@ impl Sale {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn notes(mut self, notes: String) -> Self {
|
||||
self.notes = notes;
|
||||
pub fn notes(mut self, notes: impl ToString) -> Self {
|
||||
self.notes = notes.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// Builder methods for BaseModelData fields, prefixed with base_
|
||||
pub fn set_base_id(mut self, id: u32) -> Self {
|
||||
self.base_data.id = id;
|
||||
self
|
||||
}
|
||||
|
||||
// UUID is not part of BaseModelData directly in heromodels_core
|
||||
// pub fn set_base_uuid(mut self, uuid: Option<String>) -> Self {
|
||||
// self.base_data.uuid = uuid; // Assuming uuid field exists if needed elsewhere
|
||||
// self
|
||||
// }
|
||||
|
||||
pub fn set_base_created_at(mut self, created_at: i64) -> Self {
|
||||
self.base_data.created_at = created_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_modified_at(mut self, modified_at: i64) -> Self {
|
||||
self.base_data.modified_at = modified_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_base_comment(mut self, comment_id: u32) -> Self {
|
||||
self.base_data.comments.push(comment_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_comments(mut self, comments: Vec<u32>) -> Self {
|
||||
self.base_data.comments = comments;
|
||||
self
|
||||
}
|
||||
// BaseModelData operations are now handled by BaseModelDataOps trait
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use heromodels_core::{BaseModelData, Model};
|
||||
use heromodels_core::{BaseModelData, Model, BaseModelDataOps};
|
||||
use heromodels_derive::model;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ShareholderType {
|
||||
@ -13,7 +14,8 @@ impl Default for ShareholderType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[model]
|
||||
pub struct Shareholder {
|
||||
pub base_data: BaseModelData,
|
||||
pub company_id: u32,
|
||||
@ -50,8 +52,8 @@ impl Shareholder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@ -75,28 +77,5 @@ impl Shareholder {
|
||||
self
|
||||
}
|
||||
|
||||
// Base data setters if needed for Rhai or specific scenarios
|
||||
pub fn set_base_created_at(mut self, created_at: i64) -> Self {
|
||||
self.base_data.created_at = created_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_modified_at(mut self, modified_at: i64) -> Self {
|
||||
self.base_data.modified_at = modified_at;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Model for Shareholder {
|
||||
fn db_prefix() -> &'static str {
|
||||
"shareholder"
|
||||
}
|
||||
|
||||
fn get_id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
}
|
||||
// Base data operations are now handled by BaseModelDataOps trait
|
||||
}
|
@ -1,21 +1,46 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use rhai_autobind_macros::rhai_model_export;
|
||||
// Temporarily removed to fix compilation issues
|
||||
// use rhai_autobind_macros::rhai_model_export;
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents the status of an attendee for an event
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub enum AttendanceStatus {
|
||||
Accepted,
|
||||
Declined,
|
||||
Tentative,
|
||||
#[default]
|
||||
NoResponse,
|
||||
}
|
||||
|
||||
impl AttendanceStatus {
|
||||
/// Convert a string to an AttendanceStatus
|
||||
pub fn from_string(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"Accepted" => Ok(AttendanceStatus::Accepted),
|
||||
"Declined" => Ok(AttendanceStatus::Declined),
|
||||
"Tentative" => Ok(AttendanceStatus::Tentative),
|
||||
"NoResponse" => Ok(AttendanceStatus::NoResponse),
|
||||
_ => Err(format!("Invalid attendance status: '{}'", s)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an AttendanceStatus to a string
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
AttendanceStatus::Accepted => "Accepted".to_string(),
|
||||
AttendanceStatus::Declined => "Declined".to_string(),
|
||||
AttendanceStatus::Tentative => "Tentative".to_string(),
|
||||
AttendanceStatus::NoResponse => "NoResponse".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an attendee of an event
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)]
|
||||
pub struct Attendee {
|
||||
/// ID of the user attending
|
||||
// Assuming user_id might be queryable
|
||||
@ -39,34 +64,51 @@ impl Attendee {
|
||||
}
|
||||
|
||||
/// Represents an event in a calendar
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
pub struct Event {
|
||||
/// Base model data
|
||||
#[serde(flatten)]
|
||||
pub base_data: BaseModelData,
|
||||
/// Title of the event
|
||||
#[index]
|
||||
pub title: String,
|
||||
/// Optional description of the event
|
||||
pub description: Option<String>,
|
||||
/// Start time of the event
|
||||
pub start_time: DateTime<Utc>,
|
||||
/// End time of the event
|
||||
pub end_time: DateTime<Utc>,
|
||||
/// Start time of the event (Unix timestamp)
|
||||
pub start_time: i64,
|
||||
/// End time of the event (Unix timestamp)
|
||||
pub end_time: i64,
|
||||
/// List of attendees for the event
|
||||
pub attendees: Vec<Attendee>,
|
||||
/// Optional location of the event
|
||||
pub location: Option<String>,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
/// Creates a new event
|
||||
pub fn new(title: impl ToString, start_time: DateTime<Utc>, end_time: DateTime<Utc>) -> Self {
|
||||
impl Default for Event {
|
||||
fn default() -> Self {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
title: title.to_string(),
|
||||
title: String::new(),
|
||||
description: None,
|
||||
start_time,
|
||||
end_time,
|
||||
start_time: now,
|
||||
end_time: now + 3600, // Add 1 hour in seconds
|
||||
attendees: Vec::new(),
|
||||
location: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Event {
|
||||
/// Creates a new event
|
||||
pub fn new() -> Self {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
title: String::new(),
|
||||
description: None,
|
||||
start_time: now,
|
||||
end_time: now + 3600, // Add 1 hour in seconds
|
||||
attendees: Vec::new(),
|
||||
location: None,
|
||||
}
|
||||
@ -116,8 +158,8 @@ impl Event {
|
||||
/// Reschedules the event to new start and end times
|
||||
pub fn reschedule(
|
||||
mut self,
|
||||
new_start_time: DateTime<Utc>,
|
||||
new_end_time: DateTime<Utc>,
|
||||
new_start_time: i64,
|
||||
new_end_time: i64,
|
||||
) -> Self {
|
||||
// Basic validation: end_time should be after start_time
|
||||
if new_end_time > new_start_time {
|
||||
@ -130,17 +172,18 @@ impl Event {
|
||||
}
|
||||
|
||||
/// Represents a calendar with events
|
||||
#[rhai_model_export(
|
||||
db_type = "std::sync::Arc<crate::db::hero::OurDB>",
|
||||
)]
|
||||
// Temporarily removed rhai_model_export macro to fix compilation issues
|
||||
// #[rhai_model_export(
|
||||
// db_type = "std::sync::Arc<crate::db::hero::OurDB>",
|
||||
// )]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
pub struct Calendar {
|
||||
/// Base model data
|
||||
#[serde(flatten)]
|
||||
pub base_data: BaseModelData,
|
||||
|
||||
/// Name of the calendar
|
||||
#[index]
|
||||
pub name: String,
|
||||
|
||||
/// Optional description of the calendar
|
||||
|
@ -4,4 +4,4 @@ pub mod rhai;
|
||||
|
||||
// Re-export Calendar, Event, Attendee, and AttendanceStatus from the inner calendar module (calendar.rs) within src/models/calendar/mod.rs
|
||||
pub use self::calendar::{Calendar, Event, Attendee, AttendanceStatus};
|
||||
pub use rhai::register_rhai_engine_functions as register_calendar_rhai_module;
|
||||
pub use rhai::register_calendar_rhai_module;
|
||||
|
@ -1,90 +1,362 @@
|
||||
use rhai::{Engine, EvalAltResult, NativeCallContext, ImmutableString};
|
||||
use rhai::plugin::*;
|
||||
use rhai::{Engine, EvalAltResult, Position, Module, INT, Dynamic, Array};
|
||||
use std::sync::Arc;
|
||||
use std::mem;
|
||||
use chrono::{DateTime, Utc};
|
||||
use crate::db::Db;
|
||||
|
||||
use heromodels_core::BaseModelData;
|
||||
use super::calendar::{Event, Attendee, Calendar, AttendanceStatus};
|
||||
type RhaiEvent = Event;
|
||||
type RhaiAttendee = Attendee;
|
||||
type RhaiCalendar = Calendar;
|
||||
use crate::db::hero::OurDB;
|
||||
use super::calendar::{Calendar, Event, Attendee, AttendanceStatus};
|
||||
use adapter_macros::{adapt_rhai_i64_input_fn, adapt_rhai_i64_input_method};
|
||||
use adapter_macros::rhai_timestamp_helpers;
|
||||
use crate::db::Collection;
|
||||
|
||||
// Helper function for get_all_calendars registration
|
||||
|
||||
|
||||
fn new_calendar_rhai(name: String) -> Result<Calendar, Box<EvalAltResult>> {
|
||||
Ok(Calendar::new(None, name))
|
||||
// Helper to convert i64 from Rhai to u32 for IDs
|
||||
fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(id_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Failed to convert ID '{}' to u32", id_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
fn new_event_rhai(
|
||||
context: NativeCallContext,
|
||||
title_rhai: ImmutableString,
|
||||
start_time_ts: i64,
|
||||
end_time_ts: i64,
|
||||
) -> Result<Event, Box<EvalAltResult>> {
|
||||
let start_time = rhai_timestamp_helpers::rhai_timestamp_to_datetime(start_time_ts)
|
||||
.map_err(|e_str| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to convert start_time for Event: {}", e_str).into(),
|
||||
context.position(),
|
||||
)))?;
|
||||
|
||||
let end_time = rhai_timestamp_helpers::rhai_timestamp_to_datetime(end_time_ts)
|
||||
.map_err(|e_str| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to convert end_time for Event: {}", e_str).into(),
|
||||
context.position(),
|
||||
)))?;
|
||||
|
||||
Ok(Event::new(title_rhai.to_string(), start_time, end_time))
|
||||
// Helper to convert i64 from Rhai to u64 for timestamps or other large numbers
|
||||
fn val_from_i64_to_u64(val_i64: i64) -> Result<u64, Box<EvalAltResult>> {
|
||||
u64::try_from(val_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Failed to convert value '{}' to u64", val_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub fn register_rhai_engine_functions(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
engine.register_fn("name", move |calendar: Calendar, name: String| Calendar::name(calendar, name));
|
||||
engine.register_fn("description", move |calendar: Calendar, description: String| Calendar::description(calendar, description));
|
||||
engine.register_fn("add_event", Calendar::add_event);
|
||||
// Note: Event IDs are i64 in Calendar.events, but Event model's base_data.id is u32.
|
||||
// This might require adjustment if events are fetched by ID from the DB via Calendar.events.
|
||||
#[export_module]
|
||||
mod rhai_calendar_module {
|
||||
// --- Event Functions ---
|
||||
#[rhai_fn(name = "new_event")]
|
||||
pub fn new_event() -> RhaiEvent {
|
||||
Event::new()
|
||||
}
|
||||
|
||||
engine.register_fn("new_event", |context: NativeCallContext, title_rhai: ImmutableString, start_time_ts: i64, end_time_ts: i64| -> Result<Event, Box<EvalAltResult>> {
|
||||
new_event_rhai(context, title_rhai, start_time_ts, end_time_ts)
|
||||
});
|
||||
engine.register_fn("title", move |event: Event, title: String| Event::title(event, title));
|
||||
engine.register_fn("description", move |event: Event, description: String| Event::description(event, description));
|
||||
engine.register_fn("add_attendee", move |event: Event, attendee: Attendee| Event::add_attendee(event, attendee));
|
||||
engine.register_fn("remove_attendee", adapt_rhai_i64_input_method!(Event, remove_attendee, u32));
|
||||
engine.register_fn("update_attendee_status", move |context: NativeCallContext, event: Event, contact_id_i64: i64, status: AttendanceStatus| -> Result<Event, Box<EvalAltResult>> {
|
||||
let contact_id_u32: u32 = contact_id_i64.try_into().map_err(|_e| {
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Conversion error for contact_id in Event::update_attendee_status from i64 to u32"),
|
||||
context.position(),
|
||||
))
|
||||
})?;
|
||||
Ok(event.update_attendee_status(contact_id_u32, status))
|
||||
});
|
||||
|
||||
engine.register_fn("new_attendee", adapt_rhai_i64_input_fn!(Attendee::new, u32));
|
||||
|
||||
engine.register_fn("new_calendar", |name: String| -> Result<Calendar, Box<EvalAltResult>> { new_calendar_rhai(name) });
|
||||
|
||||
// Register a function to get the database instance
|
||||
engine.register_fn("get_db", move || db.clone());
|
||||
/// Sets the event title
|
||||
#[rhai_fn(name = "title", return_raw, global, pure)]
|
||||
pub fn event_title(event: &mut RhaiEvent, title: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.title(title);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
// Register getters for Calendar
|
||||
engine.register_get("id", |c: &mut Calendar| -> Result<i64, Box<EvalAltResult>> { Ok(c.base_data.id as i64) });
|
||||
engine.register_get("name", |c: &mut Calendar| -> Result<String, Box<EvalAltResult>> {
|
||||
// println!("Rhai attempting to get Calendar.name: {}", c.name); // Debug print
|
||||
Ok(c.name.clone())
|
||||
});
|
||||
engine.register_get("description", |c: &mut Calendar| -> Result<Option<String>, Box<EvalAltResult>> { Ok(c.description.clone()) });
|
||||
/// Sets the event description
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn event_description(event: &mut RhaiEvent, description: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.description(description);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
/// Sets the event location
|
||||
#[rhai_fn(name = "location", return_raw, global, pure)]
|
||||
pub fn event_location(event: &mut RhaiEvent, location: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.location(location);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
// Register getter for Calendar.base_data
|
||||
engine.register_get("base_data", |c: &mut Calendar| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(c.base_data.clone()) });
|
||||
/// Adds an attendee to the event
|
||||
#[rhai_fn(name = "add_attendee", return_raw, global, pure)]
|
||||
pub fn event_add_attendee(event: &mut RhaiEvent, attendee: RhaiAttendee) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
// Use take to get ownership of the event
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.add_attendee(attendee);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
// Register getters for BaseModelData
|
||||
engine.register_get("id", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.id.into()) });
|
||||
/// Reschedules the event with new start and end times
|
||||
#[rhai_fn(name = "reschedule", return_raw, global, pure)]
|
||||
pub fn event_reschedule(event: &mut RhaiEvent, new_start_time: i64, new_end_time: i64) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
// Validate timestamps
|
||||
if new_end_time <= new_start_time {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"End time must be after start time".into(),
|
||||
Position::NONE
|
||||
)));
|
||||
}
|
||||
|
||||
// Use take to get ownership of the event
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.reschedule(new_start_time, new_end_time);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
/// Updates an attendee's status in the event
|
||||
#[rhai_fn(name = "update_attendee_status", return_raw, global, pure)]
|
||||
pub fn event_update_attendee_status(event: &mut RhaiEvent, contact_id: i64, status_str: String) -> Result<RhaiEvent, Box<EvalAltResult>> {
|
||||
let status_enum = AttendanceStatus::from_string(&status_str)
|
||||
.map_err(|_| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Invalid attendance status: '{}'. Expected one of: Pending, Accepted, Declined, Tentative", status_str).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
|
||||
// Use take to get ownership of the event
|
||||
let owned_event = mem::take(event);
|
||||
*event = owned_event.update_attendee_status(id_from_i64_to_u32(contact_id)?, status_enum);
|
||||
Ok(event.clone())
|
||||
}
|
||||
|
||||
// Database interaction functions for Calendar are expected to be provided by #[rhai_model_export(..)] on the Calendar struct.
|
||||
// Ensure that `db.rs` or similar correctly wires up the `OurDB` methods for these.
|
||||
// Event Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_event_id(event: &mut RhaiEvent) -> i64 { event.base_data.id as i64 }
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_event_created_at(event: &mut RhaiEvent) -> i64 { event.base_data.created_at }
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_event_modified_at(event: &mut RhaiEvent) -> i64 { event.base_data.modified_at }
|
||||
|
||||
#[rhai_fn(get = "title", pure)]
|
||||
pub fn get_event_title(event: &mut RhaiEvent) -> String { event.title.clone() }
|
||||
#[rhai_fn(get = "description", pure)]
|
||||
pub fn get_event_description(event: &mut RhaiEvent) -> Option<String> { event.description.clone() }
|
||||
#[rhai_fn(get = "start_time", pure)]
|
||||
pub fn get_event_start_time(event: &mut RhaiEvent) -> i64 { event.start_time }
|
||||
#[rhai_fn(get = "end_time", pure)]
|
||||
pub fn get_event_end_time(event: &mut RhaiEvent) -> i64 { event.end_time }
|
||||
#[rhai_fn(get = "location", pure)]
|
||||
pub fn get_event_location(event: &mut RhaiEvent) -> Option<String> { event.location.clone() }
|
||||
#[rhai_fn(get = "attendees", pure)]
|
||||
pub fn get_event_attendees(event: &mut RhaiEvent) -> Vec<RhaiAttendee> { event.attendees.clone() }
|
||||
|
||||
// --- Attendee Functions ---
|
||||
#[rhai_fn(name = "new_attendee")]
|
||||
pub fn new_attendee() -> RhaiAttendee {
|
||||
Attendee::new(0) // Default contact_id, will be set via builder
|
||||
}
|
||||
|
||||
/// Sets the contact ID for an attendee
|
||||
#[rhai_fn(name = "with_contact_id", return_raw, global, pure)]
|
||||
pub fn attendee_with_contact_id(attendee: &mut RhaiAttendee, contact_id: i64) -> Result<RhaiAttendee, Box<EvalAltResult>> {
|
||||
let new_contact_id = id_from_i64_to_u32(contact_id).unwrap_or(0);
|
||||
let owned_attendee = mem::replace(attendee, Attendee::new(0));
|
||||
*attendee = Attendee::new(new_contact_id);
|
||||
attendee.status = owned_attendee.status;
|
||||
Ok(attendee.clone())
|
||||
}
|
||||
|
||||
/// Sets the status for an attendee
|
||||
#[rhai_fn(name = "with_status", return_raw, global, pure)]
|
||||
pub fn attendee_with_status(attendee: &mut RhaiAttendee, status_str: String) -> Result<RhaiAttendee, Box<EvalAltResult>> {
|
||||
let status_enum = AttendanceStatus::from_string(&status_str)
|
||||
.map_err(|_| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Invalid attendance status: '{}'. Expected one of: Accepted, Declined, Tentative, NoResponse", status_str).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
|
||||
let owned_attendee = mem::replace(attendee, Attendee::new(0));
|
||||
*attendee = owned_attendee.status(status_enum);
|
||||
Ok(attendee.clone())
|
||||
}
|
||||
|
||||
// We now use with_status instead of update_attendee_status for consistency
|
||||
|
||||
// Attendee Getters
|
||||
#[rhai_fn(get = "contact_id", pure)]
|
||||
pub fn get_attendee_contact_id(attendee: &mut RhaiAttendee) -> i64 { attendee.contact_id as i64 }
|
||||
#[rhai_fn(get = "status", pure)]
|
||||
pub fn get_attendee_status(attendee: &mut RhaiAttendee) -> String { attendee.status.to_string() }
|
||||
|
||||
// --- Calendar Functions ---
|
||||
#[rhai_fn(name = "new_calendar", return_raw)]
|
||||
pub fn new_calendar() -> Result<RhaiCalendar, Box<EvalAltResult>> {
|
||||
let calendar = Calendar::new(None, "");
|
||||
Ok(calendar)
|
||||
}
|
||||
|
||||
/// Sets the calendar name
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn calendar_name(calendar: &mut RhaiCalendar, name: String) -> Result<RhaiCalendar, Box<EvalAltResult>> {
|
||||
// Create a default Calendar to replace the taken one
|
||||
let default_calendar = Calendar::new(None, "");
|
||||
|
||||
// Take ownership of the calendar, apply the builder method, then put it back
|
||||
let owned_calendar = std::mem::replace(calendar, default_calendar);
|
||||
*calendar = Calendar::new(Some(owned_calendar.base_data.id), name);
|
||||
Ok(calendar.clone())
|
||||
}
|
||||
|
||||
/// Sets the calendar description
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn calendar_description(calendar: &mut RhaiCalendar, description: String) -> Result<RhaiCalendar, Box<EvalAltResult>> {
|
||||
// Create a default Calendar to replace the taken one
|
||||
let default_calendar = Calendar::new(None, "");
|
||||
|
||||
// Take ownership of the calendar, apply the builder method, then put it back
|
||||
let owned_calendar = std::mem::replace(calendar, default_calendar);
|
||||
let updated_calendar = owned_calendar.description(description);
|
||||
*calendar = updated_calendar.clone();
|
||||
Ok(updated_calendar)
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "add_event_to_calendar", return_raw, global, pure)]
|
||||
pub fn calendar_add_event(calendar: &mut RhaiCalendar, event: RhaiEvent) -> Result<RhaiCalendar, Box<EvalAltResult>> {
|
||||
// Create a default Calendar to replace the taken one
|
||||
let default_calendar = Calendar::new(None, "");
|
||||
|
||||
// Take ownership of the calendar, apply the builder method, then put it back
|
||||
let owned_calendar = std::mem::replace(calendar, default_calendar);
|
||||
*calendar = owned_calendar.add_event(event.base_data.id as i64);
|
||||
Ok(calendar.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "remove_event_from_calendar", return_raw)]
|
||||
pub fn calendar_remove_event(calendar: &mut RhaiCalendar, event_id: i64) -> Result<(), Box<EvalAltResult>> {
|
||||
// Create a default Calendar to replace the taken one
|
||||
let default_calendar = Calendar::new(None, "");
|
||||
|
||||
// Take ownership of the calendar, apply the builder method, then put it back
|
||||
let owned_calendar = std::mem::replace(calendar, default_calendar);
|
||||
*calendar = owned_calendar.remove_event(id_from_i64_to_u32(event_id)? as i64);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Calendar Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_calendar_id(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.id as i64 }
|
||||
|
||||
#[rhai_fn(get = "name", pure)]
|
||||
pub fn get_calendar_name(calendar: &mut RhaiCalendar) -> String { calendar.name.clone() }
|
||||
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_calendar_created_at(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.created_at }
|
||||
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_calendar_modified_at(calendar: &mut RhaiCalendar) -> i64 { calendar.base_data.modified_at }
|
||||
|
||||
#[rhai_fn(get = "events", pure)]
|
||||
pub fn get_calendar_events(calendar: &mut RhaiCalendar) -> Vec<i64> { calendar.events.clone() }
|
||||
|
||||
#[rhai_fn(get = "description", pure)]
|
||||
pub fn get_calendar_description(calendar: &mut RhaiCalendar) -> Option<String> { calendar.description.clone() }
|
||||
|
||||
// Calendar doesn't have an owner_id field in the current implementation
|
||||
// pub fn get_calendar_owner_id(calendar: &mut RhaiCalendar) -> i64 { calendar.owner_id as i64 }
|
||||
|
||||
// Getters for Event
|
||||
engine.register_get("id", |e: &mut Event| -> Result<i64, Box<EvalAltResult>> { Ok(e.base_data.id as i64) });
|
||||
engine.register_get("title", |e: &mut Event| -> Result<String, Box<EvalAltResult>> { Ok(e.title.clone()) });
|
||||
// Add more getters for Event fields as needed
|
||||
}
|
||||
|
||||
pub fn register_calendar_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
// Register the exported module globally
|
||||
let module = exported_module!(rhai_calendar_module);
|
||||
engine.register_global_module(module.into());
|
||||
|
||||
// Create a module for database functions
|
||||
let mut db_module = Module::new();
|
||||
|
||||
// Manually register database functions as they need to capture 'db'
|
||||
let db_clone_set_event = db.clone();
|
||||
db_module.set_native_fn("save_event", move |event: Event| -> Result<Event, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_set_event.set(&event)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error set_event: {}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated event with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
// Manually register database functions as they need to capture 'db'
|
||||
let db_clone_delete_event = db.clone();
|
||||
db_module.set_native_fn("delete_event", move |event: Event| -> Result<(), Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_delete_event.collection::<Event>()
|
||||
.expect("can open event collection")
|
||||
.delete_by_id(event.base_data.id)
|
||||
.expect("can delete event");
|
||||
|
||||
// Return the updated event with the correct ID
|
||||
Ok(result)
|
||||
});
|
||||
|
||||
let db_clone_get_event = db.clone();
|
||||
db_module.set_native_fn("get_event_by_id", move |id_i64: INT| -> Result<Event, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone_get_event.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_event_by_id: {}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Event with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
let db_clone_set_calendar = db.clone();
|
||||
db_module.set_native_fn("save_calendar", move |calendar: Calendar| -> Result<Calendar, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_set_calendar.set(&calendar)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error set_calendar: {}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated calendar with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
// Manually register database functions as they need to capture 'db'
|
||||
let db_clone_delete_calendar = db.clone();
|
||||
db_module.set_native_fn("delete_calendar", move |calendar: Calendar| -> Result<(), Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_delete_calendar.collection::<Calendar>()
|
||||
.expect("can open calendar collection")
|
||||
.delete_by_id(calendar.base_data.id)
|
||||
.expect("can delete event");
|
||||
|
||||
// Return the updated event with the correct ID
|
||||
Ok(result)
|
||||
});
|
||||
|
||||
let db_clone_get_calendar = db.clone();
|
||||
db_module.set_native_fn("get_calendar_by_id", move |id_i64: INT| -> Result<Calendar, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone_get_calendar.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_calendar_by_id: {}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Calendar with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// Add list_calendars function to get all calendars
|
||||
let db_clone_list_calendars = db.clone();
|
||||
db_module.set_native_fn("list_calendars", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone_list_calendars.collection::<Calendar>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get calendar collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let calendars = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all calendars: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for calendar in calendars {
|
||||
array.push(Dynamic::from(calendar));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
// Add list_events function to get all events
|
||||
let db_clone_list_events = db.clone();
|
||||
db_module.set_native_fn("list_events", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone_list_events.collection::<Event>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get event collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let events = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all events: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for event in events {
|
||||
array.push(Dynamic::from(event));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
// Register the database module globally
|
||||
engine.register_global_module(db_module.into());
|
||||
|
||||
println!("Successfully registered calendar Rhai module using export_module approach.");
|
||||
}
|
||||
|
@ -1,36 +1,43 @@
|
||||
// heromodels/src/models/core/comment.rs
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents a comment on a model
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)] // Added PartialEq
|
||||
#[model]
|
||||
pub struct Comment {
|
||||
pub base_data: BaseModelData,
|
||||
pub base_data: BaseModelData, // Provides id, created_at, updated_at
|
||||
#[index]
|
||||
pub user_id: u32,
|
||||
pub content: String,
|
||||
pub user_id: u32, // Maps to commenter_id
|
||||
pub content: String, // Maps to text
|
||||
pub parent_comment_id: Option<u32>, // For threaded comments
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
/// Create a new comment with auto-generated ID
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
user_id: 0,
|
||||
user_id: 0, // Default, should be set via builder or method
|
||||
content: String::new(),
|
||||
parent_comment_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user ID
|
||||
// Builder method for user_id
|
||||
pub fn user_id(mut self, id: u32) -> Self {
|
||||
self.user_id = id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the content
|
||||
// Builder method for content
|
||||
pub fn content(mut self, content: impl ToString) -> Self {
|
||||
self.content = content.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// Builder method for parent_comment_id
|
||||
pub fn parent_comment_id(mut self, parent_id: Option<u32>) -> Self {
|
||||
self.parent_comment_id = parent_id;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use heromodels_core::BaseModelData;
|
||||
use super::asset::Asset;
|
||||
|
||||
/// Account represents a financial account owned by a user
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType, Default)]
|
||||
#[model] // Has base.Base in V spec
|
||||
pub struct Account {
|
||||
pub base_data: BaseModelData,
|
||||
@ -18,82 +18,75 @@ pub struct Account {
|
||||
pub ledger: String, // describes the ledger/blockchain where the account is located
|
||||
pub address: String, // address of the account on the blockchain
|
||||
pub pubkey: String, // public key
|
||||
pub assets: Vec<Asset>, // list of assets in this account
|
||||
pub assets: Vec<u32>, // list of assets in this account
|
||||
}
|
||||
|
||||
impl Account {
|
||||
/// Create a new account with auto-generated ID
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `id` - Optional ID for the account (use None for auto-generated ID)
|
||||
/// * `name` - Name of the account
|
||||
/// * `user_id` - ID of the user who owns the account
|
||||
/// * `description` - Description of the account
|
||||
/// * `ledger` - Ledger/blockchain where the account is located
|
||||
/// * `address` - Address of the account on the blockchain
|
||||
/// * `pubkey` - Public key
|
||||
pub fn new(
|
||||
id: Option<u32>,
|
||||
name: impl ToString,
|
||||
user_id: u32,
|
||||
description: impl ToString,
|
||||
ledger: impl ToString,
|
||||
address: impl ToString,
|
||||
pubkey: impl ToString,
|
||||
) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
if let Some(id) = id {
|
||||
base_data.update_id(id);
|
||||
}
|
||||
|
||||
/// Create a new account with default values
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base_data,
|
||||
name: name.to_string(),
|
||||
user_id,
|
||||
description: description.to_string(),
|
||||
ledger: ledger.to_string(),
|
||||
address: address.to_string(),
|
||||
pubkey: pubkey.to_string(),
|
||||
base_data: BaseModelData::new(),
|
||||
name: String::new(),
|
||||
user_id: 0,
|
||||
description: String::new(),
|
||||
ledger: String::new(),
|
||||
address: String::new(),
|
||||
pubkey: String::new(),
|
||||
assets: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the name of the account
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the user ID of the account owner
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the description of the account
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the ledger/blockchain where the account is located
|
||||
pub fn ledger(mut self, ledger: impl ToString) -> Self {
|
||||
self.ledger = ledger.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the address of the account on the blockchain
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the public key of the account
|
||||
pub fn pubkey(mut self, pubkey: impl ToString) -> Self {
|
||||
self.pubkey = pubkey.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an asset to the account
|
||||
pub fn add_asset(mut self, asset: Asset) -> Self {
|
||||
self.assets.push(asset);
|
||||
pub fn add_asset(mut self, asset_id: u32) -> Self {
|
||||
self.assets.push(asset_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the total value of all assets in the account
|
||||
pub fn total_value(&self) -> f64 {
|
||||
self.assets.iter().map(|asset| asset.amount).sum()
|
||||
/// TODO: implement
|
||||
0.0
|
||||
}
|
||||
|
||||
/// Find an asset by name
|
||||
pub fn find_asset_by_name(&self, name: &str) -> Option<&Asset> {
|
||||
self.assets.iter().find(|asset| asset.name == name)
|
||||
}
|
||||
|
||||
/// Update the account details
|
||||
pub fn update_details(
|
||||
mut self,
|
||||
name: Option<impl ToString>,
|
||||
description: Option<impl ToString>,
|
||||
address: Option<impl ToString>,
|
||||
pubkey: Option<impl ToString>,
|
||||
) -> Self {
|
||||
if let Some(name) = name {
|
||||
self.name = name.to_string();
|
||||
}
|
||||
if let Some(description) = description {
|
||||
self.description = description.to_string();
|
||||
}
|
||||
if let Some(address) = address {
|
||||
self.address = address.to_string();
|
||||
}
|
||||
if let Some(pubkey) = pubkey {
|
||||
self.pubkey = pubkey.to_string();
|
||||
}
|
||||
self
|
||||
/// TODO: implement
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ impl Default for AssetType {
|
||||
}
|
||||
|
||||
/// Asset represents a digital asset or token
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType, Default)]
|
||||
#[model] // Has base.Base in V spec
|
||||
pub struct Asset {
|
||||
pub base_data: BaseModelData,
|
||||
@ -34,47 +34,55 @@ pub struct Asset {
|
||||
}
|
||||
|
||||
impl Asset {
|
||||
/// Create a new asset with auto-generated ID
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `id` - Optional ID for the asset (use None for auto-generated ID)
|
||||
/// * `name` - Name of the asset
|
||||
/// * `description` - Description of the asset
|
||||
/// * `amount` - Amount of the asset
|
||||
/// * `address` - Address of the asset on the blockchain or bank
|
||||
/// * `asset_type` - Type of the asset
|
||||
/// * `decimals` - Number of decimals of the asset
|
||||
pub fn new(
|
||||
id: Option<u32>,
|
||||
name: impl ToString,
|
||||
description: impl ToString,
|
||||
amount: f64,
|
||||
address: impl ToString,
|
||||
asset_type: AssetType,
|
||||
decimals: u8,
|
||||
) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
if let Some(id) = id {
|
||||
base_data.update_id(id);
|
||||
}
|
||||
|
||||
/// Create a new asset with default values
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base_data,
|
||||
name: name.to_string(),
|
||||
description: description.to_string(),
|
||||
amount,
|
||||
address: address.to_string(),
|
||||
asset_type,
|
||||
decimals,
|
||||
base_data: BaseModelData::new(),
|
||||
name: String::new(),
|
||||
description: String::new(),
|
||||
amount: 0.0,
|
||||
address: String::new(),
|
||||
asset_type: AssetType::default(),
|
||||
decimals: 18, // Default for most tokens
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the asset amount
|
||||
pub fn update_amount(mut self, amount: f64) -> Self {
|
||||
/// Set the name of the asset
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the description of the asset
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the amount of the asset
|
||||
pub fn amount(mut self, amount: f64) -> Self {
|
||||
self.amount = amount;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the address of the asset on the blockchain
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the type of the asset
|
||||
pub fn asset_type(mut self, asset_type: AssetType) -> Self {
|
||||
self.asset_type = asset_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the number of decimals of the asset
|
||||
pub fn decimals(mut self, decimals: u8) -> Self {
|
||||
self.decimals = decimals;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the formatted amount with proper decimal places
|
||||
pub fn formatted_amount(&self) -> String {
|
||||
let factor = 10_f64.powi(self.decimals as i32);
|
||||
|
@ -54,6 +54,7 @@ impl Default for BidStatus {
|
||||
|
||||
/// Bid represents a bid on an auction listing
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[derive(Default)]
|
||||
pub struct Bid {
|
||||
pub listing_id: String, // ID of the listing this bid belongs to
|
||||
pub bidder_id: u32, // ID of the user who placed the bid
|
||||
@ -64,32 +65,44 @@ pub struct Bid {
|
||||
}
|
||||
|
||||
impl Bid {
|
||||
/// Create a new bid
|
||||
pub fn new(
|
||||
listing_id: impl ToString,
|
||||
bidder_id: u32,
|
||||
amount: f64,
|
||||
currency: impl ToString,
|
||||
) -> Self {
|
||||
Self {
|
||||
listing_id: listing_id.to_string(),
|
||||
bidder_id,
|
||||
amount,
|
||||
currency: currency.to_string(),
|
||||
status: BidStatus::default(),
|
||||
created_at: Utc::now(),
|
||||
}
|
||||
/// Create a new bid with default values
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Update the status of the bid
|
||||
pub fn update_status(mut self, status: BidStatus) -> Self {
|
||||
/// Set the listing ID for the bid
|
||||
pub fn listing_id(mut self, listing_id: impl ToString) -> Self {
|
||||
self.listing_id = listing_id.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the bidder ID for the bid
|
||||
pub fn bidder_id(mut self, bidder_id: u32) -> Self {
|
||||
self.bidder_id = bidder_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the amount for the bid
|
||||
pub fn amount(mut self, amount: f64) -> Self {
|
||||
self.amount = amount;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the currency for the bid
|
||||
pub fn currency(mut self, currency: impl ToString) -> Self {
|
||||
self.currency = currency.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the status of the bid
|
||||
pub fn status(mut self, status: BidStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Listing represents a marketplace listing for an asset
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType, Default)]
|
||||
#[model] // Has base.Base in V spec
|
||||
pub struct Listing {
|
||||
pub base_data: BaseModelData,
|
||||
@ -112,66 +125,82 @@ pub struct Listing {
|
||||
}
|
||||
|
||||
impl Listing {
|
||||
/// Create a new listing with auto-generated ID
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `id` - Optional ID for the listing (use None for auto-generated ID)
|
||||
/// * `title` - Title of the listing
|
||||
/// * `description` - Description of the listing
|
||||
/// * `asset_id` - ID of the asset being listed
|
||||
/// * `asset_type` - Type of the asset
|
||||
/// * `seller_id` - ID of the seller
|
||||
/// * `price` - Initial price for fixed price, or starting price for auction
|
||||
/// * `currency` - Currency of the price
|
||||
/// * `listing_type` - Type of the listing
|
||||
/// * `expires_at` - Optional expiration date
|
||||
/// * `tags` - Tags for the listing
|
||||
/// * `image_url` - Optional image URL
|
||||
pub fn new(
|
||||
id: Option<u32>,
|
||||
title: impl ToString,
|
||||
description: impl ToString,
|
||||
asset_id: impl ToString,
|
||||
asset_type: AssetType,
|
||||
seller_id: impl ToString,
|
||||
price: f64,
|
||||
currency: impl ToString,
|
||||
listing_type: ListingType,
|
||||
expires_at: Option<DateTime<Utc>>,
|
||||
tags: Vec<String>,
|
||||
image_url: Option<impl ToString>,
|
||||
) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
if let Some(id) = id {
|
||||
base_data.update_id(id);
|
||||
}
|
||||
/// Create a new listing with default values
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
Self {
|
||||
base_data,
|
||||
title: title.to_string(),
|
||||
description: description.to_string(),
|
||||
asset_id: asset_id.to_string(),
|
||||
asset_type,
|
||||
seller_id: seller_id.to_string(),
|
||||
price,
|
||||
currency: currency.to_string(),
|
||||
listing_type,
|
||||
status: ListingStatus::default(),
|
||||
expires_at,
|
||||
sold_at: None,
|
||||
buyer_id: None,
|
||||
sale_price: None,
|
||||
bids: Vec::new(),
|
||||
tags,
|
||||
image_url: image_url.map(|url| url.to_string()),
|
||||
}
|
||||
/// Set the title of the listing
|
||||
pub fn title(mut self, title: impl ToString) -> Self {
|
||||
self.title = title.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the description of the listing
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset ID of the listing
|
||||
pub fn asset_id(mut self, asset_id: impl ToString) -> Self {
|
||||
self.asset_id = asset_id.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset type of the listing
|
||||
pub fn asset_type(mut self, asset_type: AssetType) -> Self {
|
||||
self.asset_type = asset_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the seller ID of the listing
|
||||
pub fn seller_id(mut self, seller_id: impl ToString) -> Self {
|
||||
self.seller_id = seller_id.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the price of the listing
|
||||
pub fn price(mut self, price: f64) -> Self {
|
||||
self.price = price;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the currency of the listing
|
||||
pub fn currency(mut self, currency: impl ToString) -> Self {
|
||||
self.currency = currency.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the listing type
|
||||
pub fn listing_type(mut self, listing_type: ListingType) -> Self {
|
||||
self.listing_type = listing_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the status of the listing
|
||||
pub fn status(mut self, status: ListingStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the expiration date of the listing
|
||||
pub fn expires_at(mut self, expires_at: Option<DateTime<Utc>>) -> Self {
|
||||
self.expires_at = expires_at;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the image URL of the listing
|
||||
pub fn image_url(mut self, image_url: Option<impl ToString>) -> Self {
|
||||
self.image_url = image_url.map(|url| url.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a bid to an auction listing
|
||||
pub fn add_bid(mut self, bid: Bid) -> Result<Self, &'static str> {
|
||||
// Check if listing is an auction
|
||||
if self.listing_type != ListingType::Auction {
|
||||
return Err("Bids can only be placed on auction listings");
|
||||
return Err("Cannot add bid to non-auction listing");
|
||||
}
|
||||
|
||||
// Check if listing is active
|
||||
@ -210,27 +239,51 @@ impl Listing {
|
||||
.max_by(|a, b| a.amount.partial_cmp(&b.amount).unwrap())
|
||||
}
|
||||
|
||||
/// Set the buyer ID for completing a sale
|
||||
pub fn buyer_id(mut self, buyer_id: impl ToString) -> Self {
|
||||
self.buyer_id = Some(buyer_id.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the sale price for completing a sale
|
||||
pub fn sale_price(mut self, sale_price: f64) -> Self {
|
||||
self.sale_price = Some(sale_price);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the sold date for completing a sale
|
||||
pub fn sold_at(mut self, sold_at: Option<DateTime<Utc>>) -> Self {
|
||||
self.sold_at = sold_at;
|
||||
self
|
||||
}
|
||||
|
||||
/// Complete a sale (fixed price or auction)
|
||||
pub fn complete_sale(
|
||||
mut self,
|
||||
buyer_id: impl ToString,
|
||||
sale_price: f64,
|
||||
) -> Result<Self, &'static str> {
|
||||
pub fn complete_sale(mut self) -> Result<Self, &'static str> {
|
||||
if self.status != ListingStatus::Active {
|
||||
return Err("Cannot complete sale for inactive listing");
|
||||
}
|
||||
|
||||
if self.buyer_id.is_none() {
|
||||
return Err("Buyer ID must be set before completing sale");
|
||||
}
|
||||
|
||||
if self.sale_price.is_none() {
|
||||
return Err("Sale price must be set before completing sale");
|
||||
}
|
||||
|
||||
self.status = ListingStatus::Sold;
|
||||
self.buyer_id = Some(buyer_id.to_string());
|
||||
self.sale_price = Some(sale_price);
|
||||
self.sold_at = Some(Utc::now());
|
||||
|
||||
if self.sold_at.is_none() {
|
||||
self.sold_at = Some(Utc::now());
|
||||
}
|
||||
|
||||
// If this was an auction, accept the winning bid and reject others
|
||||
if self.listing_type == ListingType::Auction {
|
||||
let buyer_id_str = self.buyer_id.as_ref().unwrap().to_string();
|
||||
let sale_price_val = self.sale_price.unwrap();
|
||||
|
||||
for bid in &mut self.bids {
|
||||
if bid.bidder_id.to_string() == self.buyer_id.as_ref().unwrap().to_string()
|
||||
&& bid.amount == sale_price
|
||||
{
|
||||
if bid.bidder_id.to_string() == buyer_id_str && bid.amount == sale_price_val {
|
||||
bid.status = BidStatus::Accepted;
|
||||
} else {
|
||||
bid.status = BidStatus::Rejected;
|
||||
@ -279,34 +332,11 @@ impl Listing {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add tags to the listing
|
||||
pub fn add_tags(mut self, tags: Vec<impl ToString>) -> Self {
|
||||
for tag in tags {
|
||||
self.tags.push(tag.to_string());
|
||||
}
|
||||
/// Add a single tag to the listing
|
||||
pub fn add_tag(mut self, tag: impl ToString) -> Self {
|
||||
self.tags.push(tag.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Update the listing details
|
||||
pub fn update_details(
|
||||
mut self,
|
||||
title: Option<impl ToString>,
|
||||
description: Option<impl ToString>,
|
||||
price: Option<f64>,
|
||||
image_url: Option<impl ToString>,
|
||||
) -> Self {
|
||||
if let Some(title) = title {
|
||||
self.title = title.to_string();
|
||||
}
|
||||
if let Some(description) = description {
|
||||
self.description = description.to_string();
|
||||
}
|
||||
if let Some(price) = price {
|
||||
self.price = price;
|
||||
}
|
||||
if let Some(image_url) = image_url {
|
||||
self.image_url = Some(image_url.to_string());
|
||||
}
|
||||
self
|
||||
}
|
||||
// update_details method removed as we now have individual setter methods for each field
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
use super::flow_step::FlowStep;
|
||||
|
||||
/// Represents a signing flow.
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)]
|
||||
#[model]
|
||||
pub struct Flow {
|
||||
/// Base model data (id, created_at, updated_at).
|
||||
@ -27,9 +27,9 @@ pub struct Flow {
|
||||
|
||||
impl Flow {
|
||||
/// Create a new flow.
|
||||
/// The `id` is the database primary key.
|
||||
/// The `flow_uuid` should be a Uuid::new_v4().to_string().
|
||||
pub fn new(_id: u32, flow_uuid: impl ToString) -> Self {
|
||||
/// The ID is managed by `BaseModelData::new()` and the database.
|
||||
pub fn new(flow_uuid: impl ToString) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
flow_uuid: flow_uuid.to_string(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::default::Default;
|
||||
|
||||
/// Represents a step within a signing flow.
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
@ -20,6 +21,17 @@ pub struct FlowStep {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
impl Default for FlowStep {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
description: None,
|
||||
step_order: 0,
|
||||
status: String::from("Pending"), // Default status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowStep {
|
||||
/// Create a new flow step.
|
||||
pub fn new(_id: u32, step_order: u32) -> Self {
|
||||
|
@ -1,140 +1,384 @@
|
||||
use rhai::{Dynamic, Engine, EvalAltResult, NativeCallContext, Position};
|
||||
use rhai::plugin::*;
|
||||
use rhai::{Engine, EvalAltResult, Position, Module, INT, Dynamic, Array};
|
||||
use std::sync::Arc;
|
||||
use std::mem;
|
||||
|
||||
use heromodels_core::BaseModelData;
|
||||
use crate::db::hero::OurDB; // Import OurDB for actual DB operations
|
||||
use crate::db::Collection; // Collection might be needed if we add more specific DB functions
|
||||
use super::{
|
||||
flow::Flow,
|
||||
flow_step::FlowStep,
|
||||
signature_requirement::SignatureRequirement,
|
||||
};
|
||||
// use rhai_wrapper::wrap_vec_return; // Not currently used for flow, but keep for potential future use.
|
||||
use super::flow::Flow;
|
||||
use super::flow_step::FlowStep;
|
||||
use super::signature_requirement::SignatureRequirement;
|
||||
type RhaiFlow = Flow;
|
||||
type RhaiFlowStep = FlowStep;
|
||||
type RhaiSignatureRequirement = SignatureRequirement;
|
||||
use crate::db::hero::OurDB;
|
||||
use crate::db::Collection;
|
||||
use crate::db::Db;
|
||||
use heromodels_core::Model;
|
||||
|
||||
// Helper function to convert Rhai's i64 to u32 for IDs
|
||||
fn i64_to_u32(val: i64, context_pos: Position, field_name: &str, object_name: &str) -> Result<u32, Box<EvalAltResult>> {
|
||||
val.try_into().map_err(|_e| {
|
||||
// Helper to convert i64 from Rhai to u32 for IDs
|
||||
fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(id_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Conversion error for {} in {} from i64 to u32", field_name, object_name),
|
||||
context_pos,
|
||||
format!("Failed to convert ID '{}' to u32", id_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Helper to convert i64 from Rhai to u64 for timestamps or other large numbers
|
||||
fn val_from_i64_to_u64(val_i64: i64) -> Result<u64, Box<EvalAltResult>> {
|
||||
u64::try_from(val_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Failed to convert value '{}' to u64", val_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
#[export_module]
|
||||
mod rhai_flow_module {
|
||||
// --- Flow Functions ---
|
||||
#[rhai_fn(name = "new_flow")]
|
||||
pub fn new_flow(flow_uuid: String) -> RhaiFlow {
|
||||
Flow::new(flow_uuid)
|
||||
}
|
||||
|
||||
/// Sets the flow name
|
||||
#[rhai_fn(name = "name", return_raw, global, pure)]
|
||||
pub fn flow_name(flow: &mut RhaiFlow, name: String) -> Result<RhaiFlow, Box<EvalAltResult>> {
|
||||
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
|
||||
*flow = owned_flow.name(name);
|
||||
Ok(flow.clone())
|
||||
}
|
||||
|
||||
/// Sets the flow status
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn flow_status(flow: &mut RhaiFlow, status: String) -> Result<RhaiFlow, Box<EvalAltResult>> {
|
||||
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
|
||||
*flow = owned_flow.status(status);
|
||||
Ok(flow.clone())
|
||||
}
|
||||
|
||||
/// Adds a step to the flow
|
||||
#[rhai_fn(name = "add_step", return_raw, global, pure)]
|
||||
pub fn flow_add_step(flow: &mut RhaiFlow, step: RhaiFlowStep) -> Result<RhaiFlow, Box<EvalAltResult>> {
|
||||
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
|
||||
*flow = owned_flow.add_step(step);
|
||||
Ok(flow.clone())
|
||||
}
|
||||
|
||||
// Flow Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_id(flow: &mut RhaiFlow) -> i64 { flow.base_data.id as i64 }
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_created_at(flow: &mut RhaiFlow) -> i64 { flow.base_data.created_at }
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_modified_at(flow: &mut RhaiFlow) -> i64 { flow.base_data.modified_at }
|
||||
#[rhai_fn(get = "flow_uuid", pure)]
|
||||
pub fn get_flow_uuid(flow: &mut RhaiFlow) -> String { flow.flow_uuid.clone() }
|
||||
#[rhai_fn(get = "name", pure)]
|
||||
pub fn get_name(flow: &mut RhaiFlow) -> String { flow.name.clone() }
|
||||
#[rhai_fn(get = "status", pure)]
|
||||
pub fn get_status(flow: &mut RhaiFlow) -> String { flow.status.clone() }
|
||||
#[rhai_fn(get = "steps", pure)]
|
||||
pub fn get_steps(flow: &mut RhaiFlow) -> Array {
|
||||
flow.steps.iter().cloned().map(Dynamic::from).collect::<Array>()
|
||||
}
|
||||
|
||||
// --- FlowStep Functions ---
|
||||
#[rhai_fn(global)]
|
||||
pub fn new_flow_step(step_order_i64: i64) -> Dynamic {
|
||||
match id_from_i64_to_u32(step_order_i64) {
|
||||
Ok(step_order) => {
|
||||
let mut flow_step = FlowStep::default();
|
||||
flow_step.step_order = step_order;
|
||||
Dynamic::from(flow_step)
|
||||
},
|
||||
Err(err) => Dynamic::from(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the flow step description
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn flow_step_description(step: &mut RhaiFlowStep, description: String) -> Result<RhaiFlowStep, Box<EvalAltResult>> {
|
||||
let owned_step = mem::replace(step, FlowStep::default()); // Use Default trait
|
||||
*step = owned_step.description(description);
|
||||
Ok(step.clone())
|
||||
}
|
||||
|
||||
/// Sets the flow step status
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn flow_step_status(step: &mut RhaiFlowStep, status: String) -> Result<RhaiFlowStep, Box<EvalAltResult>> {
|
||||
let owned_step = mem::replace(step, FlowStep::default()); // Use Default trait
|
||||
*step = owned_step.status(status);
|
||||
Ok(step.clone())
|
||||
}
|
||||
|
||||
// FlowStep Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_step_id(step: &mut RhaiFlowStep) -> i64 { step.base_data.id as i64 }
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_step_created_at(step: &mut RhaiFlowStep) -> i64 { step.base_data.created_at }
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_step_modified_at(step: &mut RhaiFlowStep) -> i64 { step.base_data.modified_at }
|
||||
#[rhai_fn(get = "description", pure)]
|
||||
pub fn get_step_description(step: &mut RhaiFlowStep) -> Dynamic {
|
||||
match &step.description {
|
||||
Some(desc) => Dynamic::from(desc.clone()),
|
||||
None => Dynamic::UNIT,
|
||||
}
|
||||
}
|
||||
#[rhai_fn(get = "step_order", pure)]
|
||||
pub fn get_step_order(step: &mut RhaiFlowStep) -> i64 { step.step_order as i64 }
|
||||
#[rhai_fn(get = "status", pure)]
|
||||
pub fn get_step_status(step: &mut RhaiFlowStep) -> String { step.status.clone() }
|
||||
|
||||
// --- SignatureRequirement Functions ---
|
||||
/// Create a new signature requirement
|
||||
#[rhai_fn(global)]
|
||||
pub fn new_signature_requirement(flow_step_id_i64: i64, public_key: String, message: String) -> Dynamic {
|
||||
match id_from_i64_to_u32(flow_step_id_i64) {
|
||||
Ok(flow_step_id) => {
|
||||
let mut signature_requirement = SignatureRequirement::default();
|
||||
signature_requirement.flow_step_id = flow_step_id;
|
||||
signature_requirement.public_key = public_key;
|
||||
signature_requirement.message = message;
|
||||
Dynamic::from(signature_requirement)
|
||||
},
|
||||
Err(err) => Dynamic::from(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the signed_by field
|
||||
#[rhai_fn(name = "signed_by", return_raw, global, pure)]
|
||||
pub fn signature_requirement_signed_by(sr: &mut RhaiSignatureRequirement, signed_by: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
|
||||
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
|
||||
*sr = owned_sr.signed_by(signed_by);
|
||||
Ok(sr.clone())
|
||||
}
|
||||
|
||||
/// Sets the signature field
|
||||
#[rhai_fn(name = "signature", return_raw, global, pure)]
|
||||
pub fn signature_requirement_signature(sr: &mut RhaiSignatureRequirement, signature: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
|
||||
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
|
||||
*sr = owned_sr.signature(signature);
|
||||
Ok(sr.clone())
|
||||
}
|
||||
|
||||
/// Sets the status field
|
||||
#[rhai_fn(name = "status", return_raw, global, pure)]
|
||||
pub fn signature_requirement_status(sr: &mut RhaiSignatureRequirement, status: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
|
||||
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
|
||||
*sr = owned_sr.status(status);
|
||||
Ok(sr.clone())
|
||||
}
|
||||
|
||||
// SignatureRequirement Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_sr_id(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.id as i64 }
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_sr_created_at(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.created_at }
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_sr_modified_at(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.modified_at }
|
||||
#[rhai_fn(get = "flow_step_id", pure)]
|
||||
pub fn get_sr_flow_step_id(sr: &mut RhaiSignatureRequirement) -> i64 { sr.flow_step_id as i64 }
|
||||
#[rhai_fn(get = "public_key", pure)]
|
||||
pub fn get_sr_public_key(sr: &mut RhaiSignatureRequirement) -> String { sr.public_key.clone() }
|
||||
#[rhai_fn(get = "message", pure)]
|
||||
pub fn get_sr_message(sr: &mut RhaiSignatureRequirement) -> String { sr.message.clone() }
|
||||
#[rhai_fn(get = "signed_by", pure)]
|
||||
pub fn get_sr_signed_by(sr: &mut RhaiSignatureRequirement) -> Dynamic {
|
||||
match &sr.signed_by {
|
||||
Some(signed_by) => Dynamic::from(signed_by.clone()),
|
||||
None => Dynamic::UNIT,
|
||||
}
|
||||
}
|
||||
#[rhai_fn(get = "signature", pure)]
|
||||
pub fn get_sr_signature(sr: &mut RhaiSignatureRequirement) -> Dynamic {
|
||||
match &sr.signature {
|
||||
Some(signature) => Dynamic::from(signature.clone()),
|
||||
None => Dynamic::UNIT,
|
||||
}
|
||||
}
|
||||
#[rhai_fn(get = "status", pure)]
|
||||
pub fn get_sr_status(sr: &mut RhaiSignatureRequirement) -> String { sr.status.clone() }
|
||||
}
|
||||
|
||||
/// Register the flow module with the Rhai engine
|
||||
pub fn register_flow_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
// --- Flow Model ---
|
||||
|
||||
// Constructor: new_flow(id: u32, flow_uuid: String)
|
||||
engine.register_fn("new_flow", move |context: NativeCallContext, id_i64: i64, flow_uuid: String| -> Result<Flow, Box<EvalAltResult>> {
|
||||
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_flow")?;
|
||||
Ok(Flow::new(id_u32, flow_uuid))
|
||||
// Create a module for database functions
|
||||
let mut db_module = Module::new();
|
||||
|
||||
// Flow database functions
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("save_flow", move |flow: Flow| -> Result<Flow, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone.set(&flow)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_flow: {:?}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated flow with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
// Builder methods for Flow
|
||||
engine.register_fn("name", |flow: Flow, name_val: String| -> Flow { flow.name(name_val) });
|
||||
engine.register_fn("status", |flow: Flow, status_val: String| -> Flow { flow.status(status_val) });
|
||||
engine.register_fn("add_step", |flow: Flow, step: FlowStep| -> Flow { flow.add_step(step) });
|
||||
|
||||
// Getters for Flow fields
|
||||
engine.register_get("id", |flow: &mut Flow| -> Result<i64, Box<EvalAltResult>> { Ok(flow.base_data.id as i64) });
|
||||
engine.register_get("base_data", |flow: &mut Flow| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(flow.base_data.clone()) });
|
||||
engine.register_get("flow_uuid", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.flow_uuid.clone()) });
|
||||
engine.register_get("name", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.name.clone()) });
|
||||
engine.register_get("status", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.status.clone()) });
|
||||
engine.register_get("steps", |flow: &mut Flow| -> Result<rhai::Array, Box<EvalAltResult>> {
|
||||
let rhai_array = flow.steps.iter().cloned().map(Dynamic::from).collect::<rhai::Array>();
|
||||
Ok(rhai_array)
|
||||
});
|
||||
|
||||
// --- FlowStep Model ---
|
||||
|
||||
// Constructor: new_flow_step(id: u32, step_order: u32)
|
||||
engine.register_fn("new_flow_step", move |context: NativeCallContext, id_i64: i64, step_order_i64: i64| -> Result<FlowStep, Box<EvalAltResult>> {
|
||||
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_flow_step")?;
|
||||
let step_order_u32 = i64_to_u32(step_order_i64, context.position(), "step_order", "new_flow_step")?;
|
||||
Ok(FlowStep::new(id_u32, step_order_u32))
|
||||
});
|
||||
|
||||
// Builder methods for FlowStep
|
||||
engine.register_fn("description", |fs: FlowStep, desc_val: String| -> FlowStep { fs.description(desc_val) }); // Assuming FlowStep::description takes impl ToString
|
||||
engine.register_fn("status", |fs: FlowStep, status_val: String| -> FlowStep { fs.status(status_val) });
|
||||
|
||||
// Getters for FlowStep fields
|
||||
engine.register_get("id", |step: &mut FlowStep| -> Result<i64, Box<EvalAltResult>> { Ok(step.base_data.id as i64) });
|
||||
engine.register_get("base_data", |step: &mut FlowStep| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(step.base_data.clone()) });
|
||||
engine.register_get("description", |step: &mut FlowStep| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match step.description.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
|
||||
engine.register_get("step_order", |step: &mut FlowStep| -> Result<i64, Box<EvalAltResult>> { Ok(step.step_order as i64) });
|
||||
engine.register_get("status", |step: &mut FlowStep| -> Result<String, Box<EvalAltResult>> { Ok(step.status.clone()) });
|
||||
|
||||
// --- SignatureRequirement Model ---
|
||||
|
||||
// Constructor: new_signature_requirement(id: u32, flow_step_id: u32, public_key: String, message: String)
|
||||
engine.register_fn("new_signature_requirement",
|
||||
move |context: NativeCallContext, id_i64: i64, flow_step_id_i64: i64, public_key: String, message: String|
|
||||
-> Result<SignatureRequirement, Box<EvalAltResult>> {
|
||||
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_signature_requirement")?;
|
||||
let flow_step_id_u32 = i64_to_u32(flow_step_id_i64, context.position(), "flow_step_id", "new_signature_requirement")?;
|
||||
Ok(SignatureRequirement::new(id_u32, flow_step_id_u32, public_key, message))
|
||||
});
|
||||
|
||||
// Builder methods for SignatureRequirement
|
||||
engine.register_fn("signed_by", |sr: SignatureRequirement, signed_by_val: String| -> SignatureRequirement { sr.signed_by(signed_by_val) }); // Assuming SR::signed_by takes impl ToString
|
||||
engine.register_fn("signature", |sr: SignatureRequirement, sig_val: String| -> SignatureRequirement { sr.signature(sig_val) }); // Assuming SR::signature takes impl ToString
|
||||
engine.register_fn("status", |sr: SignatureRequirement, status_val: String| -> SignatureRequirement { sr.status(status_val) });
|
||||
|
||||
// Getters for SignatureRequirement fields
|
||||
engine.register_get("id", |sr: &mut SignatureRequirement| -> Result<i64, Box<EvalAltResult>> { Ok(sr.base_data.id as i64) });
|
||||
engine.register_get("base_data", |sr: &mut SignatureRequirement| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(sr.base_data.clone()) });
|
||||
engine.register_get("flow_step_id", |sr: &mut SignatureRequirement| -> Result<i64, Box<EvalAltResult>> { Ok(sr.flow_step_id as i64) });
|
||||
engine.register_get("public_key", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.public_key.clone()) });
|
||||
engine.register_get("message", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.message.clone()) });
|
||||
engine.register_get("signed_by", |sr: &mut SignatureRequirement| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match sr.signed_by.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
|
||||
engine.register_get("signature", |sr: &mut SignatureRequirement| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match sr.signature.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
|
||||
engine.register_get("status", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.status.clone()) });
|
||||
|
||||
// --- BaseModelData Getters (if not already globally registered) ---
|
||||
// Assuming these might be specific to the context or shadowed, explicit registration is safer.
|
||||
engine.register_get("id", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.id as i64) });
|
||||
engine.register_get("created_at", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.created_at) });
|
||||
engine.register_get("modified_at", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.modified_at) });
|
||||
// engine.register_get("comments", |bmd: &mut BaseModelData| Ok(bmd.comments.clone())); // Rhai might need specific handling for Vec<String>
|
||||
|
||||
// --- Database Interaction Functions ---
|
||||
|
||||
let captured_db_for_set_flow = Arc::clone(&db);
|
||||
engine.register_fn("set_flow", move |flow: Flow| -> Result<(), Box<EvalAltResult>> {
|
||||
captured_db_for_set_flow.set(&flow).map(|_| ()).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Flow (ID: {}): {}", flow.base_data.id, e).into(), Position::NONE))
|
||||
})
|
||||
});
|
||||
|
||||
let captured_db_for_get_flow = Arc::clone(&db);
|
||||
engine.register_fn("get_flow_by_id", move |context: NativeCallContext, id_i64: i64| -> Result<Flow, Box<EvalAltResult>> {
|
||||
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "get_flow_by_id")?;
|
||||
captured_db_for_get_flow.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Flow (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_flow_by_id", move |id_i64: INT| -> Result<Flow, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_flow_by_id: {:?}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Flow with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
// Add get_flows_by_uuid, flow_exists etc. as needed, using wrap_vec_return for Vec results.
|
||||
|
||||
// FlowStep DB functions are removed as FlowSteps are now part of Flow.
|
||||
|
||||
let captured_db_for_set_sig_req = Arc::clone(&db);
|
||||
engine.register_fn("set_signature_requirement", move |sr: SignatureRequirement| -> Result<(), Box<EvalAltResult>> {
|
||||
captured_db_for_set_sig_req.set(&sr).map(|_| ()).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set SignatureRequirement (ID: {}): {}", sr.base_data.id, e).into(), Position::NONE))
|
||||
})
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("delete_flow", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
let collection = db_clone.collection::<Flow>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get flow collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
collection.delete_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to delete Flow (ID: {}): {:?}", id_u32, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let captured_db_for_get_sig_req = Arc::clone(&db);
|
||||
engine.register_fn("get_signature_requirement_by_id",
|
||||
move |context: NativeCallContext, id_i64: i64|
|
||||
-> Result<SignatureRequirement, Box<EvalAltResult>> {
|
||||
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "get_signature_requirement_by_id")?;
|
||||
captured_db_for_get_sig_req.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting SignatureRequirement (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("SignatureRequirement with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("list_flows", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone.collection::<Flow>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get flow collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let flows = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all flows: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for flow in flows {
|
||||
array.push(Dynamic::from(flow));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
|
||||
// FlowStep database functions
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("save_flow_step", move |step: FlowStep| -> Result<FlowStep, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone.set(&step)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_flow_step: {:?}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated flow step with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_flow_step_by_id", move |id_i64: INT| -> Result<FlowStep, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_flow_step_by_id: {:?}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("FlowStep with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("delete_flow_step", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
let collection = db_clone.collection::<FlowStep>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get flow step collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
collection.delete_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to delete FlowStep (ID: {}): {:?}", id_u32, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("list_flow_steps", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone.collection::<FlowStep>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get flow step collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let steps = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all flow steps: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for step in steps {
|
||||
array.push(Dynamic::from(step));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
// SignatureRequirement database functions
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("save_signature_requirement", move |sr: SignatureRequirement| -> Result<SignatureRequirement, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone.set(&sr)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_signature_requirement: {:?}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated signature requirement with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("get_signature_requirement_by_id", move |id_i64: INT| -> Result<SignatureRequirement, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_signature_requirement_by_id: {:?}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("SignatureRequirement with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("delete_signature_requirement", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
let collection = db_clone.collection::<SignatureRequirement>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get signature requirement collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
collection.delete_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to delete SignatureRequirement (ID: {}): {:?}", id_u32, e).into(),
|
||||
Position::NONE
|
||||
)))
|
||||
});
|
||||
|
||||
let db_clone = Arc::clone(&db);
|
||||
db_module.set_native_fn("list_signature_requirements", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone.collection::<SignatureRequirement>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get signature requirement collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let srs = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all signature requirements: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for sr in srs {
|
||||
array.push(Dynamic::from(sr));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
// Register the database module globally
|
||||
engine.register_static_module("db", db_module.into());
|
||||
|
||||
// Register the flow module using exported_module! macro
|
||||
let module = exported_module!(rhai_flow_module);
|
||||
engine.register_global_module(module.into());
|
||||
|
||||
println!("Flow Rhai module registered.");
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::default::Default;
|
||||
|
||||
/// Represents a signature requirement for a flow step.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[model]
|
||||
pub struct SignatureRequirement {
|
||||
/// Base model data.
|
||||
|
27
heromodels/src/models/governance/attached_file.rs
Normal file
27
heromodels/src/models/governance/attached_file.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// heromodels/src/models/governance/attached_file.rs
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[model]
|
||||
pub struct AttachedFile {
|
||||
pub base_data: BaseModelData, // Provides id, created_at, updated_at
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub file_type: String, // e.g., "pdf", "image/jpeg", "application/msword"
|
||||
pub size_bytes: u64,
|
||||
// Optional: could add uploader_id: u32 if needed
|
||||
}
|
||||
|
||||
impl AttachedFile {
|
||||
pub fn new(name: String, url: String, file_type: String, size_bytes: u64) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name,
|
||||
url,
|
||||
file_type,
|
||||
size_bytes,
|
||||
}
|
||||
}
|
||||
}
|
@ -2,4 +2,7 @@
|
||||
// This module will contain the Proposal model and related types.
|
||||
pub mod proposal;
|
||||
|
||||
pub use self::proposal::{Proposal, Ballot, VoteOption, ProposalStatus, VoteEventStatus};
|
||||
pub mod attached_file;
|
||||
|
||||
pub use self::proposal::{Proposal, Ballot, VoteOption, ProposalStatus, VoteEventStatus};
|
||||
pub use self::attached_file::AttachedFile;
|
@ -3,10 +3,11 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use heromodels_derive::model; // For #[model]
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
use rhai_autobind_macros::rhai_model_export;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use heromodels_core::BaseModelData;
|
||||
use crate::models::core::Comment;
|
||||
use super::AttachedFile;
|
||||
|
||||
// --- Enums ---
|
||||
|
||||
@ -29,6 +30,7 @@ impl Default for ProposalStatus {
|
||||
/// VoteEventStatus represents the status of the voting process for a proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum VoteEventStatus {
|
||||
Upcoming, // Voting is scheduled but not yet open
|
||||
Open, // Voting is currently open
|
||||
Closed, // Voting has finished
|
||||
Cancelled, // The voting event was cancelled
|
||||
@ -36,14 +38,14 @@ pub enum VoteEventStatus {
|
||||
|
||||
impl Default for VoteEventStatus {
|
||||
fn default() -> Self {
|
||||
VoteEventStatus::Open
|
||||
VoteEventStatus::Upcoming
|
||||
}
|
||||
}
|
||||
|
||||
// --- Structs ---
|
||||
|
||||
/// VoteOption represents a specific choice that can be voted on
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType, Default)]
|
||||
pub struct VoteOption {
|
||||
pub id: u8, // Simple identifier for this option
|
||||
pub text: String, // Descriptive text of the option
|
||||
@ -65,8 +67,8 @@ impl VoteOption {
|
||||
}
|
||||
|
||||
/// Ballot represents an individual vote cast by a user
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[rhai_model_export(db_type = "std::sync::Arc<crate::db::hero::OurDB>")]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType, Default)]
|
||||
// Removed rhai_model_export macro as it's causing compilation errors
|
||||
#[model] // Has base.Base in V spec
|
||||
pub struct Ballot {
|
||||
pub base_data: BaseModelData,
|
||||
@ -102,7 +104,7 @@ impl Ballot {
|
||||
|
||||
/// Proposal represents a governance proposal that can be voted upon.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
#[rhai_model_export(db_type = "std::sync::Arc<crate::db::hero::OurDB>")]
|
||||
// Removed rhai_model_export macro as it's causing compilation errors
|
||||
#[model] // Has base.Base in V spec
|
||||
pub struct Proposal {
|
||||
pub base_data: BaseModelData,
|
||||
@ -113,9 +115,6 @@ pub struct Proposal {
|
||||
pub description: String,
|
||||
pub status: ProposalStatus,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
// Voting event aspects
|
||||
pub vote_start_date: DateTime<Utc>,
|
||||
pub vote_end_date: DateTime<Utc>,
|
||||
@ -123,6 +122,35 @@ pub struct Proposal {
|
||||
pub options: Vec<VoteOption>,
|
||||
pub ballots: Vec<Ballot>, // This will store actual Ballot structs
|
||||
pub private_group: Option<Vec<u32>>, // Optional list of eligible user IDs
|
||||
|
||||
pub tags: Vec<String>,
|
||||
pub comments: Vec<Comment>,
|
||||
pub attached_files: Vec<AttachedFile>,
|
||||
pub urgency_score: Option<f32>,
|
||||
}
|
||||
|
||||
impl Default for Proposal {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
creator_id: "".to_string(),
|
||||
creator_name: String::new(), // Added missing field
|
||||
title: "".to_string(),
|
||||
description: "".to_string(),
|
||||
status: ProposalStatus::Draft,
|
||||
// created_at and updated_at are now in base_data
|
||||
vote_start_date: Utc::now(),
|
||||
vote_end_date: Utc::now(),
|
||||
vote_status: VoteEventStatus::Upcoming,
|
||||
options: vec![],
|
||||
ballots: vec![],
|
||||
private_group: None,
|
||||
tags: vec![],
|
||||
comments: vec![],
|
||||
attached_files: vec![],
|
||||
urgency_score: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Proposal {
|
||||
@ -142,10 +170,8 @@ impl Proposal {
|
||||
title: impl ToString,
|
||||
description: impl ToString,
|
||||
status: ProposalStatus,
|
||||
created_at: DateTime<Utc>,
|
||||
updated_at: DateTime<Utc>,
|
||||
vote_start_date: DateTime<Utc>,
|
||||
vote_end_date: DateTime<Utc>,
|
||||
tags: Vec<String>,
|
||||
urgency_score: Option<f32>,
|
||||
) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
if let Some(id) = id {
|
||||
@ -159,14 +185,16 @@ impl Proposal {
|
||||
title: title.to_string(),
|
||||
description: description.to_string(),
|
||||
status,
|
||||
created_at,
|
||||
updated_at,
|
||||
vote_start_date,
|
||||
vote_end_date,
|
||||
vote_status: VoteEventStatus::Open, // Default to open when created
|
||||
vote_start_date: Utc::now(),
|
||||
vote_end_date: Utc::now(),
|
||||
vote_status: VoteEventStatus::Upcoming,
|
||||
options: Vec::new(),
|
||||
ballots: Vec::new(),
|
||||
private_group: None,
|
||||
tags,
|
||||
comments: Vec::new(),
|
||||
attached_files: Vec::new(),
|
||||
urgency_score,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl fmt::Display for SignerStatus {
|
||||
// --- Structs for nested data ---
|
||||
|
||||
/// ContractRevision represents a version of the contract content
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct ContractRevision {
|
||||
pub version: u32,
|
||||
pub content: String,
|
||||
@ -78,7 +78,7 @@ impl ContractRevision {
|
||||
}
|
||||
|
||||
/// ContractSigner represents a party involved in signing a contract
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct ContractSigner {
|
||||
pub id: String, // Unique ID for the signer (UUID string)
|
||||
pub name: String,
|
||||
@ -129,7 +129,7 @@ impl ContractSigner {
|
||||
// --- Main Contract Model ---
|
||||
|
||||
/// Represents a legal agreement
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
#[model]
|
||||
pub struct Contract {
|
||||
pub base_data: BaseModelData, // Provides id (u32), created_at (u64), updated_at (u64)
|
||||
|
@ -15,7 +15,7 @@ pub use core::Comment;
|
||||
pub use userexample::User;
|
||||
// pub use productexample::Product; // Temporarily remove
|
||||
pub use calendar::{Calendar, Event, Attendee, AttendanceStatus};
|
||||
pub use governance::{Proposal, ProposalStatus, VoteEventStatus, Ballot, VoteOption};
|
||||
pub use governance::{Proposal, ProposalStatus, VoteEventStatus, Ballot, VoteOption, AttachedFile};
|
||||
pub use finance::{Account, Asset, AssetType};
|
||||
pub use finance::marketplace::{Listing, ListingStatus, ListingType, Bid, BidStatus};
|
||||
pub use legal::{Contract, ContractRevision, ContractSigner, ContractStatus, SignerStatus};
|
||||
@ -23,6 +23,7 @@ pub use flow::{Flow, FlowStep, SignatureRequirement};
|
||||
pub use biz::{Sale, SaleItem, SaleStatus};
|
||||
|
||||
pub use flow::register_flow_rhai_module;
|
||||
#[cfg(feature = "rhai")]
|
||||
pub use calendar::register_calendar_rhai_module;
|
||||
pub use legal::register_legal_rhai_module;
|
||||
#[cfg(feature = "rhai")]
|
||||
|
83
heromodels/src/models/projects/epic.rs
Normal file
83
heromodels/src/models/projects/epic.rs
Normal file
@ -0,0 +1,83 @@
|
||||
// heromodels/src/models/projects/epic.rs
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
|
||||
use super::base::Status as ProjectStatus; // Using the generic project status for now
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
#[model]
|
||||
pub struct Epic {
|
||||
pub base_data: BaseModelData,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub status: ProjectStatus, // Or a new EpicStatus enum if needed
|
||||
|
||||
pub project_id: Option<u32>, // Link to a general project/board
|
||||
|
||||
pub start_date: Option<DateTime<Utc>>,
|
||||
pub due_date: Option<DateTime<Utc>>,
|
||||
|
||||
pub tags: Vec<String>,
|
||||
|
||||
// Explicitly list task IDs belonging to this epic
|
||||
// This helps in querying and avoids relying solely on tasks pointing to the epic.
|
||||
pub child_task_ids: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Epic {
|
||||
pub fn new(
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
status: ProjectStatus,
|
||||
project_id: Option<u32>,
|
||||
start_date: Option<DateTime<Utc>>,
|
||||
due_date: Option<DateTime<Utc>>,
|
||||
tags: Vec<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
project_id,
|
||||
start_date,
|
||||
due_date,
|
||||
tags,
|
||||
child_task_ids: Vec::new(), // Initialize as empty
|
||||
}
|
||||
}
|
||||
|
||||
// Method to add a task to this epic
|
||||
pub fn add_task_id(mut self, task_id: u32) -> Self {
|
||||
if !self.child_task_ids.contains(&task_id) {
|
||||
self.child_task_ids.push(task_id);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
// Method to remove a task from this epic
|
||||
pub fn remove_task_id(mut self, task_id: u32) -> Self {
|
||||
self.child_task_ids.retain(|&id| id != task_id);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Epic {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name: String::new(),
|
||||
description: None,
|
||||
status: ProjectStatus::default(),
|
||||
project_id: None,
|
||||
start_date: None,
|
||||
due_date: None,
|
||||
tags: Vec::new(),
|
||||
child_task_ids: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
// heromodels/src/models/projects/mod.rs
|
||||
|
||||
pub mod base;
|
||||
pub mod task_enums;
|
||||
pub mod task;
|
||||
pub mod epic;
|
||||
pub mod sprint_enums;
|
||||
pub mod sprint;
|
||||
// pub mod epic;
|
||||
// pub mod issue;
|
||||
// pub mod kanban;
|
||||
@ -8,6 +13,11 @@ pub mod base;
|
||||
// pub mod story;
|
||||
|
||||
pub use base::*;
|
||||
pub use task_enums::*;
|
||||
pub use task::*;
|
||||
pub use epic::*;
|
||||
pub use sprint_enums::*;
|
||||
pub use sprint::*;
|
||||
// pub use epic::*;
|
||||
// pub use issue::*;
|
||||
// pub use kanban::*;
|
||||
|
81
heromodels/src/models/projects/sprint.rs
Normal file
81
heromodels/src/models/projects/sprint.rs
Normal file
@ -0,0 +1,81 @@
|
||||
// heromodels/src/models/projects/sprint.rs
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
|
||||
use super::sprint_enums::SprintStatus; // Import our new enum
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
#[model]
|
||||
pub struct Sprint {
|
||||
pub base_data: BaseModelData,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub status: SprintStatus,
|
||||
pub goal: Option<String>, // Sprint goal
|
||||
|
||||
pub project_id: Option<u32>, // Link to a general project/board
|
||||
|
||||
pub start_date: Option<DateTime<Utc>>,
|
||||
pub end_date: Option<DateTime<Utc>>, // Changed from due_date for sprints
|
||||
|
||||
// Explicitly list task IDs belonging to this sprint
|
||||
pub task_ids: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Sprint {
|
||||
pub fn new(
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
status: SprintStatus,
|
||||
goal: Option<String>,
|
||||
project_id: Option<u32>,
|
||||
start_date: Option<DateTime<Utc>>,
|
||||
end_date: Option<DateTime<Utc>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
goal,
|
||||
project_id,
|
||||
start_date,
|
||||
end_date,
|
||||
task_ids: Vec::new(), // Initialize as empty
|
||||
}
|
||||
}
|
||||
|
||||
// Method to add a task to this sprint
|
||||
pub fn add_task_id(mut self, task_id: u32) -> Self {
|
||||
if !self.task_ids.contains(&task_id) {
|
||||
self.task_ids.push(task_id);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
// Method to remove a task from this sprint
|
||||
pub fn remove_task_id(mut self, task_id: u32) -> Self {
|
||||
self.task_ids.retain(|&id| id != task_id);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Sprint {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name: String::new(),
|
||||
description: None,
|
||||
status: SprintStatus::default(),
|
||||
goal: None,
|
||||
project_id: None,
|
||||
start_date: None,
|
||||
end_date: None,
|
||||
task_ids: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
16
heromodels/src/models/projects/sprint_enums.rs
Normal file
16
heromodels/src/models/projects/sprint_enums.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// heromodels/src/models/projects/sprint_enums.rs
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SprintStatus {
|
||||
Planning,
|
||||
Active,
|
||||
Completed,
|
||||
Paused,
|
||||
}
|
||||
|
||||
impl Default for SprintStatus {
|
||||
fn default() -> Self {
|
||||
SprintStatus::Planning
|
||||
}
|
||||
}
|
93
heromodels/src/models/projects/task.rs
Normal file
93
heromodels/src/models/projects/task.rs
Normal file
@ -0,0 +1,93 @@
|
||||
// heromodels/src/models/projects/task.rs
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use rhai::{CustomType, TypeBuilder}; // Assuming rhai might be used
|
||||
|
||||
use super::task_enums::{TaskStatus, TaskPriority}; // Import our new enums
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
#[model] // This will provide id, created_at, updated_at via base_data
|
||||
pub struct Task {
|
||||
pub base_data: BaseModelData,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub status: TaskStatus,
|
||||
pub priority: TaskPriority,
|
||||
|
||||
pub assignee_id: Option<u32>, // User ID
|
||||
pub reporter_id: Option<u32>, // User ID
|
||||
|
||||
pub parent_task_id: Option<u32>, // For subtasks
|
||||
pub epic_id: Option<u32>,
|
||||
pub sprint_id: Option<u32>,
|
||||
pub project_id: Option<u32>, // Link to a general project/board if applicable
|
||||
|
||||
pub due_date: Option<DateTime<Utc>>,
|
||||
pub estimated_time_hours: Option<f32>,
|
||||
pub logged_time_hours: Option<f32>,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
title: String,
|
||||
description: Option<String>,
|
||||
status: TaskStatus,
|
||||
priority: TaskPriority,
|
||||
assignee_id: Option<u32>,
|
||||
reporter_id: Option<u32>,
|
||||
parent_task_id: Option<u32>,
|
||||
epic_id: Option<u32>,
|
||||
sprint_id: Option<u32>,
|
||||
project_id: Option<u32>,
|
||||
due_date: Option<DateTime<Utc>>,
|
||||
estimated_time_hours: Option<f32>,
|
||||
logged_time_hours: Option<f32>,
|
||||
tags: Vec<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
title,
|
||||
description,
|
||||
status,
|
||||
priority,
|
||||
assignee_id,
|
||||
reporter_id,
|
||||
parent_task_id,
|
||||
epic_id,
|
||||
sprint_id,
|
||||
project_id,
|
||||
due_date,
|
||||
estimated_time_hours,
|
||||
logged_time_hours,
|
||||
tags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add Default implementation
|
||||
impl Default for Task {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
title: String::new(),
|
||||
description: None,
|
||||
status: TaskStatus::default(),
|
||||
priority: TaskPriority::default(),
|
||||
assignee_id: None,
|
||||
reporter_id: None,
|
||||
parent_task_id: None,
|
||||
epic_id: None,
|
||||
sprint_id: None,
|
||||
project_id: None,
|
||||
due_date: None,
|
||||
estimated_time_hours: None,
|
||||
logged_time_hours: None,
|
||||
tags: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
32
heromodels/src/models/projects/task_enums.rs
Normal file
32
heromodels/src/models/projects/task_enums.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// heromodels/src/models/projects/task_enums.rs
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum TaskStatus {
|
||||
ToDo,
|
||||
InProgress,
|
||||
InReview,
|
||||
Done,
|
||||
Blocked,
|
||||
Backlog,
|
||||
}
|
||||
|
||||
impl Default for TaskStatus {
|
||||
fn default() -> Self {
|
||||
TaskStatus::ToDo
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum TaskPriority {
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
Urgent,
|
||||
}
|
||||
|
||||
impl Default for TaskPriority {
|
||||
fn default() -> Self {
|
||||
TaskPriority::Medium
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents a user in the system
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[model]
|
||||
pub struct User {
|
||||
/// Base model data
|
||||
|
BIN
heromodels/tmp/event_test_db/index/0.db
Normal file
BIN
heromodels/tmp/event_test_db/index/0.db
Normal file
Binary file not shown.
1
heromodels/tmp/event_test_db/index/lookup/.inc
Normal file
1
heromodels/tmp/event_test_db/index/lookup/.inc
Normal file
@ -0,0 +1 @@
|
||||
2
|
Loading…
Reference in New Issue
Block a user