feat: Add get_all method to list all db objects based on the object model
This commit is contained in:
parent
bd36d6bda0
commit
4c0c7be574
@ -1,6 +1,6 @@
|
|||||||
// heromodels/examples/governance_proposal_example/main.rs
|
// heromodels/examples/governance_proposal_example/main.rs
|
||||||
|
|
||||||
use chrono::{Utc, Duration};
|
use chrono::{Duration, Utc};
|
||||||
use heromodels::db::{Collection, Db};
|
use heromodels::db::{Collection, Db};
|
||||||
use heromodels::models::governance::{Proposal, ProposalStatus, VoteEventStatus};
|
use heromodels::models::governance::{Proposal, ProposalStatus, VoteEventStatus};
|
||||||
|
|
||||||
@ -18,12 +18,21 @@ fn main() {
|
|||||||
"Community Fund Allocation for Q3", // title
|
"Community Fund Allocation for Q3", // title
|
||||||
"Proposal to allocate funds for community projects in the third quarter.", // description
|
"Proposal to allocate funds for community projects in the third quarter.", // description
|
||||||
Utc::now(), // vote_start_date
|
Utc::now(), // vote_start_date
|
||||||
Utc::now() + Duration::days(14) // vote_end_date (14 days from now)
|
Utc::now() + Duration::days(14), // vote_end_date (14 days from now)
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("Before saving - Created Proposal: '{}' (ID: {})", proposal.title, proposal.base_data.id);
|
println!(
|
||||||
println!("Before saving - Status: {:?}, Vote Status: {:?}", proposal.status, proposal.vote_status);
|
"Before saving - Created Proposal: '{}' (ID: {})",
|
||||||
println!("Before saving - Vote Period: {} to {}\n", proposal.vote_start_date, proposal.vote_end_date);
|
proposal.title, proposal.base_data.id
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Before saving - Status: {:?}, Vote Status: {:?}",
|
||||||
|
proposal.status, proposal.vote_status
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Before saving - Vote Period: {} to {}\n",
|
||||||
|
proposal.vote_start_date, proposal.vote_end_date
|
||||||
|
);
|
||||||
|
|
||||||
// Add vote options
|
// Add vote options
|
||||||
proposal = proposal.add_option(1, "Approve Allocation");
|
proposal = proposal.add_option(1, "Approve Allocation");
|
||||||
@ -32,15 +41,23 @@ fn main() {
|
|||||||
|
|
||||||
println!("Added Vote Options:");
|
println!("Added Vote Options:");
|
||||||
for option in &proposal.options {
|
for option in &proposal.options {
|
||||||
println!("- Option ID: {}, Text: '{}', Votes: {}", option.id, option.text, option.count);
|
println!(
|
||||||
|
"- Option ID: {}, Text: '{}', Votes: {}",
|
||||||
|
option.id, option.text, option.count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
// Save the proposal to the database
|
// Save the proposal to the database
|
||||||
let collection = db.collection::<Proposal>().expect("can open proposal collection");
|
let collection = db
|
||||||
|
.collection::<Proposal>()
|
||||||
|
.expect("can open proposal collection");
|
||||||
let (proposal_id, saved_proposal) = collection.set(&proposal).expect("can save proposal");
|
let (proposal_id, saved_proposal) = collection.set(&proposal).expect("can save proposal");
|
||||||
|
|
||||||
println!("After saving - Proposal ID: {}", saved_proposal.base_data.id);
|
println!(
|
||||||
|
"After saving - Proposal ID: {}",
|
||||||
|
saved_proposal.base_data.id
|
||||||
|
);
|
||||||
println!("After saving - Returned ID: {}", proposal_id);
|
println!("After saving - Returned ID: {}", proposal_id);
|
||||||
|
|
||||||
// Use the saved proposal for further operations
|
// Use the saved proposal for further operations
|
||||||
@ -63,13 +80,18 @@ fn main() {
|
|||||||
|
|
||||||
println!("\nVote Counts After Simulation:");
|
println!("\nVote Counts After Simulation:");
|
||||||
for option in &proposal.options {
|
for option in &proposal.options {
|
||||||
println!("- Option ID: {}, Text: '{}', Votes: {}", option.id, option.text, option.count);
|
println!(
|
||||||
|
"- Option ID: {}, Text: '{}', Votes: {}",
|
||||||
|
option.id, option.text, option.count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\nBallots Cast:");
|
println!("\nBallots Cast:");
|
||||||
for ballot in &proposal.ballots {
|
for ballot in &proposal.ballots {
|
||||||
println!("- Ballot ID: {}, User ID: {}, Option ID: {}, Shares: {}",
|
println!(
|
||||||
ballot.base_data.id, ballot.user_id, ballot.vote_option_id, ballot.shares_count);
|
"- Ballot ID: {}, User ID: {}, Option ID: {}, Shares: {}",
|
||||||
|
ballot.base_data.id, ballot.user_id, ballot.vote_option_id, ballot.shares_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
@ -92,7 +114,10 @@ fn main() {
|
|||||||
println!("Vote Status: {:?}", proposal.vote_status);
|
println!("Vote Status: {:?}", proposal.vote_status);
|
||||||
println!("Options:");
|
println!("Options:");
|
||||||
for option in &proposal.options {
|
for option in &proposal.options {
|
||||||
println!(" - {}: {} (Votes: {})", option.id, option.text, option.count);
|
println!(
|
||||||
|
" - {}: {} (Votes: {})",
|
||||||
|
option.id, option.text, option.count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
println!("Total Ballots: {}", proposal.ballots.len());
|
println!("Total Ballots: {}", proposal.ballots.len());
|
||||||
|
|
||||||
@ -103,20 +128,31 @@ fn main() {
|
|||||||
"Internal Team Restructure Vote",
|
"Internal Team Restructure Vote",
|
||||||
"Vote on proposed internal team changes.",
|
"Vote on proposed internal team changes.",
|
||||||
Utc::now(),
|
Utc::now(),
|
||||||
Utc::now() + Duration::days(7)
|
Utc::now() + Duration::days(7),
|
||||||
);
|
);
|
||||||
private_proposal.private_group = Some(vec![10, 20, 30]); // Only users 10, 20, 30 can vote
|
private_proposal.private_group = Some(vec![10, 20, 30]); // Only users 10, 20, 30 can vote
|
||||||
private_proposal = private_proposal.add_option(1, "Accept Restructure");
|
private_proposal = private_proposal.add_option(1, "Accept Restructure");
|
||||||
private_proposal = private_proposal.add_option(2, "Reject Restructure");
|
private_proposal = private_proposal.add_option(2, "Reject Restructure");
|
||||||
|
|
||||||
println!("\nBefore saving - Created Private Proposal: '{}'", private_proposal.title);
|
println!(
|
||||||
println!("Before saving - Eligible Voters (Group): {:?}", private_proposal.private_group);
|
"\nBefore saving - Created Private Proposal: '{}'",
|
||||||
|
private_proposal.title
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Before saving - Eligible Voters (Group): {:?}",
|
||||||
|
private_proposal.private_group
|
||||||
|
);
|
||||||
|
|
||||||
// Save the private proposal to the database
|
// Save the private proposal to the database
|
||||||
let (private_proposal_id, saved_private_proposal) = collection.set(&private_proposal).expect("can save private proposal");
|
let (private_proposal_id, saved_private_proposal) = collection
|
||||||
|
.set(&private_proposal)
|
||||||
|
.expect("can save private proposal");
|
||||||
private_proposal = saved_private_proposal;
|
private_proposal = saved_private_proposal;
|
||||||
|
|
||||||
println!("After saving - Private Proposal ID: {}", private_proposal.base_data.id);
|
println!(
|
||||||
|
"After saving - Private Proposal ID: {}",
|
||||||
|
private_proposal.base_data.id
|
||||||
|
);
|
||||||
println!("After saving - Returned ID: {}", private_proposal_id);
|
println!("After saving - Returned ID: {}", private_proposal_id);
|
||||||
|
|
||||||
// User 10 (eligible) votes with explicit ballot ID
|
// User 10 (eligible) votes with explicit ballot ID
|
||||||
@ -126,9 +162,41 @@ fn main() {
|
|||||||
|
|
||||||
println!("Private Proposal Vote Counts:");
|
println!("Private Proposal Vote Counts:");
|
||||||
for option in &private_proposal.options {
|
for option in &private_proposal.options {
|
||||||
println!(" - {}: {} (Votes: {})", option.id, option.text, option.count);
|
println!(
|
||||||
|
" - {}: {} (Votes: {})",
|
||||||
|
option.id, option.text, option.count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\nExample finished. DB stored at {}", db_path);
|
println!("\nExample finished. DB stored at {}", db_path);
|
||||||
println!("To clean up, you can manually delete the directory: {}", db_path);
|
println!(
|
||||||
|
"To clean up, you can manually delete the directory: {}",
|
||||||
|
db_path
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- Additional Example: Listing and Filtering Proposals ---
|
||||||
|
println!("\n--- Listing All Proposals ---");
|
||||||
|
// List all proposals from the DB
|
||||||
|
let all_proposals = collection.get_all().expect("can list all proposals");
|
||||||
|
for proposal in &all_proposals {
|
||||||
|
println!(
|
||||||
|
"- Proposal ID: {}, Title: '{}', Status: {:?}",
|
||||||
|
proposal.base_data.id, proposal.title, proposal.status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Total proposals in DB: {}", all_proposals.len());
|
||||||
|
|
||||||
|
// Filter proposals by status (e.g., only Active proposals)
|
||||||
|
let active_proposals: Vec<_> = all_proposals
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.status == ProposalStatus::Active)
|
||||||
|
.collect();
|
||||||
|
println!("\n--- Filtering Proposals by Status: Active ---");
|
||||||
|
for proposal in &active_proposals {
|
||||||
|
println!(
|
||||||
|
"- Proposal ID: {}, Title: '{}', Status: {:?}",
|
||||||
|
proposal.base_data.id, proposal.title, proposal.status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Total ACTIVE proposals: {}", active_proposals.len());
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
|
use crate::db::Transaction;
|
||||||
use heromodels_core::{Index, Model};
|
use heromodels_core::{Index, Model};
|
||||||
use ourdb::OurDBSetArgs;
|
use ourdb::OurDBSetArgs;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use crate::db::Transaction;
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex, atomic::{AtomicU32, Ordering}},
|
sync::{
|
||||||
|
Arc, Mutex,
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configuration for custom ID sequences
|
/// Configuration for custom ID sequences
|
||||||
@ -85,7 +88,11 @@ impl OurDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new instance of ourdb with a custom ID sequence
|
/// Create a new instance of ourdb with a custom ID sequence
|
||||||
pub fn with_id_sequence(path: impl Into<PathBuf>, reset: bool, id_sequence: IdSequence) -> Result<Self, tst::Error> {
|
pub fn with_id_sequence(
|
||||||
|
path: impl Into<PathBuf>,
|
||||||
|
reset: bool,
|
||||||
|
id_sequence: IdSequence,
|
||||||
|
) -> Result<Self, tst::Error> {
|
||||||
let mut base_path = path.into();
|
let mut base_path = path.into();
|
||||||
let mut data_path = base_path.clone();
|
let mut data_path = base_path.clone();
|
||||||
base_path.push("index");
|
base_path.push("index");
|
||||||
@ -138,7 +145,9 @@ where
|
|||||||
type Error = tst::Error;
|
type Error = tst::Error;
|
||||||
|
|
||||||
/// Begin a transaction for this collection
|
/// Begin a transaction for this collection
|
||||||
fn begin_transaction(&self) -> Result<Box<dyn super::Transaction<Error = Self::Error>>, super::Error<Self::Error>> {
|
fn begin_transaction(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn super::Transaction<Error = Self::Error>>, super::Error<Self::Error>> {
|
||||||
// Create a new transaction
|
// Create a new transaction
|
||||||
let transaction = OurDBTransaction::new();
|
let transaction = OurDBTransaction::new();
|
||||||
|
|
||||||
@ -287,7 +296,7 @@ where
|
|||||||
// and save it again to ensure the serialized data contains the correct ID
|
// and save it again to ensure the serialized data contains the correct ID
|
||||||
let mut value_clone = value.clone();
|
let mut value_clone = value.clone();
|
||||||
let base_data = value_clone.base_data_mut();
|
let base_data = value_clone.base_data_mut();
|
||||||
base_data.update_id(assigned_id);
|
base_data.id = assigned_id;
|
||||||
|
|
||||||
// Serialize the updated model
|
// Serialize the updated model
|
||||||
let v = bincode::serde::encode_to_vec(&value_clone, BINCODE_CONFIG)?;
|
let v = bincode::serde::encode_to_vec(&value_clone, BINCODE_CONFIG)?;
|
||||||
@ -327,10 +336,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the updated model from the database
|
// Get the updated model from the database
|
||||||
let updated_model = Self::get_ourdb_value::<M>(&mut data_db, assigned_id)?
|
let updated_model =
|
||||||
.ok_or_else(|| super::Error::InvalidId(format!(
|
Self::get_ourdb_value::<M>(&mut data_db, assigned_id)?.ok_or_else(|| {
|
||||||
"Failed to retrieve model with ID {} after saving", assigned_id
|
super::Error::InvalidId(format!(
|
||||||
)))?;
|
"Failed to retrieve model with ID {} after saving",
|
||||||
|
assigned_id
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
// Return the assigned ID and the updated model
|
// Return the assigned ID and the updated model
|
||||||
Ok((assigned_id, updated_model))
|
Ok((assigned_id, updated_model))
|
||||||
@ -413,7 +425,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_all(&self) -> Result<Vec<M>, super::Error<Self::Error>> {
|
fn get_all(&self) -> Result<Vec<M>, super::Error<Self::Error>> {
|
||||||
todo!("OurDB doesn't have a list all method yet")
|
let mut data_db = self.data.lock().expect("can lock data DB");
|
||||||
|
let mut all_objs = Vec::new();
|
||||||
|
// Get the next available ID (exclusive upper bound)
|
||||||
|
let next_id = data_db.get_next_id().map_err(super::Error::from)?;
|
||||||
|
for id in 1..next_id {
|
||||||
|
match Self::get_ourdb_value::<M>(&mut data_db, id) {
|
||||||
|
Ok(Some(obj)) => all_objs.push(obj),
|
||||||
|
Ok(None) => continue, // skip missing IDs
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(all_objs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,7 +533,9 @@ struct OurDBTransaction {
|
|||||||
impl OurDBTransaction {
|
impl OurDBTransaction {
|
||||||
/// Create a new transaction
|
/// Create a new transaction
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self { active: std::sync::atomic::AtomicBool::new(false) }
|
Self {
|
||||||
|
active: std::sync::atomic::AtomicBool::new(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,8 +544,11 @@ impl Drop for OurDBTransaction {
|
|||||||
// If the transaction is still active when dropped, roll it back
|
// If the transaction is still active when dropped, roll it back
|
||||||
if self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
if self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
||||||
// We can't return an error from drop, so we just log it
|
// We can't return an error from drop, so we just log it
|
||||||
eprintln!("Warning: Transaction was dropped without being committed or rolled back. Rolling back automatically.");
|
eprintln!(
|
||||||
self.active.store(false, std::sync::atomic::Ordering::SeqCst);
|
"Warning: Transaction was dropped without being committed or rolled back. Rolling back automatically."
|
||||||
|
);
|
||||||
|
self.active
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,10 +569,13 @@ impl super::Transaction for OurDBTransaction {
|
|||||||
// In a real implementation, you would commit the transaction in the underlying database
|
// In a real implementation, you would commit the transaction in the underlying database
|
||||||
// For now, we just check if the transaction is active
|
// For now, we just check if the transaction is active
|
||||||
if !self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
if !self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
||||||
return Err(super::Error::InvalidId("Cannot commit an inactive transaction".to_string()));
|
return Err(super::Error::InvalidId(
|
||||||
|
"Cannot commit an inactive transaction".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active.store(false, std::sync::atomic::Ordering::SeqCst);
|
self.active
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,10 +584,13 @@ impl super::Transaction for OurDBTransaction {
|
|||||||
// In a real implementation, you would roll back the transaction in the underlying database
|
// In a real implementation, you would roll back the transaction in the underlying database
|
||||||
// For now, we just check if the transaction is active
|
// For now, we just check if the transaction is active
|
||||||
if !self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
if !self.active.load(std::sync::atomic::Ordering::SeqCst) {
|
||||||
return Err(super::Error::InvalidId("Cannot roll back an inactive transaction".to_string()));
|
return Err(super::Error::InvalidId(
|
||||||
|
"Cannot roll back an inactive transaction".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active.store(false, std::sync::atomic::Ordering::SeqCst);
|
self.active
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use heromodels_core::BaseModelData;
|
use heromodels_core::BaseModelData;
|
||||||
use heromodels_derive::model;
|
use heromodels_derive::model;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use rhai_autobind_macros::rhai_model_export;
|
|
||||||
use rhai::{CustomType, TypeBuilder};
|
use rhai::{CustomType, TypeBuilder};
|
||||||
|
use rhai_autobind_macros::rhai_model_export;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Represents the status of an attendee for an event
|
/// Represents the status of an attendee for an event
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
@ -60,7 +60,12 @@ pub struct Event {
|
|||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
/// Creates a new event
|
/// Creates a new event
|
||||||
pub fn new(id: String, title: impl ToString, start_time: DateTime<Utc>, end_time: DateTime<Utc>) -> Self {
|
pub fn new(
|
||||||
|
id: String,
|
||||||
|
title: impl ToString,
|
||||||
|
start_time: DateTime<Utc>,
|
||||||
|
end_time: DateTime<Utc>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
@ -108,7 +113,11 @@ impl Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reschedules the event to new start and end times
|
/// Reschedules the event to new start and end times
|
||||||
pub fn reschedule(mut self, new_start_time: DateTime<Utc>, new_end_time: DateTime<Utc>) -> Self {
|
pub fn reschedule(
|
||||||
|
mut self,
|
||||||
|
new_start_time: DateTime<Utc>,
|
||||||
|
new_end_time: DateTime<Utc>,
|
||||||
|
) -> Self {
|
||||||
// Basic validation: end_time should be after start_time
|
// Basic validation: end_time should be after start_time
|
||||||
if new_end_time > new_start_time {
|
if new_end_time > new_start_time {
|
||||||
self.start_time = new_start_time;
|
self.start_time = new_start_time;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// heromodels/src/models/finance/account.rs
|
// heromodels/src/models/finance/account.rs
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use heromodels_derive::model;
|
|
||||||
use heromodels_core::BaseModelData;
|
use heromodels_core::BaseModelData;
|
||||||
|
use heromodels_derive::model;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::asset::Asset;
|
use super::asset::Asset;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ impl Account {
|
|||||||
description: impl ToString,
|
description: impl ToString,
|
||||||
ledger: impl ToString,
|
ledger: impl ToString,
|
||||||
address: impl ToString,
|
address: impl ToString,
|
||||||
pubkey: impl ToString
|
pubkey: impl ToString,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut base_data = BaseModelData::new();
|
let mut base_data = BaseModelData::new();
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// heromodels/src/models/finance/asset.rs
|
// heromodels/src/models/finance/asset.rs
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use heromodels_derive::model;
|
|
||||||
use heromodels_core::BaseModelData;
|
use heromodels_core::BaseModelData;
|
||||||
|
use heromodels_derive::model;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// AssetType defines the type of blockchain asset
|
/// AssetType defines the type of blockchain asset
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// heromodels/src/models/finance/marketplace.rs
|
// heromodels/src/models/finance/marketplace.rs
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use heromodels_derive::model;
|
|
||||||
use heromodels_core::BaseModelData;
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
use heromodels_core::BaseModelData;
|
||||||
|
use heromodels_derive::model;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::asset::AssetType;
|
use super::asset::AssetType;
|
||||||
|
|
||||||
@ -210,7 +210,11 @@ impl Listing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Complete a sale (fixed price or auction)
|
/// 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,
|
||||||
|
buyer_id: impl ToString,
|
||||||
|
sale_price: f64,
|
||||||
|
) -> Result<Self, &'static str> {
|
||||||
if self.status != ListingStatus::Active {
|
if self.status != ListingStatus::Active {
|
||||||
return Err("Cannot complete sale for inactive listing");
|
return Err("Cannot complete sale for inactive listing");
|
||||||
}
|
}
|
||||||
@ -223,7 +227,9 @@ impl Listing {
|
|||||||
// If this was an auction, accept the winning bid and reject others
|
// If this was an auction, accept the winning bid and reject others
|
||||||
if self.listing_type == ListingType::Auction {
|
if self.listing_type == ListingType::Auction {
|
||||||
for bid in &mut self.bids {
|
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() == self.buyer_id.as_ref().unwrap().to_string()
|
||||||
|
&& bid.amount == sale_price
|
||||||
|
{
|
||||||
bid.status = BidStatus::Accepted;
|
bid.status = BidStatus::Accepted;
|
||||||
} else {
|
} else {
|
||||||
bid.status = BidStatus::Rejected;
|
bid.status = BidStatus::Rejected;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// heromodels/src/models/governance/proposal.rs
|
// heromodels/src/models/governance/proposal.rs
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use heromodels_derive::model; // For #[model]
|
use heromodels_derive::model; // For #[model]
|
||||||
use rhai_autobind_macros::rhai_model_export;
|
|
||||||
use rhai::{CustomType, TypeBuilder};
|
use rhai::{CustomType, TypeBuilder};
|
||||||
|
use rhai_autobind_macros::rhai_model_export;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use heromodels_core::BaseModelData;
|
use heromodels_core::BaseModelData;
|
||||||
|
|
||||||
@ -26,7 +26,6 @@ impl Default for ProposalStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// VoteEventStatus represents the status of the voting process for a proposal
|
/// VoteEventStatus represents the status of the voting process for a proposal
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum VoteEventStatus {
|
pub enum VoteEventStatus {
|
||||||
@ -97,7 +96,6 @@ impl Ballot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Proposal represents a governance proposal that can be voted upon.
|
/// Proposal represents a governance proposal that can be voted upon.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||||
#[rhai_model_export(db_type = "std::sync::Arc<crate::db::hero::OurDB>")]
|
#[rhai_model_export(db_type = "std::sync::Arc<crate::db::hero::OurDB>")]
|
||||||
@ -128,7 +126,14 @@ impl Proposal {
|
|||||||
/// * `description` - Description of the proposal
|
/// * `description` - Description of the proposal
|
||||||
/// * `vote_start_date` - Date when voting starts
|
/// * `vote_start_date` - Date when voting starts
|
||||||
/// * `vote_end_date` - Date when voting ends
|
/// * `vote_end_date` - Date when voting ends
|
||||||
pub fn new(id: Option<u32>, creator_id: impl ToString, title: impl ToString, description: impl ToString, vote_start_date: DateTime<Utc>, vote_end_date: DateTime<Utc>) -> Self {
|
pub fn new(
|
||||||
|
id: Option<u32>,
|
||||||
|
creator_id: impl ToString,
|
||||||
|
title: impl ToString,
|
||||||
|
description: impl ToString,
|
||||||
|
vote_start_date: DateTime<Utc>,
|
||||||
|
vote_end_date: DateTime<Utc>,
|
||||||
|
) -> Self {
|
||||||
let mut base_data = BaseModelData::new();
|
let mut base_data = BaseModelData::new();
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
base_data.update_id(id);
|
base_data.update_id(id);
|
||||||
@ -155,18 +160,30 @@ impl Proposal {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cast_vote(mut self, ballot_id: Option<u32>, user_id: u32, chosen_option_id: u8, shares: i64) -> Self {
|
pub fn cast_vote(
|
||||||
|
mut self,
|
||||||
|
ballot_id: Option<u32>,
|
||||||
|
user_id: u32,
|
||||||
|
chosen_option_id: u8,
|
||||||
|
shares: i64,
|
||||||
|
) -> Self {
|
||||||
if self.vote_status != VoteEventStatus::Open {
|
if self.vote_status != VoteEventStatus::Open {
|
||||||
eprintln!("Voting is not open for proposal '{}'", self.title);
|
eprintln!("Voting is not open for proposal '{}'", self.title);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
if !self.options.iter().any(|opt| opt.id == chosen_option_id) {
|
if !self.options.iter().any(|opt| opt.id == chosen_option_id) {
|
||||||
eprintln!("Chosen option ID {} does not exist for proposal '{}'", chosen_option_id, self.title);
|
eprintln!(
|
||||||
|
"Chosen option ID {} does not exist for proposal '{}'",
|
||||||
|
chosen_option_id, self.title
|
||||||
|
);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
if let Some(group) = &self.private_group {
|
if let Some(group) = &self.private_group {
|
||||||
if !group.contains(&user_id) {
|
if !group.contains(&user_id) {
|
||||||
eprintln!("User {} is not eligible to vote on proposal '{}'", user_id, self.title);
|
eprintln!(
|
||||||
|
"User {} is not eligible to vote on proposal '{}'",
|
||||||
|
user_id, self.title
|
||||||
|
);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +191,11 @@ impl Proposal {
|
|||||||
let new_ballot = Ballot::new(ballot_id, user_id, chosen_option_id, shares);
|
let new_ballot = Ballot::new(ballot_id, user_id, chosen_option_id, shares);
|
||||||
self.ballots.push(new_ballot);
|
self.ballots.push(new_ballot);
|
||||||
|
|
||||||
if let Some(option) = self.options.iter_mut().find(|opt| opt.id == chosen_option_id) {
|
if let Some(option) = self
|
||||||
|
.options
|
||||||
|
.iter_mut()
|
||||||
|
.find(|opt| opt.id == chosen_option_id)
|
||||||
|
{
|
||||||
option.count += shares;
|
option.count += shares;
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
Loading…
Reference in New Issue
Block a user