adds UpdateResult class of queries
This commit is contained in:
@@ -18,9 +18,9 @@ mod schema;
|
|||||||
|
|
||||||
pub use models::{
|
pub use models::{
|
||||||
claim::{Claim, Claims},
|
claim::{Claim, Claims},
|
||||||
item::{Item, LootManager, Inventory},
|
|
||||||
player::{Player, Wealth, Players, AsPlayer},
|
|
||||||
history::{Event, UpdateList},
|
history::{Event, UpdateList},
|
||||||
|
item::{Inventory, Item, LootManager},
|
||||||
|
player::{AsPlayer, Player, Players, Wealth},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The connection used
|
/// The connection used
|
||||||
@@ -29,6 +29,7 @@ pub type DbConnection = SqliteConnection;
|
|||||||
pub type Pool = r2d2::Pool<ConnectionManager<DbConnection>>;
|
pub type Pool = r2d2::Pool<ConnectionManager<DbConnection>>;
|
||||||
/// The result of a query on DB
|
/// The result of a query on DB
|
||||||
pub type QueryResult<T> = Result<T, diesel::result::Error>;
|
pub type QueryResult<T> = Result<T, diesel::result::Error>;
|
||||||
|
pub type UpdateResult = QueryResult<Update>;
|
||||||
|
|
||||||
/// Sets up a connection pool and returns it.
|
/// Sets up a connection pool and returns it.
|
||||||
/// Uses the DATABASE_URL environment variable (must be set)
|
/// Uses the DATABASE_URL environment variable (must be set)
|
||||||
@@ -41,7 +42,6 @@ pub fn create_pool() -> Pool {
|
|||||||
.expect("Failed to create pool.")
|
.expect("Failed to create pool.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Every possible update which can happen during a query
|
/// Every possible update which can happen during a query
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum Update {
|
pub enum Update {
|
||||||
@@ -54,24 +54,25 @@ pub enum Update {
|
|||||||
|
|
||||||
impl Update {
|
impl Update {
|
||||||
/// Change back what has been updated
|
/// Change back what has been updated
|
||||||
fn undo(&self, conn: &DbConnection, id: i32) -> QueryResult<Self> {
|
fn undo(&self, conn: &DbConnection, id: i32) -> UpdateResult {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Update::Wealth(diff) => {
|
Update::Wealth(diff) => AsPlayer(conn, id).update_wealth(-diff.to_gp())?,
|
||||||
Update::Wealth(AsPlayer(conn, id).update_wealth(-diff.to_gp())?)
|
Update::ItemAdded(item) => LootManager(conn, id).find(item.id)?.remove(conn)?,
|
||||||
},
|
Update::ItemRemoved(item) => LootManager(conn, id).add_from(&item)?,
|
||||||
Update::ItemAdded(item) => {
|
|
||||||
Update::ItemRemoved(LootManager(conn, id).remove(item.id)?)
|
|
||||||
},
|
|
||||||
Update::ItemRemoved(item) => {
|
|
||||||
Update::ItemAdded(LootManager(conn, id).add_from(&item)?)
|
|
||||||
},
|
|
||||||
// Unused for now
|
// Unused for now
|
||||||
Update::ClaimAdded(claim) => { Update::ClaimRemoved(*claim) },
|
Update::ClaimAdded(claim) => Update::ClaimRemoved(*claim),
|
||||||
Update::ClaimRemoved(claim) => { Update::ClaimAdded(*claim) },
|
Update::ClaimRemoved(claim) => Update::ClaimAdded(*claim),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: use this to wrap update in UpdateResult, allowing unified interface
|
||||||
|
/// whether a query makes multiple updates or just one.
|
||||||
|
enum OneOrMore {
|
||||||
|
One(Update),
|
||||||
|
More(Vec<Update>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Every value which can be queried
|
/// Every value which can be queried
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
@@ -107,17 +108,19 @@ pub fn sell_item_transaction(
|
|||||||
id: i32,
|
id: i32,
|
||||||
loot_id: i32,
|
loot_id: i32,
|
||||||
price_mod: Option<f64>,
|
price_mod: Option<f64>,
|
||||||
) -> QueryResult<(Item, Wealth)> {
|
) -> QueryResult<(Update, Wealth)> {
|
||||||
conn.transaction(|| {
|
conn.transaction(|| {
|
||||||
let deleted = LootManager(conn, id)
|
let to_delete = LootManager(conn, id).find(loot_id)?;
|
||||||
.remove(loot_id)?;
|
let mut sell_value = to_delete.sell_value() as f64;
|
||||||
let mut sell_value = deleted.sell_value() as f64;
|
|
||||||
if let Some(modifier) = price_mod {
|
if let Some(modifier) = price_mod {
|
||||||
sell_value *= modifier;
|
sell_value *= modifier;
|
||||||
}
|
}
|
||||||
let wealth = AsPlayer(conn, id)
|
let deleted = to_delete.remove(conn)?;
|
||||||
.update_wealth(sell_value)?;
|
if let Update::Wealth(wealth) = AsPlayer(conn, id).update_wealth(sell_value)? {
|
||||||
Ok((deleted, wealth))
|
Ok((deleted, wealth))
|
||||||
|
} else {
|
||||||
|
Err(diesel::result::Error::RollbackTransaction)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +134,7 @@ pub fn buy_item_from_inventory(
|
|||||||
id: i32,
|
id: i32,
|
||||||
item_id: i32,
|
item_id: i32,
|
||||||
price_mod: Option<f64>,
|
price_mod: Option<f64>,
|
||||||
) -> QueryResult<(Item, Wealth)> {
|
) -> QueryResult<(Update, Wealth)> {
|
||||||
conn.transaction(|| {
|
conn.transaction(|| {
|
||||||
// Find item in inventory
|
// Find item in inventory
|
||||||
let item = Inventory(conn).find(item_id)?;
|
let item = Inventory(conn).find(item_id)?;
|
||||||
@@ -140,9 +143,11 @@ pub fn buy_item_from_inventory(
|
|||||||
Some(modifier) => item.value() as f64 * modifier,
|
Some(modifier) => item.value() as f64 * modifier,
|
||||||
None => item.value() as f64,
|
None => item.value() as f64,
|
||||||
};
|
};
|
||||||
AsPlayer(conn, id)
|
if let Update::Wealth(diff) = AsPlayer(conn, id).update_wealth(-sell_price)? {
|
||||||
.update_wealth(-sell_price)
|
Ok((new_item, diff))
|
||||||
.map(|diff| (new_item, diff))
|
} else {
|
||||||
|
Err(diesel::result::Error::RollbackTransaction)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,35 +166,39 @@ pub fn resolve_claims(conn: &DbConnection) -> QueryResult<()> {
|
|||||||
for (item, mut claims) in data {
|
for (item, mut claims) in data {
|
||||||
if claims.len() > 1 {
|
if claims.len() > 1 {
|
||||||
// TODO: better sorting mechanism :)
|
// TODO: better sorting mechanism :)
|
||||||
claims.sort_by(|a,b| a.resolve.cmp(&b.resolve));
|
claims.sort_by(|a, b| a.resolve.cmp(&b.resolve));
|
||||||
}
|
}
|
||||||
let winner = claims.get(0).expect("Claims should not be empty !");
|
let winner = claims.get(0).expect("Claims should not be empty !");
|
||||||
let player_id = winner.player_id;
|
let player_id = winner.player_id;
|
||||||
winner.resolve_claim(conn)?;
|
winner.resolve_claim(conn)?;
|
||||||
models::player::AsPlayer(conn, player_id)
|
models::player::AsPlayer(conn, player_id).update_debt(item.sell_value())?;
|
||||||
.update_debt(item.sell_value())?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split up and share group money among selected players
|
/// Split up and share group money among selected players
|
||||||
pub fn split_and_share(conn: &DbConnection, amount: i32, players: Vec<i32>) -> QueryResult<Wealth> {
|
pub fn split_and_share(
|
||||||
|
conn: &DbConnection,
|
||||||
|
amount: i32,
|
||||||
|
players: &Vec<i32>,
|
||||||
|
) -> QueryResult<Wealth> {
|
||||||
let share = (
|
let share = (
|
||||||
amount / (players.len() + 1) as i32 // +1 share for the group
|
amount / (players.len() + 1) as i32
|
||||||
|
// +1 share for the group
|
||||||
) as f64;
|
) as f64;
|
||||||
conn.transaction(|| {
|
conn.transaction(|| {
|
||||||
for p in players.into_iter() {
|
for p in players {
|
||||||
let player = Players(conn).find(p)?;
|
let player = Players(conn).find(*p)?;
|
||||||
// Take debt into account
|
// Take debt into account
|
||||||
match share - player.debt as f64 {
|
match share - player.debt as f64 {
|
||||||
rest if rest > 0.0 => {
|
rest if rest > 0.0 => {
|
||||||
AsPlayer(conn, p).update_debt(-player.debt)?;
|
AsPlayer(conn, *p).update_debt(-player.debt)?;
|
||||||
AsPlayer(conn, p).update_wealth(rest)?;
|
AsPlayer(conn, *p).update_wealth(rest)?;
|
||||||
AsPlayer(conn, 0).update_wealth(-rest)?;
|
AsPlayer(conn, 0).update_wealth(-rest)?;
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
AsPlayer(conn, p).update_debt(-share as i32)?;
|
AsPlayer(conn, *p).update_debt(-share as i32)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use diesel::expression::exists::Exists;
|
|||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use crate::schema::{items, looted};
|
use crate::schema::{items, looted};
|
||||||
use crate::{DbConnection, QueryResult};
|
use crate::{DbConnection, QueryResult, Update, UpdateResult };
|
||||||
type ItemColumns = (looted::id, looted::name, looted::base_price);
|
type ItemColumns = (looted::id, looted::name, looted::base_price);
|
||||||
const ITEM_COLUMNS: ItemColumns = (looted::id, looted::name, looted::base_price);
|
const ITEM_COLUMNS: ItemColumns = (looted::id, looted::name, looted::base_price);
|
||||||
type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
||||||
@@ -27,6 +27,11 @@ impl Item {
|
|||||||
self.base_price / 2
|
self.base_price / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove(self, conn: &DbConnection) -> UpdateResult {
|
||||||
|
diesel::delete(looted::table.find(self.id)).execute(conn)?;
|
||||||
|
Ok(Update::ItemRemoved(self))
|
||||||
|
}
|
||||||
|
|
||||||
fn owned_by(player: i32) -> OwnedBy {
|
fn owned_by(player: i32) -> OwnedBy {
|
||||||
Loot::owned_by(player).select(ITEM_COLUMNS)
|
Loot::owned_by(player).select(ITEM_COLUMNS)
|
||||||
}
|
}
|
||||||
@@ -124,7 +129,7 @@ impl<'q> LootManager<'q> {
|
|||||||
.first(self.0)?)
|
.first(self.0)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add<S: Into<String>>(self, name: S, base_price: i32) -> QueryResult<Item> {
|
pub(crate) fn add<S: Into<String>>(self, name: S, base_price: i32) -> UpdateResult {
|
||||||
self.add_from(&Item {
|
self.add_from(&Item {
|
||||||
id: 0,
|
id: 0,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
@@ -133,7 +138,7 @@ impl<'q> LootManager<'q> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a copy of the given item inside player chest
|
/// Adds a copy of the given item inside player chest
|
||||||
pub fn add_from(self, item: &Item) -> QueryResult<Item> {
|
pub fn add_from(self, item: &Item) -> UpdateResult {
|
||||||
let new_item = NewLoot {
|
let new_item = NewLoot {
|
||||||
name: &item.name,
|
name: &item.name,
|
||||||
base_price: item.base_price,
|
base_price: item.base_price,
|
||||||
@@ -142,13 +147,7 @@ impl<'q> LootManager<'q> {
|
|||||||
diesel::insert_into(looted::table)
|
diesel::insert_into(looted::table)
|
||||||
.values(&new_item)
|
.values(&new_item)
|
||||||
.execute(self.0)?;
|
.execute(self.0)?;
|
||||||
self.last()
|
Ok(Update::ItemAdded(self.last()?))
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(self, item_id: i32) -> QueryResult<Item> {
|
|
||||||
let deleted = self.find(item_id)?;
|
|
||||||
diesel::delete(looted::table.find(deleted.id)).execute(self.0)?;
|
|
||||||
Ok(deleted)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::schema::players;
|
use crate::schema::players;
|
||||||
use crate::{DbConnection, QueryResult};
|
use crate::{DbConnection, QueryResult, Update, UpdateResult};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
mod notification;
|
mod notification;
|
||||||
@@ -50,10 +50,7 @@ impl<'q> Players<'q> {
|
|||||||
|
|
||||||
/// Notify all players of an event
|
/// Notify all players of an event
|
||||||
pub fn notifiy_all(&self, text: &str) -> QueryResult<()> {
|
pub fn notifiy_all(&self, text: &str) -> QueryResult<()> {
|
||||||
for id in self.all()?
|
for id in self.all()?.into_iter().map(|p| p.id) {
|
||||||
.into_iter()
|
|
||||||
.map(|p| p.id)
|
|
||||||
{
|
|
||||||
self.notify(id, text);
|
self.notify(id, text);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -75,7 +72,7 @@ impl<'q> AsPlayer<'q> {
|
|||||||
notification::pop_all_for(self.1, self.0)
|
notification::pop_all_for(self.1, self.0)
|
||||||
}
|
}
|
||||||
/// Updates this player's wealth, returning the difference
|
/// Updates this player's wealth, returning the difference
|
||||||
pub fn update_wealth(&self, value_in_gp: f64) -> QueryResult<Wealth> {
|
pub fn update_wealth(&self, value_in_gp: f64) -> UpdateResult {
|
||||||
use crate::schema::players::dsl::*;
|
use crate::schema::players::dsl::*;
|
||||||
let current_wealth = players
|
let current_wealth = players
|
||||||
.find(self.1)
|
.find(self.1)
|
||||||
@@ -86,7 +83,7 @@ impl<'q> AsPlayer<'q> {
|
|||||||
.filter(id.eq(self.1))
|
.filter(id.eq(self.1))
|
||||||
.set(&updated_wealth)
|
.set(&updated_wealth)
|
||||||
.execute(self.0)?;
|
.execute(self.0)?;
|
||||||
Ok(updated_wealth - current_wealth)
|
Ok(Update::Wealth(updated_wealth - current_wealth))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates this player's debt
|
/// Updates this player's debt
|
||||||
|
|||||||
@@ -113,9 +113,7 @@ pub fn execute(
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
ApiActions::UpdateWealth(id, amount) => {
|
ApiActions::UpdateWealth(id, amount) => {
|
||||||
response.push_update(Update::Wealth(
|
response.push_update(db::AsPlayer(conn, id).update_wealth(amount)?);
|
||||||
db::AsPlayer(conn, id).update_wealth(amount)?,
|
|
||||||
));
|
|
||||||
response.notify(format!("Mis à jour ({}po)!", amount));
|
response.notify(format!("Mis à jour ({}po)!", amount));
|
||||||
Some((id, "Argent mis à jour"))
|
Some((id, "Argent mis à jour"))
|
||||||
}
|
}
|
||||||
@@ -165,15 +163,17 @@ pub fn execute(
|
|||||||
.fold(db::Wealth::from_gp(0.0), |acc, i| acc + i);
|
.fold(db::Wealth::from_gp(0.0), |acc, i| acc + i);
|
||||||
match id {
|
match id {
|
||||||
0 => {
|
0 => {
|
||||||
|
let players = params.players.expect("The player list should be passed in !");
|
||||||
let share = db::split_and_share(
|
let share = db::split_and_share(
|
||||||
conn,
|
conn,
|
||||||
total_amount.to_gp() as i32,
|
total_amount.to_gp() as i32,
|
||||||
params.players.expect("Should not be None"),
|
&players,
|
||||||
)?;
|
)?;
|
||||||
response.notify(format!(
|
response.notify(format!(
|
||||||
"Les objets ont été vendus, chaque joueur a reçu {} po",
|
"Les objets ont été vendus, chaque joueur a reçu {} po",
|
||||||
share.to_gp()
|
share.to_gp()
|
||||||
));
|
));
|
||||||
|
//response.push_update(Update::GroupShare(players, share));
|
||||||
response.push_update(Update::Wealth(share));
|
response.push_update(Update::Wealth(share));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
Reference in New Issue
Block a user