flatpage/
store.rs

1use crate::{Error, FlatPage, Result};
2use serde::de::DeserializeOwned;
3use std::{collections::HashMap, fs, path::PathBuf};
4
5/// A store for [`FlatPageMeta`]
6#[derive(Debug)]
7pub struct FlatPageStore {
8    /// The folder containing flat pages
9    root: PathBuf,
10    /// Maps file stems to pages metadata
11    pub pages: HashMap<String, FlatPageMeta>,
12}
13
14/// Flat page metadata
15#[derive(Debug)]
16pub struct FlatPageMeta {
17    /// Page title
18    pub title: String,
19    /// Page description
20    pub description: Option<String>,
21}
22
23impl FlatPageStore {
24    /// Creates a store from the folder
25    pub fn read_dir(root: impl Into<PathBuf>) -> Result<Self> {
26        let root = root.into();
27        let mut pages = HashMap::new();
28        let md_ext = Some(std::ffi::OsStr::new("md"));
29        for entry in fs::read_dir(&root).map_err(|e| Error::ReadDir(e, root.clone()))? {
30            let entry = entry.map_err(Error::DirEntry)?;
31            let path = entry.path();
32            if !path.is_file() || path.extension() != md_ext {
33                continue;
34            }
35            let stem = match path.file_stem().and_then(|x| x.to_str()) {
36                Some(s) => s,
37                None => continue,
38            };
39            let page = match FlatPage::by_path(&path)? {
40                Some(p) => p,
41                None => continue,
42            };
43            pages.insert(stem.into(), page.into());
44        }
45        Ok(Self { root, pages })
46    }
47
48    /// Returns a page metadata by its url
49    pub fn meta_by_url(&self, url: &str) -> Option<&FlatPageMeta> {
50        let stem = Self::url_to_stem(url);
51        self.meta_by_stem(&stem)
52    }
53
54    /// Returns a page by its url
55    pub fn page_by_url<E: DeserializeOwned>(&self, url: &str) -> Result<Option<FlatPage<E>>> {
56        let stem = Self::url_to_stem(url);
57        self.page_by_stem(&stem)
58    }
59
60    /// Returns a page metadata by the file stem
61    pub fn meta_by_stem(&self, stem: &str) -> Option<&FlatPageMeta> {
62        self.pages.get(stem)
63    }
64
65    /// Returns a page by the file stem
66    pub fn page_by_stem<E: DeserializeOwned>(&self, stem: &str) -> Result<Option<FlatPage<E>>> {
67        if self.pages.contains_key(stem) {
68            let mut path = self.root.clone();
69            path.push(format!("{stem}.md"));
70            FlatPage::by_path(path)
71        } else {
72            Ok(None)
73        }
74    }
75
76    /// Converts url to file stem
77    fn url_to_stem(url: &str) -> String {
78        url.replace('/', "^")
79    }
80}
81
82impl From<FlatPage> for FlatPageMeta {
83    fn from(p: FlatPage) -> Self {
84        Self {
85            title: p.title,
86            description: p.description,
87        }
88    }
89}