api: add filtering by keys

This commit is contained in:
Dmitriy Pleshevskiy 2022-05-12 00:16:25 +03:00
parent 8c367615a1
commit e2ae40b685
3 changed files with 49 additions and 6 deletions

View File

@ -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<types::Lang>,
pub keys: Option<Vec<String>>,
}
pub fn execute(repo: &impl IngredientRepo, opts: RequestOpts) -> Vec<types::Ingredient> {
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!(),
}
}
}

View File

@ -1,8 +1,18 @@
use crate::domain::ingredient::types;
use crate::domain::ingredient::{fetch_list, types};
#[derive(Default)]
pub struct GetIngredientOpts {
pub lang: Option<types::Lang>,
pub keys: Option<Vec<String>>,
}
impl From<fetch_list::RequestOpts> 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::<Vec<_>>()
}
}
@ -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::<Vec<_>>()
}
}

View File

@ -47,6 +47,7 @@ pub fn start() {
#[derive(Default, Debug)]
struct FetchIngredientsOpts<'a> {
lang: Option<&'a str>,
keys: Option<Vec<&'a str>>,
}
impl<'a> From<QueryParams<'a>> for FetchIngredientsOpts<'a> {
@ -56,6 +57,11 @@ impl<'a> From<QueryParams<'a>> 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<QueryParams<'a>> for FetchIngredientsOpts<'a> {
impl From<FetchIngredientsOpts<'_>> 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 }
}
}