term_guard/core/
validation_context.rs

1//! Validation context for passing runtime information to constraints.
2//!
3//! This module provides a context object that can be used to pass runtime
4//! information (like table names) to constraints during evaluation.
5
6use std::sync::Arc;
7
8/// Runtime context for validation operations.
9///
10/// This struct holds runtime information that constraints need during evaluation,
11/// such as the name of the table being validated. This allows constraints to
12/// work with any table name rather than being hardcoded to "data".
13#[derive(Debug, Clone)]
14pub struct ValidationContext {
15    /// The name of the table being validated
16    table_name: Arc<str>,
17}
18
19impl ValidationContext {
20    /// Creates a new validation context with the specified table name.
21    ///
22    /// # Arguments
23    ///
24    /// * `table_name` - The name of the table to validate
25    ///
26    /// # Examples
27    ///
28    /// ```rust
29    /// use term_guard::core::ValidationContext;
30    ///
31    /// let ctx = ValidationContext::new("customer_data");
32    /// assert_eq!(ctx.table_name(), "customer_data");
33    /// ```
34    pub fn new(table_name: impl Into<Arc<str>>) -> Self {
35        Self {
36            table_name: table_name.into(),
37        }
38    }
39
40    /// Creates a validation context for the default table name "data".
41    ///
42    /// This is provided for backward compatibility with existing code.
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// use term_guard::core::ValidationContext;
48    ///
49    /// let ctx = ValidationContext::with_default_table();
50    /// assert_eq!(ctx.table_name(), "data");
51    /// ```
52    pub fn with_default_table() -> Self {
53        Self::new("data")
54    }
55
56    /// Returns the name of the table being validated.
57    pub fn table_name(&self) -> &str {
58        &self.table_name
59    }
60}
61
62impl Default for ValidationContext {
63    fn default() -> Self {
64        Self::new("data")
65    }
66}
67
68// Thread-local storage for the current validation context.
69// This allows constraints to access the validation context without
70// requiring changes to the Constraint trait interface.
71tokio::task_local! {
72    pub static CURRENT_CONTEXT: ValidationContext;
73}
74
75/// Gets the current validation context.
76///
77/// Returns the default context if no context has been set.
78pub fn current_validation_context() -> ValidationContext {
79    CURRENT_CONTEXT
80        .try_with(|ctx| ctx.clone())
81        .unwrap_or_else(|_| ValidationContext::with_default_table())
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_validation_context_creation() {
90        let ctx = ValidationContext::new("test_table");
91        assert_eq!(ctx.table_name(), "test_table");
92    }
93
94    #[test]
95    fn test_validation_context_default() {
96        let ctx = ValidationContext::with_default_table();
97        assert_eq!(ctx.table_name(), "data");
98    }
99
100    #[tokio::test]
101    async fn test_task_local_context() {
102        // Default context
103        assert_eq!(current_validation_context().table_name(), "data");
104
105        // Set custom context using task local
106        let custom_ctx = ValidationContext::new("custom_table");
107        CURRENT_CONTEXT
108            .scope(custom_ctx, async {
109                assert_eq!(current_validation_context().table_name(), "custom_table");
110            })
111            .await;
112
113        // Back to default
114        assert_eq!(current_validation_context().table_name(), "data");
115    }
116
117    #[tokio::test]
118    async fn test_nested_contexts() {
119        let ctx1 = ValidationContext::new("table1");
120        let ctx2 = ValidationContext::new("table2");
121
122        CURRENT_CONTEXT
123            .scope(ctx1, async {
124                assert_eq!(current_validation_context().table_name(), "table1");
125
126                CURRENT_CONTEXT
127                    .scope(ctx2, async {
128                        assert_eq!(current_validation_context().table_name(), "table2");
129                    })
130                    .await;
131
132                assert_eq!(current_validation_context().table_name(), "table1");
133            })
134            .await;
135
136        assert_eq!(current_validation_context().table_name(), "data");
137    }
138}