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