diff --git a/lootalot_db/src/lib.rs b/lootalot_db/src/lib.rs index 4c0bba4..2e2604b 100644 --- a/lootalot_db/src/lib.rs +++ b/lootalot_db/src/lib.rs @@ -247,13 +247,7 @@ impl<'q> AsAdmin<'q> { /// /// When a player gets an item, it's debt is increased by this item sell value pub fn resolve_claims(self) -> ActionResult<()> { - // Fetch all claims, grouped by items. - let loot = models::item::Loot::owned_by(0).load(self.0)?; - let claims = schema::claims::table - .load::(self.0)? - .grouped_by(&loot); - // For each claimed item - let data = loot.into_iter().zip(claims).collect::>(); + let data = models::claim::Claims(self.0).grouped_by_loot()?; dbg!(&data); for (loot, claims) in data { @@ -262,18 +256,12 @@ impl<'q> AsAdmin<'q> { let claim = claims.get(0).unwrap(); let player_id = claim.player_id; self.0.transaction(|| { - use schema::looted::dsl::*; - diesel::update(looted.find(claim.loot_id)) - .set(owner_id.eq(player_id)) + loot.set_owner(claim.player_id) .execute(self.0)?; - diesel::delete(schema::claims::table.find(claim.id)) - .execute(self.0)?; - { - use schema::players::dsl::*; - diesel::update(players.find(player_id)) - .set(debt.eq(debt + (loot.base_price / 2))) - .execute(self.0) - } + models::player::AsPlayer(self.0, player_id) + .update_debt(loot.sell_value())?; + models::claim::Claims(self.0).remove(player_id, claim.loot_id)?; + Ok(()) })?; }, _ => (), diff --git a/lootalot_db/src/models/claim.rs b/lootalot_db/src/models/claim.rs index e0f21b9..e91d469 100644 --- a/lootalot_db/src/models/claim.rs +++ b/lootalot_db/src/models/claim.rs @@ -22,49 +22,65 @@ pub struct Claims<'q>(pub &'q DbConnection); impl<'q> Claims<'q> { - /// Finds a single claim by id. + /// Finds a single claim by association of player and loot ids. pub fn find(&self, player_id: i32, loot_id: i32) -> QueryResult { - Ok( claims::table .filter(claims::dsl::player_id.eq(player_id)) .filter(claims::dsl::loot_id.eq(loot_id)) - .first(self.0)? - ) + .first(self.0) } /// Adds a claim in database and returns it pub fn add(self, player_id: i32, loot_id: i32) -> QueryResult { - // We need to validate that the claimed item exists, and is actually owned by group (id 0) - let exists: bool = diesel::select(Loot::exists(loot_id)).get_result(self.0)?; - if !exists { - return Err(diesel::result::Error::NotFound); - }; + // We need to validate that the claimed item exists + // AND is actually owned by group (id 0) + let _item = models::item::LootManager(self.0, 0).find(loot_id)?; let claim = NewClaim::new(player_id, loot_id); diesel::insert_into(claims::table) .values(&claim) .execute(self.0)?; // Return the created claim - Ok(claims::table.order(claims::dsl::id.desc()).first::(self.0)?) + claims::table + .order(claims::dsl::id.desc()) + .first::(self.0) } /// Removes a claim from database, returning it - pub fn remove(self, req_player_id: i32, req_loot_id: i32) -> QueryResult { - let claim = self.find(req_player_id, req_loot_id)?; + pub fn remove(self, player_id: i32, loot_id: i32) -> QueryResult { + let claim = self.find(player_id, loot_id)?; diesel::delete(claims::table.find(claim.id)) .execute(self.0)?; Ok(claim) } + + pub fn filtered_by_loot(&self, loot_id: i32) -> QueryResult> { + claims::table + .filter(claims::dsl::loot_id.eq(loot_id)) + .load(self.0) + } + + pub(crate) fn grouped_by_loot(&self) -> QueryResult)>> { + let loot = models::item::Loot::owned_by(0).load(self.0)?; + let claims = claims::table + .load(self.0)? + .grouped_by(&loot); + Ok( + loot.into_iter() + .zip(claims) + .collect::>() + ) + } } #[derive(Insertable, Debug)] #[table_name = "claims"] -pub(crate) struct NewClaim { +struct NewClaim { player_id: i32, loot_id: i32, } impl NewClaim { - pub(crate) fn new(player_id: i32, loot_id: i32) -> Self { + fn new(player_id: i32, loot_id: i32) -> Self { Self { player_id, loot_id } } } diff --git a/lootalot_db/src/models/item.rs b/lootalot_db/src/models/item.rs index 0c9a891..49ca2e9 100644 --- a/lootalot_db/src/models/item.rs +++ b/lootalot_db/src/models/item.rs @@ -10,11 +10,7 @@ type ItemColumns = (looted::id, looted::name, looted::base_price); const ITEM_COLUMNS: ItemColumns = (looted::id, looted::name, looted::base_price); type OwnedBy = Select; -/// Represents a unique item in inventory -/// -/// It is also used as a public representation of Loot, since owner -/// information is implicit. -/// Or maybe this is a little too confusing ?? +/// Represents a basic item #[derive(Debug, Queryable, Serialize, Deserialize, Clone)] pub struct Item { pub id: i32, @@ -47,7 +43,10 @@ impl<'q> Inventory<'q> { type WithOwner = Eq; type OwnedLoot = Filter; -/// Represents an item that has been looted + + +/// Represents an item that has been looted, +/// hence has an owner. #[derive(Identifiable, Debug, Queryable, Serialize)] #[table_name = "looted"] pub(super) struct Loot { @@ -63,13 +62,24 @@ impl Loot { looted::table.filter(looted::owner_id.eq(id)) } - fn owns(player: i32, item: i32) -> Exists> { - exists(Loot::owned_by(player).find(item)) - } - pub(super) fn exists(id: i32) -> Exists> { exists(looted::table.find(id)) } + + pub(crate) fn set_owner(&self, owner: i32) -> () { + diesel::update(looted::table.find(self.id)) + .set(looted::dsl::owner_id.eq(owner)) + } + + /// TODO: should belong inside Item impl + pub(crate) fn value(&self) -> i32 { + self.base_price + } + + /// TODO: should belong inside Item impl + pub(crate) fn sell_value(&self) -> i32 { + self.base_price / 2 + } } /// Manager for a player's loot diff --git a/lootalot_db/src/models/player.rs b/lootalot_db/src/models/player.rs index 38efb9a..f61e3af 100644 --- a/lootalot_db/src/models/player.rs +++ b/lootalot_db/src/models/player.rs @@ -45,6 +45,15 @@ impl<'q> AsPlayer<'q> { .execute(self.0)?; Ok(difference) } + + pub fn update_debt(&self, value_in_gp: i32) -> QueryResult<()> { + diesel::update(players::table.find(self.1)) + .set(players::dsl::debt.eq( + players::dsl::debt + value_in_gp + )) + .execute(self.0)?; + Ok(()) + } }