Skip to main content

teaql_core/
safe_expression.rs

1use std::sync::Arc;
2
3use crate::{BaseEntity, SmartList, Value};
4
5pub trait TeaqlEmpty {
6    fn teaql_is_empty(&self) -> bool;
7}
8
9impl TeaqlEmpty for String {
10    fn teaql_is_empty(&self) -> bool {
11        self.is_empty()
12    }
13}
14
15impl TeaqlEmpty for &str {
16    fn teaql_is_empty(&self) -> bool {
17        self.is_empty()
18    }
19}
20
21impl<T> TeaqlEmpty for Vec<T> {
22    fn teaql_is_empty(&self) -> bool {
23        self.is_empty()
24    }
25}
26
27impl<T> TeaqlEmpty for SmartList<T> {
28    fn teaql_is_empty(&self) -> bool {
29        self.is_empty()
30    }
31}
32
33impl<T> TeaqlEmpty for Option<T> {
34    fn teaql_is_empty(&self) -> bool {
35        self.is_none()
36    }
37}
38
39impl TeaqlEmpty for Value {
40    fn teaql_is_empty(&self) -> bool {
41        match self {
42            Self::Null => true,
43            Self::Text(value) => value.is_empty(),
44            Self::List(values) => values.is_empty(),
45            Self::Object(values) => values.is_empty(),
46            Self::Json(serde_json::Value::Null) => true,
47            Self::Json(serde_json::Value::String(value)) => value.is_empty(),
48            Self::Json(serde_json::Value::Array(values)) => values.is_empty(),
49            Self::Json(serde_json::Value::Object(values)) => values.is_empty(),
50            _ => false,
51        }
52    }
53}
54
55#[derive(Clone)]
56pub struct SafeExpression<R, T> {
57    root: Arc<R>,
58    evaluator: Arc<dyn Fn(&R) -> Option<T> + Send + Sync>,
59}
60
61impl<R, T> SafeExpression<R, T>
62where
63    R: Send + Sync + 'static,
64    T: 'static,
65{
66    pub fn new(root: R, evaluator: impl Fn(&R) -> Option<T> + Send + Sync + 'static) -> Self {
67        Self {
68            root: Arc::new(root),
69            evaluator: Arc::new(evaluator),
70        }
71    }
72
73    pub fn eval(&self) -> Option<T> {
74        (self.evaluator)(&self.root)
75    }
76
77    pub fn eval_with(&self, root: &R) -> Option<T> {
78        (self.evaluator)(root)
79    }
80
81    pub fn apply<U>(self, mapper: impl Fn(T) -> U + Send + Sync + 'static) -> SafeExpression<R, U>
82    where
83        U: 'static,
84    {
85        self.apply_optional(move |value| Some(mapper(value)))
86    }
87
88    pub fn apply_optional<U>(
89        self,
90        mapper: impl Fn(T) -> Option<U> + Send + Sync + 'static,
91    ) -> SafeExpression<R, U>
92    where
93        U: 'static,
94    {
95        let root = Arc::clone(&self.root);
96        let evaluator = Arc::clone(&self.evaluator);
97        SafeExpression {
98            root,
99            evaluator: Arc::new(move |root| evaluator(root).and_then(&mapper)),
100        }
101    }
102
103    pub fn or_else(&self, default_value: T) -> T {
104        self.eval().unwrap_or(default_value)
105    }
106
107    pub fn or_else_with(&self, default_value: impl FnOnce() -> T) -> T {
108        self.eval().unwrap_or_else(default_value)
109    }
110
111    pub fn or_else_throw<E>(&self, error: impl FnOnce() -> E) -> Result<T, E> {
112        self.eval().ok_or_else(error)
113    }
114
115    pub fn is_null(&self) -> bool {
116        self.eval().is_none()
117    }
118
119    pub fn is_not_null(&self) -> bool {
120        self.eval().is_some()
121    }
122
123    pub fn is_empty(&self) -> bool
124    where
125        T: TeaqlEmpty,
126    {
127        self.eval()
128            .map(|value| value.teaql_is_empty())
129            .unwrap_or(true)
130    }
131
132    pub fn is_not_empty(&self) -> bool
133    where
134        T: TeaqlEmpty,
135    {
136        !self.is_empty()
137    }
138
139    pub fn when_is_null(&self, function: impl FnOnce()) {
140        if self.is_null() {
141            function();
142        }
143    }
144
145    pub fn when_is_not_null(&self, consumer: impl FnOnce(T)) {
146        if let Some(value) = self.eval() {
147            consumer(value);
148        }
149    }
150
151    pub fn when_is_empty(&self, function: impl FnOnce())
152    where
153        T: TeaqlEmpty,
154    {
155        if self.is_empty() {
156            function();
157        }
158    }
159
160    pub fn when_not_empty(&self, consumer: impl FnOnce(T))
161    where
162        T: TeaqlEmpty,
163    {
164        if let Some(value) = self.eval().filter(|value| !value.teaql_is_empty()) {
165            consumer(value);
166        }
167    }
168}
169
170impl<R> SafeExpression<R, R>
171where
172    R: Clone + Send + Sync + 'static,
173{
174    pub fn value(root: R) -> Self {
175        Self::new(root, |root| Some(root.clone()))
176    }
177
178    pub fn root(&self) -> &R {
179        &self.root
180    }
181}
182
183impl<R, E> SafeExpression<R, E>
184where
185    R: Send + Sync + 'static,
186    E: BaseEntity + Clone + 'static,
187{
188    pub fn entity_id(self) -> SafeExpression<R, u64> {
189        self.apply(|entity| entity.id())
190    }
191
192    pub fn entity_version(self) -> SafeExpression<R, i64> {
193        self.apply(|entity| entity.version_value())
194    }
195
196    pub fn update_entity_id(self, id: u64) -> SafeExpression<R, E> {
197        self.apply(move |mut entity| {
198            entity.set_id(id);
199            entity
200        })
201    }
202}
203
204impl<R, T> SafeExpression<R, SmartList<T>>
205where
206    R: Send + Sync + 'static,
207    T: Clone + 'static,
208{
209    pub fn size(self) -> SafeExpression<R, usize> {
210        self.apply(|list| list.len())
211    }
212
213    pub fn first(self) -> SafeExpression<R, T> {
214        self.apply_optional(|list| list.first().cloned())
215    }
216
217    pub fn get(self, index: usize) -> SafeExpression<R, T> {
218        self.apply_optional(move |list| list.get(index).cloned())
219    }
220}