176 lines
5.3 KiB
Rust
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(())
|
|
}
|
|
}
|