basalt_core/obsidian/
vault.rs

1use std::{path::PathBuf, result};
2
3use serde::{Deserialize, Deserializer};
4
5use super::vault_entry::VaultEntry;
6
7/// Represents a single Obsidian vault.
8///
9/// A vault is a folder containing notes and other metadata.
10#[derive(Debug, Clone, Default, PartialEq)]
11pub struct Vault {
12    /// The name of the vault, inferred from its directory name.
13    pub name: String,
14
15    /// Filesystem path to the vault's directory.
16    pub path: PathBuf,
17
18    /// Whether the vault is marked 'open' by Obsidian.
19    pub open: bool,
20
21    /// Timestamp of last update or creation.
22    pub ts: u64,
23}
24
25impl Vault {
26    /// Returns a [`Vec`] of Markdown vault entries in this vault as [`VaultEntry`] structs.
27    /// Entries can be either directories or files (notes). If the directory is marked hidden with
28    /// a dot (`.`) prefix it will be filtered out from the resulting [`Vec`].
29    ///
30    /// The returned entries are not sorted.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use basalt_core::obsidian::{Vault, Note};
36    ///
37    /// let vault = Vault {
38    ///     name: "MyVault".into(),
39    ///     path: "path/to/my_vault".into(),
40    ///     ..Default::default()
41    /// };
42    ///
43    /// assert_eq!(vault.entries(), vec![]);
44    /// ```
45    pub fn entries(&self) -> Vec<VaultEntry> {
46        match self.path.as_path().try_into() {
47            Ok(VaultEntry::Directory { entries, .. }) => entries
48                .into_iter()
49                .filter(|entry| !entry.name().starts_with('.'))
50                .collect(),
51            _ => vec![],
52        }
53    }
54}
55
56impl<'de> Deserialize<'de> for Vault {
57    fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
58    where
59        D: Deserializer<'de>,
60    {
61        #[derive(Deserialize)]
62        struct Json {
63            path: PathBuf,
64            open: Option<bool>,
65            ts: u64,
66        }
67
68        impl TryFrom<Json> for Vault {
69            type Error = String;
70            fn try_from(Json { path, open, ts }: Json) -> result::Result<Self, Self::Error> {
71                let name = path
72                    .file_name()
73                    .map(|file_name| file_name.to_string_lossy().to_string())
74                    .ok_or("unable to retrieve vault name")?;
75
76                Ok(Vault {
77                    name,
78                    path,
79                    open: open.unwrap_or(false),
80                    ts,
81                })
82            }
83        }
84
85        let deserialized: Json = Deserialize::deserialize(deserializer)?;
86        deserialized.try_into().map_err(serde::de::Error::custom)
87    }
88}