Files
lootalot/lootalot_db/src/models/claim.rs

176 lines
5.3 KiB
Rust

use crate::{DbConnection, QueryResult};
use diesel::prelude::*;
use crate::models::{self, item::Loot};
use crate::schema::claims;
/// A Claim is a request by a single player on an item from group chest.
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, Debug)]
#[belongs_to(Loot)]
pub struct Claim {
/// DB Identifier
pub id: i32,
/// ID that references the player making this claim
pub player_id: i32,
/// ID that references the loot claimed
pub loot_id: i32,
/// WIP: How bad the player wants this item
pub resolve: i32,
}
impl Claim {
/// Resolves this claim (player wins the item) and deletes it
pub fn resolve_claim(&self, conn: &DbConnection) -> QueryResult<()> {
let loot: Loot = Loot::find(self.loot_id).first(conn)?;
loot.set_owner(self.player_id, conn)?;
self.remove(conn)?;
Ok(())
}
fn remove(&self, conn: &DbConnection) -> QueryResult<()> {
diesel::delete(claims::table.find(self.id)).execute(conn)?;
Ok(())
}
}
pub struct Claims<'q>(pub &'q DbConnection);
impl<'q> Claims<'q> {
/// Get all claims from database
pub fn all(&self) -> QueryResult<Vec<Claim>> {
claims::table.load(self.0)
}
/// Finds a single claim by association of player and loot ids.
pub fn find(&self, player_id: i32, loot_id: i32) -> QueryResult<Claim> {
claims::table
.filter(claims::dsl::player_id.eq(player_id))
.filter(claims::dsl::loot_id.eq(loot_id))
.first(self.0)
}
/// Adds a claim in database and returns it.
///
/// Will validate that the claimed item exists and is
/// actually owned by the group.
/// Duplicates are also ignored.
pub fn add(self, player_id: i32, loot_id: i32) -> QueryResult<Claim> {
// 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)?;
// We also check if claims does not already exists
if let Ok(_) = self.find(player_id, loot_id) {
return Err(diesel::result::Error::RollbackTransaction);
}
let claim = NewClaim::new(player_id, loot_id);
diesel::insert_into(claims::table)
.values(&claim)
.execute(self.0)?;
// Return the created claim
claims::table
.order(claims::dsl::id.desc())
.first::<Claim>(self.0)
}
/// Removes a claim from database, returning it
pub fn remove(self, player_id: i32, loot_id: i32) -> QueryResult<Claim> {
let claim = self.find(player_id, loot_id)?;
claim.remove(self.0)?;
Ok(claim)
}
pub fn filtered_by_loot(&self, loot_id: i32) -> QueryResult<Vec<Claim>> {
claims::table
.filter(claims::dsl::loot_id.eq(loot_id))
.load(self.0)
}
pub(crate) fn grouped_by_item(&self) -> QueryResult<Vec<(models::item::Item, Vec<Claim>)>> {
let group_loot: Vec<Loot> = Loot::owned_by(0).load(self.0)?;
let claims = claims::table.load(self.0)?.grouped_by(&group_loot);
Ok(group_loot
.into_iter()
.map(|loot| loot.into_item())
.zip(claims)
.collect::<Vec<_>>())
}
}
#[derive(Insertable, Debug)]
#[table_name = "claims"]
struct NewClaim {
player_id: i32,
loot_id: i32,
}
impl NewClaim {
fn new(player_id: i32, loot_id: i32) -> Self {
Self { player_id, loot_id }
}
}
#[cfg(test)]
mod tests {
use super::*;
type TestResult = Result<(), diesel::result::Error>;
fn test_connection() -> Result<DbConnection, diesel::result::Error> {
let conn =
DbConnection::establish(":memory:").map_err(|_| diesel::result::Error::NotFound)?;
diesel_migrations::run_pending_migrations(&conn)
.map_err(|_| diesel::result::Error::NotFound)?;
let manager = models::player::Players(&conn);
manager.add("Player1", 0.0)?;
manager.add("Player2", 0.0)?;
crate::LootManager(&conn, 0).add_from(&crate::Item {
id: 0,
name: "Epee".to_string(),
base_price: 30,
})?;
crate::LootManager(&conn, 1).add_from(&crate::Item {
id: 0,
name: "Arc".to_string(),
base_price: 20,
})?;
Ok(conn)
}
#[test]
fn add_claim() -> TestResult {
let conn = test_connection()?;
Claims(&conn).add(1, 1)?;
assert_eq!(Claims(&conn).all()?.len(), 1);
Ok(())
}
#[test]
fn cannot_duplicate_by_adding() -> TestResult {
let conn = test_connection()?;
Claims(&conn).add(1, 1)?;
let res = Claims(&conn).add(1, 1);
assert_eq!(res.is_err(), true);
assert_eq!(Claims(&conn).all()?.len(), 1);
Ok(())
}
#[test]
fn remove_claim() -> TestResult {
let conn = test_connection()?;
let claim = Claims(&conn).add(1, 1)?;
claim.remove(&conn);
assert_eq!(Claims(&conn).all()?.len(), 0);
Ok(())
}
#[test]
fn cannot_only_claim_from_group() -> TestResult {
let conn = test_connection()?;
let claim = Claims(&conn).add(1, 2);
assert_eq!(claim.is_err(), true);
assert_eq!(Claims(&conn).all()?.len(), 0);
Ok(())
}
}