thoughts on new api structure, formats code

This commit is contained in:
2019-10-15 14:42:57 +02:00
parent 8399ffebf7
commit 6101aaa9e9
8 changed files with 176 additions and 139 deletions

View File

@@ -4,8 +4,10 @@
//! This module wraps all needed database operations.
//! It exports a public API for integration with various clients (REST Api, CLI, ...)
extern crate dotenv;
#[macro_use] extern crate diesel;
#[macro_use] extern crate serde_derive;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate serde_derive;
use diesel::prelude::*;
use diesel::query_dsl::RunQueryDsl;
@@ -16,8 +18,8 @@ pub mod models;
mod schema;
pub use models::{
item::{Item, LootManager},
claim::{Claim, Claims},
item::{Item, LootManager},
player::{Player, Players},
};
@@ -30,6 +32,33 @@ pub type QueryResult<T> = Result<T, diesel::result::Error>;
/// The result of an action provided by DbApi
pub type ActionResult<R> = Result<R, diesel::result::Error>;
pub enum ApiError {
DieselError(diesel::result::Error),
InvalidAction(String),
}
pub type ApiResult<R> = Result<R, ApiError>;
pub enum ApiActions<'a> {
FetchPlayers,
FetchInventory,
// Player actions
FetchLoot(i32),
UpdateWealth(i32, f32),
BuyItems(i32, &'a Vec<(i32, Option<f32>)>),
SellItems(i32, &'a Vec<(i32, Option<f32>)>),
ClaimItem(i32, i32),
UnclaimItem(i32, i32),
// Group actions
AddLoot(&'a Vec<Item>),
}
pub enum AdminActions {
AddPlayer(String, f32),
//AddInventoryItem(pub String, pub i32),
ResolveClaims,
//SetClaimsTimeout(pub i32),
}
/// A wrapper providing an API over the database
/// It offers a convenient way to deal with connection.
@@ -138,18 +167,20 @@ impl<'q> AsPlayer<'q> {
///
/// # Returns
/// Result containing the difference in coins after operation
pub fn buy<'a>(self, params: &Vec<(i32, Option<f32>)>) -> ActionResult<(Vec<models::Item>, (i32, i32, i32, i32))> {
pub fn buy<'a>(
self,
params: &Vec<(i32, Option<f32>)>,
) -> ActionResult<(Vec<models::Item>, (i32, i32, i32, i32))> {
let mut cumulated_diff: Vec<(i32, i32, i32, i32)> = Vec::with_capacity(params.len());
let mut added_items: Vec<models::Item> = Vec::with_capacity(params.len());
for (item_id, price_mod) in params.into_iter() {
if let Ok((item, diff)) = self.conn.transaction(|| {
// Find item in inventory
let item = models::item::Inventory(self.conn).find(*item_id)?;
let new_item = models::item::LootManager(self.conn, self.id)
.add_from(&item)?;
let new_item = models::item::LootManager(self.conn, self.id).add_from(&item)?;
let sell_price = match price_mod {
Some(modifier) => item.base_price as f32 * modifier,
None => item.base_price as f32
None => item.base_price as f32,
};
models::player::AsPlayer(self.conn, self.id)
.update_wealth(-sell_price)
@@ -159,8 +190,13 @@ impl<'q> AsPlayer<'q> {
added_items.push(item);
}
}
let all_diff = cumulated_diff.into_iter().fold((0,0,0,0), |sum, diff| {
(sum.0 + diff.0, sum.1 + diff.1, sum.2 + diff.2, sum.3 + diff.3)
let all_diff = cumulated_diff.into_iter().fold((0, 0, 0, 0), |sum, diff| {
(
sum.0 + diff.0,
sum.1 + diff.1,
sum.2 + diff.2,
sum.3 + diff.3,
)
});
Ok((added_items, all_diff))
}
@@ -168,10 +204,7 @@ impl<'q> AsPlayer<'q> {
///
/// # Returns
/// Result containing the difference in coins after operation
pub fn sell(
self,
params: &Vec<(i32, Option<f32>)>,
) -> ActionResult<(i32, i32, i32, i32)> {
pub fn sell(self, params: &Vec<(i32, Option<f32>)>) -> ActionResult<(i32, i32, i32, i32)> {
let mut all_results: Vec<(i32, i32, i32, i32)> = Vec::with_capacity(params.len());
for (loot_id, price_mod) in params.into_iter() {
let res = self.conn.transaction(|| {
@@ -186,13 +219,17 @@ impl<'q> AsPlayer<'q> {
all_results.push(diff.as_tuple())
} else {
// TODO: need to find a better way to deal with errors
return Err(diesel::result::Error::NotFound)
return Err(diesel::result::Error::NotFound);
}
}
Ok(all_results.into_iter().fold((0,0,0,0), |sum, diff| {
(sum.0 + diff.0, sum.1 + diff.1, sum.2 + diff.2, sum.3 + diff.3)
Ok(all_results.into_iter().fold((0, 0, 0, 0), |sum, diff| {
(
sum.0 + diff.0,
sum.1 + diff.1,
sum.2 + diff.2,
sum.3 + diff.3,
)
}))
}
/// Adds the value in gold to the player's wealth.
@@ -202,7 +239,6 @@ impl<'q> AsPlayer<'q> {
models::player::AsPlayer(self.conn, self.id)
.update_wealth(value_in_gp)
.map(|w| w.as_tuple())
}
/// Put a claim on a specific item
pub fn claim(self, item: i32) -> ActionResult<()> {
@@ -232,8 +268,7 @@ impl<'q> AsAdmin<'q> {
///
/// Takes the player name and starting wealth (in gold value).
pub fn add_player(self, name: &str, start_wealth: f32) -> ActionResult<()> {
models::player::Players(self.0)
.add(name, start_wealth)?;
models::player::Players(self.0).add(name, start_wealth)?;
Ok(())
}
@@ -260,10 +295,9 @@ impl<'q> AsAdmin<'q> {
self.0.transaction(|| {
claim.resolve_claim(self.0)?;
//models::item::LootManager(self.0, 0).set_owner(claim.loot_id, claim.player_id)?;
models::player::AsPlayer(self.0, player_id)
.update_debt(item.sell_value())
models::player::AsPlayer(self.0, player_id).update_debt(item.sell_value())
})?;
},
}
_ => (),
}
}
@@ -355,13 +389,22 @@ mod tests_old {
assert_eq!(claims.len(), 0);
// Add items
assert_eq!(DbApi::with_conn(&conn).as_admin().add_loot(vec![
("Épée", 40),
("Arc", 40),
]).is_ok(), true);
assert_eq!(
DbApi::with_conn(&conn)
.as_admin()
.add_loot(vec![("Épée", 40), ("Arc", 40),])
.is_ok(),
true
);
// Add players
DbApi::with_conn(&conn).as_admin().add_player("Player1", 0.0).unwrap();
DbApi::with_conn(&conn).as_admin().add_player("Player2", 0.0).unwrap();
DbApi::with_conn(&conn)
.as_admin()
.add_player("Player1", 0.0)
.unwrap();
DbApi::with_conn(&conn)
.as_admin()
.add_player("Player2", 0.0)
.unwrap();
// Put claims on one different item each
DbApi::with_conn(&conn).as_player(1).claim(1).unwrap();
DbApi::with_conn(&conn).as_player(2).claim(2).unwrap();
@@ -370,7 +413,10 @@ mod tests_old {
// Check that both players received an item
let players = DbApi::with_conn(&conn).fetch_players().unwrap();
for &i in [1, 2].into_iter() {
assert_eq!(DbApi::with_conn(&conn).as_player(i).loot().unwrap().len(), 1);
assert_eq!(
DbApi::with_conn(&conn).as_player(i).loot().unwrap().len(),
1
);
let player = players.get(i as usize).unwrap();
assert_eq!(player.debt, 20);
}
@@ -448,9 +494,7 @@ mod tests_old {
.add_player("Player", 1000.0)
.unwrap();
// Buy an item
let bought = DbApi::with_conn(&conn)
.as_player(1)
.buy(&vec![(1, None)]);
let bought = DbApi::with_conn(&conn).as_player(1).buy(&vec![(1, None)]);
assert_eq!(bought.ok(), Some((0, 0, 0, -8))); // Returns diff of player wealth ?
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
assert_eq!(chest.len(), 1);
@@ -461,10 +505,14 @@ mod tests_old {
let player = players.get(1).unwrap();
assert_eq!(player.pp, 2);
// A player cannot sell loot from an other's chest
let result = DbApi::with_conn(&conn).as_player(0).sell(&vec![(loot.id, None)]);
let result = DbApi::with_conn(&conn)
.as_player(0)
.sell(&vec![(loot.id, None)]);
assert_eq!(result.is_ok(), false);
// Sell back
let sold = DbApi::with_conn(&conn).as_player(1).sell(&vec![(loot.id, None)]);
let sold = DbApi::with_conn(&conn)
.as_player(1)
.sell(&vec![(loot.id, None)]);
assert_eq!(sold.ok(), Some((0, 0, 0, 4)));
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
assert_eq!(chest.len(), 0);