cosmetic changes
This commit is contained in:
parent
b9fdcb96d7
commit
d15faa1f65
|
@ -1,5 +1,4 @@
|
||||||
use super::types;
|
use crate::domain::{Context, Ingredient};
|
||||||
use crate::domain::misc_types::Context;
|
|
||||||
use crate::repo::ingredient::IngredientRepo;
|
use crate::repo::ingredient::IngredientRepo;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
@ -7,18 +6,15 @@ pub struct RequestOpts {
|
||||||
pub keys: Option<Vec<String>>,
|
pub keys: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(
|
pub fn execute(repo: &impl IngredientRepo, ctx: &Context, opts: RequestOpts) -> Vec<Ingredient> {
|
||||||
repo: &impl IngredientRepo,
|
|
||||||
ctx: &Context,
|
|
||||||
opts: RequestOpts,
|
|
||||||
) -> Vec<types::Ingredient> {
|
|
||||||
repo.get_ingredients(ctx, opts.into())
|
repo.get_ingredients(ctx, opts.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{domain::misc_types::Lang, repo::ingredient::InMemoryIngredientRepo};
|
use crate::domain::Lang;
|
||||||
|
use crate::repo::ingredient::InMemoryIngredientRepo;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_all_ingredients() {
|
fn should_return_all_ingredients() {
|
||||||
|
|
|
@ -6,25 +6,3 @@ pub struct Ingredient {
|
||||||
pub lang: Lang,
|
pub lang: Lang,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&db::data::Ingredient> for Ingredient {
|
|
||||||
fn from(db: &db::data::Ingredient) -> Self {
|
|
||||||
Self::from((db, Lang::Rus))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&db::data::Ingredient, Lang)> for Ingredient {
|
|
||||||
fn from((db, lang): (&db::data::Ingredient, Lang)) -> Self {
|
|
||||||
let tr = &db.translates;
|
|
||||||
let name = match lang {
|
|
||||||
Lang::Rus => tr.rus,
|
|
||||||
Lang::Eng => tr.eng.unwrap_or(tr.rus),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
key: db.key.to_string(),
|
|
||||||
lang: if name == tr.rus { Lang::Rus } else { lang },
|
|
||||||
name: name.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,4 +2,6 @@ pub mod ingredient;
|
||||||
pub mod misc_types;
|
pub mod misc_types;
|
||||||
pub mod recipe;
|
pub mod recipe;
|
||||||
|
|
||||||
|
pub use ingredient::types::Ingredient;
|
||||||
pub use misc_types::{Context, Lang};
|
pub use misc_types::{Context, Lang};
|
||||||
|
pub use recipe::types::{Measure, Recipe, RecipeIngredient};
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub fn execute(repo: &impl RecipeRepo, ctx: &Context) -> Vec<types::Recipe> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{recipe::types::RecipeIngredientMeasure, Lang},
|
domain::{Lang, Measure},
|
||||||
repo::recipe::InMemoryRecipeRepo,
|
repo::recipe::InMemoryRecipeRepo,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@ mod tests {
|
||||||
match salad.ingredients.as_slice() {
|
match salad.ingredients.as_slice() {
|
||||||
[banana, apple, orange] => {
|
[banana, apple, orange] => {
|
||||||
assert_eq!(banana.ingredient.key, "banana");
|
assert_eq!(banana.ingredient.key, "banana");
|
||||||
assert_eq!(banana.measure, RecipeIngredientMeasure::Gram(150));
|
assert_eq!(banana.measure, Measure::Gram(150));
|
||||||
assert_eq!(apple.ingredient.key, "apple");
|
assert_eq!(apple.ingredient.key, "apple");
|
||||||
assert_eq!(apple.measure, RecipeIngredientMeasure::Gram(150));
|
assert_eq!(apple.measure, Measure::Gram(150));
|
||||||
assert_eq!(orange.ingredient.key, "orange");
|
assert_eq!(orange.ingredient.key, "orange");
|
||||||
assert_eq!(orange.measure, RecipeIngredientMeasure::Gram(150));
|
assert_eq!(orange.measure, Measure::Gram(150));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,60 +9,17 @@ pub struct Recipe {
|
||||||
pub ingredients: Vec<RecipeIngredient>,
|
pub ingredients: Vec<RecipeIngredient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<(&db::data::Recipe, Lang, Vec<Ingredient>)> for Recipe {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(
|
|
||||||
(db, lang, ingredients): (&db::data::Recipe, Lang, Vec<Ingredient>),
|
|
||||||
) -> Result<Self, Self::Error> {
|
|
||||||
let tr = &db.translates;
|
|
||||||
let ctr = match lang {
|
|
||||||
Lang::Rus => &tr.rus,
|
|
||||||
Lang::Eng => tr.eng.as_ref().unwrap_or(&tr.rus),
|
|
||||||
};
|
|
||||||
|
|
||||||
let ingredients = db
|
|
||||||
.ingredients
|
|
||||||
.iter()
|
|
||||||
.map(|sing| {
|
|
||||||
ingredients
|
|
||||||
.iter()
|
|
||||||
.find(|ing| sing.key == ing.key)
|
|
||||||
.map(|ing| RecipeIngredient {
|
|
||||||
ingredient: ing.clone(),
|
|
||||||
measure: sing.measure.into(),
|
|
||||||
})
|
|
||||||
.ok_or(())
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
let instructions = ctr.instructions.iter().copied().map(String::from).collect();
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
key: db.key.to_string(),
|
|
||||||
lang: if ctr.name == tr.rus.name {
|
|
||||||
Lang::Rus
|
|
||||||
} else {
|
|
||||||
lang
|
|
||||||
},
|
|
||||||
name: ctr.name.to_string(),
|
|
||||||
instructions,
|
|
||||||
ingredients,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct RecipeIngredient {
|
pub struct RecipeIngredient {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub ingredient: Ingredient,
|
pub ingredient: Ingredient,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub measure: RecipeIngredientMeasure,
|
pub measure: Measure,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||||
#[serde(tag = "measure", content = "amount")]
|
#[serde(tag = "measure", content = "amount")]
|
||||||
pub enum RecipeIngredientMeasure {
|
pub enum Measure {
|
||||||
#[serde(rename = "g")]
|
#[serde(rename = "g")]
|
||||||
Gram(u32),
|
Gram(u32),
|
||||||
#[serde(rename = "kg")]
|
#[serde(rename = "kg")]
|
||||||
|
@ -72,17 +29,3 @@ pub enum RecipeIngredientMeasure {
|
||||||
#[serde(rename = "l")]
|
#[serde(rename = "l")]
|
||||||
Liter(u32),
|
Liter(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<db::data::RecipeIngredientMeasure> for RecipeIngredientMeasure {
|
|
||||||
fn from(db: db::data::RecipeIngredientMeasure) -> Self {
|
|
||||||
use db::data::RecipeIngredientMeasure as DbRIM;
|
|
||||||
use RecipeIngredientMeasure as RIM;
|
|
||||||
|
|
||||||
match db {
|
|
||||||
DbRIM::Gram(val) => RIM::Gram(val),
|
|
||||||
DbRIM::KiloGram(val) => RIM::KiloGram(val),
|
|
||||||
DbRIM::MilliLiter(val) => RIM::MilliLiter(val),
|
|
||||||
DbRIM::Liter(val) => RIM::Liter(val),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
use crate::domain::ingredient::{fetch_by_key, fetch_list, types};
|
use crate::domain::ingredient::fetch_list;
|
||||||
use crate::domain::misc_types::{self, Context};
|
use crate::domain::{Context, Ingredient, Lang};
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct GetIngredientOpts {
|
|
||||||
pub lang: Option<misc_types::Lang>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<fetch_by_key::RequestOpts> for GetIngredientOpts {
|
|
||||||
fn from(app: fetch_by_key::RequestOpts) -> Self {
|
|
||||||
Self { lang: app.lang }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GetIngredientsOpts {
|
pub struct GetIngredientsOpts {
|
||||||
|
@ -24,27 +13,27 @@ impl From<fetch_list::RequestOpts> for GetIngredientsOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IngredientRepo {
|
pub trait IngredientRepo {
|
||||||
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<types::Ingredient>;
|
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<Ingredient>;
|
||||||
|
|
||||||
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<types::Ingredient>;
|
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<Ingredient>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StaticIngredientRepo;
|
pub struct StaticIngredientRepo;
|
||||||
|
|
||||||
impl IngredientRepo for StaticIngredientRepo {
|
impl IngredientRepo for StaticIngredientRepo {
|
||||||
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<types::Ingredient> {
|
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<Ingredient> {
|
||||||
db::INGREDIENTS
|
db::data::INGREDIENTS
|
||||||
.iter()
|
.iter()
|
||||||
.find(|ing| ing.key == &key)
|
.find(|ing| ing.key == &key)
|
||||||
.map(|ing| types::Ingredient::from((ing, ctx.lang)))
|
.map(|ing| Ingredient::from((ing, ctx.lang)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<types::Ingredient> {
|
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<Ingredient> {
|
||||||
let langs = [ctx.lang].repeat(db::INGREDIENTS.len());
|
let langs = [ctx.lang].repeat(db::data::INGREDIENTS.len());
|
||||||
db::INGREDIENTS
|
db::data::INGREDIENTS
|
||||||
.iter()
|
.iter()
|
||||||
.zip(langs)
|
.zip(langs)
|
||||||
.map(types::Ingredient::from)
|
.map(Ingredient::from)
|
||||||
.filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key))
|
.filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
@ -52,7 +41,27 @@ impl IngredientRepo for StaticIngredientRepo {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub struct InMemoryIngredientRepo {
|
pub struct InMemoryIngredientRepo {
|
||||||
pub ingredients: Vec<db::data::Ingredient>,
|
pub ingredients: Vec<db::Ingredient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl IngredientRepo for InMemoryIngredientRepo {
|
||||||
|
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<Ingredient> {
|
||||||
|
self.ingredients
|
||||||
|
.iter()
|
||||||
|
.find(|ing| ing.key == &key)
|
||||||
|
.map(|ing| Ingredient::from((ing, ctx.lang)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<Ingredient> {
|
||||||
|
let langs = [ctx.lang].repeat(self.ingredients.len());
|
||||||
|
self.ingredients
|
||||||
|
.iter()
|
||||||
|
.zip(langs)
|
||||||
|
.map(Ingredient::from)
|
||||||
|
.filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -60,37 +69,37 @@ impl InMemoryIngredientRepo {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ingredients: vec![
|
ingredients: vec![
|
||||||
db::data::Ingredient {
|
db::Ingredient {
|
||||||
key: "banana",
|
key: "banana",
|
||||||
translates: db::data::IngredientTranslate {
|
translates: db::IngredientTranslate {
|
||||||
rus: "Банан",
|
rus: "Банан",
|
||||||
eng: Some("Banana"),
|
eng: Some("Banana"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db::data::Ingredient {
|
db::Ingredient {
|
||||||
key: "apple",
|
key: "apple",
|
||||||
translates: db::data::IngredientTranslate {
|
translates: db::IngredientTranslate {
|
||||||
rus: "Яблоко",
|
rus: "Яблоко",
|
||||||
eng: Some("Apple"),
|
eng: Some("Apple"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db::data::Ingredient {
|
db::Ingredient {
|
||||||
key: "orange",
|
key: "orange",
|
||||||
translates: db::data::IngredientTranslate {
|
translates: db::IngredientTranslate {
|
||||||
rus: "Апельсин",
|
rus: "Апельсин",
|
||||||
eng: None,
|
eng: None,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db::data::Ingredient {
|
db::Ingredient {
|
||||||
key: "salt",
|
key: "salt",
|
||||||
translates: db::data::IngredientTranslate {
|
translates: db::IngredientTranslate {
|
||||||
rus: "Соль",
|
rus: "Соль",
|
||||||
eng: Some("Salt"),
|
eng: Some("Salt"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db::data::Ingredient {
|
db::Ingredient {
|
||||||
key: "sugar",
|
key: "sugar",
|
||||||
translates: db::data::IngredientTranslate {
|
translates: db::IngredientTranslate {
|
||||||
rus: "Сахар",
|
rus: "Сахар",
|
||||||
eng: None,
|
eng: None,
|
||||||
},
|
},
|
||||||
|
@ -100,22 +109,18 @@ impl InMemoryIngredientRepo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl From<(&db::Ingredient, Lang)> for Ingredient {
|
||||||
impl IngredientRepo for InMemoryIngredientRepo {
|
fn from((db, lang): (&db::Ingredient, Lang)) -> Self {
|
||||||
fn get_ingredient_opt(&self, ctx: &Context, key: String) -> Option<types::Ingredient> {
|
let tr = &db.translates;
|
||||||
self.ingredients
|
let name = match lang {
|
||||||
.iter()
|
Lang::Rus => tr.rus,
|
||||||
.find(|ing| ing.key == &key)
|
Lang::Eng => tr.eng.unwrap_or(tr.rus),
|
||||||
.map(|ing| types::Ingredient::from((ing, ctx.lang)))
|
};
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ingredients(&self, ctx: &Context, opts: GetIngredientsOpts) -> Vec<types::Ingredient> {
|
Self {
|
||||||
let langs = [ctx.lang].repeat(self.ingredients.len());
|
key: db.key.to_string(),
|
||||||
self.ingredients
|
lang: if name == tr.rus { Lang::Rus } else { lang },
|
||||||
.iter()
|
name: name.to_string(),
|
||||||
.zip(langs)
|
}
|
||||||
.map(types::Ingredient::from)
|
|
||||||
.filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,68 @@
|
||||||
use crate::domain::{recipe::types, Context};
|
use crate::domain::{Context, Ingredient, Lang, Measure, Recipe, RecipeIngredient};
|
||||||
use crate::repo;
|
|
||||||
|
|
||||||
use super::ingredient::IngredientRepo;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use db::data as Db;
|
use crate::repo::ingredient::InMemoryIngredientRepo;
|
||||||
#[cfg(test)]
|
use crate::repo::ingredient::{IngredientRepo, StaticIngredientRepo};
|
||||||
use db::data::RecipeIngredientMeasure as DbRIM;
|
|
||||||
|
|
||||||
pub trait RecipeRepo {
|
pub trait RecipeRepo {
|
||||||
fn get_recipes(&self, ctx: &Context) -> Vec<types::Recipe>;
|
fn get_recipes(&self, ctx: &Context) -> Vec<Recipe>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StaticRecipeRepo;
|
pub struct StaticRecipeRepo;
|
||||||
|
|
||||||
impl RecipeRepo for StaticRecipeRepo {
|
impl RecipeRepo for StaticRecipeRepo {
|
||||||
fn get_recipes(&self, ctx: &Context) -> Vec<types::Recipe> {
|
fn get_recipes(&self, ctx: &Context) -> Vec<Recipe> {
|
||||||
let ings_repo = repo::ingredient::StaticIngredientRepo;
|
let ings_repo = StaticIngredientRepo;
|
||||||
let ings = ings_repo.get_ingredients(ctx, Default::default());
|
let ings = ings_repo.get_ingredients(ctx, Default::default());
|
||||||
|
|
||||||
let langs = [ctx.lang].repeat(db::RECIPES.len());
|
db::data::RECIPES
|
||||||
db::RECIPES
|
|
||||||
.iter()
|
.iter()
|
||||||
.zip(langs)
|
.filter_map(|rec| Recipe::try_from((rec, ctx.lang, ings.clone())).ok())
|
||||||
.filter_map(|(rec, lang)| types::Recipe::try_from((rec, lang, ings.clone())).ok())
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub struct InMemoryRecipeRepo {
|
pub struct InMemoryRecipeRepo {
|
||||||
pub recipes: Vec<db::data::Recipe>,
|
pub recipes: Vec<db::Recipe>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl RecipeRepo for InMemoryRecipeRepo {
|
||||||
|
fn get_recipes(&self, ctx: &Context) -> Vec<Recipe> {
|
||||||
|
let ings_repo = InMemoryIngredientRepo::new();
|
||||||
|
let ings = ings_repo.get_ingredients(ctx, Default::default());
|
||||||
|
|
||||||
|
self.recipes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|rec| Recipe::try_from((rec, ctx.lang, ings.clone())).ok())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl InMemoryRecipeRepo {
|
impl InMemoryRecipeRepo {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
recipes: vec![Db::Recipe {
|
recipes: vec![db::Recipe {
|
||||||
key: "fruit_salad",
|
key: "fruit_salad",
|
||||||
steps: 0,
|
steps: 0,
|
||||||
ingredients: vec![
|
ingredients: vec![
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "banana",
|
key: "banana",
|
||||||
measure: DbRIM::Gram(150),
|
measure: db::Measure::Gram(150),
|
||||||
},
|
},
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "apple",
|
key: "apple",
|
||||||
measure: DbRIM::Gram(150),
|
measure: db::Measure::Gram(150),
|
||||||
},
|
},
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "orange",
|
key: "orange",
|
||||||
measure: DbRIM::Gram(150),
|
measure: db::Measure::Gram(150),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
translates: Db::RecipeTranslates {
|
translates: db::RecipeTranslates {
|
||||||
rus: Db::RecipeTranslate {
|
rus: db::RecipeTranslate {
|
||||||
name: "Фруктовый салат",
|
name: "Фруктовый салат",
|
||||||
instructions: vec![
|
instructions: vec![
|
||||||
"Нарезать бананы кружочками",
|
"Нарезать бананы кружочками",
|
||||||
|
@ -70,25 +77,25 @@ impl InMemoryRecipeRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_no_ingredients_found(mut self) -> Self {
|
pub fn with_no_ingredients_found(mut self) -> Self {
|
||||||
self.recipes.push(Db::Recipe {
|
self.recipes.push(db::Recipe {
|
||||||
key: "no_ingredients_found",
|
key: "no_ingredients_found",
|
||||||
steps: 0,
|
steps: 0,
|
||||||
ingredients: vec![
|
ingredients: vec![
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "salt",
|
key: "salt",
|
||||||
measure: DbRIM::Gram(5),
|
measure: db::Measure::Gram(5),
|
||||||
},
|
},
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "sugar",
|
key: "sugar",
|
||||||
measure: DbRIM::Gram(4),
|
measure: db::Measure::Gram(4),
|
||||||
},
|
},
|
||||||
Db::RecipeIngredient {
|
db::RecipeIngredient {
|
||||||
key: "wheat_flour",
|
key: "wheat_flour",
|
||||||
measure: DbRIM::Gram(500),
|
measure: db::Measure::Gram(500),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
translates: Db::RecipeTranslates {
|
translates: db::RecipeTranslates {
|
||||||
rus: Db::RecipeTranslate {
|
rus: db::RecipeTranslate {
|
||||||
name: "Не найдены ингредиенты",
|
name: "Не найдены ингредиенты",
|
||||||
instructions: vec![],
|
instructions: vec![],
|
||||||
},
|
},
|
||||||
|
@ -99,17 +106,56 @@ impl InMemoryRecipeRepo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl TryFrom<(&db::Recipe, Lang, Vec<Ingredient>)> for Recipe {
|
||||||
impl RecipeRepo for InMemoryRecipeRepo {
|
type Error = ();
|
||||||
fn get_recipes(&self, ctx: &Context) -> Vec<types::Recipe> {
|
|
||||||
let ings_repo = repo::ingredient::InMemoryIngredientRepo::new();
|
|
||||||
let ings = ings_repo.get_ingredients(ctx, Default::default());
|
|
||||||
|
|
||||||
let langs = [ctx.lang].repeat(self.recipes.len());
|
fn try_from(
|
||||||
self.recipes
|
(db, lang, ingredients): (&db::Recipe, Lang, Vec<Ingredient>),
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let tr = &db.translates;
|
||||||
|
let ctr = match lang {
|
||||||
|
Lang::Rus => &tr.rus,
|
||||||
|
Lang::Eng => tr.eng.as_ref().unwrap_or(&tr.rus),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ingredients = db
|
||||||
|
.ingredients
|
||||||
.iter()
|
.iter()
|
||||||
.zip(langs)
|
.map(|sing| {
|
||||||
.filter_map(|(rec, lang)| types::Recipe::try_from((rec, lang, ings.clone())).ok())
|
ingredients
|
||||||
.collect()
|
.iter()
|
||||||
|
.find(|ing| sing.key == ing.key)
|
||||||
|
.map(|ing| RecipeIngredient {
|
||||||
|
ingredient: ing.clone(),
|
||||||
|
measure: sing.measure.into(),
|
||||||
|
})
|
||||||
|
.ok_or(())
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let instructions = ctr.instructions.iter().copied().map(String::from).collect();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
key: db.key.to_string(),
|
||||||
|
lang: if ctr.name == tr.rus.name {
|
||||||
|
Lang::Rus
|
||||||
|
} else {
|
||||||
|
lang
|
||||||
|
},
|
||||||
|
name: ctr.name.to_string(),
|
||||||
|
instructions,
|
||||||
|
ingredients,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<db::Measure> for Measure {
|
||||||
|
fn from(db: db::Measure) -> Self {
|
||||||
|
match db {
|
||||||
|
db::Measure::Gram(val) => Measure::Gram(val),
|
||||||
|
db::Measure::KiloGram(val) => Measure::KiloGram(val),
|
||||||
|
db::Measure::MilliLiter(val) => Measure::MilliLiter(val),
|
||||||
|
db::Measure::Liter(val) => Measure::Liter(val),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
db/build.rs
63
db/build.rs
|
@ -14,7 +14,8 @@ fn main() {
|
||||||
fn gen_data_mod() -> Result<(), std::io::Error> {
|
fn gen_data_mod() -> Result<(), std::io::Error> {
|
||||||
let file = fs::File::create("src/data.rs")?;
|
let file = fs::File::create("src/data.rs")?;
|
||||||
let mut buf = BufWriter::new(file);
|
let mut buf = BufWriter::new(file);
|
||||||
write_structs(&mut buf)?;
|
|
||||||
|
writeln!(buf, "use crate::types::*;\n")?;
|
||||||
println!("cargo:rerun-if-changed=data/ingredients/*.toml");
|
println!("cargo:rerun-if-changed=data/ingredients/*.toml");
|
||||||
write_ingredients(&mut buf)?;
|
write_ingredients(&mut buf)?;
|
||||||
println!("cargo:rerun-if-changed=data/recipes/*.toml");
|
println!("cargo:rerun-if-changed=data/recipes/*.toml");
|
||||||
|
@ -22,61 +23,6 @@ fn gen_data_mod() -> Result<(), std::io::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_structs(file: &mut BufWriter<fs::File>) -> Result<(), std::io::Error> {
|
|
||||||
let structs = r#"#![allow(dead_code)]
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Ingredient {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub translates: IngredientTranslate,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IngredientTranslate {
|
|
||||||
pub rus: &'static str,
|
|
||||||
pub eng: Option<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Recipe {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub steps: u8,
|
|
||||||
pub ingredients: Vec<RecipeIngredient>,
|
|
||||||
pub translates: RecipeTranslates,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeIngredient {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub measure: RecipeIngredientMeasure,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum RecipeIngredientMeasure {
|
|
||||||
Gram(u32),
|
|
||||||
KiloGram(u32),
|
|
||||||
MilliLiter(u32),
|
|
||||||
Liter(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeTranslates {
|
|
||||||
pub rus: RecipeTranslate,
|
|
||||||
pub eng: Option<RecipeTranslate>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeTranslate {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub instructions: Vec<&'static str>,
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
writeln!(file, "{}", structs)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Main {
|
pub struct Main {
|
||||||
ingredients: Option<Vec<Ingredient>>,
|
ingredients: Option<Vec<Ingredient>>,
|
||||||
|
@ -127,10 +73,7 @@ impl fmt::Debug for RecipeIngredient {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("RecipeIngredient")
|
f.debug_struct("RecipeIngredient")
|
||||||
.field("key", &self.key)
|
.field("key", &self.key)
|
||||||
.field(
|
.field("measure", &format_args!("Measure::{:?}", self.measure))
|
||||||
"measure",
|
|
||||||
&format_args!("RecipeIngredientMeasure::{:?}", self.measure),
|
|
||||||
)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,4 @@
|
||||||
#![allow(dead_code)]
|
use crate::types::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Ingredient {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub translates: IngredientTranslate,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IngredientTranslate {
|
|
||||||
pub rus: &'static str,
|
|
||||||
pub eng: Option<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Recipe {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub steps: u8,
|
|
||||||
pub ingredients: Vec<RecipeIngredient>,
|
|
||||||
pub translates: RecipeTranslates,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeIngredient {
|
|
||||||
pub key: &'static str,
|
|
||||||
pub measure: RecipeIngredientMeasure,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum RecipeIngredientMeasure {
|
|
||||||
Gram(u32),
|
|
||||||
KiloGram(u32),
|
|
||||||
MilliLiter(u32),
|
|
||||||
Liter(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeTranslates {
|
|
||||||
pub rus: RecipeTranslate,
|
|
||||||
pub eng: Option<RecipeTranslate>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecipeTranslate {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub instructions: Vec<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const INGREDIENTS: [Ingredient; 11] = [
|
pub const INGREDIENTS: [Ingredient; 11] = [
|
||||||
Ingredient {
|
Ingredient {
|
||||||
|
@ -156,27 +110,27 @@ pub static ref RECIPES: [Recipe; 1] = [
|
||||||
ingredients: vec![
|
ingredients: vec![
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "salt",
|
key: "salt",
|
||||||
measure: RecipeIngredientMeasure::Gram(5),
|
measure: Measure::Gram(5),
|
||||||
},
|
},
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "sugar",
|
key: "sugar",
|
||||||
measure: RecipeIngredientMeasure::Gram(4),
|
measure: Measure::Gram(4),
|
||||||
},
|
},
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "wheat_flour",
|
key: "wheat_flour",
|
||||||
measure: RecipeIngredientMeasure::Gram(500),
|
measure: Measure::Gram(500),
|
||||||
},
|
},
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "dry_yeast",
|
key: "dry_yeast",
|
||||||
measure: RecipeIngredientMeasure::Gram(7),
|
measure: Measure::Gram(7),
|
||||||
},
|
},
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "olive_oil",
|
key: "olive_oil",
|
||||||
measure: RecipeIngredientMeasure::MilliLiter(25),
|
measure: Measure::MilliLiter(25),
|
||||||
},
|
},
|
||||||
RecipeIngredient {
|
RecipeIngredient {
|
||||||
key: "water",
|
key: "water",
|
||||||
measure: RecipeIngredientMeasure::MilliLiter(250),
|
measure: Measure::MilliLiter(250),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
translates: RecipeTranslates {
|
translates: RecipeTranslates {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
pub use data::{INGREDIENTS, RECIPES};
|
pub use types::*;
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Ingredient {
|
||||||
|
pub key: &'static str,
|
||||||
|
pub translates: IngredientTranslate,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IngredientTranslate {
|
||||||
|
pub rus: &'static str,
|
||||||
|
pub eng: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Recipe {
|
||||||
|
pub key: &'static str,
|
||||||
|
pub steps: u8,
|
||||||
|
pub ingredients: Vec<RecipeIngredient>,
|
||||||
|
pub translates: RecipeTranslates,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RecipeIngredient {
|
||||||
|
pub key: &'static str,
|
||||||
|
pub measure: Measure,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Measure {
|
||||||
|
Gram(u32),
|
||||||
|
KiloGram(u32),
|
||||||
|
MilliLiter(u32),
|
||||||
|
Liter(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RecipeTranslates {
|
||||||
|
pub rus: RecipeTranslate,
|
||||||
|
pub eng: Option<RecipeTranslate>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RecipeTranslate {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub instructions: Vec<&'static str>,
|
||||||
|
}
|
Loading…
Reference in New Issue