refac: add fetch one ingredient use case
This commit is contained in:
parent
1a7c1f099c
commit
f2d24e89db
|
@ -1,3 +1,4 @@
|
||||||
mod domain;
|
mod domain;
|
||||||
|
mod use_case;
|
||||||
|
|
||||||
pub use domain::Ingredient;
|
pub use domain::Ingredient;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::app_core::shared::{domain::Lang, lib::EntityId};
|
use crate::app_core::shared::lib::EntityId;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Ingredient {
|
pub struct Ingredient {
|
||||||
pub key: EntityId,
|
pub key: EntityId,
|
||||||
pub lang: Lang,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
mod fetch_one;
|
|
@ -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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::app_core::shared::{domain::Lang, lib::EntityId};
|
use crate::app_core::shared::lib::EntityId;
|
||||||
|
|
||||||
use super::RecipeIngredient;
|
use super::RecipeIngredient;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Recipe {
|
pub struct Recipe {
|
||||||
pub key: EntityId,
|
pub key: EntityId,
|
||||||
pub lang: Lang,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub instructions: Vec<String>,
|
pub instructions: Vec<String>,
|
||||||
pub ingredients: Vec<RecipeIngredient>,
|
pub ingredients: Vec<RecipeIngredient>,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
mod repo;
|
pub mod repo;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
mod ingredient;
|
mod ingredient;
|
||||||
mod recipe;
|
mod recipe;
|
||||||
|
|
||||||
|
pub use ingredient::IngredientRepoPort;
|
||||||
|
pub use recipe::RecipeRepoPort;
|
||||||
|
|
||||||
use crate::app_core::shared::lib::{Entity, EntityId};
|
use crate::app_core::shared::lib::{Entity, EntityId};
|
||||||
|
|
||||||
use shaku::Interface;
|
use shaku::Interface;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod domain;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod lib;
|
pub mod lib;
|
||||||
|
|
||||||
|
pub mod app;
|
||||||
|
pub mod domain;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod context;
|
||||||
|
mod lang;
|
||||||
|
|
||||||
|
pub use context::Context;
|
||||||
|
pub use lang::Lang;
|
|
@ -0,0 +1,9 @@
|
||||||
|
use shaku::Interface;
|
||||||
|
|
||||||
|
use super::lang::Lang;
|
||||||
|
|
||||||
|
pub trait Context: Interface {
|
||||||
|
fn lang(&self) -> &Lang {
|
||||||
|
&self.lang
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub enum Lang {
|
||||||
|
#[default]
|
||||||
|
Rus,
|
||||||
|
Eng,
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
mod lang;
|
|
||||||
|
|
||||||
pub use lang::Lang;
|
|
|
@ -1,11 +0,0 @@
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Lang {
|
|
||||||
Rus,
|
|
||||||
Eng,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Lang {
|
|
||||||
fn default() -> Self {
|
|
||||||
Lang::Rus
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate async_trait;
|
extern crate async_trait;
|
||||||
|
#[macro_use]
|
||||||
extern crate shaku;
|
extern crate shaku;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
Loading…
Reference in New Issue