fix: Use incremental ID
This commit is contained in:
parent
bde5db0e52
commit
a676854251
@ -130,7 +130,7 @@ pub fn model(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> u32 {
|
fn get_id(&self) -> u32 {
|
||||||
self.base_data.id.unwrap_or(0)
|
self.base_data.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base_data_mut(&mut self) -> &mut heromodels_core::BaseModelData {
|
fn base_data_mut(&mut self) -> &mut heromodels_core::BaseModelData {
|
||||||
|
@ -33,68 +33,73 @@ fn main() {
|
|||||||
println!("Hero Models - Basic Usage Example");
|
println!("Hero Models - Basic Usage Example");
|
||||||
println!("================================");
|
println!("================================");
|
||||||
|
|
||||||
// Create users with different ID configurations
|
// Create users with auto-generated IDs
|
||||||
|
|
||||||
// User 1: With explicit ID
|
// User 1
|
||||||
let user1 = User::new(Some(1))
|
let user1 = User::new()
|
||||||
.username("johndoe")
|
.username("johndoe")
|
||||||
.email("john.doe@example.com")
|
.email("john.doe@example.com")
|
||||||
.full_name("John Doe")
|
.full_name("John Doe")
|
||||||
.is_active(false)
|
.is_active(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// User 2: With auto-generated ID
|
// User 2
|
||||||
let user2 = User::new(None)
|
let user2 = User::new()
|
||||||
.username("janesmith")
|
.username("janesmith")
|
||||||
.email("jane.smith@example.com")
|
.email("jane.smith@example.com")
|
||||||
.full_name("Jane Smith")
|
.full_name("Jane Smith")
|
||||||
.is_active(true)
|
.is_active(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// User 3: With explicit ID
|
// User 3
|
||||||
let user3 = User::new(Some(3))
|
let user3 = User::new()
|
||||||
.username("willism")
|
.username("willism")
|
||||||
.email("willis.masters@example.com")
|
.email("willis.masters@example.com")
|
||||||
.full_name("Willis Masters")
|
.full_name("Willis Masters")
|
||||||
.is_active(true)
|
.is_active(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// User 4: With explicit ID
|
// User 4
|
||||||
let user4 = User::new(Some(4))
|
let user4 = User::new()
|
||||||
.username("carrols")
|
.username("carrols")
|
||||||
.email("carrol.smith@example.com")
|
.email("carrol.smith@example.com")
|
||||||
.full_name("Carrol Smith")
|
.full_name("Carrol Smith")
|
||||||
.is_active(false)
|
.is_active(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Save all users to database
|
// Save all users to database and get their assigned IDs
|
||||||
db.collection().expect("can open user collection").set(&user1).expect("can set user");
|
let user1_id = db.collection().expect("can open user collection").set(&user1).expect("can set user");
|
||||||
db.collection().expect("can open user collection").set(&user2).expect("can set user");
|
let user2_id = db.collection().expect("can open user collection").set(&user2).expect("can set user");
|
||||||
db.collection().expect("can open user collection").set(&user3).expect("can set user");
|
let user3_id = db.collection().expect("can open user collection").set(&user3).expect("can set user");
|
||||||
db.collection().expect("can open user collection").set(&user4).expect("can set user");
|
let user4_id = db.collection().expect("can open user collection").set(&user4).expect("can set user");
|
||||||
|
|
||||||
// Retrieve all users from database
|
println!("User 1 assigned ID: {}", user1_id);
|
||||||
|
println!("User 2 assigned ID: {}", user2_id);
|
||||||
|
println!("User 3 assigned ID: {}", user3_id);
|
||||||
|
println!("User 4 assigned ID: {}", user4_id);
|
||||||
|
|
||||||
|
// Retrieve all users from database using the assigned IDs
|
||||||
let db_user1 = db.collection::<User>().expect("can open user collection")
|
let db_user1 = db.collection::<User>().expect("can open user collection")
|
||||||
.get_by_id(user1.get_id()).expect("can load user").expect("user should exist");
|
.get_by_id(user1_id).expect("can load user").expect("user should exist");
|
||||||
let db_user2 = db.collection::<User>().expect("can open user collection")
|
let db_user2 = db.collection::<User>().expect("can open user collection")
|
||||||
.get_by_id(user2.get_id()).expect("can load user").expect("user should exist");
|
.get_by_id(user2_id).expect("can load user").expect("user should exist");
|
||||||
let db_user3 = db.collection::<User>().expect("can open user collection")
|
let db_user3 = db.collection::<User>().expect("can open user collection")
|
||||||
.get_by_id(user3.get_id()).expect("can load user").expect("user should exist");
|
.get_by_id(user3_id).expect("can load user").expect("user should exist");
|
||||||
let db_user4 = db.collection::<User>().expect("can open user collection")
|
let db_user4 = db.collection::<User>().expect("can open user collection")
|
||||||
.get_by_id(user4.get_id()).expect("can load user").expect("user should exist");
|
.get_by_id(user4_id).expect("can load user").expect("user should exist");
|
||||||
|
|
||||||
// Print all users retrieved from database
|
// Print all users retrieved from database
|
||||||
println!("\n--- Users Retrieved from Database ---");
|
println!("\n--- Users Retrieved from Database ---");
|
||||||
println!("\n1. User with explicit ID (1):");
|
println!("\n1. First user:");
|
||||||
print_user_details(&db_user1);
|
print_user_details(&db_user1);
|
||||||
|
|
||||||
println!("\n2. User with auto-generated ID:");
|
println!("\n2. Second user:");
|
||||||
print_user_details(&db_user2);
|
print_user_details(&db_user2);
|
||||||
|
|
||||||
println!("\n3. User with explicit ID (3):");
|
println!("\n3. Third user:");
|
||||||
print_user_details(&db_user3);
|
print_user_details(&db_user3);
|
||||||
|
|
||||||
println!("\n4. User with explicit ID (4):");
|
println!("\n4. Fourth user:");
|
||||||
print_user_details(&db_user4);
|
print_user_details(&db_user4);
|
||||||
|
|
||||||
// Demonstrate different ways to retrieve users from the database
|
// Demonstrate different ways to retrieve users from the database
|
||||||
@ -126,9 +131,11 @@ fn main() {
|
|||||||
|
|
||||||
// 3. Delete a user and show the updated results
|
// 3. Delete a user and show the updated results
|
||||||
println!("\n3. After Deleting a User:");
|
println!("\n3. After Deleting a User:");
|
||||||
|
let user_to_delete_id = active_users[0].get_id();
|
||||||
|
println!("Deleting user with ID: {}", user_to_delete_id);
|
||||||
db.collection::<User>()
|
db.collection::<User>()
|
||||||
.expect("can open user collection")
|
.expect("can open user collection")
|
||||||
.delete_by_id(active_users[0].get_id())
|
.delete_by_id(user_to_delete_id)
|
||||||
.expect("can delete existing user");
|
.expect("can delete existing user");
|
||||||
|
|
||||||
// Show remaining active users
|
// Show remaining active users
|
||||||
@ -165,21 +172,24 @@ fn main() {
|
|||||||
|
|
||||||
// 1. Create and save a comment
|
// 1. Create and save a comment
|
||||||
println!("\n1. Creating a Comment:");
|
println!("\n1. Creating a Comment:");
|
||||||
let comment = Comment::new(None)
|
let comment = Comment::new()
|
||||||
.user_id(db_user1.get_id()) // commenter's user ID
|
.user_id(db_user1.get_id()) // commenter's user ID
|
||||||
.content("This is a comment on the user")
|
.content("This is a comment on the user")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
db.collection()
|
// Save the comment and get its assigned ID
|
||||||
|
let comment_id = db.collection()
|
||||||
.expect("can open comment collection")
|
.expect("can open comment collection")
|
||||||
.set(&comment)
|
.set(&comment)
|
||||||
.expect("can set comment");
|
.expect("can set comment");
|
||||||
|
|
||||||
// 2. Retrieve the comment from database
|
println!("Comment assigned ID: {}", comment_id);
|
||||||
|
|
||||||
|
// 2. Retrieve the comment from database using the assigned ID
|
||||||
let db_comment = db
|
let db_comment = db
|
||||||
.collection::<Comment>()
|
.collection::<Comment>()
|
||||||
.expect("can open comment collection")
|
.expect("can open comment collection")
|
||||||
.get_by_id(comment.get_id())
|
.get_by_id(comment_id)
|
||||||
.expect("can load comment")
|
.expect("can load comment")
|
||||||
.expect("comment should exist");
|
.expect("comment should exist");
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ fn main() {
|
|||||||
println!("SimpleUser DB Prefix: {}", SimpleUser::db_prefix());
|
println!("SimpleUser DB Prefix: {}", SimpleUser::db_prefix());
|
||||||
|
|
||||||
let user = SimpleUser {
|
let user = SimpleUser {
|
||||||
base_data: BaseModelData::new(1),
|
base_data: BaseModelData::new(),
|
||||||
login: "johndoe".to_string(),
|
login: "johndoe".to_string(),
|
||||||
full_name: "John Doe".to_string(),
|
full_name: "John Doe".to_string(),
|
||||||
};
|
};
|
||||||
|
@ -32,8 +32,9 @@ where
|
|||||||
/// Get an object from its ID. This does not use an index lookup
|
/// Get an object from its ID. This does not use an index lookup
|
||||||
fn get_by_id(&self, id: u32) -> Result<Option<V>, Error<Self::Error>>;
|
fn get_by_id(&self, id: u32) -> Result<Option<V>, Error<Self::Error>>;
|
||||||
|
|
||||||
/// Store an item in the DB.
|
/// Store an item in the DB and return the assigned ID.
|
||||||
fn set(&self, value: &V) -> Result<(), Error<Self::Error>>;
|
/// This method does not modify the original model.
|
||||||
|
fn set(&self, value: &V) -> Result<u32, Error<Self::Error>>;
|
||||||
|
|
||||||
/// Delete all items from the db with a given index.
|
/// Delete all items from the db with a given index.
|
||||||
fn delete<I, Q>(&self, key: &Q) -> Result<(), Error<Self::Error>>
|
fn delete<I, Q>(&self, key: &Q) -> Result<(), Error<Self::Error>>
|
||||||
|
@ -26,7 +26,7 @@ impl OurDB {
|
|||||||
data_path.push("data");
|
data_path.push("data");
|
||||||
|
|
||||||
let data_db = ourdb::OurDB::new(ourdb::OurDBConfig {
|
let data_db = ourdb::OurDB::new(ourdb::OurDBConfig {
|
||||||
incremental_mode: false,
|
incremental_mode: true,
|
||||||
path: data_path,
|
path: data_path,
|
||||||
file_size: None,
|
file_size: None,
|
||||||
keysize: None,
|
keysize: None,
|
||||||
@ -87,7 +87,7 @@ where
|
|||||||
Self::get_ourdb_value(&mut data_db, id)
|
Self::get_ourdb_value(&mut data_db, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&self, value: &M) -> Result<(), super::Error<Self::Error>> {
|
fn set(&self, value: &M) -> Result<u32, super::Error<Self::Error>> {
|
||||||
// Before inserting the new object, check if an object with this ID already exists. If it does, we potentially need to update indices.
|
// Before inserting the new object, check if an object with this ID already exists. If it does, we potentially need to update indices.
|
||||||
let mut data_db = self.data.lock().expect("can lock data DB");
|
let mut data_db = self.data.lock().expect("can lock data DB");
|
||||||
let old_obj: Option<M> = Self::get_ourdb_value(&mut data_db, value.get_id())?;
|
let old_obj: Option<M> = Self::get_ourdb_value(&mut data_db, value.get_id())?;
|
||||||
@ -134,13 +134,52 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set or update the object
|
// Get the current ID
|
||||||
let v = bincode::serde::encode_to_vec(value, BINCODE_CONFIG)?;
|
|
||||||
let id = value.get_id();
|
let id = value.get_id();
|
||||||
data_db.set(OurDBSetArgs {
|
|
||||||
id: Some(id),
|
// If id is 0, it's a new object, so let OurDB auto-generate an ID
|
||||||
data: &v,
|
// Otherwise, it's an update to an existing object
|
||||||
})?;
|
let id_param = if id == 0 { None } else { Some(id) };
|
||||||
|
|
||||||
|
// For new objects (id == 0), we need to get the assigned ID from OurDB
|
||||||
|
// and update the model before serializing it
|
||||||
|
let assigned_id = if id == 0 {
|
||||||
|
// First, get the next ID that OurDB will assign
|
||||||
|
let next_id = data_db.get_next_id()?;
|
||||||
|
|
||||||
|
// Create a mutable clone of the value and update its ID
|
||||||
|
// This is a bit of a hack, but we need to update the ID before serializing
|
||||||
|
let mut value_clone = value.clone();
|
||||||
|
let base_data = value_clone.base_data_mut();
|
||||||
|
base_data.update_id(next_id);
|
||||||
|
|
||||||
|
// Now serialize the updated model
|
||||||
|
let v = bincode::serde::encode_to_vec(&value_clone, BINCODE_CONFIG)?;
|
||||||
|
|
||||||
|
// Save to OurDB with the ID parameter set to None to let OurDB auto-generate the ID
|
||||||
|
let assigned_id = data_db.set(OurDBSetArgs {
|
||||||
|
id: id_param,
|
||||||
|
data: &v,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// The assigned ID should match the next_id we got earlier
|
||||||
|
assert_eq!(assigned_id, next_id, "OurDB assigned a different ID than expected");
|
||||||
|
|
||||||
|
// Return the assigned ID
|
||||||
|
assigned_id
|
||||||
|
} else {
|
||||||
|
// For existing objects, just serialize and save
|
||||||
|
let v = bincode::serde::encode_to_vec(value, BINCODE_CONFIG)?;
|
||||||
|
|
||||||
|
// Save to OurDB with the existing ID
|
||||||
|
let assigned_id = data_db.set(OurDBSetArgs {
|
||||||
|
id: id_param,
|
||||||
|
data: &v,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Return the existing ID
|
||||||
|
assigned_id
|
||||||
|
};
|
||||||
|
|
||||||
// Now add the new indices
|
// Now add the new indices
|
||||||
for index_key in indices_to_add {
|
for index_key in indices_to_add {
|
||||||
@ -148,12 +187,14 @@ where
|
|||||||
// Load the existing id set for the index or create a new set
|
// Load the existing id set for the index or create a new set
|
||||||
let mut existing_ids =
|
let mut existing_ids =
|
||||||
Self::get_tst_value::<HashSet<u32>>(&mut index_db, &key)?.unwrap_or_default();
|
Self::get_tst_value::<HashSet<u32>>(&mut index_db, &key)?.unwrap_or_default();
|
||||||
existing_ids.insert(id);
|
// Use the assigned ID for new objects
|
||||||
|
existing_ids.insert(assigned_id);
|
||||||
let encoded_ids = bincode::serde::encode_to_vec(existing_ids, BINCODE_CONFIG)?;
|
let encoded_ids = bincode::serde::encode_to_vec(existing_ids, BINCODE_CONFIG)?;
|
||||||
index_db.set(&key, encoded_ids)?;
|
index_db.set(&key, encoded_ids)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// Return the assigned ID
|
||||||
|
Ok(assigned_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete<I, Q>(&self, key: &Q) -> Result<(), super::Error<Self::Error>>
|
fn delete<I, Q>(&self, key: &Q) -> Result<(), super::Error<Self::Error>>
|
||||||
|
@ -139,14 +139,13 @@ pub struct Calendar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Calendar {
|
impl Calendar {
|
||||||
/// Creates a new calendar
|
/// Creates a new calendar with auto-generated ID
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `id` - Optional ID for the calendar. If None, the ID will be auto-generated.
|
|
||||||
/// * `name` - Name of the calendar
|
/// * `name` - Name of the calendar
|
||||||
pub fn new(id: Option<u32>, name: impl ToString) -> Self {
|
pub fn new(name: impl ToString) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
description: None,
|
description: None,
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
|
@ -13,13 +13,10 @@ pub struct Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Comment {
|
impl Comment {
|
||||||
/// Create a new comment
|
/// Create a new comment with auto-generated ID
|
||||||
///
|
pub fn new() -> Self {
|
||||||
/// # Arguments
|
|
||||||
/// * `id` - Optional ID for the comment. If None, the ID will be auto-generated.
|
|
||||||
pub fn new(id: Option<u32>) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
user_id: 0,
|
user_id: 0,
|
||||||
content: String::new(),
|
content: String::new(),
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,9 @@ pub struct Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Account {
|
impl Account {
|
||||||
/// Create a new account
|
/// Create a new account with auto-generated ID
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `id` - Optional ID for the account. If None, the ID will be auto-generated.
|
|
||||||
/// * `name` - Name of the account
|
/// * `name` - Name of the account
|
||||||
/// * `user_id` - ID of the user who owns the account
|
/// * `user_id` - ID of the user who owns the account
|
||||||
/// * `description` - Description of the account
|
/// * `description` - Description of the account
|
||||||
@ -32,7 +31,6 @@ impl Account {
|
|||||||
/// * `address` - Address of the account on the blockchain
|
/// * `address` - Address of the account on the blockchain
|
||||||
/// * `pubkey` - Public key
|
/// * `pubkey` - Public key
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: Option<u32>,
|
|
||||||
name: impl ToString,
|
name: impl ToString,
|
||||||
user_id: u32,
|
user_id: u32,
|
||||||
description: impl ToString,
|
description: impl ToString,
|
||||||
@ -41,7 +39,7 @@ impl Account {
|
|||||||
pubkey: impl ToString
|
pubkey: impl ToString
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
user_id,
|
user_id,
|
||||||
description: description.to_string(),
|
description: description.to_string(),
|
||||||
|
@ -33,9 +33,8 @@ pub struct Asset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Asset {
|
impl Asset {
|
||||||
/// Create a new asset
|
/// Create a new asset with auto-generated ID
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: Option<u32>,
|
|
||||||
name: impl ToString,
|
name: impl ToString,
|
||||||
description: impl ToString,
|
description: impl ToString,
|
||||||
amount: f64,
|
amount: f64,
|
||||||
@ -44,7 +43,7 @@ impl Asset {
|
|||||||
decimals: u8,
|
decimals: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
description: description.to_string(),
|
description: description.to_string(),
|
||||||
amount,
|
amount,
|
||||||
@ -72,14 +71,14 @@ impl Asset {
|
|||||||
if amount <= 0.0 {
|
if amount <= 0.0 {
|
||||||
return Err("Transfer amount must be positive");
|
return Err("Transfer amount must be positive");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.amount < amount {
|
if self.amount < amount {
|
||||||
return Err("Insufficient balance for transfer");
|
return Err("Insufficient balance for transfer");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.amount -= amount;
|
self.amount -= amount;
|
||||||
target.amount += amount;
|
target.amount += amount;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,9 +111,8 @@ pub struct Listing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Listing {
|
impl Listing {
|
||||||
/// Create a new listing
|
/// Create a new listing with auto-generated ID
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: Option<u32>,
|
|
||||||
title: impl ToString,
|
title: impl ToString,
|
||||||
description: impl ToString,
|
description: impl ToString,
|
||||||
asset_id: impl ToString,
|
asset_id: impl ToString,
|
||||||
@ -127,7 +126,7 @@ impl Listing {
|
|||||||
image_url: Option<impl ToString>,
|
image_url: Option<impl ToString>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
description: description.to_string(),
|
description: description.to_string(),
|
||||||
asset_id: asset_id.to_string(),
|
asset_id: asset_id.to_string(),
|
||||||
@ -153,32 +152,32 @@ impl Listing {
|
|||||||
if self.listing_type != ListingType::Auction {
|
if self.listing_type != ListingType::Auction {
|
||||||
return Err("Bids can only be placed on auction listings");
|
return Err("Bids can only be placed on auction listings");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if listing is active
|
// Check if listing is active
|
||||||
if self.status != ListingStatus::Active {
|
if self.status != ListingStatus::Active {
|
||||||
return Err("Cannot place bid on inactive listing");
|
return Err("Cannot place bid on inactive listing");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if bid amount is higher than current price
|
// Check if bid amount is higher than current price
|
||||||
if bid.amount <= self.price {
|
if bid.amount <= self.price {
|
||||||
return Err("Bid amount must be higher than current price");
|
return Err("Bid amount must be higher than current price");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are existing bids and if the new bid is higher
|
// Check if there are existing bids and if the new bid is higher
|
||||||
if let Some(highest_bid) = self.highest_bid() {
|
if let Some(highest_bid) = self.highest_bid() {
|
||||||
if bid.amount <= highest_bid.amount {
|
if bid.amount <= highest_bid.amount {
|
||||||
return Err("Bid amount must be higher than current highest bid");
|
return Err("Bid amount must be higher than current highest bid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the bid
|
// Add the bid
|
||||||
self.bids.push(bid);
|
self.bids.push(bid);
|
||||||
|
|
||||||
// Update the current price to the new highest bid
|
// Update the current price to the new highest bid
|
||||||
if let Some(highest_bid) = self.highest_bid() {
|
if let Some(highest_bid) = self.highest_bid() {
|
||||||
self.price = highest_bid.amount;
|
self.price = highest_bid.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,12 +194,12 @@ impl Listing {
|
|||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status = ListingStatus::Sold;
|
self.status = ListingStatus::Sold;
|
||||||
self.buyer_id = Some(buyer_id.to_string());
|
self.buyer_id = Some(buyer_id.to_string());
|
||||||
self.sale_price = Some(sale_price);
|
self.sale_price = Some(sale_price);
|
||||||
self.sold_at = Some(Utc::now());
|
self.sold_at = Some(Utc::now());
|
||||||
|
|
||||||
// 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 {
|
||||||
@ -211,7 +210,7 @@ impl Listing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,16 +219,16 @@ impl Listing {
|
|||||||
if self.status != ListingStatus::Active {
|
if self.status != ListingStatus::Active {
|
||||||
return Err("Cannot cancel inactive listing");
|
return Err("Cannot cancel inactive listing");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status = ListingStatus::Cancelled;
|
self.status = ListingStatus::Cancelled;
|
||||||
|
|
||||||
// Cancel all active bids
|
// Cancel all active bids
|
||||||
for bid in &mut self.bids {
|
for bid in &mut self.bids {
|
||||||
if bid.status == BidStatus::Active {
|
if bid.status == BidStatus::Active {
|
||||||
bid.status = BidStatus::Cancelled;
|
bid.status = BidStatus::Cancelled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +238,7 @@ impl Listing {
|
|||||||
if let Some(expires_at) = self.expires_at {
|
if let Some(expires_at) = self.expires_at {
|
||||||
if Utc::now() > expires_at {
|
if Utc::now() > expires_at {
|
||||||
self.status = ListingStatus::Expired;
|
self.status = ListingStatus::Expired;
|
||||||
|
|
||||||
// Cancel all active bids
|
// Cancel all active bids
|
||||||
for bid in &mut self.bids {
|
for bid in &mut self.bids {
|
||||||
if bid.status == BidStatus::Active {
|
if bid.status == BidStatus::Active {
|
||||||
@ -249,7 +248,7 @@ impl Listing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,16 +75,15 @@ pub struct Ballot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ballot {
|
impl Ballot {
|
||||||
/// Create a new ballot
|
/// Create a new ballot with auto-generated ID
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `id` - Optional ID for the ballot. If None, the ID will be auto-generated.
|
|
||||||
/// * `user_id` - ID of the user who cast this ballot
|
/// * `user_id` - ID of the user who cast this ballot
|
||||||
/// * `vote_option_id` - ID of the vote option chosen
|
/// * `vote_option_id` - ID of the vote option chosen
|
||||||
/// * `shares_count` - Number of shares/tokens/voting power
|
/// * `shares_count` - Number of shares/tokens/voting power
|
||||||
pub fn new(id: Option<u32>, user_id: u32, vote_option_id: u8, shares_count: i64) -> Self {
|
pub fn new(user_id: u32, vote_option_id: u8, shares_count: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
user_id,
|
user_id,
|
||||||
vote_option_id,
|
vote_option_id,
|
||||||
shares_count,
|
shares_count,
|
||||||
@ -114,18 +113,17 @@ pub struct Proposal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Proposal {
|
impl Proposal {
|
||||||
/// Create a new proposal
|
/// Create a new proposal with auto-generated ID
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `id` - Optional ID for the proposal. If None, the ID will be auto-generated.
|
|
||||||
/// * `creator_id` - ID of the user who created the proposal
|
/// * `creator_id` - ID of the user who created the proposal
|
||||||
/// * `title` - Title of the proposal
|
/// * `title` - Title of the 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(creator_id: impl ToString, title: impl ToString, description: impl ToString, vote_start_date: DateTime<Utc>, vote_end_date: DateTime<Utc>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
creator_id: creator_id.to_string(),
|
creator_id: creator_id.to_string(),
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
description: description.to_string(),
|
description: description.to_string(),
|
||||||
@ -145,7 +143,7 @@ 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, 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;
|
||||||
@ -161,7 +159,7 @@ impl Proposal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_ballot = Ballot::new(ballot_id, user_id, chosen_option_id, shares);
|
let new_ballot = Ballot::new(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) {
|
||||||
|
@ -26,13 +26,10 @@ pub struct User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
/// Create a new user
|
/// Create a new user with auto-generated ID
|
||||||
///
|
pub fn new() -> Self {
|
||||||
/// # Arguments
|
|
||||||
/// * `id` - Optional ID for the user. If None, the ID will be auto-generated.
|
|
||||||
pub fn new(id: Option<u32>) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
base_data: BaseModelData::new(id),
|
base_data: BaseModelData::new(),
|
||||||
username: String::new(),
|
username: String::new(),
|
||||||
email: String::new(),
|
email: String::new(),
|
||||||
full_name: String::new(),
|
full_name: String::new(),
|
||||||
|
@ -59,21 +59,11 @@ pub trait Model:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the unique ID for this model
|
/// Get the unique ID for this model
|
||||||
/// Returns 0 if the ID is None
|
|
||||||
fn get_id(&self) -> u32;
|
fn get_id(&self) -> u32;
|
||||||
|
|
||||||
/// Get a mutable reference to the base_data field
|
/// Get a mutable reference to the base_data field
|
||||||
fn base_data_mut(&mut self) -> &mut BaseModelData;
|
fn base_data_mut(&mut self) -> &mut BaseModelData;
|
||||||
|
|
||||||
/// Set the ID for this model
|
|
||||||
fn id(mut self, id: Option<u32>) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
self.base_data_mut().id = id;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build the model, updating the modified timestamp
|
/// Build the model, updating the modified timestamp
|
||||||
fn build(mut self) -> Self
|
fn build(mut self) -> Self
|
||||||
where
|
where
|
||||||
@ -98,8 +88,8 @@ pub trait Index {
|
|||||||
/// Base struct that all models should include
|
/// Base struct that all models should include
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct BaseModelData {
|
pub struct BaseModelData {
|
||||||
/// Unique incremental ID per circle
|
/// Unique incremental ID - will be auto-generated by OurDB
|
||||||
pub id: Option<u32>,
|
pub id: u32,
|
||||||
|
|
||||||
/// Unix epoch timestamp for creation time
|
/// Unix epoch timestamp for creation time
|
||||||
pub created_at: i64,
|
pub created_at: i64,
|
||||||
@ -112,11 +102,12 @@ pub struct BaseModelData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BaseModelData {
|
impl BaseModelData {
|
||||||
/// Create a new BaseModelData instance
|
/// Create a new BaseModelData instance with ID set to 0
|
||||||
pub fn new(id: Option<u32>) -> Self {
|
/// The ID will be auto-generated by OurDB when the model is saved
|
||||||
|
pub fn new() -> Self {
|
||||||
let now = chrono::Utc::now().timestamp();
|
let now = chrono::Utc::now().timestamp();
|
||||||
Self {
|
Self {
|
||||||
id,
|
id: 0, // This will be replaced by OurDB with an auto-generated ID
|
||||||
created_at: now,
|
created_at: now,
|
||||||
modified_at: now,
|
modified_at: now,
|
||||||
comments: Vec::new(),
|
comments: Vec::new(),
|
||||||
@ -124,8 +115,8 @@ impl BaseModelData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new BaseModelDataBuilder
|
/// Create a new BaseModelDataBuilder
|
||||||
pub fn builder(id: Option<u32>) -> BaseModelDataBuilder {
|
pub fn builder() -> BaseModelDataBuilder {
|
||||||
BaseModelDataBuilder::new(id)
|
BaseModelDataBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment to this model
|
/// Add a comment to this model
|
||||||
@ -144,11 +135,15 @@ impl BaseModelData {
|
|||||||
pub fn update_modified(&mut self) {
|
pub fn update_modified(&mut self) {
|
||||||
self.modified_at = chrono::Utc::now().timestamp();
|
self.modified_at = chrono::Utc::now().timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the ID of this model
|
||||||
|
pub fn update_id(&mut self, id: u32) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder for BaseModelData
|
/// Builder for BaseModelData
|
||||||
pub struct BaseModelDataBuilder {
|
pub struct BaseModelDataBuilder {
|
||||||
id: Option<u32>,
|
|
||||||
created_at: Option<i64>,
|
created_at: Option<i64>,
|
||||||
modified_at: Option<i64>,
|
modified_at: Option<i64>,
|
||||||
comments: Vec<u32>,
|
comments: Vec<u32>,
|
||||||
@ -156,9 +151,8 @@ pub struct BaseModelDataBuilder {
|
|||||||
|
|
||||||
impl BaseModelDataBuilder {
|
impl BaseModelDataBuilder {
|
||||||
/// Create a new BaseModelDataBuilder
|
/// Create a new BaseModelDataBuilder
|
||||||
pub fn new(id: Option<u32>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
|
||||||
created_at: None,
|
created_at: None,
|
||||||
modified_at: None,
|
modified_at: None,
|
||||||
comments: Vec::new(),
|
comments: Vec::new(),
|
||||||
@ -193,7 +187,7 @@ impl BaseModelDataBuilder {
|
|||||||
pub fn build(self) -> BaseModelData {
|
pub fn build(self) -> BaseModelData {
|
||||||
let now = chrono::Utc::now().timestamp();
|
let now = chrono::Utc::now().timestamp();
|
||||||
BaseModelData {
|
BaseModelData {
|
||||||
id: self.id,
|
id: 0, // This will be replaced by OurDB with an auto-generated ID
|
||||||
created_at: self.created_at.unwrap_or(now),
|
created_at: self.created_at.unwrap_or(now),
|
||||||
modified_at: self.modified_at.unwrap_or(now),
|
modified_at: self.modified_at.unwrap_or(now),
|
||||||
comments: self.comments,
|
comments: self.comments,
|
||||||
|
Loading…
Reference in New Issue
Block a user