1use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum EntityHydrationError {
8 #[error("EntityHydrationError - UninitializedFieldError: {0}")]
9 UninitializedFieldError(#[from] derive_builder::UninitializedFieldError),
10 #[error("EntityHydrationError - Deserialization: {0}")]
11 EventDeserialization(#[from] serde_json::Error),
12}
13
14#[derive(Error, Debug)]
15#[error("CursorDestructureError: couldn't turn {0} into {1}")]
16pub struct CursorDestructureError(&'static str, &'static str);
17
18impl From<(&'static str, &'static str)> for CursorDestructureError {
19 fn from((name, variant): (&'static str, &'static str)) -> Self {
20 Self(name, variant)
21 }
22}
23
24#[doc(hidden)]
25pub fn parse_constraint_detail_value(detail: Option<&str>) -> Option<String> {
32 let detail = detail?;
33 let start = detail.find("=(")? + 2;
34 let end = detail.rfind(") already")?;
35 if start <= end {
36 Some(detail[start..end].to_string())
37 } else {
38 None
39 }
40}
41
42#[doc(hidden)]
43pub struct NotFoundValue<'a, T: ?Sized>(pub &'a T);
46
47impl<T: std::fmt::Display + ?Sized> NotFoundValue<'_, T> {
48 pub fn to_not_found_value(&self) -> String {
49 self.0.to_string()
50 }
51}
52
53#[doc(hidden)]
54pub trait ToNotFoundValueFallback {
55 fn to_not_found_value(&self) -> String;
56}
57
58impl<T: std::fmt::Debug + ?Sized> ToNotFoundValueFallback for NotFoundValue<'_, T> {
59 fn to_not_found_value(&self) -> String {
60 format!("{:?}", self.0)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn parse_simple_uuid_value() {
70 let detail = Some("Key (id)=(550e8400-e29b-41d4-a716-446655440000) already exists.");
71 assert_eq!(
72 parse_constraint_detail_value(detail),
73 Some("550e8400-e29b-41d4-a716-446655440000".to_string())
74 );
75 }
76
77 #[test]
78 fn parse_string_value() {
79 let detail = Some("Key (email)=(user@example.com) already exists.");
80 assert_eq!(
81 parse_constraint_detail_value(detail),
82 Some("user@example.com".to_string())
83 );
84 }
85
86 #[test]
87 fn parse_composite_key_value() {
88 let detail = Some("Key (tenant_id, email)=(abc, user@example.com) already exists.");
89 assert_eq!(
90 parse_constraint_detail_value(detail),
91 Some("abc, user@example.com".to_string())
92 );
93 }
94
95 #[test]
96 fn parse_none_detail() {
97 assert_eq!(parse_constraint_detail_value(None), None);
98 }
99
100 #[test]
101 fn parse_unexpected_format() {
102 let detail = Some("something unexpected");
103 assert_eq!(parse_constraint_detail_value(detail), None);
104 }
105
106 #[test]
107 fn parse_value_containing_parentheses() {
108 let detail = Some("Key (name)=(foo (bar)) already exists.");
109 assert_eq!(
110 parse_constraint_detail_value(detail),
111 Some("foo (bar)".to_string())
112 );
113 }
114
115 #[test]
116 fn parse_empty_value() {
117 let detail = Some("Key (col)=() already exists.");
118 assert_eq!(parse_constraint_detail_value(detail), Some("".to_string()));
119 }
120
121 #[test]
122 fn not_found_value_uses_display_when_available() {
123 #[allow(unused_imports)]
124 use crate::ToNotFoundValueFallback;
125
126 let val = "hello";
128 assert_eq!(NotFoundValue(val).to_not_found_value(), "hello");
129
130 let num = 42;
132 assert_eq!(NotFoundValue(&num).to_not_found_value(), "42");
133 }
134
135 #[test]
136 fn not_found_value_falls_back_to_debug() {
137 use crate::ToNotFoundValueFallback;
138
139 #[derive(Debug)]
141 #[allow(dead_code)]
142 struct OnlyDebug(i32);
143
144 let val = OnlyDebug(7);
145 assert_eq!(NotFoundValue(&val).to_not_found_value(), "OnlyDebug(7)");
146 }
147}