impls more DbApi actions, adds a test
This commit is contained in:
@@ -47,16 +47,23 @@ impl ActionStatus<()> {
|
|||||||
response: (),
|
response: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn nop() -> ActionStatus<()> {
|
|
||||||
Self {
|
|
||||||
executed: false,
|
|
||||||
response: (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T: Default + serde::Serialize> ActionStatus<T> {
|
||||||
|
fn nop() -> ActionStatus<T> {
|
||||||
|
Self {
|
||||||
|
executed: false,
|
||||||
|
response: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// A wrapper providing an API over the database
|
/// A wrapper providing an API over the database
|
||||||
/// It offers a convenient way to deal with connection
|
/// It offers a convenient way to deal with connection.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// All methods consumes the DbApi, so that only one action
|
||||||
|
/// can be performed using a single instance.
|
||||||
///
|
///
|
||||||
/// # Todo list
|
/// # Todo list
|
||||||
/// ```text
|
/// ```text
|
||||||
@@ -70,8 +77,8 @@ impl ActionStatus<()> {
|
|||||||
/// v .loot() -> List of items owned (Vec<Item>)
|
/// v .loot() -> List of items owned (Vec<Item>)
|
||||||
/// v .claim(loot_id) -> Success status (bool)
|
/// v .claim(loot_id) -> Success status (bool)
|
||||||
/// v .unclaim(loot_id) -> Success status (bool)
|
/// v .unclaim(loot_id) -> Success status (bool)
|
||||||
/// x .sell(loot_id) -> Success status (bool, earned)
|
/// v .sell(loot_id) -> Success status (bool, earned)
|
||||||
/// x .buy(item_desc) -> Success status (bool, cost)
|
/// v .buy(item_desc) -> Success status (bool, cost)
|
||||||
/// v .update_wealth(value_in_gold) -> Success status (bool, new_wealth)
|
/// v .update_wealth(value_in_gold) -> Success status (bool, new_wealth)
|
||||||
/// v .as_admin()
|
/// v .as_admin()
|
||||||
/// x .add_loot(identifier, [items_desc]) -> Success status
|
/// x .add_loot(identifier, [items_desc]) -> Success status
|
||||||
@@ -153,6 +160,48 @@ impl<'q> AsPlayer<'q> {
|
|||||||
pub fn loot(self) -> QueryResult<Vec<models::Item>> {
|
pub fn loot(self) -> QueryResult<Vec<models::Item>> {
|
||||||
Ok(models::Item::owned_by(self.id).load(self.conn)?)
|
Ok(models::Item::owned_by(self.id).load(self.conn)?)
|
||||||
}
|
}
|
||||||
|
/// Buy an item and add it to this player chest
|
||||||
|
///
|
||||||
|
/// TODO: Items should be picked from a custom list
|
||||||
|
pub fn buy<'a>(self, name: &'a str, price: i32) -> ActionResult<Option<(i32, i32, i32, i32)>> {
|
||||||
|
let new_item = models::item::NewLoot::to_player(self.id, (name, price));
|
||||||
|
diesel::insert_into(schema::looted::table)
|
||||||
|
.values(&new_item)
|
||||||
|
.execute(self.conn)
|
||||||
|
.and_then(|r| match r {
|
||||||
|
1 => self.update_wealth(-(price as f32)),
|
||||||
|
_ => Ok(ActionStatus::nop())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Sell an item from this player chest
|
||||||
|
pub fn sell(self, loot_id: i32, _price_mod: Option<f32>) -> ActionResult<Option<(i32, i32, i32, i32)>> {
|
||||||
|
// Check that the item belongs to player
|
||||||
|
let exists_and_owned: bool = diesel::select(models::Loot::owns(self.id, loot_id))
|
||||||
|
.get_result(self.conn)?;
|
||||||
|
if !exists_and_owned {
|
||||||
|
Ok(ActionStatus {
|
||||||
|
executed: false,
|
||||||
|
response: None })
|
||||||
|
} else {
|
||||||
|
use schema::looted::dsl::*;
|
||||||
|
let loot_value = looted.find(loot_id)
|
||||||
|
.select(base_price)
|
||||||
|
.first::<i32>(self.conn)?;
|
||||||
|
let sell_value = (loot_value / 2) as f32;
|
||||||
|
diesel::delete(looted.find(loot_id))
|
||||||
|
.execute(self.conn)
|
||||||
|
.and_then(|r| match r {
|
||||||
|
// On deletion, update this player wealth
|
||||||
|
1 => self.update_wealth(sell_value),
|
||||||
|
_ => Ok(ActionStatus {
|
||||||
|
executed: false,
|
||||||
|
response: None,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds the value in gold to the player's wealth.
|
/// Adds the value in gold to the player's wealth.
|
||||||
///
|
///
|
||||||
/// Value can be negative to substract wealth.
|
/// Value can be negative to substract wealth.
|
||||||
@@ -222,6 +271,17 @@ impl<'q> AsAdmin<'q> {
|
|||||||
.map(ActionStatus::was_updated)
|
.map(ActionStatus::was_updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a list of items to the group loot
|
||||||
|
pub fn add_loot<'a>(self, items: Vec<(&'a str, i32)>) -> ActionResult<()> {
|
||||||
|
for item_desc in items.into_iter() {
|
||||||
|
let new_item = models::item::NewLoot::to_group(item_desc);
|
||||||
|
diesel::insert_into(schema::looted::table)
|
||||||
|
.values(&new_item)
|
||||||
|
.execute(self.0)?;
|
||||||
|
}
|
||||||
|
Ok(ActionStatus::ok())
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve all pending claims and dispatch claimed items.
|
/// Resolve all pending claims and dispatch claimed items.
|
||||||
///
|
///
|
||||||
/// When a player gets an item, it's debt is increased by this item sell value
|
/// When a player gets an item, it's debt is increased by this item sell value
|
||||||
@@ -325,6 +385,37 @@ mod tests {
|
|||||||
fn test_player_unclaim_item() {
|
fn test_player_unclaim_item() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All-in-one checks one a simple buy/sell procedure
|
||||||
|
///
|
||||||
|
/// Checks that player's chest and wealth are updated.
|
||||||
|
/// Checks that items are sold at half their value.
|
||||||
|
#[test]
|
||||||
|
fn test_buy_sell_simple() {
|
||||||
|
let conn = test_connection();
|
||||||
|
DbApi::with_conn(&conn).as_admin().add_player("Player".to_string(), 1000.0).unwrap();
|
||||||
|
// Buy an item
|
||||||
|
let bought = DbApi::with_conn(&conn).as_player(1).buy("Sword", 800).unwrap();
|
||||||
|
assert_eq!(bought.executed, true);
|
||||||
|
assert_eq!(bought.response, Some((0,0,0,-8)));
|
||||||
|
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
|
||||||
|
assert_eq!(chest.len(), 1);
|
||||||
|
let loot = chest.get(0).unwrap();
|
||||||
|
assert_eq!(loot.name, "Sword");
|
||||||
|
assert_eq!(loot.base_price, 800);
|
||||||
|
let players = DbApi::with_conn(&conn).fetch_players().unwrap();
|
||||||
|
let player = players.get(1).unwrap();
|
||||||
|
assert_eq!(player.pp, 2);
|
||||||
|
// Sell back
|
||||||
|
let sold = DbApi::with_conn(&conn).as_player(1).sell(loot.id, None).unwrap();
|
||||||
|
assert_eq!(sold.executed, true);
|
||||||
|
assert_eq!(sold.response, Some((0,0,0,4)));
|
||||||
|
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
|
||||||
|
assert_eq!(chest.len(), 0);
|
||||||
|
let players = DbApi::with_conn(&conn).fetch_players().unwrap();
|
||||||
|
let player = players.get(1).unwrap();
|
||||||
|
assert_eq!(player.pp, 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
|||||||
/// Or maybe this is a little too confusing ??
|
/// Or maybe this is a little too confusing ??
|
||||||
#[derive(Debug, Queryable, Serialize)]
|
#[derive(Debug, Queryable, Serialize)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
id: i32,
|
pub id: i32,
|
||||||
name: String,
|
pub name: String,
|
||||||
base_price: i32,
|
pub base_price: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
@@ -35,7 +35,7 @@ type OwnedLoot = Filter<looted::table, WithOwner>;
|
|||||||
pub(crate) struct Loot {
|
pub(crate) struct Loot {
|
||||||
id: i32,
|
id: i32,
|
||||||
name: String,
|
name: String,
|
||||||
base_value: i32,
|
base_price: i32,
|
||||||
owner: i32,
|
owner: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,13 +45,17 @@ impl Loot {
|
|||||||
looted::table.filter(looted::owner_id.eq(id))
|
looted::table.filter(looted::owner_id.eq(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn owns(player: i32, item: i32) -> Exists<Find<OwnedLoot, i32>> {
|
||||||
|
exists(Loot::owned_by(player).find(item))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn exists(id: i32) -> Exists<Find<looted::table, i32>> {
|
pub(crate) fn exists(id: i32) -> Exists<Find<looted::table, i32>> {
|
||||||
exists(looted::table.find(id))
|
exists(looted::table.find(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Description of an item : (name, value in gold)
|
/// Description of an item : (name, value in gold)
|
||||||
type ItemDesc<'a> = (&'a str, i32);
|
pub type ItemDesc<'a> = (&'a str, i32);
|
||||||
|
|
||||||
/// An item being looted or bought.
|
/// An item being looted or bought.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user