datalogic_rs/builder/
rule_builder.rs

1use crate::arena::DataArena;
2use crate::logic::Logic;
3use crate::value::DataValue;
4
5use super::arithmetic_builder::ArithmeticBuilder;
6use super::array_builder::ArrayBuilder;
7use super::comparison_builder::ComparisonBuilder;
8use super::control_builder::ControlBuilder;
9use super::datetime_builder::DateTimeBuilder;
10use super::string_builder::StringBuilder;
11use super::type_builder;
12use super::variable_builder::VariableBuilder;
13
14/// Main builder for creating JSONLogic rules.
15///
16/// This is the entry point for the builder API, providing access to different
17/// specialized builders for different types of operations.
18pub struct RuleBuilder<'a> {
19    /// The arena in which all allocations will be made.
20    arena: &'a DataArena,
21}
22
23impl<'a> RuleBuilder<'a> {
24    /// Creates a new rule builder.
25    pub fn new(arena: &'a DataArena) -> Self {
26        Self { arena }
27    }
28
29    /// Returns the arena this builder uses.
30    pub fn arena(&self) -> &'a DataArena {
31        self.arena
32    }
33
34    /// Creates a comparison builder.
35    pub fn compare(&self) -> ComparisonBuilder<'a> {
36        ComparisonBuilder::new(self.arena)
37    }
38
39    /// Creates an arithmetic builder.
40    pub fn arithmetic(&self) -> ArithmeticBuilder<'a> {
41        ArithmeticBuilder::new(self.arena)
42    }
43
44    /// Creates a control flow builder.
45    pub fn control(&self) -> ControlBuilder<'a> {
46        ControlBuilder::new(self.arena)
47    }
48
49    /// Creates an array operation builder.
50    pub fn array(&self) -> ArrayBuilder<'a> {
51        ArrayBuilder::new(self.arena)
52    }
53
54    /// Creates a string operation builder.
55    pub fn string_ops(&self) -> StringBuilder<'a> {
56        StringBuilder::new(self.arena)
57    }
58
59    /// Creates a datetime operation builder.
60    pub fn datetime(&self) -> DateTimeBuilder<'a> {
61        DateTimeBuilder::new(self.arena)
62    }
63
64    /// Creates a variable reference.
65    pub fn var(&self, path: &str) -> VariableBuilder<'a> {
66        VariableBuilder::new(self.arena, path)
67    }
68
69    /// Creates a val token with the given path components.
70    /// The path can be a string, number, or array of components.
71    pub fn val_op<T: Into<DataValue<'a>>>(&self, path: T) -> Logic<'a> {
72        let path_value = path.into();
73        let path_logic = Logic::literal(path_value, self.arena);
74        Logic::operator(
75            crate::logic::OperatorType::Val,
76            vec![path_logic],
77            self.arena,
78        )
79    }
80
81    /// Creates a val token with a string path.
82    pub fn val_str(&self, path: &str) -> Logic<'a> {
83        self.val_op(DataValue::string(self.arena, path))
84    }
85
86    /// Creates a val token with an array of path components.
87    /// Each component can be a string or number for array indices.
88    pub fn val_path<I, T>(&self, components: I) -> Logic<'a>
89    where
90        I: IntoIterator<Item = T>,
91        T: Into<DataValue<'a>>,
92    {
93        let mut path_components = Vec::new();
94        for component in components {
95            path_components.push(component.into());
96        }
97        let array_value = DataValue::Array(self.arena.vec_into_slice(path_components));
98        self.val_op(array_value)
99    }
100
101    /// Creates a literal value.
102    pub fn value<T: Into<DataValue<'a>>>(&self, value: T) -> Logic<'a> {
103        Logic::literal(value.into(), self.arena)
104    }
105
106    /// Creates a literal boolean value.
107    pub fn bool(&self, value: bool) -> Logic<'a> {
108        Logic::literal(DataValue::bool(value), self.arena)
109    }
110
111    /// Creates a literal integer value.
112    pub fn int(&self, value: i64) -> Logic<'a> {
113        Logic::literal(DataValue::integer(value), self.arena)
114    }
115
116    /// Creates a literal float value.
117    pub fn float(&self, value: f64) -> Logic<'a> {
118        Logic::literal(DataValue::float(value), self.arena)
119    }
120
121    /// Creates a literal string value.
122    pub fn string_value(&self, value: &str) -> Logic<'a> {
123        Logic::literal(DataValue::string(self.arena, value), self.arena)
124    }
125
126    /// Creates a literal null value.
127    pub fn null(&self) -> Logic<'a> {
128        Logic::literal(DataValue::null(), self.arena)
129    }
130
131    /// Creates a logic that gets a variable and returns a default if it doesn't exist.
132    pub fn var_with_default(&self, path: &str, default: Logic<'a>) -> Logic<'a> {
133        Logic::variable(path, Some(default), self.arena)
134    }
135
136    /// Creates a missing check for the specified variables.
137    /// Returns an array of variables that are missing from the data context.
138    pub fn missing_op<T: Into<Logic<'a>>>(&self, variables: T) -> Logic<'a> {
139        let vars = variables.into();
140        Logic::operator(crate::logic::OperatorType::Missing, vec![vars], self.arena)
141    }
142
143    /// Creates a missing check for a single variable.
144    pub fn missing_var(&self, variable: &str) -> Logic<'a> {
145        self.missing_op(self.string_value(variable))
146    }
147
148    /// Creates a missing check for multiple variables.
149    pub fn missing_vars<I, S>(&self, variables: I) -> Logic<'a>
150    where
151        I: IntoIterator<Item = S>,
152        S: AsRef<str>,
153    {
154        let vars = variables
155            .into_iter()
156            .map(|s| self.string_value(s.as_ref()))
157            .collect::<Vec<_>>();
158
159        self.missing_op(self.array().array_literal_op(vars))
160    }
161
162    /// Creates a missing_some check, which returns an array of variables that
163    /// are missing from the data context if the number of present variables is
164    /// less than the required number.
165    pub fn missing_some_op<T: Into<Logic<'a>>>(
166        &self,
167        min_required: i64,
168        variables: T,
169    ) -> Logic<'a> {
170        let vars = variables.into();
171        let min = self.int(min_required);
172
173        Logic::operator(
174            crate::logic::OperatorType::MissingSome,
175            vec![min, vars],
176            self.arena,
177        )
178    }
179
180    /// Creates a throw operator that throws an error with the given value.
181    pub fn throw_op<T: Into<Logic<'a>>>(&self, error: T) -> Logic<'a> {
182        let error_value = error.into();
183        Logic::operator(
184            crate::logic::OperatorType::Throw,
185            vec![error_value],
186            self.arena,
187        )
188    }
189
190    /// Creates a try operator that attempts to evaluate a sequence of expressions.
191    /// Returns the result of the first one that succeeds. If all expressions fail,
192    /// the last error is propagated.
193    pub fn try_op<I, T>(&self, expressions: I) -> Logic<'a>
194    where
195        I: IntoIterator<Item = T>,
196        T: Into<Logic<'a>>,
197    {
198        let expressions = expressions
199            .into_iter()
200            .map(|expr| expr.into())
201            .collect::<Vec<_>>();
202
203        Logic::operator(crate::logic::OperatorType::Try, expressions, self.arena)
204    }
205
206    /// Create a type operator that returns the type of a value
207    pub fn type_op(&self) -> type_builder::TypeBuilder<'a> {
208        type_builder::TypeBuilder::new(self.arena)
209    }
210}