From e2ae40b685ae6e384f575bd5fb4d04ac591d1866 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Thu, 12 May 2022 00:16:25 +0300 Subject: [PATCH] api: add filtering by keys --- api/src/domain/ingredient/fetch_list.rs | 26 +++++++++++++++++++++++-- api/src/repo/ingredient.rs | 18 ++++++++++++++--- api/src/server.rs | 11 ++++++++++- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/api/src/domain/ingredient/fetch_list.rs b/api/src/domain/ingredient/fetch_list.rs index 860f889..2a9f1e8 100644 --- a/api/src/domain/ingredient/fetch_list.rs +++ b/api/src/domain/ingredient/fetch_list.rs @@ -1,13 +1,14 @@ use super::types; -use crate::repo::ingredient::{GetIngredientOpts, IngredientRepo}; +use crate::repo::ingredient::IngredientRepo; #[derive(Default, Debug)] pub struct RequestOpts { pub lang: Option, + pub keys: Option>, } pub fn execute(repo: &impl IngredientRepo, opts: RequestOpts) -> Vec { - repo.get_ingredients(GetIngredientOpts { lang: opts.lang }) + repo.get_ingredients(opts.into()) } #[cfg(test)] @@ -66,4 +67,25 @@ mod tests { _ => unimplemented!(), } } + + #[test] + fn should_return_filtered_by_keys() { + let repo = crate::repo::ingredient::InMemoryIngredientRepo::new(); + let res = execute( + &repo, + RequestOpts { + keys: Some(vec![String::from("apple")]), + ..RequestOpts::default() + }, + ); + + match res.as_slice() { + [apple] => { + assert_eq!(apple.key, String::from("apple")); + assert_eq!(apple.lang, Lang::Rus); + assert_eq!(apple.name, String::from("Яблоко")); + } + _ => unimplemented!(), + } + } } diff --git a/api/src/repo/ingredient.rs b/api/src/repo/ingredient.rs index acf391d..3c86ab4 100644 --- a/api/src/repo/ingredient.rs +++ b/api/src/repo/ingredient.rs @@ -1,8 +1,18 @@ -use crate::domain::ingredient::types; +use crate::domain::ingredient::{fetch_list, types}; #[derive(Default)] pub struct GetIngredientOpts { pub lang: Option, + pub keys: Option>, +} + +impl From for GetIngredientOpts { + fn from(app: fetch_list::RequestOpts) -> Self { + Self { + lang: app.lang, + keys: app.keys, + } + } } pub trait IngredientRepo { @@ -17,7 +27,8 @@ impl IngredientRepo for StaticIngredientRepo { db::INGREDIENTS .iter() .zip(langs) - .filter_map(|tup| TryFrom::try_from(tup).ok()) + .filter_map(|tup| types::Ingredient::try_from(tup).ok()) + .filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key)) .collect::>() } } @@ -72,7 +83,8 @@ impl IngredientRepo for InMemoryIngredientRepo { self.ingredients .iter() .zip(langs) - .filter_map(|tup| TryFrom::try_from(tup).ok()) + .filter_map(|tup| types::Ingredient::try_from(tup).ok()) + .filter(|ing| opts.keys.is_none() || opts.keys.as_ref().unwrap().contains(&ing.key)) .collect::>() } } diff --git a/api/src/server.rs b/api/src/server.rs index 8d4c168..363b5e4 100644 --- a/api/src/server.rs +++ b/api/src/server.rs @@ -47,6 +47,7 @@ pub fn start() { #[derive(Default, Debug)] struct FetchIngredientsOpts<'a> { lang: Option<&'a str>, + keys: Option>, } impl<'a> From> for FetchIngredientsOpts<'a> { @@ -56,6 +57,11 @@ impl<'a> From> for FetchIngredientsOpts<'a> { .fold(FetchIngredientsOpts::default(), |mut opts, p| { match p { ("lang", val) => opts.lang = Some(val), + ("key", val) => { + let mut keys = opts.keys.unwrap_or_default(); + keys.push(val); + opts.keys = Some(keys) + } _ => {} }; @@ -67,7 +73,10 @@ impl<'a> From> for FetchIngredientsOpts<'a> { impl From> for domain::ingredient::fetch_list::RequestOpts { fn from(rest: FetchIngredientsOpts) -> Self { let lang = rest.lang.and_then(|l| Lang::from_str(l).ok()); - Self { lang } + let keys = rest + .keys + .map(|keys| keys.into_iter().map(String::from).collect()); + Self { lang, keys } } }