Skip to main content

lance_jsonb/jsonpath/
path.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3// SPDX-FileCopyrightText: Copyright 2023 Datafuse Labs
4// Adapted from databendlabs/jsonb at commit fba895c5ebe77ce2539e187f9c652f51cbf195c3.
5
6use crate::RawJsonb;
7use std::borrow::Cow;
8use std::cmp::Ordering;
9use std::collections::HashSet;
10use std::fmt::Display;
11use std::fmt::Formatter;
12
13use crate::number::Number;
14
15/// Represents a set of JSON Path chains.
16#[derive(Debug, Clone, PartialEq)]
17pub struct JsonPath<'a> {
18    pub paths: Vec<Path<'a>>,
19}
20
21impl JsonPath<'_> {}
22
23/// Represents a valid JSON Path.
24#[derive(Debug, Clone, PartialEq)]
25pub enum Path<'a> {
26    /// `$` represents the root node or element.
27    Root,
28    /// `@` represents the current node or element being processed in the filter expression.
29    Current,
30    /// `.*` represents selecting all elements in an Object.
31    DotWildcard,
32    /// `.**` represents recursive selecting all elements in Array and Object.
33    /// The optional `RecursiveLevel` indicates the selected levels.
34    RecursiveDotWildcard(Option<RecursiveLevel>),
35    /// `[*]` represents selecting all elements in an Array.
36    BracketWildcard,
37    /// `.<name>` represents selecting element that matched the name in an Object, like `$.event`.
38    /// The name can also be written as a string literal, allowing the name to contain special characters, like `$." $price"`.
39    DotField(Cow<'a, str>),
40    /// `:<name>` represents selecting element that matched the name in an Object, like `$:event`.
41    ColonField(Cow<'a, str>),
42    /// `["<name>"]` represents selecting element that matched the name in an Object, like `$["event"]`.
43    ObjectField(Cow<'a, str>),
44    /// `[<index1>,<index2>,..]` represents selecting elements specified by the indices in an Array.
45    /// There are several forms of index.
46    /// 1. A single number representing the 0-based `n-th` element in the Array.
47    ///    e.g. `$[0]` represents the first element in an Array.
48    /// 2. The keyword `last` represents the last element in the Array,
49    ///    and last minus a number represents the n-th element before the last element,
50    ///    e.g. `$[last-1]` represents the penultimate element.
51    /// 3. The keyword `to` between two numbers represent all elements of a range in an Array,
52    ///    e.g. `$[1 to last]` represents all the elements in the Array from the second to the last.
53    ///
54    /// There can be more than one index, e.g. `$[0, last-1 to last, 5]` represents the first,
55    /// the last two, and the sixth element in an Array.
56    ArrayIndices(Vec<ArrayIndex>),
57    /// `?(<expression>)` represents selecting all elements in an object or array that match the filter expression, like `$.book[?(@.price < 10)]`.
58    FilterExpr(Box<Expr<'a>>),
59    /// `<expression>` standalone filter expression, like `$.book[*].price > 10`,
60    /// and arithmetic expression, like `-$.a[*]` or `$.a + 3`
61    Expr(Box<Expr<'a>>),
62}
63
64/// Represents the single index in an Array.
65#[derive(Debug, Clone, PartialEq)]
66pub enum Index {
67    /// The 0-based index in an Array.
68    Index(i32),
69    /// The last n-th index in an Array.
70    LastIndex(i32),
71}
72
73/// Represents the index in an Array.
74#[derive(Debug, Clone, PartialEq)]
75pub enum ArrayIndex {
76    /// The single number index.
77    Index(Index),
78    /// The range index between two number.
79    Slice((Index, Index)),
80}
81
82impl ArrayIndex {
83    /// Converts an `ArrayIndex` to a `HashSet` of indices that should be selected from an Array.
84    ///
85    /// # Arguments
86    ///
87    /// * `length` - The length of the array.
88    ///
89    /// # Returns
90    ///
91    /// A `HashSet<usize>` containing the indices to select.
92    pub(crate) fn to_indices(&self, length: usize) -> HashSet<usize> {
93        let length = length as i32;
94
95        let mut indices = HashSet::new();
96        match self {
97            Self::Index(idx) => {
98                let idx = Self::convert_index(idx, length);
99                if idx >= 0 && idx < length {
100                    indices.insert(idx as usize);
101                }
102            }
103            Self::Slice((start, end)) => {
104                let start_idx = Self::convert_index(start, length);
105                let end_idx = Self::convert_index(end, length);
106
107                let start_idx = if start_idx < 0 { 0 } else { start_idx as usize };
108                let end_idx = if end_idx >= length {
109                    (length - 1) as usize
110                } else {
111                    end_idx as usize
112                };
113                for idx in start_idx..=end_idx {
114                    indices.insert(idx);
115                }
116            }
117        }
118        indices
119    }
120
121    fn convert_index(index: &Index, length: i32) -> i32 {
122        match index {
123            Index::Index(idx) => *idx,
124            Index::LastIndex(idx) => length + *idx - 1,
125        }
126    }
127}
128
129/// Represents the end level in hierarchical structure.
130#[derive(Debug, Clone, PartialEq)]
131pub enum RecursiveLevelEnd {
132    /// Specifies the end of the recursive level.
133    Index(u8),
134    /// Specifies that the recursion should continue to the last level.
135    Last,
136}
137
138/// Represents the selected levels in hierarchical structure.
139#[derive(Debug, Clone, PartialEq)]
140pub struct RecursiveLevel {
141    /// The starting level of the recursive level.
142    pub start: u8,
143    /// The optional end of the recursive level. If None, the level applies only to the start level.
144    pub end: Option<RecursiveLevelEnd>,
145}
146
147impl RecursiveLevel {
148    /// Checks if the current level matches the recursive level.
149    ///
150    /// # Arguments
151    ///
152    /// * `level` - The current level in hierarchical structure.
153    ///
154    /// # Returns
155    ///
156    /// A tuple (is_match, should_continue):
157    /// - is_match: Indicates whether the current level matches the level criteria.
158    /// - should_continue: Indicates whether to continue processing data at the next level.
159    pub(crate) fn check_recursive_level(&self, level: u8) -> (bool, bool) {
160        if let Some(end) = &self.end {
161            match end {
162                RecursiveLevelEnd::Index(end) => {
163                    if level < self.start && self.start <= *end {
164                        (false, true)
165                    } else if level >= self.start && level <= *end {
166                        (true, true)
167                    } else {
168                        (false, false)
169                    }
170                }
171                RecursiveLevelEnd::Last => {
172                    if level < self.start {
173                        (false, true)
174                    } else {
175                        (true, true)
176                    }
177                }
178            }
179        } else if level < self.start {
180            (false, true)
181        } else if level == self.start {
182            (true, false)
183        } else {
184            (false, false)
185        }
186    }
187}
188
189/// Represents a literal value used in filter expression.
190#[derive(Debug, Clone)]
191pub enum PathValue<'a> {
192    /// Null value.
193    Null,
194    /// Boolean value.
195    Boolean(bool),
196    /// Number value.
197    Number(Number),
198    /// UTF-8 string.
199    String(Cow<'a, str>),
200    /// RawJsonb (Array or Object) value, can't be used for calculation.
201    Raw(RawJsonb<'a>),
202}
203
204impl PartialOrd for PathValue<'_> {
205    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
206        match (self, other) {
207            (PathValue::Null, PathValue::Null) => Some(Ordering::Equal),
208            (PathValue::Boolean(l), PathValue::Boolean(r)) => l.partial_cmp(r),
209            (PathValue::Number(l), PathValue::Number(r)) => l.partial_cmp(r),
210            (PathValue::String(l), PathValue::String(r)) => l.partial_cmp(r),
211            (_, _) => None,
212        }
213    }
214}
215
216impl PartialEq for PathValue<'_> {
217    fn eq(&self, other: &Self) -> bool {
218        self.partial_cmp(other) == Some(Ordering::Equal)
219    }
220}
221
222/// Represents the operators used in filter expression.
223#[derive(Debug, Clone, PartialEq, Eq)]
224pub enum BinaryOperator {
225    /// `&&` represents logical And operation.
226    And,
227    /// `||` represents logical Or operation.
228    Or,
229    /// `==` represents left is equal to right.
230    Eq,
231    /// `!=` and `<>` represents left is not equal to right.
232    NotEq,
233    /// `<` represents left is less than right.
234    Lt,
235    /// `<=` represents left is less or equal to right.
236    Lte,
237    /// `>` represents left is greater than right.
238    Gt,
239    /// `>=` represents left is greater than or equal to right.
240    Gte,
241    /// `starts with` represents right is an initial substring of left.
242    StartsWith,
243    /// `Add` represents binary arithmetic + operation.
244    Add,
245    /// `Subtract` represents binary arithmetic - operation.
246    Subtract,
247    /// `Multiply` represents binary arithmetic * operation.
248    Multiply,
249    /// `Divide` represents binary arithmetic / operation.
250    Divide,
251    /// `Modulo` represents binary arithmetic % operation.
252    Modulo,
253}
254
255#[derive(Debug, Clone, PartialEq)]
256pub enum UnaryOperator {
257    /// `Add` represents unary arithmetic + operation.
258    Add,
259    /// `Subtract` represents unary arithmetic - operation.
260    Subtract,
261}
262
263/// Represents a filter expression used to filter Array or Object.
264#[derive(Debug, Clone, PartialEq)]
265pub enum Expr<'a> {
266    /// JSON Path chains.
267    Paths(Vec<Path<'a>>),
268    /// Literal value.
269    Value(Box<PathValue<'a>>),
270    /// Filter expression that performs a binary operation, returns a boolean value,
271    /// Or arithmetic expression that performs an arithmetic operation, returns a number value.
272    BinaryOp {
273        op: BinaryOperator,
274        left: Box<Self>,
275        right: Box<Self>,
276    },
277    /// Unary expression that performs an arithmetic operation.
278    UnaryOp {
279        op: UnaryOperator,
280        operand: Box<Self>,
281    },
282    /// Filter function, returns a boolean value.
283    ExistsFunc(Vec<Path<'a>>),
284}
285
286impl Display for JsonPath<'_> {
287    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
288        for path in &self.paths {
289            write!(f, "{path}")?;
290        }
291        Ok(())
292    }
293}
294
295impl Display for Index {
296    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
297        match self {
298            Self::Index(idx) => {
299                write!(f, "{idx}")?;
300            }
301            Self::LastIndex(idx) => {
302                write!(f, "last")?;
303                match idx.cmp(&0) {
304                    Ordering::Greater => {
305                        write!(f, "+{idx}")?;
306                    }
307                    Ordering::Less => {
308                        write!(f, "{idx}")?;
309                    }
310                    Ordering::Equal => {}
311                }
312            }
313        }
314        Ok(())
315    }
316}
317
318impl Display for ArrayIndex {
319    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
320        match self {
321            Self::Index(idx) => {
322                write!(f, "{idx}")?;
323            }
324            Self::Slice((start, end)) => {
325                write!(f, "{start} to {end}")?;
326            }
327        }
328        Ok(())
329    }
330}
331
332impl Display for RecursiveLevel {
333    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
334        if let Some(end_index) = &self.end {
335            match end_index {
336                RecursiveLevelEnd::Index(end) => {
337                    write!(f, "{} to {}", self.start, end)?;
338                }
339                RecursiveLevelEnd::Last => {
340                    write!(f, "{} to last", self.start)?;
341                }
342            }
343        } else {
344            write!(f, "{}", self.start)?;
345        }
346        Ok(())
347    }
348}
349
350impl Display for Path<'_> {
351    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
352        match self {
353            Path::Root => {
354                write!(f, "$")?;
355            }
356            Path::Current => {
357                write!(f, "@")?;
358            }
359            Path::DotWildcard => {
360                write!(f, ".*")?;
361            }
362            Path::RecursiveDotWildcard(level_opt) => {
363                write!(f, ".**")?;
364                if let Some(level) = level_opt {
365                    write!(f, "{{")?;
366                    write!(f, "{level}")?;
367                    write!(f, "}}")?;
368                }
369            }
370            Path::BracketWildcard => {
371                write!(f, "[*]")?;
372            }
373            Path::ColonField(field) => {
374                write!(f, ":{field}")?;
375            }
376            Path::DotField(field) => {
377                write!(f, ".{field}")?;
378            }
379            Path::ObjectField(field) => {
380                write!(f, "[\"{field}\"]")?;
381            }
382            Path::ArrayIndices(indices) => {
383                write!(f, "[")?;
384                for (i, index) in indices.iter().enumerate() {
385                    if i > 0 {
386                        write!(f, ", ")?;
387                    }
388                    write!(f, "{index}")?;
389                }
390                write!(f, "]")?;
391            }
392            Path::FilterExpr(expr) => {
393                write!(f, "?({expr})")?;
394            }
395            Path::Expr(expr) => {
396                write!(f, "{expr}")?;
397            }
398        }
399        Ok(())
400    }
401}
402
403impl Display for PathValue<'_> {
404    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
405        match self {
406            PathValue::Null => {
407                write!(f, "null")
408            }
409            PathValue::Boolean(v) => {
410                if *v {
411                    write!(f, "true")
412                } else {
413                    write!(f, "false")
414                }
415            }
416            PathValue::Number(v) => {
417                write!(f, "{v}")
418            }
419            PathValue::String(v) => {
420                write!(f, "\"{v}\"")
421            }
422            PathValue::Raw(v) => {
423                write!(f, "{}", v.to_string())
424            }
425        }
426    }
427}
428
429impl Display for BinaryOperator {
430    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
431        match self {
432            Self::And => {
433                write!(f, "&&")
434            }
435            Self::Or => {
436                write!(f, "||")
437            }
438            Self::Eq => {
439                write!(f, "==")
440            }
441            Self::NotEq => {
442                write!(f, "!=")
443            }
444            Self::Lt => {
445                write!(f, "<")
446            }
447            Self::Lte => {
448                write!(f, "<=")
449            }
450            Self::Gt => {
451                write!(f, ">")
452            }
453            Self::Gte => {
454                write!(f, ">=")
455            }
456            Self::StartsWith => {
457                write!(f, "starts with")
458            }
459            Self::Add => {
460                write!(f, "+")
461            }
462            Self::Subtract => {
463                write!(f, "-")
464            }
465            Self::Multiply => {
466                write!(f, "*")
467            }
468            Self::Divide => {
469                write!(f, "/")
470            }
471            Self::Modulo => {
472                write!(f, "%")
473            }
474        }
475    }
476}
477
478impl Display for UnaryOperator {
479    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
480        match self {
481            Self::Add => {
482                write!(f, "+")
483            }
484            Self::Subtract => {
485                write!(f, "-")
486            }
487        }
488    }
489}
490
491impl Display for Expr<'_> {
492    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
493        match self {
494            Expr::Paths(paths) => {
495                for path in paths {
496                    write!(f, "{path}")?;
497                }
498            }
499            Expr::Value(v) => {
500                write!(f, "{v}")?;
501            }
502            Expr::BinaryOp { op, left, right } => {
503                if let Expr::BinaryOp { op: left_op, .. } = &**left {
504                    if left_op == &BinaryOperator::And || left_op == &BinaryOperator::Or {
505                        write!(f, "({left})")?;
506                    } else {
507                        write!(f, "{left}")?;
508                    }
509                } else {
510                    write!(f, "{left}")?;
511                }
512                write!(f, " {op} ")?;
513                if let Expr::BinaryOp { op: right_op, .. } = &**right {
514                    if right_op == &BinaryOperator::And || right_op == &BinaryOperator::Or {
515                        write!(f, "({right})")?;
516                    } else {
517                        write!(f, "{right}")?;
518                    }
519                } else {
520                    write!(f, "{right}")?;
521                }
522            }
523            Expr::UnaryOp { op, operand } => {
524                write!(f, "{}{}", op, operand)?;
525            }
526            Expr::ExistsFunc(paths) => {
527                f.write_str("exists(")?;
528                for path in paths {
529                    write!(f, "{path}")?;
530                }
531                f.write_str(")")?;
532            }
533        }
534        Ok(())
535    }
536}