cobalt/pagination/
tags.rs

1use std::collections::HashMap;
2
3use crate::cobalt_model::pagination::PaginationConfig;
4use crate::cobalt_model::slug;
5use crate::document::Document;
6
7use super::{Result, ValueView, all, helpers, paginator, sort_posts};
8use helpers::extract_tags;
9use paginator::Paginator;
10
11#[allow(clippy::bind_instead_of_map)]
12pub(crate) fn create_tags_paginators(
13    all_posts: &[&liquid::model::Value],
14    doc: &Document,
15    config: &PaginationConfig,
16) -> Result<Vec<Paginator>> {
17    let mut per_tags = distribute_posts_by_tags(all_posts)?;
18    walk_tags(&mut per_tags, config, doc)
19}
20
21fn distribute_posts_by_tags<'a>(
22    all_posts: &[&'a liquid::model::Value],
23) -> Result<HashMap<String, Vec<&'a liquid::model::Value>>> {
24    let mut per_tags: HashMap<String, Vec<&'a liquid::model::Value>> = HashMap::new();
25    for post in all_posts {
26        if let Some(tags) = extract_tags(post.as_view()) {
27            for tag in tags.values() {
28                let tag = tag
29                    .as_scalar()
30                    .ok_or_else(|| anyhow::format_err!("Should have string tags"))?
31                    .to_kstr()
32                    .into_string();
33                let cur_tag = per_tags.entry(tag).or_default();
34                cur_tag.push(post);
35            }
36        }
37    }
38    Ok(per_tags)
39}
40
41#[derive(Default, Debug)]
42struct TagPaginators {
43    firsts_of_tags: Vec<Paginator>,
44    paginators: Vec<Paginator>,
45}
46
47fn walk_tags(
48    per_tags: &mut HashMap<String, Vec<&liquid::model::Value>>,
49    config: &PaginationConfig,
50    doc: &Document,
51) -> Result<Vec<Paginator>> {
52    // create all other paginators
53    let mut tag_paginators = TagPaginators::default();
54    for (tag, posts) in per_tags.iter_mut() {
55        sort_posts(posts, config);
56        let cur_tag_paginators = all::create_all_paginators(
57            posts,
58            doc,
59            config,
60            Some(&liquid::model::Value::scalar(tag.to_owned())),
61        )?;
62        tag_paginators
63            .firsts_of_tags
64            .push(cur_tag_paginators[0].clone());
65        tag_paginators
66            .paginators
67            .extend(cur_tag_paginators.into_iter());
68    }
69
70    tag_paginators.firsts_of_tags.sort_unstable_by_key(|p| {
71        p.index_title
72            .as_ref()
73            .map(|index_title| slug::slugify(index_title.to_kstr()).to_lowercase())
74    });
75    let first = Paginator {
76        indexes: Some(tag_paginators.firsts_of_tags),
77        ..Default::default()
78    };
79    tag_paginators.paginators.insert(0, first);
80    Ok(tag_paginators.paginators)
81}