notedthat_core/search/
error.rs1use thiserror::Error;
2
3#[derive(Debug, Error)]
11pub enum SearchError {
12 #[error("invalid input: {message}")]
14 InvalidInput {
15 message: String,
17 },
18
19 #[error("knowledge base not found: {slug}")]
21 UnknownKb {
22 slug: String,
24 },
25
26 #[error("search backend unavailable: {message}")]
28 BackendUnavailable {
29 message: String,
31 },
32
33 #[error("internal error: {message}")]
35 Internal {
36 message: String,
38 },
39}
40
41impl SearchError {
42 pub fn invalid_input(message: impl Into<String>) -> Self {
44 Self::InvalidInput {
45 message: message.into(),
46 }
47 }
48
49 pub fn unknown_kb(slug: impl Into<String>) -> Self {
51 Self::UnknownKb { slug: slug.into() }
52 }
53
54 pub fn backend_unavailable(message: impl Into<String>) -> Self {
56 Self::BackendUnavailable {
57 message: message.into(),
58 }
59 }
60
61 pub fn internal(message: impl Into<String>) -> Self {
63 Self::Internal {
64 message: message.into(),
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::error::Error;
73
74 #[test]
75 fn invalid_input_display() {
76 let e = SearchError::invalid_input("query must not be empty");
77 assert!(e.to_string().contains("query must not be empty"));
78 }
79
80 #[test]
81 fn unknown_kb_display() {
82 let e = SearchError::unknown_kb("notes");
83 assert!(e.to_string().contains("notes"));
84 }
85
86 #[test]
87 fn backend_unavailable_display() {
88 let e = SearchError::backend_unavailable("connection refused");
89 assert!(e.to_string().contains("connection refused"));
90 }
91
92 #[test]
93 fn internal_display() {
94 let e = SearchError::internal("unexpected state");
95 assert!(e.to_string().contains("unexpected state"));
96 }
97
98 #[test]
99 fn maps_invalid_input_to_error_invalid_input() {
100 let e = SearchError::invalid_input("bad query");
101 let mapped: Error = e.into();
102 assert!(matches!(mapped, Error::InvalidInput { .. }));
103 }
104
105 #[test]
106 fn maps_unknown_kb_to_error_not_found() {
107 let e = SearchError::unknown_kb("my-kb");
108 let mapped: Error = e.into();
109 assert!(matches!(mapped, Error::NotFound { .. }));
110 }
111
112 #[test]
113 fn maps_backend_unavailable_to_error_storage() {
114 let e = SearchError::backend_unavailable("qdrant down");
115 let mapped: Error = e.into();
116 assert!(matches!(mapped, Error::Storage(_)));
118 }
119
120 #[test]
121 fn maps_internal_to_error_config() {
122 let e = SearchError::internal("unexpected state");
123 let mapped: Error = e.into();
124 assert!(matches!(mapped, Error::Config { .. }));
126 }
127
128 #[test]
129 fn send_sync_bounds() {
130 fn assert_send_sync<T: Send + Sync + std::error::Error>() {}
131 assert_send_sync::<SearchError>();
132 }
133}