diff --git a/geoffrey_api/src/commands/add_location.rs b/geoffrey_api/src/commands/add_location.rs index 4342444..43b3d47 100644 --- a/geoffrey_api/src/commands/add_location.rs +++ b/geoffrey_api/src/commands/add_location.rs @@ -2,12 +2,13 @@ use crate::commands::{Command, RequestType}; use crate::context::Context; use crate::helper::get_player_from_req; use crate::Result; -use geoffrey_models::models::locations::Location; +use geoffrey_models::models::locations::{LocationDb, Location}; use geoffrey_models::models::parameters::add_location_params::AddLocationParams; use geoffrey_models::models::parameters::CommandRequest; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::CommandLevel; use std::sync::Arc; +use geoffrey_db::helper::load_location; pub struct AddLocation {} @@ -30,17 +31,19 @@ impl Command for AddLocation { fn run_command(ctx: Arc, req: Self::Req) -> Result { if let Some(player) = get_player_from_req(&ctx.db, &req)? { let args = &req.arguments; - let location = Location::new( + let location = LocationDb::new( args.name.as_str(), args.position, player.id.unwrap(), args.tunnel.clone(), - args.loc_type.clone(), + args.loc_type.into(), ); - ctx.db - .insert(location) - .map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string())) + let location = ctx.db + .insert(location)?; + + load_location(&ctx.db, &location).map_err(|err| err.into()) + } else { Err(GeoffreyAPIError::PlayerNotRegistered) } diff --git a/geoffrey_api/src/commands/find.rs b/geoffrey_api/src/commands/find.rs index 20cd859..8cc61ee 100644 --- a/geoffrey_api/src/commands/find.rs +++ b/geoffrey_api/src/commands/find.rs @@ -1,12 +1,14 @@ use crate::commands::{Command, RequestType}; use crate::context::Context; use crate::Result; -use geoffrey_models::models::locations::Location; +use geoffrey_models::models::locations::{LocationDb, Location}; +use geoffrey_models::models::player::Player; use geoffrey_models::models::parameters::find_params::FindParams; use geoffrey_models::models::parameters::CommandRequest; use geoffrey_models::models::response::api_error::GeoffreyAPIError; use geoffrey_models::models::CommandLevel; use std::sync::Arc; +use geoffrey_db::helper::load_location; pub struct FindCommand {} @@ -27,17 +29,29 @@ impl Command for FindCommand { } fn run_command(ctx: Arc, req: Self::Req) -> Result { - let locations = ctx + let query = req.arguments.query.to_lowercase(); + let players: Vec = ctx .db - .filter(|_, loc: &Location| { - let name = loc.name.to_lowercase(); - let query = req.arguments.query.to_lowercase(); + .filter(|_, player: &Player| { + let player_name = player.name.to_lowercase(); - name.contains(&query) - }) - .map_err(|err| GeoffreyAPIError::DatabaseError(err.to_string()))? + player_name.contains(&query) + })? + .map(|player| player.id.unwrap()) .collect(); - Ok(locations) + let locations: Vec = ctx + .db + .filter(|_, loc: &LocationDb| { + let name = loc.name.to_lowercase(); + + name.contains(&query) || loc.owners().iter().any(|owner_id| players.contains(owner_id)) + }).map_err(|err| GeoffreyAPIError::from(err))?.collect(); + + + let locations: Result> = locations.iter().map(|loc| load_location(&ctx.db, loc).map_err(|err| GeoffreyAPIError::from(err))).collect(); + + locations + } } diff --git a/geoffrey_api/src/logging.rs b/geoffrey_api/src/logging.rs index cbe719f..284f5ee 100644 --- a/geoffrey_api/src/logging.rs +++ b/geoffrey_api/src/logging.rs @@ -12,7 +12,8 @@ pub enum LogLevel { impl From<&str> for LogLevel { fn from(s: &str) -> Self { - match s { + let s = s.to_lowercase(); + match s.as_str() { "warn" | "w" => LogLevel::Warn, "info" | "i" => LogLevel::Info, "debug" | "d" => LogLevel::Debug, diff --git a/geoffrey_db/src/database.rs b/geoffrey_db/src/database.rs index 62238eb..8514a7f 100644 --- a/geoffrey_db/src/database.rs +++ b/geoffrey_db/src/database.rs @@ -107,13 +107,14 @@ impl Database { #[cfg(test)] mod tests { use crate::database::Database; - use geoffrey_models::models::locations::{Location, LocationType}; + use geoffrey_models::models::locations::{LocationDb, LocationDataDb}; use geoffrey_models::models::player::{Player, UserID}; use geoffrey_models::models::{Dimension, Position}; use geoffrey_models::GeoffreyDatabaseModel; use lazy_static::lazy_static; use std::path::Path; use std::time::Instant; + use geoffrey_models::models::locations::shop::Shop; lazy_static! { static ref DB: Database = Database::new(Path::new("../test_database")).unwrap(); @@ -121,12 +122,14 @@ mod tests { fn cleanup() { DB.clear_tree::().unwrap(); - DB.clear_tree::().unwrap(); + DB.clear_tree::().unwrap(); + DB.db.clear().unwrap(); DB.db.flush().unwrap(); } #[test] fn test_insert() { + cleanup(); let player = Player::new("CoolZero123", UserID::DiscordUUID { discord_uuid: 0u64 }); let p2 = DB.insert::(player.clone()).unwrap(); @@ -139,6 +142,7 @@ mod tests { #[test] fn test_unique_insert() { + cleanup(); let player1 = Player::new("CoolZero123", UserID::DiscordUUID { discord_uuid: 0u64 }); let player2 = Player::new("CoolZero123", UserID::DiscordUUID { discord_uuid: 0u64 }); @@ -150,6 +154,7 @@ mod tests { #[test] fn test_get() { + cleanup(); let player = Player::new("CoolZero123", UserID::DiscordUUID { discord_uuid: 0u64 }); let p2 = DB.insert::(player.clone()).unwrap(); @@ -162,19 +167,22 @@ mod tests { #[test] fn test_filter() { + cleanup(); let player = Player::new("CoolZero123", UserID::DiscordUUID { discord_uuid: 0u64 }); let player = DB.insert::(player.clone()).unwrap(); - let loc = Location::new( + let loc = LocationDb::new( "Test Shop", Position::new(0, 0, Dimension::Overworld), player.id.unwrap(), None, - LocationType::Shop(0), + LocationDataDb::Shop(Shop { + item_listings: Default::default() + }), ); - let loc = DB.insert::(loc.clone()).unwrap(); + let loc = DB.insert::(loc.clone()).unwrap(); let count = DB - .filter(|id: u64, l: &Location| { + .filter(|id: u64, l: &LocationDb| { assert_eq!(id, l.id().unwrap()); loc.id().unwrap() == id }) diff --git a/geoffrey_db/src/helper.rs b/geoffrey_db/src/helper.rs new file mode 100644 index 0000000..ad8b4a6 --- /dev/null +++ b/geoffrey_db/src/helper.rs @@ -0,0 +1,39 @@ +use geoffrey_models::models::locations::{LocationDb, LocationDataDb, LocationData, Location}; +use crate::database::Database; +use geoffrey_models::models::player::Player; +use crate::error::Result; +use geoffrey_models::models::locations::town::Town; +use geoffrey_models::models::locations::market::Market; + +pub fn load_location_data(db: &Database, data: &LocationDataDb) -> Result { + Ok(match data { + LocationDataDb::Base => LocationData::Base, + LocationDataDb::Shop(shop_data) => LocationData::Shop(shop_data.clone()), + LocationDataDb::Attraction => LocationData::Attraction, + LocationDataDb::Town(town_data) => { + let town_data = Town { + residents: db.filter(|id, _: &Player| town_data.residents.contains(&id))?.collect() + }; + + LocationData::Town(town_data) + } + LocationDataDb::Farm(farm_data) => LocationData::Farm(farm_data.clone()), + LocationDataDb::Market(market_data) => { + let shops: Result> = db.filter(|id, _: &LocationDb| market_data.shops.contains(&id))?.map(|loc| load_location(db, &loc)).collect(); + + let market_data = Market { + is_public: market_data.is_public, + shops: shops? + }; + + LocationData::Market(market_data) + } + }) +} + +pub fn load_location(db: &Database, location: &LocationDb) -> Result { + let owners: Vec = db.filter(|id, _: &Player| location.owners().contains(&id))?.collect(); + let loc_data = load_location_data(db, &location.loc_data)?; + + Ok(Location::from_db_location(location.clone(), owners, loc_data)) +} \ No newline at end of file diff --git a/geoffrey_db/src/lib.rs b/geoffrey_db/src/lib.rs index 0b6be88..d56cdff 100644 --- a/geoffrey_db/src/lib.rs +++ b/geoffrey_db/src/lib.rs @@ -2,3 +2,4 @@ pub mod database; pub mod error; +pub mod helper; diff --git a/geoffrey_models/src/models/locations/farm.rs b/geoffrey_models/src/models/locations/farm.rs index 1d897bd..df1ebc3 100644 --- a/geoffrey_models/src/models/locations/farm.rs +++ b/geoffrey_models/src/models/locations/farm.rs @@ -1,24 +1,8 @@ use crate::models::item::Item; -use crate::GeoffreyDatabaseModel; use serde::{Deserialize, Serialize}; use std::collections::HashSet; #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct FarmData { - id: Option, pub items_produced: HashSet, } - -impl GeoffreyDatabaseModel for FarmData { - fn id(&self) -> Option { - self.id - } - - fn set_id(&mut self, id: u64) { - self.id = Some(id) - } - - fn tree() -> String { - "farm".to_string() - } -} diff --git a/geoffrey_models/src/models/locations/market.rs b/geoffrey_models/src/models/locations/market.rs index 68ef9d6..e25db31 100644 --- a/geoffrey_models/src/models/locations/market.rs +++ b/geoffrey_models/src/models/locations/market.rs @@ -1,23 +1,15 @@ -use crate::GeoffreyDatabaseModel; use serde::{Deserialize, Serialize}; use std::collections::HashSet; +use crate::models::locations::Location; #[derive(Serialize, Deserialize, Debug, Clone, Default)] -pub struct Market { - pub id: Option, +pub struct MarketDb { + pub is_public: bool, pub shops: HashSet, } -impl GeoffreyDatabaseModel for Market { - fn id(&self) -> Option { - self.id - } - - fn set_id(&mut self, id: u64) { - self.id = Some(id) - } - - fn tree() -> String { - "market".to_string() - } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct Market { + pub is_public: bool, + pub shops: Vec, } diff --git a/geoffrey_models/src/models/locations/mod.rs b/geoffrey_models/src/models/locations/mod.rs index 69c97f3..f9e223b 100644 --- a/geoffrey_models/src/models/locations/mod.rs +++ b/geoffrey_models/src/models/locations/mod.rs @@ -3,39 +3,91 @@ use std::collections::HashSet; use crate::models::{Position, Tunnel}; use crate::GeoffreyDatabaseModel; +use crate::models::locations::shop::Shop; +use crate::models::locations::town::{TownDb, Town}; +use crate::models::locations::farm::FarmData; +use crate::models::locations::market::{MarketDb, Market}; +use crate::models::player::Player; pub mod farm; pub mod market; pub mod shop; pub mod town; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum LocationType { Base, - Shop(u64), + Shop, Attraction, - Town(u64), - Farm(u64), - Market(u64), + Town, + Farm, + Market, +} + +impl From for LocationType { + fn from(l: LocationDataDb) -> Self { + match l { + LocationDataDb::Base => LocationType::Base, + LocationDataDb::Shop(_) => LocationType::Shop, + LocationDataDb::Attraction => LocationType::Attraction, + LocationDataDb::Town(_) => LocationType::Town, + LocationDataDb::Farm(_) => LocationType::Farm, + LocationDataDb::Market(_) => LocationType::Market, + } + } } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Location { +pub enum LocationDataDb { + Base, + Shop(Shop), + Attraction, + Town(TownDb), + Farm(FarmData), + Market(MarketDb), +} + +impl From for LocationDataDb { + fn from(t: LocationType) -> Self { + match t { + LocationType::Base => LocationDataDb::Base, + LocationType::Shop => LocationDataDb::Shop(Default::default()), + LocationType::Attraction => LocationDataDb::Attraction, + LocationType::Town => LocationDataDb::Town(Default::default()), + LocationType::Farm => LocationDataDb::Farm(Default::default()), + LocationType::Market => LocationDataDb::Market(Default::default()) + } + } +} + + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum LocationData { + Base, + Shop(Shop), + Attraction, + Town(Town), + Farm(FarmData), + Market(Market), +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LocationDb { id: Option, pub name: String, pub position: Position, owners: HashSet, pub tunnel: Option, - loc_type: LocationType, + pub loc_data: LocationDataDb, } -impl Location { +impl LocationDb { pub fn new( name: &str, position: Position, owner: u64, tunnel: Option, - loc_type: LocationType, + loc_type: LocationDataDb, ) -> Self { let mut owners = HashSet::new(); owners.insert(owner); @@ -46,7 +98,7 @@ impl Location { position, owners, tunnel, - loc_type, + loc_data: loc_type, } } @@ -63,7 +115,7 @@ impl Location { } } -impl GeoffreyDatabaseModel for Location { +impl GeoffreyDatabaseModel for LocationDb { fn id(&self) -> Option { self.id } @@ -81,44 +133,68 @@ impl GeoffreyDatabaseModel for Location { } } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Location { + pub id: u64, + pub name: String, + pub position: Position, + pub owners: Vec, + pub tunnel: Option, + pub loc_data: LocationData, +} + +impl Location { + pub fn from_db_location(location: LocationDb, owners: Vec, loc_data: LocationData) -> Self { + Self { + id: location.id.unwrap(), + name: location.name, + position: location.position, + owners, + tunnel: location.tunnel, + loc_data + } + } +} + + #[cfg(test)] mod tests { - use crate::models::locations::{Location, LocationType}; + use crate::models::locations::{LocationDb, LocationDataDb}; use crate::models::{Dimension, Position}; use crate::GeoffreyDatabaseModel; #[test] fn test_location_check_unique() { - let l1 = Location::new( + let l1 = LocationDb::new( "Test", Position::new(0, 0, Dimension::Overworld), 0u64, None, - LocationType::Base, + LocationDataDb::Base, ); - let l2 = Location::new( + let l2 = LocationDb::new( "NotTest", Position::new(0, 0, Dimension::Overworld), 0u64, None, - LocationType::Base, + LocationDataDb::Base, ); assert!(l1.check_unique(&l2)); - let l1 = Location::new( + let l1 = LocationDb::new( "Test", Position::new(0, 0, Dimension::Overworld), 0u64, None, - LocationType::Base, + LocationDataDb::Base, ); - let l2 = Location::new( + let l2 = LocationDb::new( "teSt", Position::new(0, 0, Dimension::Overworld), 0u64, None, - LocationType::Base, + LocationDataDb::Base, ); assert!(!l1.check_unique(&l2)); diff --git a/geoffrey_models/src/models/locations/shop.rs b/geoffrey_models/src/models/locations/shop.rs index a3e0dc9..76a790c 100644 --- a/geoffrey_models/src/models/locations/shop.rs +++ b/geoffrey_models/src/models/locations/shop.rs @@ -3,24 +3,8 @@ use std::collections::HashSet; use serde::{Deserialize, Serialize}; use crate::models::item::ItemListing; -use crate::GeoffreyDatabaseModel; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct Shop { - id: Option, pub item_listings: HashSet, } - -impl GeoffreyDatabaseModel for Shop { - fn id(&self) -> Option { - self.id - } - - fn set_id(&mut self, id: u64) { - self.id = Some(id); - } - - fn tree() -> String { - "shop".to_string() - } -} diff --git a/geoffrey_models/src/models/locations/town.rs b/geoffrey_models/src/models/locations/town.rs index 4413d56..5e55a1e 100644 --- a/geoffrey_models/src/models/locations/town.rs +++ b/geoffrey_models/src/models/locations/town.rs @@ -1,23 +1,13 @@ -use crate::GeoffreyDatabaseModel; use serde::{Deserialize, Serialize}; use std::collections::HashSet; +use crate::models::player::Player; #[derive(Serialize, Deserialize, Debug, Clone, Default)] -pub struct Town { - id: Option, +pub struct TownDb { pub residents: HashSet, } -impl GeoffreyDatabaseModel for Town { - fn id(&self) -> Option { - self.id - } - - fn set_id(&mut self, id: u64) { - self.id = Some(id) - } - - fn tree() -> String { - "town".to_string() - } +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct Town { + pub residents: Vec, } diff --git a/geoffrey_models/src/models/parameters/add_location_params.rs b/geoffrey_models/src/models/parameters/add_location_params.rs index f7b74d9..a24f98f 100644 --- a/geoffrey_models/src/models/parameters/add_location_params.rs +++ b/geoffrey_models/src/models/parameters/add_location_params.rs @@ -1,4 +1,4 @@ -use crate::models::locations::LocationType; +use crate::models::locations::{LocationType}; use crate::models::{Position, Tunnel}; use serde::{Deserialize, Serialize}; diff --git a/geoffrey_models/src/models/player.rs b/geoffrey_models/src/models/player.rs index d70b2ec..0606adc 100644 --- a/geoffrey_models/src/models/player.rs +++ b/geoffrey_models/src/models/player.rs @@ -57,19 +57,19 @@ impl GeoffreyDatabaseModel for Player { #[cfg(test)] mod tests { - use crate::models::player::Player; + use crate::models::player::{Player, UserID}; use crate::models::player::UserID::{DiscordUUID, MinecraftUUID}; use crate::GeoffreyDatabaseModel; #[test] fn test_player_check_unique() { - let p1 = Player::new("CoolTest123", DiscordUUID(0u64)); - let p2 = Player::new("NotCoolTest123", DiscordUUID(1u64)); + let p1 = Player::new("CoolTest123", UserID::DiscordUUID {discord_uuid: 0u64}); + let p2 = Player::new("NotCoolTest123", UserID::DiscordUUID {discord_uuid: 1u64}); assert!(p1.check_unique(&p2)); - let p1 = Player::new("CoolTest123", MinecraftUUID("0".to_string())); - let p2 = Player::new("NotCoolTest123", MinecraftUUID("0".to_string())); + let p1 = Player::new("CoolTest123", UserID::MinecraftUUID{mc_uuid: "0".to_string()}); + let p2 = Player::new("NotCoolTest123", UserID::MinecraftUUID{ mc_uuid: "0".to_string()}); assert!(!p1.check_unique(&p2)); }