refac: add fetch one ingredient use case

This commit is contained in:
Dmitriy Pleshevskiy 2023-03-18 17:42:20 +03:00
parent 1a7c1f099c
commit f2d24e89db
Signed by: pleshevskiy
GPG Key ID: 79C4487B44403985
15 changed files with 142 additions and 20 deletions

View File

@ -1,3 +1,4 @@
mod domain;
mod use_case;
pub use domain::Ingredient;

View File

@ -1,9 +1,8 @@
use crate::app_core::shared::{domain::Lang, lib::EntityId};
use crate::app_core::shared::lib::EntityId;
#[derive(Debug, Clone)]
pub struct Ingredient {
pub key: EntityId,
pub lang: Lang,
pub name: String,
}

View File

@ -0,0 +1 @@
mod fetch_one;

View File

@ -0,0 +1,110 @@
use crate::app_core::{
components::ingredient::Ingredient,
port::repo::{FindOneError, IngredientRepoPort},
shared::lib::UseCase,
};
#[derive(Default, Debug)]
pub struct Request {
pub key: String,
}
type Response = Ingredient;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Ingredient not found")]
NotFound,
#[error("Unknown error")]
Unknown,
}
pub trait FetchOneIngredientUseCase: UseCase<Request, Response, Error> {}
#[derive(Provider)]
#[shaku(interface = FetchOneIngredientUseCase)]
pub struct FetchOneIngredient {
#[shaku(provide)]
ingredient_repo: Box<dyn IngredientRepoPort>,
}
#[async_trait]
impl UseCase<Request, Response, Error> for FetchOneIngredient {
async fn execute(&self, req: Request) -> Result<Response, Error> {
self.ingredient_repo
.find_one(&req.key)
.await
.map_err(|e| match e {
FindOneError::Unknown => Error::Unknown,
FindOneError::NotFound => Error::NotFound,
})
}
}
impl FetchOneIngredientUseCase for FetchOneIngredient {}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
domain::{Context, Lang},
repo::ingredient::InMemoryIngredientRepo,
};
#[test]
fn should_return_ingredient() {
let repo = InMemoryIngredientRepo::new();
let res = execute(&repo, &Context::default(), String::from("apple"));
match res {
Ok(apple) => {
assert_eq!(apple.key, String::from("apple"));
assert_eq!(apple.lang, Lang::Rus);
assert_eq!(apple.name, String::from("Яблоко"));
}
_ => unimplemented!(),
}
}
#[test]
fn should_return_ingredient_with_choosed_lang() {
let repo = InMemoryIngredientRepo::new();
let res = execute(&repo, &Context::eng(), String::from("apple"));
match res {
Ok(apple) => {
assert_eq!(apple.key, String::from("apple"));
assert_eq!(apple.lang, Lang::Eng);
assert_eq!(apple.name, String::from("Apple"));
}
_ => unimplemented!(),
}
}
#[test]
fn should_return_ingredient_with_fallback_lang() {
let repo = InMemoryIngredientRepo::new();
let res = execute(&repo, &Context::eng(), String::from("orange"));
match res {
Ok(orange) => {
assert_eq!(orange.key, String::from("orange"));
assert_eq!(orange.lang, Lang::Rus);
assert_eq!(orange.name, String::from("Апельсин"));
}
_ => unimplemented!(),
}
}
#[test]
fn should_throw_not_found_error() {
let repo = InMemoryIngredientRepo::new();
let res = execute(&repo, &Context::default(), String::from("wildberries"));
match res {
Err(ResponseError::NotFound) => {}
_ => unimplemented!(),
}
}
}

View File

@ -1,11 +1,10 @@
use crate::app_core::shared::{domain::Lang, lib::EntityId};
use crate::app_core::shared::lib::EntityId;
use super::RecipeIngredient;
#[derive(Debug, Clone)]
pub struct Recipe {
pub key: EntityId,
pub lang: Lang,
pub name: String,
pub instructions: Vec<String>,
pub ingredients: Vec<RecipeIngredient>,

View File

@ -1 +1 @@
mod repo;
pub mod repo;

View File

View File

@ -1,6 +1,9 @@
mod ingredient;
mod recipe;
pub use ingredient::IngredientRepoPort;
pub use recipe::RecipeRepoPort;
use crate::app_core::shared::lib::{Entity, EntityId};
use shaku::Interface;

View File

@ -1,3 +1,5 @@
pub mod domain;
#[macro_use]
pub mod lib;
pub mod app;
pub mod domain;

View File

@ -0,0 +1,5 @@
mod context;
mod lang;
pub use context::Context;
pub use lang::Lang;

View File

@ -0,0 +1,9 @@
use shaku::Interface;
use super::lang::Lang;
pub trait Context: Interface {
fn lang(&self) -> &Lang {
&self.lang
}
}

View File

@ -0,0 +1,6 @@
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub enum Lang {
#[default]
Rus,
Eng,
}

View File

@ -1,3 +0,0 @@
mod lang;
pub use lang::Lang;

View File

@ -1,11 +0,0 @@
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Lang {
Rus,
Eng,
}
impl Default for Lang {
fn default() -> Self {
Lang::Rus
}
}

View File

@ -3,6 +3,7 @@
#[macro_use]
extern crate async_trait;
#[macro_use]
extern crate shaku;
#[cfg(test)]
#[macro_use]