1use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
13pub struct ParseError {
14 pub file: PathBuf,
15 pub message: String,
16}
17
18#[derive(Error, Debug)]
19#[non_exhaustive]
20pub enum VaultdbError {
21 #[error("vault not found: no .obsidian/ directory in {0} or any parent")]
22 VaultNotFound(String),
23
24 #[error("folder not found: {0}")]
25 FolderNotFound(String),
26
27 #[error("no frontmatter in file: {0}")]
28 NoFrontmatter(String),
29
30 #[error("invalid frontmatter YAML in {file}: {reason}")]
31 InvalidFrontmatter { file: String, reason: String },
32
33 #[error("invalid where expression: {0}")]
34 InvalidWhereExpr(String),
35
36 #[error("type mismatch: field '{field}' is {actual}, cannot compare as {expected}")]
37 TypeMismatch {
38 field: String,
39 actual: String,
40 expected: String,
41 },
42
43 #[error("regex error in pattern '{pattern}': {reason}")]
44 RegexError { pattern: String, reason: String },
45
46 #[error("schema error: {0}")]
47 SchemaError(String),
48
49 #[error("operation refused: {reason}")]
50 SafetyRefused { reason: String },
51
52 #[error("internal error: {0}")]
58 Internal(String),
59
60 #[error(transparent)]
61 Io(#[from] std::io::Error),
62}
63
64pub type Result<T> = std::result::Result<T, VaultdbError>;
65
66#[cfg(test)]
67mod parse_error_tests {
68 use super::ParseError;
69 use std::path::PathBuf;
70
71 #[test]
72 fn parse_error_serializes() {
73 let err = ParseError {
74 file: PathBuf::from("foo.md"),
75 message: "bad yaml".into(),
76 };
77 let json = serde_json::to_string(&err).unwrap();
78 assert!(json.contains("foo.md"));
79 assert!(json.contains("bad yaml"));
80 }
81
82 #[test]
83 fn parse_error_round_trips() {
84 let err = ParseError {
85 file: PathBuf::from("notes/x.md"),
86 message: "oops".into(),
87 };
88 let json = serde_json::to_string(&err).unwrap();
89 let back: ParseError = serde_json::from_str(&json).unwrap();
90 assert_eq!(back.file, err.file);
91 assert_eq!(back.message, err.message);
92 }
93}