1use notedthat_core::{Error as CoreError, StorageError};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum WriteEffect {
8 Stored,
10 Deleted,
12}
13
14impl std::fmt::Display for WriteEffect {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.write_str(match self {
17 Self::Stored => "stored",
18 Self::Deleted => "deleted",
19 })
20 }
21}
22
23#[derive(Debug, thiserror::Error)]
25pub enum WriteError {
26 #[error(transparent)]
28 Storage(StorageError),
29 #[error("payload too large: {size} bytes (limit {limit})")]
31 TooLarge {
32 size: u64,
34 limit: u64,
36 },
37 #[error(transparent)]
39 Path(CoreError),
40 #[error("indexer queue full during upsert")]
42 IndexerBackpressureUpsert,
43 #[error("indexer queue full during tombstone")]
45 IndexerBackpressureTombstone,
46 #[error("change event not published after the object was {after}")]
51 EventPublishFailed {
52 after: WriteEffect,
54 },
55 #[error("patch payload too large: {size} bytes (limit {limit})")]
57 PatchTooLarge {
58 size: u64,
60 limit: u64,
62 },
63 #[error("line range {first}..{last} out of range (total {total_lines} lines)")]
65 PatchLineOutOfRange {
66 first: u64,
68 last: u64,
70 total_lines: u64,
72 total_bytes: u64,
74 },
75 #[error("invalid patch request: {message}")]
77 PatchInvalidRange {
78 message: String,
80 },
81 #[error("replace: no match found for old_string")]
83 ReplaceNoMatch,
84 #[error("replace: found {count} matches; use replace_all to replace them all")]
86 ReplaceAmbiguous {
87 count: u64,
89 },
90}
91
92impl From<StorageError> for WriteError {
93 fn from(err: StorageError) -> Self {
94 Self::Storage(err)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::WriteError;
101
102 #[test]
103 fn patch_too_large_displays_size_limit_when_constructed() {
104 let err = WriteError::PatchTooLarge {
105 size: 200 * 1024 * 1024,
106 limit: 100 * 1024 * 1024,
107 };
108
109 assert!(err.to_string().contains("too large"));
110 }
111
112 #[test]
113 fn patch_line_out_of_range_constructs_with_line_and_byte_totals() {
114 let err = WriteError::PatchLineOutOfRange {
115 first: 999,
116 last: 1000,
117 total_lines: 20,
118 total_bytes: 100,
119 };
120
121 assert!(err.to_string().contains("out of range"));
122 }
123
124 #[test]
125 fn patch_invalid_range_displays_reason_when_constructed() {
126 let err = WriteError::PatchInvalidRange {
127 message: "test".into(),
128 };
129
130 assert!(err.to_string().contains("invalid patch"));
131 }
132
133 #[test]
134 fn replace_ambiguous_displays_match_count_when_constructed() {
135 let err = WriteError::ReplaceAmbiguous { count: 3 };
136
137 assert_eq!(
138 err.to_string(),
139 "replace: found 3 matches; use replace_all to replace them all"
140 );
141 }
142}