Initial commit
This commit is contained in:
251
src/infrastructure/repository/inmem/books.rs
Normal file
251
src/infrastructure/repository/inmem/books.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use crate::domain::author::Author;
|
||||
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<String>,
|
||||
language: String,
|
||||
description: String,
|
||||
tags: Vec<String>,
|
||||
published_at: String,
|
||||
publisher: String,
|
||||
updated: String,
|
||||
}
|
||||
|
||||
impl From<book::Book> 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<book::Book> 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<Book>,
|
||||
authors: HashMap<Uuid, Author>,
|
||||
author_uniques: HashMap<String, Uuid>,
|
||||
}
|
||||
|
||||
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<book::Book, BookFilter> 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<I>(&mut self, items: I)
|
||||
where
|
||||
I: IntoIterator<Item = book::Book>,
|
||||
{
|
||||
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<book::Book> {
|
||||
let id_uuid: Uuid = id.parse().unwrap();
|
||||
|
||||
let mut book: Option<book::Book> = 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<dyn Iterator<Item = book::Book>> {
|
||||
let mut author_ids: Vec<String> = vec![];
|
||||
|
||||
if let Some(author) = f.author {
|
||||
if let Some(id) = author.id {
|
||||
author_ids.push(id);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if author_ids.is_empty() {
|
||||
return Box::new(std::iter::empty::<book::Book>())
|
||||
}
|
||||
|
||||
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::<Vec<book::Book>>();
|
||||
|
||||
for book in &mut res {
|
||||
self.populate_authors(book);
|
||||
}
|
||||
|
||||
Box::new(res.into_iter())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user