condition_matcher/
builder.rs

1//! Builder pattern for creating matchers.
2
3use crate::{
4    condition::{Condition, ConditionMode, ConditionOperator, ConditionSelector},
5    matchable::Matchable,
6    matchers::RuleMatcher,
7};
8use std::any::Any;
9
10// ============================================================================
11// Builder API
12// ============================================================================
13
14/// A builder for creating matchers with a fluent API
15///
16/// ## Example
17///
18/// ```rust
19/// use condition_matcher::{MatcherBuilder, MatcherMode, ConditionOperator, Matcher};
20///
21/// let matcher = MatcherBuilder::<i32>::new()
22///     .mode(MatcherMode::AND)
23///     .value_equals(42)
24///     .build();
25///
26/// assert!(matcher.matches(&42));
27/// ```
28pub struct MatcherBuilder<'a, T: Matchable> {
29    mode: ConditionMode,
30    conditions: Vec<Condition<'a, T>>,
31}
32
33impl<'a, T: Matchable + 'static> MatcherBuilder<'a, T> {
34    /// Create a new builder with default AND mode
35    pub fn new() -> Self {
36        Self {
37            mode: ConditionMode::AND,
38            conditions: Vec::new(),
39        }
40    }
41
42    /// Set the matching mode
43    pub fn mode(mut self, mode: ConditionMode) -> Self {
44        self.mode = mode;
45        self
46    }
47
48    /// Add a condition that the value equals the expected value
49    pub fn value_equals(mut self, expected: T) -> Self {
50        self.conditions.push(Condition {
51            selector: ConditionSelector::Value(expected),
52            operator: ConditionOperator::Equals,
53        });
54        self
55    }
56
57    /// Add a condition that the value does not equal the expected value
58    pub fn value_not_equals(mut self, expected: T) -> Self {
59        self.conditions.push(Condition {
60            selector: ConditionSelector::Value(expected),
61            operator: ConditionOperator::NotEquals,
62        });
63        self
64    }
65
66    /// Add a length condition
67    pub fn length(mut self, len: usize, operator: ConditionOperator) -> Self {
68        self.conditions.push(Condition {
69            selector: ConditionSelector::Length(len),
70            operator,
71        });
72        self
73    }
74
75    /// Add a condition that length equals the expected value
76    pub fn length_equals(self, len: usize) -> Self {
77        self.length(len, ConditionOperator::Equals)
78    }
79
80    /// Add a condition that length is greater than or equal to the expected value
81    pub fn length_gte(self, len: usize) -> Self {
82        self.length(len, ConditionOperator::GreaterThanOrEqual)
83    }
84
85    /// Add a condition that length is less than or equal to the expected value
86    pub fn length_lte(self, len: usize) -> Self {
87        self.length(len, ConditionOperator::LessThanOrEqual)
88    }
89
90    /// Add a raw condition
91    pub fn condition(mut self, condition: Condition<'a, T>) -> Self {
92        self.conditions.push(condition);
93        self
94    }
95
96    /// Build the matcher
97    pub fn build(self) -> RuleMatcher<'a, T> {
98        RuleMatcher {
99            mode: self.mode,
100            conditions: self.conditions,
101        }
102    }
103}
104
105impl<'a, T: Matchable + 'static> Default for MatcherBuilder<'a, T> {
106    fn default() -> Self {
107        Self::new()
108    }
109}
110
111/// Builder for field-based conditions
112///
113/// ## Example
114///
115/// ```rust
116/// use condition_matcher::{FieldConditionBuilder, Matchable, MatchableDerive, RuleMatcher, MatcherMode, Matcher};
117///
118/// #[derive(MatchableDerive, PartialEq)]
119/// struct User {
120///     age: u32,
121/// }
122///
123/// let condition = FieldConditionBuilder::<User>::new("age").gte(&18u32);
124///
125/// let mut matcher = RuleMatcher::new(MatcherMode::AND);
126/// matcher.add_condition(condition);
127///
128/// let user = User { age: 25 };
129/// assert!(matcher.matches(&user));
130/// ```
131pub struct FieldConditionBuilder<'a, T> {
132    field: &'a str,
133    _phantom: std::marker::PhantomData<T>,
134}
135
136impl<'a, T: Matchable> FieldConditionBuilder<'a, T> {
137    /// Create a new field condition builder for the given field
138    pub fn new(field: &'a str) -> Self {
139        Self {
140            field,
141            _phantom: std::marker::PhantomData,
142        }
143    }
144
145    /// Field equals value
146    pub fn equals(self, value: &'a dyn Any) -> Condition<'a, T> {
147        Condition {
148            selector: ConditionSelector::FieldValue(self.field, value),
149            operator: ConditionOperator::Equals,
150        }
151    }
152
153    /// Field not equals value
154    pub fn not_equals(self, value: &'a dyn Any) -> Condition<'a, T> {
155        Condition {
156            selector: ConditionSelector::FieldValue(self.field, value),
157            operator: ConditionOperator::NotEquals,
158        }
159    }
160
161    /// Field greater than value
162    pub fn gt(self, value: &'a dyn Any) -> Condition<'a, T> {
163        Condition {
164            selector: ConditionSelector::FieldValue(self.field, value),
165            operator: ConditionOperator::GreaterThan,
166        }
167    }
168
169    /// Field greater than or equal value
170    pub fn gte(self, value: &'a dyn Any) -> Condition<'a, T> {
171        Condition {
172            selector: ConditionSelector::FieldValue(self.field, value),
173            operator: ConditionOperator::GreaterThanOrEqual,
174        }
175    }
176
177    /// Field less than value
178    pub fn lt(self, value: &'a dyn Any) -> Condition<'a, T> {
179        Condition {
180            selector: ConditionSelector::FieldValue(self.field, value),
181            operator: ConditionOperator::LessThan,
182        }
183    }
184
185    /// Field less than or equal value
186    pub fn lte(self, value: &'a dyn Any) -> Condition<'a, T> {
187        Condition {
188            selector: ConditionSelector::FieldValue(self.field, value),
189            operator: ConditionOperator::LessThanOrEqual,
190        }
191    }
192
193    /// Field contains substring (for string fields)
194    pub fn contains(self, value: &'a dyn Any) -> Condition<'a, T> {
195        Condition {
196            selector: ConditionSelector::FieldValue(self.field, value),
197            operator: ConditionOperator::Contains,
198        }
199    }
200
201    /// Field starts with prefix (for string fields)
202    pub fn starts_with(self, value: &'a dyn Any) -> Condition<'a, T> {
203        Condition {
204            selector: ConditionSelector::FieldValue(self.field, value),
205            operator: ConditionOperator::StartsWith,
206        }
207    }
208
209    /// Field ends with suffix (for string fields)
210    pub fn ends_with(self, value: &'a dyn Any) -> Condition<'a, T> {
211        Condition {
212            selector: ConditionSelector::FieldValue(self.field, value),
213            operator: ConditionOperator::EndsWith,
214        }
215    }
216}
217
218/// Convenience function to create a field condition builder
219pub fn field<'a, T: Matchable>(name: &'a str) -> FieldConditionBuilder<'a, T> {
220    FieldConditionBuilder::new(name)
221}