teaql_core/
safe_expression.rs1use 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}