Skip to main content

drasi_core/evaluation/variable_value/
mod.rs

1// Copyright 2024 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime};
16use core::fmt::{self, Debug, Display};
17use drasi_query_ast::ast::Expression as AstExpression;
18use duration::Duration;
19use float::Float;
20use index::Index;
21use integer::Integer;
22use serde_json::Value;
23use std::{
24    collections::BTreeMap,
25    hash::{Hash, Hasher},
26    sync::Arc,
27};
28use zoned_datetime::ZonedDateTime;
29use zoned_time::ZonedTime;
30
31use crate::models::{Element, ElementMetadata, ElementReference};
32
33#[allow(clippy::derived_hash_with_manual_eq)]
34#[derive(Clone, Hash, Eq, Default)]
35pub enum VariableValue {
36    #[default]
37    Null,
38    Bool(bool),
39    Float(Float),
40    Integer(Integer),
41    String(String),
42    List(Vec<VariableValue>),
43    Object(BTreeMap<String, VariableValue>), //Do we need our own map type?
44
45    Date(NaiveDate), //NaiveDate does not support TimeZone, which is consistent with Neo4j's documentation
46    LocalTime(NaiveTime),
47    ZonedTime(ZonedTime),
48    LocalDateTime(NaiveDateTime), // no timezone info
49    ZonedDateTime(ZonedDateTime),
50    Duration(Duration),
51    Expression(AstExpression),
52    ListRange(ListRange),
53    Element(Arc<Element>),
54    ElementMetadata(ElementMetadata),
55    ElementReference(ElementReference),
56    Awaiting,
57}
58
59impl From<VariableValue> for Value {
60    fn from(val: VariableValue) -> Self {
61        match val {
62            VariableValue::Null => Value::Null,
63            VariableValue::Bool(b) => Value::Bool(b),
64            VariableValue::Float(f) => Value::Number(f.into()),
65            VariableValue::Integer(i) => Value::Number(i.into()),
66            VariableValue::String(s) => Value::String(s),
67            VariableValue::List(l) => Value::Array(l.into_iter().map(|x| x.into()).collect()),
68            VariableValue::Object(o) => {
69                Value::Object(o.into_iter().map(|(k, v)| (k, v.into())).collect())
70            }
71            VariableValue::Date(d) => Value::String(d.to_string()),
72            VariableValue::LocalTime(t) => Value::String(t.to_string()),
73            VariableValue::ZonedTime(t) => Value::String(t.to_string()),
74            VariableValue::LocalDateTime(t) => Value::String(t.to_string()),
75            VariableValue::ZonedDateTime(t) => Value::String(t.to_string()),
76            VariableValue::Duration(d) => Value::String(d.to_string()),
77            VariableValue::Expression(e) => Value::String(format!("{e:?}")),
78            VariableValue::ListRange(r) => Value::String(r.to_string()),
79            VariableValue::Element(e) => e.as_ref().into(),
80            VariableValue::ElementMetadata(m) => Value::String(m.to_string()),
81            VariableValue::ElementReference(r) => Value::String(r.to_string()),
82            VariableValue::Awaiting => Value::String("Awaiting".to_string()),
83        }
84    }
85}
86
87#[derive(Clone, Debug, Hash, PartialEq, Eq)]
88pub struct ListRange {
89    pub start: RangeBound,
90    pub end: RangeBound,
91}
92
93impl Display for ListRange {
94    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95        write!(f, "{}..{}", self.start, self.end)
96    }
97}
98
99#[derive(Clone, Debug, Hash, PartialEq, Eq)]
100pub enum RangeBound {
101    Index(i64),
102    Unbounded,
103}
104
105impl Display for RangeBound {
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        match self {
108            RangeBound::Index(i) => write!(f, "{i}"),
109            RangeBound::Unbounded => write!(f, "..."),
110        }
111    }
112}
113
114impl VariableValue {
115    pub fn get<I: Index>(&self, index: I) -> Option<&VariableValue> {
116        index.index_into(self)
117    }
118
119    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut VariableValue> {
120        index.index_into_mut(self)
121    }
122
123    pub fn as_object(&self) -> Option<&BTreeMap<String, VariableValue>> {
124        match self {
125            VariableValue::Object(map) => Some(map),
126            _ => None,
127        }
128    }
129
130    pub fn as_object_mut(&mut self) -> Option<&mut BTreeMap<String, VariableValue>> {
131        match self {
132            VariableValue::Object(map) => Some(map),
133            _ => None,
134        }
135    }
136
137    pub fn is_object(&self) -> bool {
138        self.as_object().is_some()
139    }
140
141    pub fn as_array(&self) -> Option<&Vec<VariableValue>> {
142        match self {
143            VariableValue::List(list) => Some(list),
144            _ => None,
145        }
146    }
147
148    pub fn as_array_mut(&mut self) -> Option<&mut Vec<VariableValue>> {
149        match self {
150            VariableValue::List(list) => Some(list),
151            _ => None,
152        }
153    }
154
155    pub fn is_array(&self) -> bool {
156        self.as_array().is_some()
157    }
158
159    pub fn as_str(&self) -> Option<&str> {
160        match self {
161            VariableValue::String(s) => Some(s),
162            _ => None,
163        }
164    }
165
166    pub fn is_string(&self) -> bool {
167        self.as_str().is_some()
168    }
169
170    pub fn is_number(&self) -> bool {
171        matches!(*self, VariableValue::Integer(_) | VariableValue::Float(_))
172    }
173
174    pub fn is_i64(&self) -> bool {
175        match self {
176            VariableValue::Integer(n) => n.is_i64(),
177            _ => false,
178        }
179    }
180
181    pub fn is_f64(&self) -> bool {
182        match self {
183            VariableValue::Float(n) => n.is_f64(),
184            _ => false,
185        }
186    }
187
188    pub fn is_u64(&self) -> bool {
189        match self {
190            VariableValue::Integer(n) => n.is_u64(),
191            _ => false,
192        }
193    }
194
195    pub fn as_i64(&self) -> Option<i64> {
196        match self {
197            VariableValue::Integer(n) => n.as_i64(),
198            _ => None,
199        }
200    }
201
202    pub fn as_f64(&self) -> Option<f64> {
203        match self {
204            VariableValue::Float(n) => n.as_f64(),
205            VariableValue::Integer(n) => n.as_i64().map(|n| n as f64),
206            _ => None,
207        }
208    }
209
210    pub fn as_u64(&self) -> Option<u64> {
211        match self {
212            VariableValue::Integer(n) => n.as_u64(),
213            _ => None,
214        }
215    }
216
217    pub fn as_bool(&self) -> Option<bool> {
218        match *self {
219            VariableValue::Bool(b) => Some(b),
220            _ => None,
221        }
222    }
223
224    pub fn is_boolean(&self) -> bool {
225        self.as_bool().is_some()
226    }
227
228    pub fn as_null(&self) -> Option<()> {
229        match *self {
230            VariableValue::Null => Some(()),
231            _ => None,
232        }
233    }
234
235    pub fn is_null(&self) -> bool {
236        self.as_null().is_some()
237    }
238
239    pub fn as_date(&self) -> Option<NaiveDate> {
240        match *self {
241            VariableValue::Date(d) => Some(d),
242            _ => None,
243        }
244    }
245
246    pub fn is_date(&self) -> bool {
247        self.as_date().is_some()
248    }
249
250    pub fn as_local_time(&self) -> Option<NaiveTime> {
251        match *self {
252            VariableValue::LocalTime(t) => Some(t),
253            _ => None,
254        }
255    }
256
257    pub fn is_local_time(&self) -> bool {
258        self.as_local_time().is_some()
259    }
260
261    pub fn as_time(&self) -> Option<ZonedTime> {
262        match self {
263            VariableValue::ZonedTime(t) => Some(*t),
264            _ => None,
265        }
266    }
267
268    pub fn is_time(&self) -> bool {
269        self.as_time().is_some()
270    }
271
272    pub fn as_local_date_time(&self) -> Option<NaiveDateTime> {
273        match *self {
274            VariableValue::LocalDateTime(t) => Some(t),
275            _ => None,
276        }
277    }
278
279    pub fn is_local_date_time(&self) -> bool {
280        self.as_local_date_time().is_some()
281    }
282
283    pub fn as_zoned_date_time(&self) -> Option<ZonedDateTime> {
284        match self {
285            VariableValue::ZonedDateTime(t) => Some(t.clone()),
286            _ => None,
287        }
288    }
289
290    pub fn get_date_property(&self, property: String) -> Option<String> {
291        if self.is_date() {
292            match property.as_str() {
293                "year" => Some(match self.as_date() {
294                    Some(date) => date.year().to_string(),
295                    None => return None,
296                }),
297                "month" => Some(match self.as_date() {
298                    Some(date) => date.month().to_string(),
299                    None => return None,
300                }),
301                "day" => Some(match self.as_date() {
302                    Some(date) => date.day().to_string(),
303                    None => return None,
304                }),
305                _ => None,
306            }
307        } else {
308            None
309        }
310    }
311
312    pub fn is_zoned_date_time(&self) -> bool {
313        self.as_zoned_date_time().is_some()
314    }
315
316    pub fn as_duration(&self) -> Option<Duration> {
317        match self {
318            VariableValue::Duration(d) => Some(d.clone()),
319            _ => None,
320        }
321    }
322
323    pub fn is_duration(&self) -> bool {
324        self.as_duration().is_some()
325    }
326
327    pub fn as_expression(&self) -> Option<AstExpression> {
328        match self {
329            VariableValue::Expression(e) => Some(e.clone()),
330            _ => None,
331        }
332    }
333
334    pub fn is_expression(&self) -> bool {
335        self.as_expression().is_some()
336    }
337
338    pub fn as_list_range(&self) -> Option<ListRange> {
339        match self {
340            VariableValue::ListRange(r) => Some(r.clone()),
341            _ => None,
342        }
343    }
344
345    pub fn is_list_range(&self) -> bool {
346        self.as_list_range().is_some()
347    }
348
349    pub fn pointer(&self, pointer: &str) -> Option<&VariableValue> {
350        if pointer.is_empty() {
351            return Some(self);
352        }
353        if !pointer.starts_with('/') {
354            return None;
355        }
356        pointer
357            .split('/')
358            .skip(1)
359            .map(|x| x.replace("~1", "/").replace("~0", "~"))
360            .try_fold(self, |target, token| match target {
361                VariableValue::Object(map) => map.get(&token),
362                VariableValue::List(list) => parse_index(&token).and_then(|x| list.get(x)),
363                _ => None,
364            })
365    }
366
367    pub fn hash_for_groupby<H: Hasher>(&self, state: &mut H) {
368        match self {
369            VariableValue::Element(element) => element.get_reference().hash(state),
370            _ => self.hash(state),
371        }
372    }
373}
374
375fn parse_index(s: &str) -> Option<usize> {
376    if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
377        return None;
378    }
379    s.parse().ok()
380}
381
382impl Debug for VariableValue {
383    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
384        match self {
385            VariableValue::Null => formatter.write_str("Null"),
386            VariableValue::Bool(boolean) => write!(formatter, "Bool({boolean})"),
387            VariableValue::Integer(integer) => write!(formatter, "Integer({integer})"),
388            VariableValue::Float(float) => write!(formatter, "Float({float})"),
389            VariableValue::String(string) => write!(formatter, "String({string:?})"),
390            VariableValue::List(vec) => {
391                let _ = formatter.write_str("List ");
392                Debug::fmt(vec, formatter)
393            }
394            VariableValue::Object(map) => {
395                let _ = formatter.write_str("Object ");
396                Debug::fmt(map, formatter)
397            }
398            VariableValue::Date(date) => write!(formatter, "Date({date})"),
399            VariableValue::LocalTime(time) => write!(formatter, "LocalTime({time})"),
400            VariableValue::ZonedTime(time) => write!(formatter, "Time({time})"),
401            VariableValue::LocalDateTime(time) => write!(formatter, "LocalDateTime({time})"),
402            VariableValue::ZonedDateTime(time) => write!(formatter, "ZonedDateTime({time})"),
403            VariableValue::Duration(duration) => write!(formatter, "Duration({duration})"),
404            VariableValue::Expression(expression) => {
405                write!(formatter, "Expression({expression:?})")
406            }
407            VariableValue::ListRange(range) => write!(formatter, "ListRange({range:?})"),
408            VariableValue::Element(element) => write!(formatter, "Element({element:?})"),
409            VariableValue::ElementMetadata(metadata) => {
410                write!(formatter, "ElementMetadata({metadata:?})")
411            }
412            VariableValue::ElementReference(reference) => {
413                write!(formatter, "ElementReference({reference:?})")
414            }
415            VariableValue::Awaiting => write!(formatter, "Awaiting"),
416        }
417    }
418}
419
420impl Display for VariableValue {
421    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
422        match &self {
423            VariableValue::Null => write!(f, "null"),
424            VariableValue::Bool(b) => write!(f, "{b}"),
425            VariableValue::Integer(i) => write!(f, "{i}"),
426            VariableValue::Float(fl) => write!(f, "{fl}"),
427            VariableValue::String(s) => write!(f, "{s}"),
428            VariableValue::List(l) => {
429                let mut first = true;
430                write!(f, "[")?;
431                for item in l {
432                    if first {
433                        first = false;
434                    } else {
435                        write!(f, ", ")?;
436                    }
437                    write!(f, "{item}")?;
438                }
439                write!(f, "]")
440            }
441            VariableValue::Object(o) => {
442                let mut first = true;
443                write!(f, "{{")?;
444                for (key, value) in o {
445                    if first {
446                        first = false;
447                    } else {
448                        write!(f, ", ")?;
449                    }
450                    write!(f, "{key}: {value}")?;
451                }
452                write!(f, "}}")
453            }
454            VariableValue::Date(d) => write!(f, "{d}"),
455            VariableValue::LocalTime(t) => write!(f, "{t}"),
456            VariableValue::ZonedTime(t) => write!(f, "{t}"),
457            VariableValue::LocalDateTime(t) => write!(f, "{t}"),
458            VariableValue::ZonedDateTime(t) => write!(f, "{t}"),
459            VariableValue::Duration(d) => write!(f, "{d}"),
460            VariableValue::Expression(e) => write!(f, "{e:?}"),
461            VariableValue::ListRange(r) => write!(f, "{r}"),
462            VariableValue::Element(e) => write!(f, "{e:?}"),
463            VariableValue::ElementMetadata(m) => write!(f, "{m}"),
464            VariableValue::ElementReference(r) => write!(f, "{r}"),
465            VariableValue::Awaiting => write!(f, "Awaiting"),
466        }
467    }
468}
469
470pub mod de;
471pub mod duration;
472pub mod float;
473mod from;
474mod index;
475pub mod integer;
476mod partial_eq;
477pub mod ser;
478#[cfg(test)]
479mod tests;
480pub mod zoned_datetime;
481pub mod zoned_time;