Skip to main content

leptos_forms_rs/error/
context.rs

1//! Error context module - Error context and debugging information
2//!
3//! This module provides ErrorContext for collecting debugging information,
4//! context building methods, debugging information collection,
5//! and timestamp and metadata handling.
6
7use std::collections::HashMap;
8
9/// Error context for additional debugging information
10#[derive(Debug, Clone)]
11pub struct ErrorContext {
12    pub form_name: Option<String>,
13    pub field_name: Option<String>,
14    pub operation: Option<String>,
15    pub timestamp: Option<chrono::DateTime<chrono::Utc>>,
16    pub user_agent: Option<String>,
17    pub additional_data: HashMap<String, String>,
18}
19
20impl ErrorContext {
21    /// Create a new error context
22    pub fn new() -> Self {
23        Self {
24            form_name: None,
25            field_name: None,
26            operation: None,
27            timestamp: Some(chrono::Utc::now()),
28            user_agent: None,
29            additional_data: HashMap::new(),
30        }
31    }
32
33    /// Set the form name
34    pub fn with_form_name(mut self, form_name: impl Into<String>) -> Self {
35        self.form_name = Some(form_name.into());
36        self
37    }
38
39    /// Set the field name
40    pub fn with_field_name(mut self, field_name: impl Into<String>) -> Self {
41        self.field_name = Some(field_name.into());
42        self
43    }
44
45    /// Set the operation
46    pub fn with_operation(mut self, operation: impl Into<String>) -> Self {
47        self.operation = Some(operation.into());
48        self
49    }
50
51    /// Set the user agent
52    pub fn with_user_agent(mut self, user_agent: impl Into<String>) -> Self {
53        self.user_agent = Some(user_agent.into());
54        self
55    }
56
57    /// Add additional data
58    pub fn with_data(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
59        self.additional_data.insert(key.into(), value.into());
60        self
61    }
62
63    /// Get the form name
64    pub fn form_name(&self) -> Option<&str> {
65        self.form_name.as_deref()
66    }
67
68    /// Get the field name
69    pub fn field_name(&self) -> Option<&str> {
70        self.field_name.as_deref()
71    }
72
73    /// Get the operation
74    pub fn operation(&self) -> Option<&str> {
75        self.operation.as_deref()
76    }
77
78    /// Get the timestamp
79    pub fn timestamp(&self) -> Option<chrono::DateTime<chrono::Utc>> {
80        self.timestamp
81    }
82
83    /// Get the user agent
84    pub fn user_agent(&self) -> Option<&str> {
85        self.user_agent.as_deref()
86    }
87
88    /// Get additional data by key
89    pub fn get_data(&self, key: &str) -> Option<&String> {
90        self.additional_data.get(key)
91    }
92
93    /// Get all additional data
94    pub fn all_data(&self) -> &HashMap<String, String> {
95        &self.additional_data
96    }
97
98    /// Check if context has form name
99    pub fn has_form_name(&self) -> bool {
100        self.form_name.is_some()
101    }
102
103    /// Check if context has field name
104    pub fn has_field_name(&self) -> bool {
105        self.field_name.is_some()
106    }
107
108    /// Check if context has operation
109    pub fn has_operation(&self) -> bool {
110        self.operation.is_some()
111    }
112
113    /// Check if context has timestamp
114    pub fn has_timestamp(&self) -> bool {
115        self.timestamp.is_some()
116    }
117
118    /// Check if context has user agent
119    pub fn has_user_agent(&self) -> bool {
120        self.user_agent.is_some()
121    }
122
123    /// Check if context has additional data
124    pub fn has_additional_data(&self) -> bool {
125        !self.additional_data.is_empty()
126    }
127
128    /// Get the number of additional data entries
129    pub fn additional_data_count(&self) -> usize {
130        self.additional_data.len()
131    }
132
133    /// Clear all additional data
134    pub fn clear_additional_data(&mut self) {
135        self.additional_data.clear();
136    }
137
138    /// Remove a specific data entry
139    pub fn remove_data(&mut self, key: &str) -> Option<String> {
140        self.additional_data.remove(key)
141    }
142
143    /// Update timestamp to current time
144    pub fn update_timestamp(&mut self) {
145        self.timestamp = Some(chrono::Utc::now());
146    }
147
148    /// Create a context for a specific form
149    pub fn for_form(form_name: impl Into<String>) -> Self {
150        Self::new().with_form_name(form_name)
151    }
152
153    /// Create a context for a specific field
154    pub fn for_field(field_name: impl Into<String>) -> Self {
155        Self::new().with_field_name(field_name)
156    }
157
158    /// Create a context for a specific operation
159    pub fn for_operation(operation: impl Into<String>) -> Self {
160        Self::new().with_operation(operation)
161    }
162}
163
164impl Default for ErrorContext {
165    fn default() -> Self {
166        Self::new()
167    }
168}
169
170impl std::fmt::Display for ErrorContext {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(f, "ErrorContext(")?;
173
174        let mut parts = Vec::new();
175
176        if let Some(form_name) = &self.form_name {
177            parts.push(format!("form: {}", form_name));
178        }
179
180        if let Some(field_name) = &self.field_name {
181            parts.push(format!("field: {}", field_name));
182        }
183
184        if let Some(operation) = &self.operation {
185            parts.push(format!("operation: {}", operation));
186        }
187
188        if let Some(timestamp) = &self.timestamp {
189            parts.push(format!(
190                "timestamp: {}",
191                timestamp.format("%Y-%m-%d %H:%M:%S UTC")
192            ));
193        }
194
195        if let Some(user_agent) = &self.user_agent {
196            parts.push(format!("user_agent: {}", user_agent));
197        }
198
199        if !self.additional_data.is_empty() {
200            parts.push(format!("data: {} entries", self.additional_data.len()));
201        }
202
203        write!(f, "{}", parts.join(", "))?;
204        write!(f, ")")
205    }
206}