use crate::domain::repository::{BookFilter, Repository}; use crate::domain::{author, book}; use std::collections::HashMap; use uuid::Uuid; #[derive(Clone)] struct Book { id: Uuid, title: String, author: Vec, language: String, description: String, tags: Vec, published_at: String, publisher: String, updated: String, } impl From for Book { fn from(book: book::Book) -> Self { Book { id: book.id, title: book.title, author: book.author.iter().map(|a| a.id.to_string()).collect(), language: book.language, description: book.description, tags: book.tags, published_at: book.published_at, publisher: book.publisher, updated: book.updated, } } } impl Into for Book { fn into(self) -> book::Book { book::Book { id: self.id, title: self.title, author: self .author .iter() .map(|a| { let mut na: author::Author = Default::default(); if let Ok(id) = Uuid::parse_str(a) { na.id = id; } na }) .collect(), language: self.language, description: self.description, tags: self.tags, published_at: self.published_at, publisher: self.publisher, updated: self.updated, } } } pub struct BookRepository { books: Vec, authors: HashMap, author_uniques: HashMap, } impl BookRepository { pub fn new() -> Self { BookRepository { books: vec![], authors: HashMap::new(), author_uniques: HashMap::new(), } } fn populate_authors(&self, book: &mut book::Book) { for a in &mut book.author { if let Some(stored) = self.authors.get(&a.id) { a.first_name = stored.first_name.clone(); a.last_name = stored.last_name.clone(); a.middle_name = stored.middle_name.clone(); } } } fn extract_authors(&mut self, item: &mut book::Book) { for a in item.author.iter_mut() { let uniq = a.uniq_id().to_string(); if let Some(&id) = self.author_uniques.get(&uniq) { a.id = id; } else { self.author_uniques.insert(uniq, a.id); } self.authors.insert(a.id, a.clone()); } } } impl Repository for BookRepository { fn add(&mut self, mut item: book::Book) { if self.get(item.id.to_string()).is_some() { return; } self.extract_authors(&mut item); self.books.push(item.into()); } fn bulk_add(&mut self, items: Vec) { items.into_iter().for_each(|item| { if self.get(item.id.to_string()).is_none() { self.add(item) } }); } fn remove(&mut self, item: book::Book) { self.books.retain(|book| book.id != item.id); } fn get(&self, id: String) -> Option { let id_uuid: Uuid = id.parse().unwrap(); let mut book: Option = self .books .iter() .cloned() .find(|x| x.id.eq(&id_uuid)) .and_then(|x| Some(x.into())); if book.is_none() { return None; } if let Some(book) = book.as_mut() { self.populate_authors(book); } book } fn update(&mut self, mut item: book::Book) { self.extract_authors(&mut item); for res in &mut self.books { if res.id == item.id { *res = item.into(); break; } } } fn filter(&self, f: BookFilter) -> Box> { let mut author_ids: Vec = vec![]; let mut use_author = false; if let Some(author) = f.author { if let Some(id) = author.id { author_ids.push(id); use_author = true; } if let Some(name) = author.name { for (id, author) in self.authors.iter() { if author.first_name.contains(&name) || (author.last_name.is_some() && author.clone().last_name.unwrap().contains(&name)) || (author.middle_name.is_some() && author.clone().middle_name.unwrap().contains(&name)) { author_ids.push(id.to_string()); use_author = true; } } } } if author_ids.is_empty() && use_author { return Box::new(std::iter::empty::()) } let mut res = self .books .iter() .filter(move |book| { // Фильтр по названию if let Some(ref search_title) = f.title { if !book.title.contains(search_title) { return false; } } // Фильтр по описанию if let Some(ref descr) = f.description { if !book.description.contains(descr) { return false; } } // Фильтр по языку if let Some(ref lang) = f.language { if !book.language.eq(lang) { return false; } } // Фильтр по тегам if let Some(ref tags) = f.tags { if !tags.iter().all(|tag| book.tags.contains(tag)) { return false; } } // Фильтр по издателю if let Some(ref publisher) = f.publisher { if !book.publisher.eq(publisher) { return false; } } // Фильтр по датам (пример, можно доработать) if let Some(ref published_at) = f.published_at { if book.published_at != *published_at { return false; } } if let Some(ref updated) = f.updated { if book.updated != *updated { return false; } } if !author_ids.is_empty() { if !book.author.iter().all(|x| author_ids.contains(x)) { return false; } } true }) .cloned() .map(Into::into) .collect::>(); for book in &mut res { self.populate_authors(book); } Box::new(res.into_iter()) } }