类型改为Result
This commit is contained in:
parent
52b8d0a235
commit
499bdfa9fc
|
@ -6,7 +6,9 @@ use crate::repo::pokemon::Repository;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Response{
|
struct Response{
|
||||||
message: String,
|
number: u16,
|
||||||
|
name: String,
|
||||||
|
types: Vec<String>,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Request {
|
struct Request {
|
||||||
|
@ -24,10 +26,19 @@ pub fn serve(repo: Arc<dyn Repository>, req: &rouille::Request) -> rouille::Resp
|
||||||
},
|
},
|
||||||
_ => return rouille::Response::from(Status::BadRequest),
|
_ => return rouille::Response::from(Status::BadRequest),
|
||||||
};
|
};
|
||||||
|
// rouille::Response::from(Status::InternalServerError)
|
||||||
match create_pokemon::execute(repo, req) {
|
match create_pokemon::execute(repo, req) {
|
||||||
create_pokemon::Response::Ok(number) => rouille::Response::json(&Response{message: number.to_string()}),
|
Ok(create_pokemon::Response {
|
||||||
create_pokemon::Response::BadRequest => rouille::Response::from(Status::BadRequest),
|
number,
|
||||||
create_pokemon::Response::Conflict => rouille::Response::from(Status::Conflict),
|
name,
|
||||||
create_pokemon::Response::Error => rouille::Response::from(Status::InternalServerError),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::domain::entity::{PokemonName, PokemonNumber, PokemonTypes};
|
use crate::domain::entity::{Pokemon, PokemonName, PokemonNumber, PokemonTypes};
|
||||||
use crate::repo::pokemon::{Insert, Repository};
|
use crate::repo::pokemon::{InsertError, Repository};
|
||||||
|
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub(crate) number: u16,
|
pub(crate) number: u16,
|
||||||
|
@ -8,14 +8,19 @@ pub struct Request {
|
||||||
pub(crate) types: Vec<String>,
|
pub(crate) types: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Response {
|
pub enum Error {
|
||||||
Ok(u16),
|
|
||||||
BadRequest,
|
BadRequest,
|
||||||
Conflict,
|
Conflict,
|
||||||
Error,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(repo: Arc<dyn Repository>, req: Request) -> Response {
|
pub struct Response {
|
||||||
|
pub number: u16,
|
||||||
|
pub name: String,
|
||||||
|
pub types: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(repo: Arc<dyn Repository>, req: Request) -> Result<Response, Error> {
|
||||||
println!("execute");
|
println!("execute");
|
||||||
match (
|
match (
|
||||||
PokemonNumber::try_from(req.number),
|
PokemonNumber::try_from(req.number),
|
||||||
|
@ -23,11 +28,19 @@ pub fn execute(repo: Arc<dyn Repository>, req: Request) -> Response {
|
||||||
PokemonTypes::try_from(req.types)
|
PokemonTypes::try_from(req.types)
|
||||||
) {
|
) {
|
||||||
(Ok(number), Ok(name), Ok(types)) => match repo.insert(number, name, types){
|
(Ok(number), Ok(name), Ok(types)) => match repo.insert(number, name, types){
|
||||||
Insert::Ok(num) => Response::Ok(u16::from(num)),
|
Ok(Pokemon {
|
||||||
Insert::Conflict => Response::Conflict,
|
number,
|
||||||
Insert::Error => Response::Error,
|
name,
|
||||||
|
types,
|
||||||
|
}) => Ok(Response{
|
||||||
|
number: u16::from(number),
|
||||||
|
name: String::from(name),
|
||||||
|
types: Vec::<String>::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::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[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 mut repo = Arc::new(InMemoryRepository::new());
|
||||||
let number = 25;
|
let number = 25;
|
||||||
let req = Request {
|
let req = Request {
|
||||||
|
@ -47,7 +60,27 @@ mod tests {
|
||||||
};
|
};
|
||||||
let res = execute(repo, req);
|
let res = execute(repo, req);
|
||||||
match res {
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,16 +88,20 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn it_should_return_a_bad_request_error_when_request_is_invalid() {
|
fn it_should_return_a_bad_request_error_when_request_is_invalid() {
|
||||||
let mut repo = Arc::new(InMemoryRepository::new());
|
let mut repo = Arc::new(InMemoryRepository::new());
|
||||||
let number = 25;
|
let num = 25;
|
||||||
let req = Request {
|
let req = Request {
|
||||||
number: number,
|
number: num,
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
types: vec!["Electric".to_string(), ],
|
types: vec!["Electric".to_string(), ],
|
||||||
};
|
};
|
||||||
let res = execute(repo, req);
|
let res = execute(repo, req);
|
||||||
match res {
|
match res {
|
||||||
Response::Ok(num) => assert_eq!(num, number),
|
Ok(Response{
|
||||||
Response::BadRequest => {},
|
number,
|
||||||
|
name,
|
||||||
|
types,
|
||||||
|
}) => assert_eq!(number, num),
|
||||||
|
Err(Error::BadRequest) => {},
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +120,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let res = execute(repo, req);
|
let res = execute(repo, req);
|
||||||
match res {
|
match res {
|
||||||
Response::Conflict => {},
|
Err(Error::Conflict) => {},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Pokemon {
|
pub struct Pokemon {
|
||||||
pub number: PokemonNumber,
|
pub number: PokemonNumber,
|
||||||
name: PokemonName,
|
pub name: PokemonName,
|
||||||
types: PokemonTypes,
|
pub types: PokemonTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pokemon {
|
impl Pokemon {
|
||||||
|
@ -36,7 +36,7 @@ impl From<PokemonNumber> for u16 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PokemonName(String);
|
pub struct PokemonName(String);
|
||||||
|
|
||||||
impl TryFrom<String> for PokemonName {
|
impl TryFrom<String> for PokemonName {
|
||||||
|
@ -51,7 +51,13 @@ impl TryFrom<String> for PokemonName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl From<PokemonName> for String {
|
||||||
|
fn from(value: PokemonName) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct PokemonTypes(Vec<PokemonType>);
|
pub struct PokemonTypes(Vec<PokemonType>);
|
||||||
|
|
||||||
impl TryFrom<Vec<String>> for PokemonTypes {
|
impl TryFrom<Vec<String>> for PokemonTypes {
|
||||||
|
@ -73,7 +79,26 @@ impl TryFrom<Vec<String>> for PokemonTypes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl From<PokemonTypes> for Vec<String> {
|
||||||
|
fn from(value: PokemonTypes) -> Self {
|
||||||
|
let mut ts = vec![];
|
||||||
|
for pt in value.0.into_iter() {
|
||||||
|
ts.push(String::from(pt));
|
||||||
|
}
|
||||||
|
ts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PokemonType> for String {
|
||||||
|
fn from(value: PokemonType) -> Self {
|
||||||
|
String::from(match value {
|
||||||
|
PokemonType::Electric => "Electric",
|
||||||
|
PokemonType::Fire => "Fire",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
enum PokemonType {
|
enum PokemonType {
|
||||||
Electric,
|
Electric,
|
||||||
Fire,
|
Fire,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Mutex;
|
||||||
use crate::domain::entity::{Pokemon, PokemonName, PokemonNumber, PokemonTypes};
|
use crate::domain::entity::{Pokemon, PokemonName, PokemonNumber, PokemonTypes};
|
||||||
|
|
||||||
pub trait Repository: Send + Sync {
|
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<Pokemon, InsertError>;
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InMemoryRepository {
|
pub struct InMemoryRepository {
|
||||||
|
@ -17,32 +17,38 @@ impl InMemoryRepository {
|
||||||
pokemons
|
pokemons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn with_error(self) -> Self {
|
||||||
|
Self {
|
||||||
|
error: true,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Insert {
|
pub enum InsertError {
|
||||||
Ok(PokemonNumber),
|
|
||||||
Conflict,
|
Conflict,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repository for InMemoryRepository {
|
impl Repository for InMemoryRepository {
|
||||||
fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Insert {
|
fn insert(&self, number: PokemonNumber, name: PokemonName, types: PokemonTypes) -> Result<Pokemon, InsertError> {
|
||||||
if self.error {
|
if self.error {
|
||||||
return Insert::Error;
|
return Err(InsertError::Error);
|
||||||
}
|
}
|
||||||
let mut lock = match self.pokemons.lock() {
|
let mut lock = match self.pokemons.lock() {
|
||||||
Ok(lock) => lock,
|
Ok(lock) => lock,
|
||||||
_ => return Insert::Error,
|
_ => return Err(InsertError::Error),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
println!("{number:?} {:?}", self.pokemons);
|
println!("{number:?} {:?}", self.pokemons);
|
||||||
if lock.iter().any(|pokemon| pokemon.number == number) {
|
if lock.iter().any(|pokemon| pokemon.number == number) {
|
||||||
return Insert::Conflict;
|
return Err(InsertError::Conflict);
|
||||||
}
|
}
|
||||||
let number_clone = number.clone();
|
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);
|
println!("{number:?} {:?}", self.pokemons);
|
||||||
Insert::Ok(number)
|
Ok(pokemon)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue