...
This commit is contained in:
parent
6d64b7b651
commit
f993d74ea1
@ -1,12 +1,14 @@
|
||||
use chrono::{Duration, Utc};
|
||||
use crate::models::biz::{
|
||||
use herodb::db::{DBBuilder, DB, Model};
|
||||
use herodb::models::biz::{
|
||||
Currency, CurrencyBuilder,
|
||||
Product, ProductBuilder, ProductComponent, ProductComponentBuilder, ProductType, ProductStatus,
|
||||
Sale, SaleBuilder, SaleItem, SaleItemBuilder, SaleStatus,
|
||||
Invoice, InvoiceBuilder, InvoiceItem, InvoiceItemBuilder, InvoiceStatus, Payment, PaymentStatus,
|
||||
Customer, CustomerBuilder,
|
||||
};
|
||||
use crate::db::model::Model;
|
||||
use std::path::PathBuf;
|
||||
use std::fs;
|
||||
|
||||
/// This example demonstrates the business models in action:
|
||||
/// 1. Defining products (2 types of server nodes)
|
||||
@ -17,19 +19,40 @@ use crate::db::model::Model;
|
||||
/// 6. Generating an invoice
|
||||
/// 7. Simulating payment
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Business Models Example");
|
||||
println!("=======================\n");
|
||||
|
||||
// Create a temporary directory for the database
|
||||
let db_path = PathBuf::from("/tmp/dbexample_biz");
|
||||
if db_path.exists() {
|
||||
fs::remove_dir_all(&db_path)?;
|
||||
}
|
||||
fs::create_dir_all(&db_path)?;
|
||||
println!("Database path: {:?}", db_path);
|
||||
|
||||
// Create a database instance with our business models registered
|
||||
let db = DBBuilder::new(&db_path)
|
||||
.register_model::<Customer>()
|
||||
.register_model::<Product>()
|
||||
.register_model::<Sale>()
|
||||
.register_model::<Invoice>()
|
||||
.build()?;
|
||||
|
||||
// Create a customer
|
||||
let customer = create_customer();
|
||||
println!("Created customer: {}", customer.name);
|
||||
db.set(&customer)?;
|
||||
|
||||
// Define products (server nodes)
|
||||
let (standard_node, premium_node) = create_server_products();
|
||||
println!("Created server products:");
|
||||
println!(" - Standard Node: ${} {}", standard_node.price.amount, standard_node.price.currency_code);
|
||||
println!(" - Premium Node: ${} {}", premium_node.price.amount, premium_node.price.currency_code);
|
||||
|
||||
// Store products in the database
|
||||
db.set(&standard_node)?;
|
||||
db.set(&premium_node)?;
|
||||
|
||||
// Check which products can be purchased
|
||||
println!("\nChecking which products can be purchased:");
|
||||
@ -43,6 +66,7 @@ fn main() {
|
||||
let sale = create_sale(&customer, &premium_node);
|
||||
println!(" - Sale created with ID: {}", sale.get_id());
|
||||
println!(" - Total amount: ${} {}", sale.total_amount.amount, sale.total_amount.currency_code);
|
||||
db.set(&sale)?;
|
||||
|
||||
// Generate an invoice
|
||||
println!("\nGenerating invoice:");
|
||||
@ -51,16 +75,39 @@ fn main() {
|
||||
println!(" - Total amount: ${} {}", invoice.total_amount.amount, invoice.total_amount.currency_code);
|
||||
println!(" - Due date: {}", invoice.due_date);
|
||||
println!(" - Status: {:?}", invoice.status);
|
||||
db.set(&invoice)?;
|
||||
|
||||
// Simulate payment
|
||||
println!("\nSimulating payment:");
|
||||
let paid_invoice = process_payment(invoice);
|
||||
let mut invoice_copy = invoice.clone();
|
||||
process_payment(&mut invoice_copy);
|
||||
println!(" - Payment processed");
|
||||
println!(" - New balance due: ${} {}", paid_invoice.balance_due.amount, paid_invoice.balance_due.currency_code);
|
||||
println!(" - Payment status: {:?}", paid_invoice.payment_status);
|
||||
println!(" - Invoice status: {:?}", paid_invoice.status);
|
||||
println!(" - New balance due: ${} {}", invoice_copy.balance_due.amount, invoice_copy.balance_due.currency_code);
|
||||
println!(" - Payment status: {:?}", invoice_copy.payment_status);
|
||||
println!(" - Invoice status: {:?}", invoice_copy.status);
|
||||
db.set(&invoice_copy)?;
|
||||
|
||||
// Retrieve data from the database to verify persistence
|
||||
println!("\nRetrieving data from database:");
|
||||
|
||||
// Retrieve customer
|
||||
let retrieved_customer = db.get::<Customer>(customer.get_id())?;
|
||||
println!("Retrieved customer: {} (ID: {})", retrieved_customer.name, retrieved_customer.get_id());
|
||||
|
||||
// Retrieve product
|
||||
let retrieved_product = db.get::<Product>(premium_node.get_id())?;
|
||||
println!("Retrieved product: {} (ID: {})", retrieved_product.name, retrieved_product.get_id());
|
||||
|
||||
// Retrieve sale
|
||||
let retrieved_sale = db.get::<Sale>(sale.get_id())?;
|
||||
println!("Retrieved sale: ID {} with {} items", retrieved_sale.get_id(), retrieved_sale.items.len());
|
||||
|
||||
// Retrieve invoice
|
||||
let retrieved_invoice = db.get::<Invoice>(invoice.get_id())?;
|
||||
println!("Retrieved invoice: ID {} with status {:?}", retrieved_invoice.get_id(), retrieved_invoice.status);
|
||||
|
||||
println!("\nBusiness transaction completed successfully!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a customer for our example
|
||||
@ -76,14 +123,20 @@ fn create_customer() -> Customer {
|
||||
|
||||
/// Create two types of server node products with their components
|
||||
fn create_server_products() -> (Product, Product) {
|
||||
// Create currency for pricing
|
||||
let usd = |amount| {
|
||||
CurrencyBuilder::new()
|
||||
.amount(amount)
|
||||
.currency_code("USD")
|
||||
.build()
|
||||
.expect("Failed to create currency")
|
||||
};
|
||||
// Create currencies for pricing
|
||||
let standard_price = CurrencyBuilder::new()
|
||||
.id(100)
|
||||
.amount(99.99)
|
||||
.currency_code("USD")
|
||||
.build()
|
||||
.expect("Failed to create currency");
|
||||
|
||||
let premium_price = CurrencyBuilder::new()
|
||||
.id(101)
|
||||
.amount(199.99)
|
||||
.currency_code("USD")
|
||||
.build()
|
||||
.expect("Failed to create currency");
|
||||
|
||||
// Standard Node Components
|
||||
let cpu_standard = ProductComponentBuilder::new()
|
||||
@ -148,7 +201,7 @@ fn create_server_products() -> (Product, Product) {
|
||||
.id(1)
|
||||
.name("Standard Server Node")
|
||||
.description("Basic server node for general workloads")
|
||||
.price(usd(99.99))
|
||||
.price(standard_price)
|
||||
.type_(ProductType::Product)
|
||||
.category("Servers")
|
||||
.status(ProductStatus::Available)
|
||||
@ -165,7 +218,7 @@ fn create_server_products() -> (Product, Product) {
|
||||
.id(2)
|
||||
.name("Premium Server Node")
|
||||
.description("High-performance server node for demanding workloads")
|
||||
.price(usd(199.99))
|
||||
.price(premium_price)
|
||||
.type_(ProductType::Product)
|
||||
.category("Servers")
|
||||
.status(ProductStatus::Available)
|
||||
@ -198,7 +251,7 @@ fn create_sale(customer: &Customer, product: &Product) -> Sale {
|
||||
let sale_item = SaleItemBuilder::new()
|
||||
.id(1)
|
||||
.sale_id(1)
|
||||
.product_id(product.get_id())
|
||||
.product_id(Some(product.get_id()))
|
||||
.name(product.name.clone())
|
||||
.description(product.description.clone())
|
||||
.comments("Customer requested expedited setup")
|
||||
@ -256,7 +309,7 @@ fn create_invoice(customer: &Customer, sale: &Sale) -> Invoice {
|
||||
}
|
||||
|
||||
/// Process a payment for an invoice
|
||||
fn process_payment(mut invoice: Invoice) -> Invoice {
|
||||
fn process_payment(invoice: &mut Invoice) {
|
||||
// Create a payment for the full amount
|
||||
let payment = Payment::new(
|
||||
invoice.total_amount.clone(),
|
||||
@ -270,6 +323,4 @@ fn process_payment(mut invoice: Invoice) -> Invoice {
|
||||
// The invoice should now be marked as paid
|
||||
assert_eq!(invoice.payment_status, PaymentStatus::Paid);
|
||||
assert_eq!(invoice.status, InvoiceStatus::Paid);
|
||||
|
||||
invoice
|
||||
}
|
@ -3,8 +3,5 @@
|
||||
//! This module demonstrates business models in action,
|
||||
//! including products, sales, invoices, and payments.
|
||||
|
||||
// Re-export the main function
|
||||
pub use self::main::*;
|
||||
|
||||
// Include the main module
|
||||
mod main;
|
||||
// Include the main module directly
|
||||
pub mod main;
|
@ -9,6 +9,7 @@ use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Note: This example has been modified to work with the current API
|
||||
println!("DB Example 2: Using Builder Pattern and Model-Specific Methods");
|
||||
println!("============================================================");
|
||||
|
||||
@ -20,148 +21,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fs::create_dir_all(&db_path)?;
|
||||
println!("Database path: {:?}", db_path);
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine
|
||||
.build_type::<Product>()
|
||||
.build_type::<ProductBuilder>()
|
||||
.build_type::<ProductComponentBuilder>()
|
||||
.build_type::<Currency>()
|
||||
.build_type::<CurrencyBuilder>()
|
||||
.build_type::<Sale>()
|
||||
.build_type::<SaleBuilder>()
|
||||
.build_type::<DBBuilder>()
|
||||
.build_type::<DB>();
|
||||
|
||||
// Register currency builder methods
|
||||
engine.register_fn("new_currency_builder", CurrencyBuilder::new);
|
||||
engine.register_fn("amount", CurrencyBuilder::amount);
|
||||
engine.register_fn("currency_code", CurrencyBuilder::currency_code::<String>);
|
||||
engine.register_fn("build", CurrencyBuilder::build);
|
||||
|
||||
// Register method to verify currency
|
||||
engine.register_fn("amount", Currency::amount);
|
||||
|
||||
// Register product component builder methods
|
||||
engine.register_fn(
|
||||
"new_product_component_builder",
|
||||
ProductComponentBuilder::new,
|
||||
);
|
||||
engine.register_fn("id", ProductComponentBuilder::id);
|
||||
engine.register_fn("name", ProductComponentBuilder::name::<String>);
|
||||
engine.register_fn(
|
||||
"description",
|
||||
ProductComponentBuilder::description::<String>,
|
||||
);
|
||||
engine.register_fn("quantity", ProductComponentBuilder::quantity);
|
||||
engine.register_fn("build", ProductComponentBuilder::build);
|
||||
|
||||
// Register product builder methods
|
||||
engine.register_fn("new_product_builder", ProductBuilder::new);
|
||||
engine.register_fn("id", ProductBuilder::id);
|
||||
engine.register_fn("name", ProductBuilder::name::<String>);
|
||||
engine.register_fn("description", ProductBuilder::description::<String>);
|
||||
engine.register_fn("price", ProductBuilder::price);
|
||||
engine.register_fn("type", ProductBuilder::type_);
|
||||
engine.register_fn("category", ProductBuilder::category::<String>);
|
||||
engine.register_fn("status", ProductBuilder::status);
|
||||
engine.register_fn("max_amount", ProductBuilder::max_amount);
|
||||
engine.register_fn("validity_days", ProductBuilder::validity_days);
|
||||
engine.register_fn("add_component", ProductBuilder::add_component);
|
||||
engine.register_fn("build", ProductBuilder::build);
|
||||
|
||||
// Register db builder methods
|
||||
engine.register_fn("new_db_builder", DBBuilder::new::<String>);
|
||||
engine.register_fn("register_currency", DBBuilder::register_model::<Currency>);
|
||||
engine.register_fn("register_product", DBBuilder::register_model::<Product>);
|
||||
engine.register_fn("register_sale", DBBuilder::register_model::<Sale>);
|
||||
engine.register_fn("currency_code", CurrencyBuilder::currency_code::<String>);
|
||||
engine.register_fn("build", DBBuilder::build);
|
||||
|
||||
// Register db methods
|
||||
engine.register_fn("insert_currency", DB::insert_currency);
|
||||
engine.register_fn("insert_product", DB::insert_product);
|
||||
|
||||
let script = r#"
|
||||
let usd = new_currency_builder()
|
||||
.amount(0.0)
|
||||
.currency_code("USD")
|
||||
.build();
|
||||
|
||||
// Can we access and print this from the actual Currency?
|
||||
print(usd.amount());
|
||||
|
||||
let db = new_db_builder("./tmp/dbexample2")
|
||||
.register_product()
|
||||
.register_currency()
|
||||
.register_sale()
|
||||
.build();
|
||||
|
||||
db.insert_currency(usd);
|
||||
|
||||
let component1 = new_product_component_builder()
|
||||
.id(101)
|
||||
.name("Basic Support")
|
||||
.description("24/7 email support")
|
||||
.quantity(1)
|
||||
.build();
|
||||
|
||||
let component2 = new_product_component_builder()
|
||||
.id(102)
|
||||
.name("Premium Support")
|
||||
.description("24/7 phone and email support")
|
||||
.quantity(1)
|
||||
.build();
|
||||
|
||||
// Create products using the builder
|
||||
// let product1 = new_product_builder()
|
||||
// .id(1)
|
||||
// .name("Standard Plan")
|
||||
// .description("Our standard service offering")
|
||||
// .price(
|
||||
// new_currency_builder()
|
||||
// .amount(29.99)
|
||||
// .currency_code("USD")
|
||||
// .build()
|
||||
// )
|
||||
// .type_(ProductType::Service)
|
||||
// .category("Subscription")
|
||||
// .status(ProductStatus::Available)
|
||||
// .max_amount(1000)
|
||||
// .validity_days(30)
|
||||
// .add_component(component1)
|
||||
// .build();
|
||||
//
|
||||
// let product2 = new_product_builder()
|
||||
// .id(2)
|
||||
// .name("Premium Plan")
|
||||
// .description("Our premium service offering with priority support")
|
||||
// .price(
|
||||
// new_currency_builder()
|
||||
// .amount(99.99)
|
||||
// .currency_code("USD")
|
||||
// .build()
|
||||
// )
|
||||
// .type_(ProductType::Service)
|
||||
// .category("Subscription")
|
||||
// .status(ProductStatus::Available)
|
||||
// .max_amount(500)
|
||||
// .validity_days(30)
|
||||
// .add_component(component2)
|
||||
// .build();
|
||||
|
||||
// Insert products using model-specific methods
|
||||
// db.insert_product(product1);
|
||||
// db.insert_product(product2);
|
||||
"#;
|
||||
|
||||
|
||||
println!("\n0. Executing Script");
|
||||
println!("----------------------------------------");
|
||||
|
||||
|
||||
engine.eval::<()>(script)?;
|
||||
|
||||
// Skip the Rhai engine part as it has compatibility issues
|
||||
println!("\nSkipping Rhai engine part due to compatibility issues");
|
||||
|
||||
// Create a database instance with our models registered
|
||||
let mut db = DBBuilder::new(&db_path)
|
||||
.register_model::<Product>()
|
||||
@ -169,26 +31,19 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.register_model::<Sale>()
|
||||
.build()?;
|
||||
|
||||
// Check if the currency created in the script is actually present, if it is this value should
|
||||
// be 1 (NOTE: it will be :) ).
|
||||
let currencies = db.list_currencies()?;
|
||||
println!("Found {} currencies in db", currencies.len());
|
||||
for currency in currencies {
|
||||
println!("{} {}", currency.amount, currency.currency_code);
|
||||
}
|
||||
|
||||
println!("\n1. Creating Products with Builder Pattern");
|
||||
println!("----------------------------------------");
|
||||
|
||||
// // Create a currency using the builder
|
||||
// let usd = CurrencyBuilder::new()
|
||||
// .amount(0.0) // Initial amount
|
||||
// .currency_code("USD")
|
||||
// .build()?;
|
||||
//
|
||||
// // Insert the currency
|
||||
// db.insert_currency(usd.clone())?;
|
||||
// println!("Currency created: ${:.2} {}", usd.amount, usd.currency_code);
|
||||
// Create a currency using the builder
|
||||
let usd = CurrencyBuilder::new()
|
||||
.id(1) // Add the required ID
|
||||
.amount(0.0) // Initial amount
|
||||
.currency_code("USD")
|
||||
.build()?;
|
||||
|
||||
// Insert the currency
|
||||
db.insert_currency(usd.clone())?;
|
||||
println!("Currency created: ${:.2} {}", usd.amount, usd.currency_code);
|
||||
|
||||
// Create product components using the builder
|
||||
let component1 = ProductComponentBuilder::new()
|
||||
@ -204,6 +59,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.description("24/7 phone and email support")
|
||||
.quantity(1)
|
||||
.build()?;
|
||||
|
||||
// Create products using the builder
|
||||
let product1 = ProductBuilder::new()
|
||||
.id(1)
|
||||
@ -211,6 +67,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.description("Our standard service offering")
|
||||
.price(
|
||||
CurrencyBuilder::new()
|
||||
.id(2) // Add ID
|
||||
.amount(29.99)
|
||||
.currency_code("USD")
|
||||
.build()?,
|
||||
@ -229,6 +86,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.description("Our premium service offering with priority support")
|
||||
.price(
|
||||
CurrencyBuilder::new()
|
||||
.id(3) // Add ID
|
||||
.amount(99.99)
|
||||
.currency_code("USD")
|
||||
.build()?,
|
||||
@ -296,11 +154,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let item1 = SaleItemBuilder::new()
|
||||
.id(201)
|
||||
.sale_id(1)
|
||||
.product_id(1)
|
||||
.product_id(Some(1))
|
||||
.name("Standard Plan")
|
||||
.quantity(1)
|
||||
.unit_price(
|
||||
CurrencyBuilder::new()
|
||||
.id(4) // Add ID
|
||||
.amount(29.99)
|
||||
.currency_code("USD")
|
||||
.build()?,
|
||||
@ -311,8 +170,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let sale = SaleBuilder::new()
|
||||
.id(1)
|
||||
.company_id(101)
|
||||
.buyer_name("John Doe")
|
||||
.buyer_email("john.doe@example.com")
|
||||
.customer_id(123)
|
||||
.currency_code("USD")
|
||||
.status(SaleStatus::Pending)
|
||||
.add_item(item1)
|
||||
@ -321,8 +179,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Insert the sale using model-specific methods
|
||||
db.insert_sale(sale.clone())?;
|
||||
println!(
|
||||
"Sale created: #{} for {} (${:.2})",
|
||||
sale.id, sale.buyer_name, sale.total_amount.amount
|
||||
"Sale created: #{} for customer #{} (${:.2})",
|
||||
sale.id, sale.customer_id, sale.total_amount.amount
|
||||
);
|
||||
|
||||
println!("\n5. Updating a Sale");
|
||||
|
@ -4,4 +4,4 @@
|
||||
//! that demonstrate how to use HeroDB in different scenarios.
|
||||
|
||||
// Export the example modules
|
||||
pub mod dbexample_biz;
|
||||
// pub mod dbexample_biz; // Commented out to avoid circular imports
|
@ -21,6 +21,9 @@ pub use tst_index::TSTIndexManager;
|
||||
// Export macros for model methods
|
||||
pub mod macros;
|
||||
|
||||
// Export model-specific methods
|
||||
pub mod model_methods;
|
||||
|
||||
// Tests
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::db::db::DB;
|
||||
use crate::db::model::Model;
|
||||
use crate::impl_model_methods;
|
||||
use crate::DbResult; // Add DbResult import
|
||||
use crate::models::biz::{Product, Sale, Currency, ExchangeRate, Service, Customer, Contract, Invoice};
|
||||
use crate::models::gov::{
|
||||
Company, Shareholder, Meeting, User, Vote, Resolution,
|
||||
Committee, ComplianceRequirement, ComplianceDocument, ComplianceAudit
|
||||
Committee
|
||||
// ComplianceRequirement, ComplianceDocument, ComplianceAudit - These don't exist
|
||||
};
|
||||
use crate::models::circle::{Circle, Member, Name, Wallet, Asset};
|
||||
use crate::models::circle::{Circle, Member, Name, Wallet}; // Remove Asset
|
||||
|
||||
// Implement model-specific methods for Product
|
||||
impl_model_methods!(Product, product, products);
|
||||
@ -53,14 +55,15 @@ impl_model_methods!(Resolution, resolution, resolutions);
|
||||
// Implement model-specific methods for Committee
|
||||
impl_model_methods!(Committee, committee, committees);
|
||||
|
||||
// Implement model-specific methods for ComplianceRequirement
|
||||
impl_model_methods!(ComplianceRequirement, compliance_requirement, compliance_requirements);
|
||||
// These models don't exist, so comment them out
|
||||
// // Implement model-specific methods for ComplianceRequirement
|
||||
// impl_model_methods!(ComplianceRequirement, compliance_requirement, compliance_requirements);
|
||||
|
||||
// Implement model-specific methods for ComplianceDocument
|
||||
impl_model_methods!(ComplianceDocument, compliance_document, compliance_documents);
|
||||
// // Implement model-specific methods for ComplianceDocument
|
||||
// impl_model_methods!(ComplianceDocument, compliance_document, compliance_documents);
|
||||
|
||||
// Implement model-specific methods for ComplianceAudit
|
||||
impl_model_methods!(ComplianceAudit, compliance_audit, compliance_audits);
|
||||
// // Implement model-specific methods for ComplianceAudit
|
||||
// impl_model_methods!(ComplianceAudit, compliance_audit, compliance_audits);
|
||||
|
||||
// Implement model-specific methods for Circle
|
||||
impl_model_methods!(Circle, circle, circles);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::models::biz::Currency; // Use crate:: for importing from the module
|
||||
use crate::db::{Model, Storable, IndexKey}; // Import Model trait and IndexKey from db module
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::{DateTime, Utc, Datelike};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// InvoiceStatus represents the status of an invoice
|
||||
@ -555,13 +555,13 @@ impl Model for Invoice {
|
||||
// Add an index for issue date (year-month)
|
||||
keys.push(IndexKey {
|
||||
name: "issue_date",
|
||||
value: format!("{}-{:02}", self.issue_date.year(), self.issue_date.month()),
|
||||
value: format!("{}", self.issue_date.format("%Y-%m")),
|
||||
});
|
||||
|
||||
// Add an index for due date (year-month)
|
||||
keys.push(IndexKey {
|
||||
name: "due_date",
|
||||
value: format!("{}-{:02}", self.due_date.year(), self.due_date.month()),
|
||||
value: format!("{}", self.due_date.format("%Y-%m")),
|
||||
});
|
||||
|
||||
// Add an index for overdue invoices
|
||||
|
Loading…
Reference in New Issue
Block a user