db/heromodels/examples/governance_rhai/example.rs
2025-05-13 01:58:35 +03:00

190 lines
7.3 KiB
Rust

use heromodels::db::hero::OurDB;
use heromodels::models::governance::{Proposal, ProposalStatus, VoteEventStatus, VoteOption, Ballot};
use rhai::Engine;
use rhai_wrapper::wrap_vec_return;
use std::sync::Arc;
use std::{fs, path::Path};
use chrono::{Utc, Duration};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize Rhai engine
let mut engine = Engine::new();
// Initialize database
let db = Arc::new(OurDB::new("temp_governance_db", true).expect("Failed to create database"));
// Register the Proposal type with Rhai
// This function is generated by the #[rhai_model_export] attribute
Proposal::register_rhai_bindings_for_proposal(&mut engine, db.clone());
// Register the Ballot type with Rhai
Ballot::register_rhai_bindings_for_ballot(&mut engine, db.clone());
// Register a function to get the database instance
engine.register_fn("get_db", move || db.clone());
// Register builder functions for Proposal and related types
engine.register_fn("create_proposal", |id: i64, creator_id: String, title: String, description: String| {
let start_date = Utc::now();
let end_date = start_date + Duration::days(14);
Proposal::new(id as u32, creator_id, title, description, start_date, end_date)
});
engine.register_fn("create_vote_option", |id: i64, text: String| {
VoteOption::new(id as u8, text)
});
engine.register_fn("create_ballot", |id: i64, user_id: i64, vote_option_id: i64, shares_count: i64| {
Ballot::new(id as u32, user_id as u32, vote_option_id as u8, shares_count)
});
// Register getter and setter methods for Proposal properties
engine.register_fn("get_title", |proposal: Proposal| -> String {
proposal.title.clone()
});
engine.register_fn("get_description", |proposal: Proposal| -> String {
proposal.description.clone()
});
engine.register_fn("get_creator_id", |proposal: Proposal| -> String {
proposal.creator_id.clone()
});
engine.register_fn("get_id", |proposal: Proposal| -> i64 {
proposal.base_data.id as i64
});
engine.register_fn("get_status", |proposal: Proposal| -> String {
format!("{:?}", proposal.status)
});
engine.register_fn("get_vote_status", |proposal: Proposal| -> String {
format!("{:?}", proposal.vote_status)
});
// Register methods for proposal operations
engine.register_fn("add_option_to_proposal", |mut proposal: Proposal, option_id: i64, option_text: String| -> Proposal {
proposal.add_option(option_id as u8, option_text)
});
engine.register_fn("cast_vote_on_proposal", |mut proposal: Proposal, ballot_id: i64, user_id: i64, option_id: i64, shares: i64| -> Proposal {
proposal.cast_vote(ballot_id as u32, user_id as u32, option_id as u8, shares)
});
engine.register_fn("change_proposal_status", |mut proposal: Proposal, status_str: String| -> Proposal {
let new_status = match status_str.as_str() {
"Draft" => ProposalStatus::Draft,
"Active" => ProposalStatus::Active,
"Approved" => ProposalStatus::Approved,
"Rejected" => ProposalStatus::Rejected,
"Cancelled" => ProposalStatus::Cancelled,
_ => ProposalStatus::Draft,
};
proposal.change_proposal_status(new_status)
});
engine.register_fn("change_vote_event_status", |mut proposal: Proposal, status_str: String| -> Proposal {
let new_status = match status_str.as_str() {
"Open" => VoteEventStatus::Open,
"Closed" => VoteEventStatus::Closed,
"Cancelled" => VoteEventStatus::Cancelled,
_ => VoteEventStatus::Open,
};
proposal.change_vote_event_status(new_status)
});
// Register functions for database operations
engine.register_fn("save_proposal", |_db: Arc<OurDB>, proposal: Proposal| {
println!("Proposal saved: {}", proposal.title);
});
engine.register_fn("get_proposal_by_id", |_db: Arc<OurDB>, id: i64| -> Proposal {
// In a real implementation, this would retrieve the proposal from the database
let start_date = Utc::now();
let end_date = start_date + Duration::days(14);
Proposal::new(id as u32, "Retrieved Creator", "Retrieved Proposal", "Retrieved Description", start_date, end_date)
});
// Register a function to check if a proposal exists
engine.register_fn("proposal_exists", |_db: Arc<OurDB>, id: i64| -> bool {
// In a real implementation, this would check if the proposal exists in the database
id == 1 || id == 2
});
// Define the function for get_all_proposals
fn get_all_proposals(_db: Arc<OurDB>) -> Vec<Proposal> {
// In a real implementation, this would retrieve all proposals from the database
let start_date = Utc::now();
let end_date = start_date + Duration::days(14);
vec![
Proposal::new(1, "Creator 1", "Proposal 1", "Description 1", start_date, end_date),
Proposal::new(2, "Creator 2", "Proposal 2", "Description 2", start_date, end_date)
]
}
// Register the function with the wrap_vec_return macro
engine.register_fn("get_all_proposals", wrap_vec_return!(get_all_proposals, Arc<OurDB> => Proposal));
engine.register_fn("delete_proposal_by_id", |_db: Arc<OurDB>, _id: i64| {
// In a real implementation, this would delete the proposal from the database
println!("Proposal deleted with ID: {}", _id);
});
// Register helper functions for accessing proposal options and ballots
engine.register_fn("get_option_count", |proposal: Proposal| -> i64 {
proposal.options.len() as i64
});
engine.register_fn("get_option_at", |proposal: Proposal, index: i64| -> VoteOption {
if index >= 0 && index < proposal.options.len() as i64 {
proposal.options[index as usize].clone()
} else {
VoteOption::new(0, "Invalid Option")
}
});
engine.register_fn("get_option_text", |option: VoteOption| -> String {
option.text.clone()
});
engine.register_fn("get_option_votes", |option: VoteOption| -> i64 {
option.count
});
engine.register_fn("get_ballot_count", |proposal: Proposal| -> i64 {
proposal.ballots.len() as i64
});
engine.register_fn("get_ballot_at", |proposal: Proposal, index: i64| -> Ballot {
if index >= 0 && index < proposal.ballots.len() as i64 {
proposal.ballots[index as usize].clone()
} else {
Ballot::new(0, 0, 0, 0)
}
});
engine.register_fn("get_ballot_user_id", |ballot: Ballot| -> i64 {
ballot.user_id as i64
});
engine.register_fn("get_ballot_option_id", |ballot: Ballot| -> i64 {
ballot.vote_option_id as i64
});
engine.register_fn("get_ballot_shares", |ballot: Ballot| -> i64 {
ballot.shares_count
});
// Load and evaluate the Rhai script
let script_path = Path::new("examples/governance_rhai/governance.rhai");
let script = fs::read_to_string(script_path)?;
match engine.eval::<()>(&script) {
Ok(_) => println!("Script executed successfully!"),
Err(e) => eprintln!("Script execution failed: {}", e),
}
Ok(())
}