use std::collections::HashSet;
use crate::models::{ArticleID, ArticleOrder, CategoryID, FeedID, Marked, OrderBy, Read, TagID};
use chrono::{DateTime, Utc};
use super::{CategoryMapping, FeedMapping};
#[derive(Clone, Debug, Default)]
pub struct ArticleFilter {
pub limit: Option<i64>,
pub offset: Option<i64>,
pub order: Option<ArticleOrder>,
pub order_by: Option<OrderBy>,
pub unread: Option<Read>,
pub marked: Option<Marked>,
pub feeds: Option<Vec<FeedID>>,
pub feed_blacklist: Option<Vec<FeedID>>,
pub categories: Option<Vec<CategoryID>>,
pub category_blacklist: Option<Vec<CategoryID>>,
pub tags: Option<Vec<TagID>>,
pub ids: Option<Vec<ArticleID>>,
pub newer_than: Option<DateTime<Utc>>,
pub older_than: Option<DateTime<Utc>>,
pub synced_before: Option<DateTime<Utc>>,
pub synced_after: Option<DateTime<Utc>>,
pub search_term: Option<String>,
}
impl ArticleFilter {
pub fn ids(article_ids: Vec<ArticleID>) -> Self {
Self {
ids: Some(article_ids),
..Self::default()
}
}
pub fn read_ids(article_ids: Vec<ArticleID>, read: Read) -> Self {
Self {
unread: Some(read),
ids: Some(article_ids),
..Self::default()
}
}
pub fn marked_ids(article_ids: Vec<ArticleID>, marked: Marked) -> Self {
Self {
marked: Some(marked),
ids: Some(article_ids),
..Self::default()
}
}
pub fn feed_unread(feed_id: &FeedID) -> Self {
Self {
unread: Some(Read::Unread),
feeds: Some([feed_id.clone()].into()),
..Self::default()
}
}
pub fn category_unread(category_id: &CategoryID) -> Self {
Self {
unread: Some(Read::Unread),
categories: Some([category_id.clone()].into()),
..Self::default()
}
}
pub fn tag_unread(tag_id: &TagID) -> Self {
Self {
unread: Some(Read::Unread),
tags: Some([tag_id.clone()].into()),
..Self::default()
}
}
pub fn all_unread() -> Self {
Self {
unread: Some(Read::Unread),
..Self::default()
}
}
pub fn all_marked() -> Self {
Self {
marked: Some(Marked::Marked),
..Self::default()
}
}
pub fn feeds_to_load(&self, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
let mut result = HashSet::new();
if let Some(feeds) = &self.feeds {
for feed_id in feeds {
result.insert(feed_id.clone());
}
}
if let Some(categories) = &self.categories {
for category_id in categories {
let feed_ids = Self::find_all_feeds(category_id, category_mappings, feed_mappings);
for feed_id in feed_ids {
result.insert(feed_id);
}
}
}
result
}
pub fn feeds_to_blacklist(&self, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
let mut result = HashSet::new();
if let Some(feed_blacklist) = &self.feed_blacklist {
for feed_id in feed_blacklist {
result.insert(feed_id.clone());
}
}
if let Some(category_blacklist) = &self.category_blacklist {
for category_id in category_blacklist {
let feed_ids = Self::find_all_feeds(category_id, category_mappings, feed_mappings);
for feed_id in feed_ids {
result.insert(feed_id);
}
}
}
result
}
fn find_all_feeds(category_id: &CategoryID, category_mappings: &Vec<CategoryMapping>, feed_mappings: &Vec<FeedMapping>) -> HashSet<FeedID> {
fn find_all_feeds_impl(
category_id: &CategoryID,
category_mappings: &Vec<CategoryMapping>,
feed_mappings: &Vec<FeedMapping>,
result: &mut HashSet<FeedID>,
) {
for mapping in feed_mappings {
if &mapping.category_id == category_id {
result.insert(mapping.feed_id.clone());
}
}
for mapping in category_mappings {
if &mapping.parent_id == category_id {
find_all_feeds_impl(&mapping.category_id, category_mappings, feed_mappings, result);
}
}
}
let mut result = HashSet::new();
find_all_feeds_impl(category_id, category_mappings, feed_mappings, &mut result);
result
}
}