172 lines
4.6 KiB
Rust
172 lines
4.6 KiB
Rust
use diesel::dsl::{exists, Eq, Filter, Find, Select};
|
|
use diesel::expression::exists::Exists;
|
|
use diesel::prelude::*;
|
|
|
|
use crate::schema::{items, looted};
|
|
use crate::{DbConnection, QueryResult, Update, UpdateResult, Claims };
|
|
type ItemColumns = (looted::id, looted::name, looted::base_price);
|
|
const ITEM_COLUMNS: ItemColumns = (looted::id, looted::name, looted::base_price);
|
|
type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
|
|
|
/// Represents a basic item
|
|
#[derive(Debug, Queryable, Serialize, Deserialize, Clone)]
|
|
pub struct Item {
|
|
pub id: i32,
|
|
pub name: String,
|
|
base_price: i32,
|
|
}
|
|
|
|
impl Item {
|
|
/// Returns this item value
|
|
pub fn value(&self) -> i32 {
|
|
self.base_price
|
|
}
|
|
|
|
/// Returns this item sell value
|
|
pub fn sell_value(&self) -> i32 {
|
|
self.base_price / 2
|
|
}
|
|
|
|
pub fn remove(self, conn: &DbConnection) -> UpdateResult {
|
|
conn.transaction(
|
|
|| -> UpdateResult
|
|
{
|
|
Claims(conn).delete_for_loot(self.id)?;
|
|
diesel::delete(looted::table.find(self.id)).execute(conn)?;
|
|
|
|
Ok(Update::ItemRemoved(self))
|
|
}
|
|
)
|
|
}
|
|
|
|
fn owned_by(player: i32) -> OwnedBy {
|
|
Loot::owned_by(player).select(ITEM_COLUMNS)
|
|
}
|
|
}
|
|
|
|
pub struct Inventory<'q>(pub &'q DbConnection);
|
|
|
|
impl<'q> Inventory<'q> {
|
|
/// Get all items from Inventory
|
|
pub fn all(&self) -> QueryResult<Vec<Item>> {
|
|
items::table.load::<Item>(self.0)
|
|
}
|
|
|
|
/// Find an item in Inventory
|
|
pub fn find(&self, item_id: i32) -> QueryResult<Item> {
|
|
items::table.find(item_id).first::<Item>(self.0)
|
|
}
|
|
}
|
|
|
|
type WithOwner = Eq<looted::owner_id, i32>;
|
|
type OwnedLoot = Filter<looted::table, WithOwner>;
|
|
|
|
/// Represents an item that has been looted,
|
|
/// hence has an owner.
|
|
#[derive(Identifiable, Debug, Queryable)]
|
|
#[table_name = "looted"]
|
|
pub(super) struct Loot {
|
|
id: i32,
|
|
name: String,
|
|
base_price: i32,
|
|
owner: i32,
|
|
}
|
|
|
|
impl Loot {
|
|
/// A filter on Loot that is owned by given player
|
|
pub(super) fn owned_by(id: i32) -> OwnedLoot {
|
|
looted::table.filter(looted::owner_id.eq(id))
|
|
}
|
|
|
|
fn exists(id: i32) -> Exists<Find<looted::table, i32>> {
|
|
exists(looted::table.find(id))
|
|
}
|
|
|
|
pub(super) fn set_owner(&self, owner: i32, conn: &DbConnection) -> QueryResult<()> {
|
|
diesel::update(looted::table.find(self.id))
|
|
.set(looted::dsl::owner_id.eq(owner))
|
|
.execute(conn)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn into_item(self) -> Item {
|
|
Item {
|
|
id: self.id,
|
|
name: self.name,
|
|
base_price: self.base_price,
|
|
}
|
|
}
|
|
|
|
pub(super) fn find(id: i32) -> Find<looted::table, i32> {
|
|
looted::table.find(id)
|
|
}
|
|
}
|
|
|
|
/// Manager for a *single* player loot
|
|
pub struct LootManager<'q>(pub &'q DbConnection, pub i32);
|
|
|
|
impl<'q> LootManager<'q> {
|
|
/// All items from this player chest
|
|
pub fn all(&self) -> QueryResult<Vec<Item>> {
|
|
Ok(Item::owned_by(self.1).load(self.0)?)
|
|
}
|
|
|
|
/// Finds an item by id
|
|
///
|
|
/// Returns a NotFound error if an item is found by it
|
|
/// does not belong to this player
|
|
pub fn find(&self, loot_id: i32) -> QueryResult<Item> {
|
|
Ok(Loot::find(loot_id).first(self.0).and_then(|loot: Loot| {
|
|
if loot.owner != self.1 {
|
|
Err(diesel::result::Error::NotFound)
|
|
} else {
|
|
Ok(Item {
|
|
id: loot.id,
|
|
name: loot.name,
|
|
base_price: loot.base_price,
|
|
})
|
|
}
|
|
})?)
|
|
}
|
|
|
|
/// The last item added to the chest
|
|
pub fn last(&self) -> QueryResult<Item> {
|
|
Ok(Item::owned_by(self.1)
|
|
.order(looted::dsl::id.desc())
|
|
.first(self.0)?)
|
|
}
|
|
|
|
pub(crate) fn add<S: Into<String>>(self, name: S, base_price: i32) -> UpdateResult {
|
|
self.add_from(&Item {
|
|
id: 0,
|
|
name: name.into(),
|
|
base_price,
|
|
})
|
|
}
|
|
|
|
/// Adds a copy of the given item inside player chest
|
|
pub fn add_from(self, item: &Item) -> UpdateResult {
|
|
let new_item = NewLoot {
|
|
name: &item.name,
|
|
base_price: item.base_price,
|
|
owner_id: self.1,
|
|
};
|
|
diesel::insert_into(looted::table)
|
|
.values(&new_item)
|
|
.execute(self.0)?;
|
|
Ok(Update::ItemAdded(self.last()?))
|
|
}
|
|
}
|
|
|
|
/// An item being looted or bought.
|
|
///
|
|
/// The owner is set to 0 in case of looting,
|
|
/// to the id of buying player otherwise.
|
|
#[derive(Insertable)]
|
|
#[table_name = "looted"]
|
|
struct NewLoot<'a> {
|
|
name: &'a str,
|
|
base_price: i32,
|
|
owner_id: i32,
|
|
}
|