From 499bdfa9fcdd96589fd8518ece84835852183e52 Mon Sep 17 00:00:00 2001 From: Jeremy Yin Date: Mon, 3 Jul 2023 20:59:03 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=94=B9=E4=B8=BAResult?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/create_pokemon.rs | 21 ++++++++--- src/domain/create_pokemon.rs | 71 +++++++++++++++++++++++++++--------- src/domain/entity.rs | 37 ++++++++++++++++--- src/repo/pokemon.rs | 26 ++++++++----- 4 files changed, 117 insertions(+), 38 deletions(-) diff --git a/src/api/create_pokemon.rs b/src/api/create_pokemon.rs index d8c7a10..006354d 100644 --- a/src/api/create_pokemon.rs +++ b/src/api/create_pokemon.rs @@ -6,7 +6,9 @@ use crate::repo::pokemon::Repository; #[derive(Serialize)] struct Response{ - message: String, + number: u16, + name: String, + types: Vec, } #[derive(Deserialize)] struct Request { @@ -24,10 +26,19 @@ pub fn serve(repo: Arc, req: &rouille::Request) -> rouille::Resp }, _ => return rouille::Response::from(Status::BadRequest), }; + // rouille::Response::from(Status::InternalServerError) match create_pokemon::execute(repo, req) { - create_pokemon::Response::Ok(number) => rouille::Response::json(&Response{message: number.to_string()}), - create_pokemon::Response::BadRequest => rouille::Response::from(Status::BadRequest), - create_pokemon::Response::Conflict => rouille::Response::from(Status::Conflict), - create_pokemon::Response::Error => rouille::Response::from(Status::InternalServerError), + Ok(create_pokemon::Response { + number, + name, + types, + }) => rouille::Response::json(&Response{ + number, + name, + types, + }), + Err(create_pokemon::Error::BadRequest) => rouille::Response::from(Status::BadRequest), + Err(create_pokemon::Error::Conflict) => rouille::Response::from(Status::Conflict), + Err(create_pokemon::Error::Unknown) => rouille::Response::from(Status::InternalServerError), } } \ No newline at end of file diff --git a/src/domain/create_pokemon.rs b/src/domain/create_pokemon.rs index 14840d1..720a114 100644 --- a/src/domain/create_pokemon.rs +++ b/src/domain/create_pokemon.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::domain::entity::{PokemonName, PokemonNumber, PokemonTypes}; -use crate::repo::pokemon::{Insert, Repository}; +use crate::domain::entity::{Pokemon, PokemonName, PokemonNumber, PokemonTypes}; +use crate::repo::pokemon::{InsertError, Repository}; pub struct Request { pub(crate) number: u16, @@ -8,14 +8,19 @@ pub struct Request { pub(crate) types: Vec, } -pub enum Response { - Ok(u16), +pub enum Error { BadRequest, Conflict, - Error, + Unknown, } -pub fn execute(repo: Arc, req: Request) -> Response { +pub struct Response { + pub number: u16, + pub name: String, + pub types: Vec, +} + +pub fn execute(repo: Arc, req: Request) -> Result { println!("execute"); match ( PokemonNumber::try_from(req.number), @@ -23,11 +28,19 @@ pub fn execute(repo: Arc, req: Request) -> Response { PokemonTypes::try_from(req.types) ) { (Ok(number), Ok(name), Ok(types)) => match repo.insert(number, name, types){ - Insert::Ok(num) => Response::Ok(u16::from(num)), - Insert::Conflict => Response::Conflict, - Insert::Error => Response::Error, + Ok(Pokemon { + number, + name, + types, + }) => Ok(Response{ + number: u16::from(number), + name: String::from(name), + types: Vec::::from(types), + }), + Err(InsertError::Conflict) => Err(Error::Conflict), + Err(InsertError::Error) => Err(Error::Unknown), }, - _ => Response::BadRequest, + _ => Err(Error::BadRequest), } } @@ -37,7 +50,7 @@ mod tests { use super::*; #[test] - fn it_should_return_the_pokemon_number_otherwise() { + fn it_should_return_an_unknown_error_when_an_unexpected_error_happens(){ let mut repo = Arc::new(InMemoryRepository::new()); let number = 25; let req = Request { @@ -47,7 +60,27 @@ mod tests { }; let res = execute(repo, req); match res { - Response::Ok(num) => assert_eq!(num, number), + Err(Error::Unknown) => {}, + _ => unreachable!(), + } + } + + #[test] + fn it_should_return_the_pokemon_number_otherwise() { + let repo = Arc::new(InMemoryRepository::new()); + let num = 25; + let req = Request { + number: num, + name: "Pikachu".to_string(), + types: vec!["Electric".to_string(), ], + }; + let res = execute(repo, req); + match res { + Ok(Response { + number, + name, + types, + }) => assert_eq!(number, num), _ => unreachable!(), } } @@ -55,16 +88,20 @@ mod tests { #[test] fn it_should_return_a_bad_request_error_when_request_is_invalid() { let mut repo = Arc::new(InMemoryRepository::new()); - let number = 25; + let num = 25; let req = Request { - number: number, + number: num, name: "".to_string(), types: vec!["Electric".to_string(), ], }; let res = execute(repo, req); match res { - Response::Ok(num) => assert_eq!(num, number), - Response::BadRequest => {}, + Ok(Response{ + number, + name, + types, + }) => assert_eq!(number, num), + Err(Error::BadRequest) => {}, _ => unreachable!() } } @@ -83,7 +120,7 @@ mod tests { }; let res = execute(repo, req); match res { - Response::Conflict => {}, + Err(Error::Conflict) => {}, _ => unreachable!(), } } diff --git a/src/domain/entity.rs b/src/domain/entity.rs index 814e527..ba851ee 100644 --- a/src/domain/entity.rs +++ b/src/domain/entity.rs @@ -1,8 +1,8 @@ -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Pokemon { pub number: PokemonNumber, - name: PokemonName, - types: PokemonTypes, + pub name: PokemonName, + pub types: PokemonTypes, } impl Pokemon { @@ -36,7 +36,7 @@ impl From for u16 { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PokemonName(String); impl TryFrom for PokemonName { @@ -51,7 +51,13 @@ impl TryFrom for PokemonName { } } -#[derive(Debug)] +impl From for String { + fn from(value: PokemonName) -> Self { + value.0 + } +} + +#[derive(Debug, Clone)] pub struct PokemonTypes(Vec); impl TryFrom> for PokemonTypes { @@ -73,7 +79,26 @@ impl TryFrom> for PokemonTypes { } } -#[derive(Debug)] +impl From for Vec { + fn from(value: PokemonTypes) -> Self { + let mut ts = vec![]; + for pt in value.0.into_iter() { + ts.push(String::from(pt)); + } + ts + } +} + +impl From for String { + fn from(value: PokemonType) -> Self { + String::from(match value { + PokemonType::Electric => "Electric", + PokemonType::Fire => "Fire", + }) + } +} + +#[derive(Debug, Clone)] enum PokemonType { Electric, Fire, diff --git a/src/repo/pokemon.rs b/src/repo/pokemon.rs index 50b5c99..0b5ae6a 100644 --- a/src/repo/pokemon.rs +++ b/src/repo/pokemon.rs @@ -2,7 +2,7 @@ use std::sync::Mutex; use crate::domain::entity::{Pokemon, PokemonName, PokemonNumber, PokemonTypes}; pub trait Repository: Send + Sync { - fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Insert; + fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Result; } #[derive(Debug)] pub struct InMemoryRepository { @@ -17,32 +17,38 @@ impl InMemoryRepository { pokemons } } + #[cfg(test)] + pub fn with_error(self) -> Self { + Self { + error: true, + ..self + } + } } -pub enum Insert { - Ok(PokemonNumber), +pub enum InsertError { Conflict, Error, } impl Repository for InMemoryRepository { - fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Insert { + fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Result { if self.error { - return Insert::Error; + return Err(InsertError::Error); } let mut lock = match self.pokemons.lock() { Ok(lock) => lock, - _ => return Insert::Error, + _ => return Err(InsertError::Error), }; - println!("{number:?} {:?}", self.pokemons); if lock.iter().any(|pokemon| pokemon.number == number) { - return Insert::Conflict; + return Err(InsertError::Conflict); } let number_clone = number.clone(); - lock.push(Pokemon::new(number_clone, name, types)); + let pokemon = Pokemon::new(number_clone, name, types); + lock.push(pokemon.clone()); println!("{number:?} {:?}", self.pokemons); - Insert::Ok(number) + Ok(pokemon) } } \ No newline at end of file