Skip to main content

sql_json_path/
eval.rs

1// Copyright 2023 RisingWave Labs
2// Modifications Copyright (c) Citadel contributors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// This file has been modified by Citadel contributors.
17
18use serde_json::Number;
19
20use crate::{
21    ast::*,
22    json::{ArrayRef, Cow, Json, JsonRef, ObjectRef},
23};
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27/// The error type returned when evaluating a JSON path.
28#[non_exhaustive]
29#[derive(Debug, thiserror::Error, PartialEq, Eq)]
30pub enum Error {
31    // structural errors
32    #[error("JSON object does not contain key \"{0}\"")]
33    NoKey(Box<str>),
34    #[error("jsonpath array accessor can only be applied to an array")]
35    ArrayAccess,
36    #[error("jsonpath wildcard array accessor can only be applied to an array")]
37    WildcardArrayAccess,
38    #[error("jsonpath member accessor can only be applied to an object")]
39    MemberAccess,
40    #[error("jsonpath wildcard member accessor can only be applied to an object")]
41    WildcardMemberAccess,
42    #[error("jsonpath array subscript is out of bounds")]
43    ArrayIndexOutOfBounds,
44
45    #[error("jsonpath array subscript is out of integer range")]
46    ArrayIndexOutOfRange,
47    #[error("jsonpath array subscript is not a single numeric value")]
48    ArrayIndexNotNumeric,
49    #[error("could not find jsonpath variable \"{0}\"")]
50    NoVariable(Box<str>),
51    #[error("\"vars\" argument is not an object")]
52    VarsNotObject,
53    #[error("operand of unary jsonpath operator {0} is not a numeric value")]
54    UnaryOperandNotNumeric(UnaryOp),
55    #[error("left operand of jsonpath operator {0} is not a single numeric value")]
56    LeftOperandNotNumeric(BinaryOp),
57    #[error("right operand of jsonpath operator {0} is not a single numeric value")]
58    RightOperandNotNumeric(BinaryOp),
59    #[error("jsonpath item method .{0}() can only be applied to a numeric value")]
60    MethodNotNumeric(&'static str),
61    #[error("jsonpath item method .size() can only be applied to an array")]
62    SizeNotArray,
63    #[error("jsonpath item method .double() can only be applied to a string or numeric value")]
64    DoubleTypeError,
65    #[error("numeric argument of jsonpath item method .double() is out of range for type double precision")]
66    DoubleOutOfRange,
67    #[error("string argument of jsonpath item method .double() is not a valid representation of a double precision number")]
68    InvalidDouble,
69    #[error("jsonpath item method .keyvalue() can only be applied to an object")]
70    KeyValueNotObject,
71    #[error("division by zero")]
72    DivisionByZero,
73    #[error("single boolean result is expected")]
74    ExpectSingleBoolean,
75    #[error("jsonpath item method .datetime() can only be applied to a string")]
76    DatetimeNotString,
77    #[error("datetime format is not recognized: {0}")]
78    DatetimeFormatNotRecognized(Box<str>),
79    #[error("datetime format is zoned but not timed")]
80    DatetimeZonedNotTimed,
81    #[error("invalid datetime input: {0}")]
82    InvalidDatetimeInput(Box<str>),
83    #[error("invalid datetime format separator: {0}")]
84    DatetimeInvalidSeparator(Box<str>),
85    #[error("invalid value {0} for {1}")]
86    DatetimeInvalidValue(Box<str>, Box<str>),
87    #[error("trailing characters remain in input string after datetime format")]
88    DatetimeTrailingInput,
89    #[error("unmatched format character {0}")]
90    DatetimeUnmatchedChar(Box<str>),
91    #[error("input string is too short for datetime format")]
92    DatetimeInputTooShort,
93    #[error("cannot convert value from {0} to {1} without time zone usage")]
94    DatetimeConvertWithoutTz(Box<str>, Box<str>),
95    #[error("invalid datetime template: {0}")]
96    InvalidDatetimeTemplate(Box<str>),
97    #[error("template directive {0} is not supported by jsonpath")]
98    UnsupportedDatetimeDirective(Box<str>),
99}
100
101impl Error {
102    pub const fn can_silent(&self) -> bool {
103        !matches!(
104            self,
105            Self::NoVariable(_) | Self::DatetimeConvertWithoutTz(_, _)
106        )
107    }
108
109    // A structural error is an attempt to access a non-existent member of an object or element of an array.
110    pub const fn is_structural(&self) -> bool {
111        matches!(
112            self,
113            Self::NoKey(_)
114                | Self::ArrayAccess
115                | Self::WildcardArrayAccess
116                | Self::MemberAccess
117                | Self::WildcardMemberAccess
118                | Self::ArrayIndexOutOfBounds
119        )
120    }
121}
122
123/// Truth value used in SQL/JSON path predicates.
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125enum Truth {
126    True,
127    False,
128    Unknown,
129}
130
131impl From<bool> for Truth {
132    fn from(b: bool) -> Self {
133        if b {
134            Truth::True
135        } else {
136            Truth::False
137        }
138    }
139}
140
141impl Truth {
142    /// Returns true if the value is true.
143    fn is_true(self) -> bool {
144        matches!(self, Truth::True)
145    }
146
147    /// Returns true if the value is false.
148    #[allow(unused)]
149    fn is_false(self) -> bool {
150        matches!(self, Truth::False)
151    }
152
153    /// Returns true if the value is unknown.
154    fn is_unknown(self) -> bool {
155        matches!(self, Truth::Unknown)
156    }
157
158    /// AND operation.
159    fn and(self, other: Self) -> Self {
160        match (self, other) {
161            (Truth::True, Truth::True) => Truth::True,
162            (Truth::False, _) | (_, Truth::False) => Truth::False,
163            _ => Truth::Unknown,
164        }
165    }
166
167    /// OR operation.
168    fn or(self, other: Self) -> Self {
169        match (self, other) {
170            (Truth::True, _) | (_, Truth::True) => Truth::True,
171            (Truth::False, Truth::False) => Truth::False,
172            _ => Truth::Unknown,
173        }
174    }
175
176    /// NOT operation.
177    fn not(self) -> Self {
178        match self {
179            Truth::True => Truth::False,
180            Truth::False => Truth::True,
181            Truth::Unknown => Truth::Unknown,
182        }
183    }
184
185    fn merge(self, other: Self) -> Self {
186        match (self, other) {
187            (Truth::True, _) | (_, Truth::True) => Truth::True,
188            (Truth::Unknown, _) | (_, Truth::Unknown) => Truth::Unknown,
189            (Truth::False, Truth::False) => Truth::False,
190        }
191    }
192
193    /// Converts to JSON value.
194    fn to_json<T: Json>(self) -> T {
195        match self {
196            Truth::True => T::bool(true),
197            Truth::False => T::bool(false),
198            Truth::Unknown => T::null(),
199        }
200    }
201}
202
203fn unwrap_datetime_markers<'a, T: JsonRef<'a>>(
204    set: Vec<Cow<'a, T::Owned>>,
205) -> Vec<Cow<'a, T::Owned>> {
206    let mut out = Vec::with_capacity(set.len());
207    for c in set {
208        let owned = c.into_owned();
209        let is_marker = check_marker::<T::Owned>(&owned);
210        if let Some(iso) = is_marker {
211            out.push(Cow::Owned(<T::Owned as crate::json::Json>::from_string(
212                &iso,
213            )));
214        } else {
215            out.push(Cow::Owned(owned));
216        }
217    }
218    out
219}
220
221fn check_marker<J: crate::json::Json>(v: &J) -> Option<String> {
222    crate::datetime::extract_marker(v.as_ref()).map(|(iso, _)| iso)
223}
224
225impl JsonPath {
226    /// Evaluate the JSON path against the given JSON value.
227    pub fn query<'a, T: JsonRef<'a>>(&self, value: T) -> Result<Vec<Cow<'a, T::Owned>>> {
228        Evaluator {
229            root: value,
230            current: value,
231            vars: T::null(),
232            array: T::null(),
233            mode: self.mode,
234            first: false,
235            use_tz: false,
236            silent: false,
237        }
238        .eval_expr_or_predicate(&self.expr)
239        .map(unwrap_datetime_markers::<T>)
240    }
241
242    /// Evaluate the JSON path against the given JSON value with variables.
243    pub fn query_with_vars<'a, T: JsonRef<'a>>(
244        &self,
245        value: T,
246        vars: T,
247    ) -> Result<Vec<Cow<'a, T::Owned>>> {
248        if !vars.is_object() {
249            return Err(Error::VarsNotObject);
250        }
251        Evaluator {
252            root: value,
253            current: value,
254            vars,
255            array: T::null(),
256            mode: self.mode,
257            first: false,
258            use_tz: false,
259            silent: false,
260        }
261        .eval_expr_or_predicate(&self.expr)
262        .map(unwrap_datetime_markers::<T>)
263    }
264
265    /// Evaluate the JSON path against the given JSON value.
266    pub fn query_first<'a, T: JsonRef<'a>>(&self, value: T) -> Result<Option<Cow<'a, T::Owned>>> {
267        Evaluator {
268            root: value,
269            current: value,
270            vars: T::null(),
271            array: T::null(),
272            mode: self.mode,
273            first: true,
274            use_tz: false,
275            silent: false,
276        }
277        .eval_expr_or_predicate(&self.expr)
278        .map(unwrap_datetime_markers::<T>)
279        .map(|set| set.into_iter().next())
280    }
281
282    /// Evaluate the JSON path against the given JSON value with variables.
283    pub fn query_first_with_vars<'a, T: JsonRef<'a>>(
284        &self,
285        value: T,
286        vars: T,
287    ) -> Result<Option<Cow<'a, T::Owned>>> {
288        if !vars.is_object() {
289            return Err(Error::VarsNotObject);
290        }
291        Evaluator {
292            root: value,
293            current: value,
294            vars,
295            array: T::null(),
296            mode: self.mode,
297            first: true,
298            use_tz: false,
299            silent: false,
300        }
301        .eval_expr_or_predicate(&self.expr)
302        .map(unwrap_datetime_markers::<T>)
303        .map(|set| set.into_iter().next())
304    }
305
306    /// Checks whether the JSON path returns any item for the specified JSON value.
307    pub fn exists<'a, T: JsonRef<'a>>(&self, value: T) -> Result<bool> {
308        self.query_first(value).map(|v| v.is_some())
309    }
310
311    /// Checks whether the JSON path returns any item for the specified JSON value,
312    /// with variables.
313    pub fn exists_with_vars<'a, T: JsonRef<'a>>(&self, value: T, vars: T) -> Result<bool> {
314        self.query_first_with_vars(value, vars).map(|v| v.is_some())
315    }
316
317    // ---- Citadel `_tz` entry points -----------------------------------
318
319    pub fn query_tz<'a, T: JsonRef<'a>>(&self, value: T) -> Result<Vec<Cow<'a, T::Owned>>> {
320        Evaluator {
321            root: value,
322            current: value,
323            vars: T::null(),
324            array: T::null(),
325            mode: self.mode,
326            first: false,
327            use_tz: true,
328            silent: false,
329        }
330        .eval_expr_or_predicate(&self.expr)
331        .map(unwrap_datetime_markers::<T>)
332    }
333
334    pub fn query_with_vars_tz<'a, T: JsonRef<'a>>(
335        &self,
336        value: T,
337        vars: T,
338    ) -> Result<Vec<Cow<'a, T::Owned>>> {
339        if !vars.is_object() {
340            return Err(Error::VarsNotObject);
341        }
342        Evaluator {
343            root: value,
344            current: value,
345            vars,
346            array: T::null(),
347            mode: self.mode,
348            first: false,
349            use_tz: true,
350            silent: false,
351        }
352        .eval_expr_or_predicate(&self.expr)
353        .map(unwrap_datetime_markers::<T>)
354    }
355
356    pub fn query_first_tz<'a, T: JsonRef<'a>>(
357        &self,
358        value: T,
359    ) -> Result<Option<Cow<'a, T::Owned>>> {
360        Evaluator {
361            root: value,
362            current: value,
363            vars: T::null(),
364            array: T::null(),
365            mode: self.mode,
366            first: true,
367            use_tz: true,
368            silent: false,
369        }
370        .eval_expr_or_predicate(&self.expr)
371        .map(unwrap_datetime_markers::<T>)
372        .map(|set| set.into_iter().next())
373    }
374
375    pub fn query_first_with_vars_tz<'a, T: JsonRef<'a>>(
376        &self,
377        value: T,
378        vars: T,
379    ) -> Result<Option<Cow<'a, T::Owned>>> {
380        if !vars.is_object() {
381            return Err(Error::VarsNotObject);
382        }
383        Evaluator {
384            root: value,
385            current: value,
386            vars,
387            array: T::null(),
388            mode: self.mode,
389            first: true,
390            use_tz: true,
391            silent: false,
392        }
393        .eval_expr_or_predicate(&self.expr)
394        .map(unwrap_datetime_markers::<T>)
395        .map(|set| set.into_iter().next())
396    }
397
398    pub fn exists_tz<'a, T: JsonRef<'a>>(&self, value: T) -> Result<bool> {
399        self.query_first_tz(value).map(|v| v.is_some())
400    }
401
402    pub fn exists_with_vars_tz<'a, T: JsonRef<'a>>(&self, value: T, vars: T) -> Result<bool> {
403        self.query_first_with_vars_tz(value, vars)
404            .map(|v| v.is_some())
405    }
406
407    // ---- Citadel `_silent` entry points -------------------------------
408
409    pub fn query_silent<'a, T: JsonRef<'a>>(&self, value: T) -> Result<Vec<Cow<'a, T::Owned>>> {
410        Evaluator {
411            root: value,
412            current: value,
413            vars: T::null(),
414            array: T::null(),
415            mode: self.mode,
416            first: false,
417            use_tz: false,
418            silent: true,
419        }
420        .eval_expr_or_predicate(&self.expr)
421        .map(unwrap_datetime_markers::<T>)
422    }
423
424    pub fn query_with_vars_silent<'a, T: JsonRef<'a>>(
425        &self,
426        value: T,
427        vars: T,
428    ) -> Result<Vec<Cow<'a, T::Owned>>> {
429        if !vars.is_object() {
430            return Err(Error::VarsNotObject);
431        }
432        Evaluator {
433            root: value,
434            current: value,
435            vars,
436            array: T::null(),
437            mode: self.mode,
438            first: false,
439            use_tz: false,
440            silent: true,
441        }
442        .eval_expr_or_predicate(&self.expr)
443        .map(unwrap_datetime_markers::<T>)
444    }
445
446    pub fn query_first_silent<'a, T: JsonRef<'a>>(
447        &self,
448        value: T,
449    ) -> Result<Option<Cow<'a, T::Owned>>> {
450        Evaluator {
451            root: value,
452            current: value,
453            vars: T::null(),
454            array: T::null(),
455            mode: self.mode,
456            first: true,
457            use_tz: false,
458            silent: true,
459        }
460        .eval_expr_or_predicate(&self.expr)
461        .map(unwrap_datetime_markers::<T>)
462        .map(|set| set.into_iter().next())
463    }
464
465    pub fn query_first_with_vars_silent<'a, T: JsonRef<'a>>(
466        &self,
467        value: T,
468        vars: T,
469    ) -> Result<Option<Cow<'a, T::Owned>>> {
470        if !vars.is_object() {
471            return Err(Error::VarsNotObject);
472        }
473        Evaluator {
474            root: value,
475            current: value,
476            vars,
477            array: T::null(),
478            mode: self.mode,
479            first: true,
480            use_tz: false,
481            silent: true,
482        }
483        .eval_expr_or_predicate(&self.expr)
484        .map(unwrap_datetime_markers::<T>)
485        .map(|set| set.into_iter().next())
486    }
487
488    pub fn exists_silent<'a, T: JsonRef<'a>>(&self, value: T) -> Result<bool> {
489        self.query_silent(value).map(|set| !set.is_empty())
490    }
491
492    pub fn exists_with_vars_silent<'a, T: JsonRef<'a>>(&self, value: T, vars: T) -> Result<bool> {
493        self.query_with_vars_silent(value, vars)
494            .map(|set| !set.is_empty())
495    }
496}
497
498/// Evaluation context.
499#[derive(Debug, Clone, Copy)]
500struct Evaluator<'a, T: Json + 'a> {
501    /// The current value referenced by `@`.
502    current: T::Borrowed<'a>,
503    /// The root value referenced by `$`.
504    root: T::Borrowed<'a>,
505    /// The innermost array value referenced by `last`.
506    array: T::Borrowed<'a>,
507    /// An object containing the variables referenced by `$var`.
508    vars: T::Borrowed<'a>,
509    /// The path mode.
510    /// If the query is in lax mode, then errors are ignored and the result is empty or unknown.
511    mode: Mode,
512    /// Only return the first result.
513    first: bool,
514    use_tz: bool,
515    silent: bool,
516}
517
518/// Unwrap the result or return an empty result if the evaluator is in lax mode.
519macro_rules! lax {
520    // for `Option`
521    ($self:expr, $expr:expr, $err:expr) => {
522        match $expr {
523            Some(x) => x,
524            None if $self.is_lax() => return Ok(vec![]),
525            None => return Err($err),
526        }
527    };
528    // for `Option`
529    ($self:expr, $expr:expr, $err:expr; continue) => {
530        match $expr {
531            Some(x) => x,
532            None if $self.is_lax() => continue,
533            None => return Err($err),
534        }
535    };
536    // for `Option`
537    ($self:expr, $expr:expr, $err:expr; break) => {
538        match $expr {
539            Some(x) => x,
540            None if $self.is_lax() => break,
541            None => return Err($err),
542        }
543    };
544    // for `Result` in predicate
545    ($self:expr, $expr:expr) => {
546        match $expr {
547            Ok(x) => x,
548            Err(e @ Error::NoVariable(_)) => return Err(e),
549            Err(_) => return Ok(Truth::Unknown),
550        }
551    };
552}
553
554impl<'a, T: Json> Evaluator<'a, T> {
555    /// Returns true if the evaluator is in lax mode.
556    fn is_lax(&self) -> bool {
557        matches!(self.mode, Mode::Lax)
558    }
559
560    /// Returns true if the path engine is permitted to stop evaluation early on the first success.
561    fn is_first(&self) -> bool {
562        self.first && self.is_lax()
563    }
564
565    /// Creates a new evaluator with the given current value.
566    fn with_current<'b>(&self, current: T::Borrowed<'b>) -> Evaluator<'b, T>
567    where
568        'a: 'b,
569    {
570        Evaluator {
571            current,
572            root: T::borrow(self.root),
573            vars: T::borrow(self.vars),
574            array: T::borrow(self.array),
575            mode: self.mode,
576            first: self.first,
577            use_tz: self.use_tz,
578            silent: self.silent,
579        }
580    }
581
582    fn all(&self) -> Self {
583        Evaluator {
584            first: false,
585            ..*self
586        }
587    }
588
589    fn first(&self) -> Self {
590        Evaluator {
591            first: true,
592            ..*self
593        }
594    }
595
596    /// Returns the value of the given variable.
597    fn get_variable(&self, name: &str) -> Result<T::Borrowed<'a>> {
598        self.vars
599            .as_object()
600            // no `vars` input
601            .ok_or_else(|| Error::NoVariable(name.into()))?
602            .get(name)
603            .ok_or_else(|| Error::NoVariable(name.into()))
604    }
605
606    /// Evaluates the expression or predicate.
607    fn eval_expr_or_predicate(&self, expr: &ExprOrPredicate) -> Result<Vec<Cow<'a, T>>> {
608        match expr {
609            ExprOrPredicate::Expr(expr) => self.eval_expr(expr),
610            ExprOrPredicate::Pred(pred) => self
611                .eval_predicate(pred)
612                .map(|t| vec![Cow::Owned(t.to_json())]),
613        }
614    }
615
616    /// Evaluates the predicate.
617    fn eval_predicate(&self, pred: &Predicate) -> Result<Truth> {
618        match pred {
619            Predicate::Compare(op, left, right) => {
620                let left = lax!(self, self.all().eval_expr(left));
621                let right = lax!(self, self.all().eval_expr(right));
622
623                let mut result = Truth::False;
624                // The cross product of these SQL/JSON sequences is formed.
625                // Each SQL/JSON item in one SQL/JSON sequence is compared to each item in the other SQL/JSON sequence.
626                'product: for r in right.iter() {
627                    for l in left.iter() {
628                        let res = eval_compare::<T>(*op, l.as_ref(), r.as_ref(), self.use_tz)?;
629                        if res.is_unknown() && !self.is_lax() {
630                            return Ok(Truth::Unknown);
631                        }
632                        result = result.merge(res);
633                        if result.is_true() && self.is_lax() {
634                            break 'product;
635                        }
636                    }
637                }
638                Ok(result)
639            }
640            Predicate::Exists(expr) => {
641                let set = lax!(self, self.first().eval_expr(expr));
642                // If the result of the path expression is an empty SQL/JSON sequence, then result is False.
643                // Otherwise, result is True.
644                Ok(Truth::from(!set.is_empty()))
645            }
646            Predicate::And(left, right) => {
647                let left = self.eval_predicate(left)?;
648                let right = self.eval_predicate(right)?;
649                Ok(left.and(right))
650            }
651            Predicate::Or(left, right) => {
652                let left = self.eval_predicate(left)?;
653                let right = self.eval_predicate(right)?;
654                Ok(left.or(right))
655            }
656            Predicate::Not(inner) => {
657                let inner = self.eval_predicate(inner)?;
658                Ok(inner.not())
659            }
660            Predicate::IsUnknown(inner) => {
661                let inner = self.eval_predicate(inner)?;
662                Ok(Truth::from(inner.is_unknown()))
663            }
664            Predicate::StartsWith(expr, prefix) => {
665                let set = lax!(self, self.all().eval_expr(expr));
666                let prefix = self.eval_value(prefix)?;
667                let prefix = prefix.as_ref().as_str().unwrap();
668                let mut result = Truth::False;
669                for v in set {
670                    let res = match v.as_ref().as_str() {
671                        Some(s) => s.starts_with(prefix).into(),
672                        None => Truth::Unknown,
673                    };
674                    if res.is_unknown() && !self.is_lax() {
675                        return Ok(Truth::Unknown);
676                    }
677                    result = result.merge(res);
678                    if result.is_true() && self.is_lax() {
679                        break;
680                    }
681                }
682                Ok(result)
683            }
684            Predicate::LikeRegex(expr, regex) => {
685                let set = lax!(self, self.all().eval_expr(expr));
686                let mut result = Truth::False;
687                for v in set {
688                    let res = match v.as_ref().as_str() {
689                        Some(s) => regex.is_match(s).into(),
690                        None => Truth::Unknown,
691                    };
692                    if res.is_unknown() && !self.is_lax() {
693                        return Ok(Truth::Unknown);
694                    }
695                    result = result.merge(res);
696                    if result.is_true() && self.is_lax() {
697                        break;
698                    }
699                }
700                Ok(result)
701            }
702        }
703    }
704
705    /// Evaluates the expression.
706    fn eval_expr(&self, expr: &Expr) -> Result<Vec<Cow<'a, T>>> {
707        match expr {
708            Expr::PathPrimary(primary) => self.eval_path_primary(primary),
709            Expr::Accessor(base, op) => {
710                let set = self.all().eval_expr(base)?;
711                let mut new_set = vec![];
712                for v in &set {
713                    match v {
714                        Cow::Owned(v) => {
715                            let sset = self.with_current(v.as_ref()).eval_accessor_op(op)?;
716                            new_set.extend(
717                                // the returned set requires lifetime 'a,
718                                // however, elements in `sset` only have lifetime 'b < 'v = 'set < 'a
719                                // therefore, we need to convert them to owned values
720                                sset.into_iter().map(|cow| Cow::Owned(cow.into_owned())),
721                            )
722                        }
723                        Cow::Borrowed(v) => {
724                            new_set.extend(self.with_current(*v).eval_accessor_op(op)?);
725                        }
726                    }
727                    if self.is_first() && !new_set.is_empty() {
728                        break;
729                    }
730                }
731                Ok(new_set)
732            }
733            Expr::UnaryOp(op, expr) => {
734                let set = self.eval_expr(expr)?;
735                let mut new_set = Vec::with_capacity(set.len());
736                let item_skip = self.silent && self.is_lax();
737                'outer: for v in set {
738                    let v = v.as_ref();
739                    if v.is_array() && self.is_lax() {
740                        for v in v.as_array().unwrap().list() {
741                            match eval_unary_op(*op, v) {
742                                Ok(r) => new_set.push(Cow::Owned(r)),
743                                Err(_) if item_skip => break 'outer,
744                                Err(e) => return Err(e),
745                            }
746                        }
747                    } else {
748                        match eval_unary_op(*op, v) {
749                            Ok(r) => new_set.push(Cow::Owned(r)),
750                            Err(e) if item_skip && e.can_silent() => continue,
751                            Err(e) => return Err(e),
752                        }
753                    }
754                }
755                Ok(new_set)
756            }
757            Expr::BinaryOp(op, left, right) => {
758                let left = self.eval_expr(left)?;
759                let right = self.eval_expr(right)?;
760                if left.len() != 1 {
761                    return Err(Error::LeftOperandNotNumeric(*op));
762                }
763                if right.len() != 1 {
764                    return Err(Error::RightOperandNotNumeric(*op));
765                }
766                // unwrap left if it is an array
767                let left = if self.is_lax() {
768                    if let Some(array) = left[0].as_ref().as_array() {
769                        if array.len() != 1 {
770                            return Err(Error::LeftOperandNotNumeric(*op));
771                        }
772                        array.get(0).unwrap()
773                    } else {
774                        left[0].as_ref()
775                    }
776                } else {
777                    left[0].as_ref()
778                };
779                // unwrap right if it is an array
780                let right = if self.is_lax() {
781                    if let Some(array) = right[0].as_ref().as_array() {
782                        if array.len() != 1 {
783                            return Err(Error::RightOperandNotNumeric(*op));
784                        }
785                        array.get(0).unwrap()
786                    } else {
787                        right[0].as_ref()
788                    }
789                } else {
790                    right[0].as_ref()
791                };
792                Ok(vec![Cow::Owned(eval_binary_op(*op, left, right)?)])
793            }
794        }
795    }
796
797    /// Evaluates the path primary.
798    fn eval_path_primary(&self, primary: &PathPrimary) -> Result<Vec<Cow<'a, T>>> {
799        match primary {
800            PathPrimary::Root => Ok(vec![Cow::Borrowed(self.root)]),
801            PathPrimary::Current => Ok(vec![Cow::Borrowed(self.current)]),
802            PathPrimary::Value(v) => Ok(vec![self.eval_value(v)?]),
803            PathPrimary::Last => {
804                let array = self
805                    .array
806                    .as_array()
807                    .expect("LAST is allowed only in array subscripts");
808                Ok(vec![Cow::Owned(T::from_i64(array.len() as i64 - 1))])
809            }
810            PathPrimary::ExprOrPred(expr) => self.eval_expr_or_predicate(expr),
811        }
812    }
813
814    /// Evaluates the accessor operator.
815    fn eval_accessor_op(&self, op: &AccessorOp) -> Result<Vec<Cow<'a, T>>> {
816        match op {
817            AccessorOp::MemberWildcard => self.eval_member_wildcard(),
818            AccessorOp::DescendantMemberWildcard(levels) => {
819                self.eval_descendant_member_wildcard(levels)
820            }
821            AccessorOp::ElementWildcard => self.eval_element_wildcard(),
822            AccessorOp::Member(name) => self.eval_member(name),
823            AccessorOp::Element(indices) => self.eval_element_accessor(indices),
824            AccessorOp::FilterExpr(pred) => self.eval_filter_expr(pred),
825            AccessorOp::Method(method) => self.eval_method(method),
826        }
827    }
828
829    fn eval_member_wildcard(&self) -> Result<Vec<Cow<'a, T>>> {
830        let set = match self.current.as_array() {
831            Some(array) if self.is_lax() => array.list(),
832            _ => vec![self.current],
833        };
834        let mut new_set = vec![];
835        for v in set {
836            let object = lax!(self, v.as_object(), Error::WildcardMemberAccess);
837            for v in object.list_value() {
838                new_set.push(Cow::Borrowed(v));
839            }
840        }
841        Ok(new_set)
842    }
843
844    fn eval_descendant_member_wildcard(&self, levels: &LevelRange) -> Result<Vec<Cow<'a, T>>> {
845        let mut set = match self.current.as_array() {
846            Some(array) if self.is_lax() => array.list(),
847            _ => vec![self.current],
848        };
849        // expand all levels
850        // level i is set[level_start[i] .. level_start[i+1]]
851        let mut level_start = vec![0, set.len()];
852        for l in 1..=levels.end() {
853            let last_level_range = level_start[l as usize - 1]..level_start[l as usize];
854            for i in last_level_range {
855                if let Some(object) = set[i].as_object() {
856                    set.extend(object.list_value());
857                }
858            }
859            if set.len() == level_start[l as usize] {
860                // this level is empty
861                break;
862            }
863            level_start.push(set.len());
864        }
865        // return the set in level range
866        let last_level = level_start.len() - 2;
867        let level_range = levels.to_range(last_level);
868        let set_range = level_start[level_range.start]..level_start[level_range.end];
869        let new_set = set[set_range].iter().cloned().map(Cow::Borrowed).collect();
870        Ok(new_set)
871    }
872
873    fn eval_element_wildcard(&self) -> Result<Vec<Cow<'a, T>>> {
874        if !self.current.is_array() && self.is_lax() {
875            // wrap the current value into an array
876            return Ok(vec![Cow::Borrowed(self.current)]);
877        }
878        let array = lax!(self, self.current.as_array(), Error::WildcardArrayAccess);
879        if self.is_first() && !self.silent {
880            return Ok(array.get(0).map(Cow::Borrowed).into_iter().collect());
881        }
882        Ok(array.list().into_iter().map(Cow::Borrowed).collect())
883    }
884
885    /// Evaluates the member accessor.
886    fn eval_member(&self, name: &str) -> Result<Vec<Cow<'a, T>>> {
887        let set = match self.current.as_array() {
888            Some(array) if self.is_lax() => array.list(),
889            _ => vec![self.current],
890        };
891        let mut new_set = vec![];
892        for v in set {
893            let object = match v.as_object() {
894                Some(o) => o,
895                None if self.is_lax() => return Ok(vec![]),
896                None => return Err(Error::MemberAccess),
897            };
898            let elem = match object.get(name) {
899                Some(e) => e,
900                None if self.silent && self.first => continue,
901                None if self.is_lax() => return Ok(vec![]),
902                None => return Err(Error::NoKey(name.into())),
903            };
904            new_set.push(Cow::Borrowed(elem));
905        }
906        Ok(new_set)
907    }
908
909    /// Evaluates the element accessor.
910    fn eval_element_accessor(&self, indices: &[ArrayIndex]) -> Result<Vec<Cow<'a, T>>> {
911        // wrap the scalar value into an array in lax mode
912        enum ArrayOrScalar<'a, T: JsonRef<'a>> {
913            Array(T::Array),
914            Scalar(T),
915        }
916        impl<'a, T: JsonRef<'a>> ArrayOrScalar<'a, T> {
917            fn get(&self, index: usize) -> Option<T> {
918                match self {
919                    ArrayOrScalar::Array(array) => array.get(index),
920                    ArrayOrScalar::Scalar(scalar) if index == 0 => Some(*scalar),
921                    _ => None,
922                }
923            }
924        }
925        let array = match self.current.as_array() {
926            Some(array) => ArrayOrScalar::Array(array),
927            None if self.is_lax() => ArrayOrScalar::Scalar(self.current),
928            None => return Err(Error::ArrayAccess),
929        };
930        let mut elems = Vec::with_capacity(indices.len());
931        for index in indices {
932            let eval_index = |expr: &Expr| {
933                // errors in this closure can not be ignored
934                let set = Self {
935                    // update `array` context
936                    array: self.current,
937                    ..*self
938                }
939                .eval_expr(expr)?;
940                if set.len() != 1 {
941                    return Err(Error::ArrayIndexNotNumeric);
942                }
943                set[0]
944                    .as_ref()
945                    .as_number()
946                    .ok_or(Error::ArrayIndexNotNumeric)?
947                    .to_i64()
948                    .ok_or(Error::ArrayIndexOutOfRange)
949            };
950            match index {
951                ArrayIndex::Index(expr) => {
952                    let index = eval_index(expr)?;
953                    let index =
954                        lax!(self, index.try_into().ok(), Error::ArrayIndexOutOfBounds; continue);
955                    let elem = lax!(self, array.get(index), Error::ArrayIndexOutOfBounds; continue);
956                    elems.push(Cow::Borrowed(elem));
957                }
958                ArrayIndex::Slice(begin, end) => {
959                    let begin = eval_index(begin)?;
960                    let end = eval_index(end)?;
961                    let begin: usize = match begin.try_into() {
962                        Ok(i) => i,
963                        Err(_) if self.is_lax() => 0,
964                        Err(_) => return Err(Error::ArrayIndexOutOfBounds),
965                    };
966                    let end: usize =
967                        lax!(self, end.try_into().ok(), Error::ArrayIndexOutOfBounds; continue);
968                    if begin > end && !self.is_lax() {
969                        return Err(Error::ArrayIndexOutOfBounds);
970                    }
971                    for i in begin..=end {
972                        let elem = lax!(self, array.get(i), Error::ArrayIndexOutOfBounds; break);
973                        elems.push(Cow::Borrowed(elem));
974                    }
975                }
976            }
977        }
978        Ok(elems)
979    }
980
981    fn eval_filter_expr(&self, pred: &Predicate) -> Result<Vec<Cow<'a, T>>> {
982        let set = match self.current.as_array() {
983            Some(array) if self.is_lax() => array.list(),
984            _ => vec![self.current],
985        };
986        let mut new_set = vec![];
987        for v in set {
988            if self.with_current(v).eval_predicate(pred)?.is_true() {
989                new_set.push(Cow::Borrowed(v));
990                if self.is_first() {
991                    break;
992                }
993            }
994        }
995        Ok(new_set)
996    }
997
998    /// Evaluates the item method.
999    fn eval_method(&self, method: &Method) -> Result<Vec<Cow<'a, T>>> {
1000        // unwrap the current value if it is an array
1001        if self.current.is_array()
1002            && self.is_lax()
1003            && !matches!(method, Method::Size | Method::Type)
1004        {
1005            let mut new_set = vec![];
1006            for v in self.current.as_array().unwrap().list() {
1007                new_set.extend(self.with_current(v).eval_method(method)?);
1008            }
1009            return Ok(new_set);
1010        }
1011        match method {
1012            Method::Type => self.eval_method_type().map(|v| vec![v]),
1013            Method::Size => self.eval_method_size().map(|v| vec![v]),
1014            Method::Double => self.eval_method_double().map(|v| vec![v]),
1015            Method::Ceiling => self.eval_method_ceiling().map(|v| vec![v]),
1016            Method::Floor => self.eval_method_floor().map(|v| vec![v]),
1017            Method::Abs => self.eval_method_abs().map(|v| vec![v]),
1018            Method::Keyvalue => self.eval_method_keyvalue(),
1019            Method::Datetime { template } => self
1020                .eval_method_datetime(template.as_deref())
1021                .map(|v| vec![v]),
1022        }
1023    }
1024
1025    fn eval_method_datetime(&self, template: Option<&str>) -> Result<Cow<'a, T>> {
1026        let input = self.current.as_str().ok_or(Error::DatetimeNotString)?;
1027        let parsed = match template {
1028            None => crate::datetime::iso::try_13_formats(input)?,
1029            Some(t) => crate::datetime::template::parse_apply(input, t)?,
1030        };
1031        Ok(Cow::Owned(parsed.to_marker_object::<T>()))
1032    }
1033
1034    fn eval_method_type(&self) -> Result<Cow<'a, T>> {
1035        if let Some((_, kind)) = crate::datetime::extract_marker(self.current) {
1036            return Ok(Cow::Owned(T::from_string(kind.as_str())));
1037        }
1038        let s = if self.current.is_null() {
1039            "null"
1040        } else if self.current.is_bool() {
1041            "boolean"
1042        } else if self.current.is_number() {
1043            "number"
1044        } else if self.current.is_string() {
1045            "string"
1046        } else if self.current.is_array() {
1047            "array"
1048        } else if self.current.is_object() {
1049            "object"
1050        } else {
1051            unreachable!()
1052        };
1053        Ok(Cow::Owned(T::from_string(s)))
1054    }
1055
1056    fn eval_method_size(&self) -> Result<Cow<'a, T>> {
1057        let size = if let Some(array) = self.current.as_array() {
1058            // The size of an SQL/JSON array is the number of elements in the array.
1059            array.len()
1060        } else if self.is_lax() {
1061            // The size of an SQL/JSON object or a scalar is 1.
1062            1
1063        } else {
1064            return Err(Error::SizeNotArray);
1065        };
1066        Ok(Cow::Owned(T::from_u64(size as u64)))
1067    }
1068
1069    fn eval_method_double(&self) -> Result<Cow<'a, T>> {
1070        if let Some(s) = self.current.as_str() {
1071            let n = s.parse::<f64>().map_err(|_| Error::InvalidDouble)?;
1072            if n.is_infinite() || n.is_nan() {
1073                return Err(Error::InvalidDouble);
1074            }
1075            Ok(Cow::Owned(T::from_f64(n)))
1076        } else if self.current.is_number() {
1077            let n = self
1078                .current
1079                .as_number()
1080                .and_then(|n| n.as_f64())
1081                .ok_or(Error::DoubleOutOfRange)?;
1082            if n.is_infinite() || n.is_nan() {
1083                return Err(Error::DoubleOutOfRange);
1084            }
1085            Ok(Cow::Borrowed(self.current))
1086        } else {
1087            Err(Error::DoubleTypeError)
1088        }
1089    }
1090
1091    fn eval_method_ceiling(&self) -> Result<Cow<'a, T>> {
1092        let n = self
1093            .current
1094            .as_number()
1095            .ok_or(Error::MethodNotNumeric("ceiling"))?;
1096        Ok(Cow::Owned(T::from_number(n.ceil())))
1097    }
1098
1099    fn eval_method_floor(&self) -> Result<Cow<'a, T>> {
1100        let n = self
1101            .current
1102            .as_number()
1103            .ok_or(Error::MethodNotNumeric("floor"))?;
1104        Ok(Cow::Owned(T::from_number(n.floor())))
1105    }
1106
1107    fn eval_method_abs(&self) -> Result<Cow<'a, T>> {
1108        let n = self
1109            .current
1110            .as_number()
1111            .ok_or(Error::MethodNotNumeric("abs"))?;
1112        Ok(Cow::Owned(T::from_number(n.abs())))
1113    }
1114
1115    fn eval_method_keyvalue(&self) -> Result<Vec<Cow<'a, T>>> {
1116        use std::hash::Hasher;
1117        let object = self.current.as_object().ok_or(Error::KeyValueNotObject)?;
1118        let mut hasher = rustc_hash::FxHasher::default();
1119        let entries: Vec<_> = object.list();
1120        for (k, _) in &entries {
1121            hasher.write(k.as_bytes());
1122            hasher.write_u8(0);
1123        }
1124        let id = hasher.finish() as i64;
1125        Ok(entries
1126            .into_iter()
1127            .map(|(k, v)| {
1128                Cow::Owned(T::object([
1129                    ("key", T::from_string(k)),
1130                    ("value", v.to_owned()),
1131                    ("id", T::from_i64(id)),
1132                ]))
1133            })
1134            .collect())
1135    }
1136
1137    /// Evaluates the scalar value.
1138    fn eval_value(&self, value: &Value) -> Result<Cow<'a, T>> {
1139        Ok(match value {
1140            Value::Null => Cow::Owned(T::null()),
1141            Value::Boolean(b) => Cow::Owned(T::bool(*b)),
1142            Value::Number(n) => Cow::Owned(T::from_number(n.clone())),
1143            Value::String(s) => Cow::Owned(T::from_string(s)),
1144            Value::Variable(v) => Cow::Borrowed(self.get_variable(v)?),
1145        })
1146    }
1147}
1148
1149/// Compare two values.
1150///
1151/// Return unknown if the values are not comparable.
1152fn eval_compare<T: Json>(
1153    op: CompareOp,
1154    left: T::Borrowed<'_>,
1155    right: T::Borrowed<'_>,
1156    use_tz: bool,
1157) -> Result<Truth> {
1158    use CompareOp::*;
1159    let left_marker = crate::datetime::extract_marker(left);
1160    let right_marker = crate::datetime::extract_marker(right);
1161    if left_marker.is_some() || right_marker.is_some() {
1162        return eval_compare_datetime(op, left_marker, right_marker, use_tz);
1163    }
1164    // arrays and objects are not comparable
1165    if left.is_array() || left.is_object() || right.is_array() || right.is_object() {
1166        return Ok(Truth::Unknown);
1167    }
1168    if left.is_null() && right.is_null() {
1169        return Ok(compare_ord(op, (), ()).into());
1170    }
1171    if left.is_null() || right.is_null() {
1172        return Ok((op == CompareOp::Ne).into());
1173    }
1174    if let (Some(left), Some(right)) = (left.as_bool(), right.as_bool()) {
1175        return Ok(compare_ord(op, left, right).into());
1176    }
1177    if let (Some(left), Some(right)) = (left.as_number(), right.as_number()) {
1178        return Ok(match op {
1179            Eq => left.equal(&right),
1180            Ne => !left.equal(&right),
1181            Gt => right.less_than(&left),
1182            Ge => !left.less_than(&right),
1183            Lt => left.less_than(&right),
1184            Le => !right.less_than(&left),
1185        }
1186        .into());
1187    }
1188    if let (Some(left), Some(right)) = (left.as_str(), right.as_str()) {
1189        return Ok(compare_ord(op, left, right).into());
1190    }
1191    Ok(Truth::Unknown)
1192}
1193
1194fn eval_compare_datetime(
1195    op: CompareOp,
1196    left: Option<(String, crate::datetime::DatetimeKind)>,
1197    right: Option<(String, crate::datetime::DatetimeKind)>,
1198    use_tz: bool,
1199) -> Result<Truth> {
1200    use crate::datetime::DatetimeKind as K;
1201    let (Some((l_iso, l_kind)), Some((r_iso, r_kind))) = (left, right) else {
1202        return Ok(Truth::Unknown);
1203    };
1204    let needs_tz = match (l_kind, r_kind) {
1205        (a, b) if a == b => false,
1206        (K::Date, K::Timestamp) | (K::Timestamp, K::Date) => false,
1207        (K::TimestampTz, _) | (_, K::TimestampTz) => true,
1208        (K::TimeTz, _) | (_, K::TimeTz) => true,
1209        (K::Date, K::Time) | (K::Time, K::Date) => return Ok(Truth::Unknown),
1210        (K::Timestamp, K::Time) | (K::Time, K::Timestamp) => return Ok(Truth::Unknown),
1211        _ => return Ok(Truth::Unknown),
1212    };
1213    if needs_tz && !use_tz {
1214        let (from, target_kind) = if matches!(l_kind, K::TimestampTz | K::TimeTz) {
1215            (r_kind, l_kind)
1216        } else {
1217            (l_kind, r_kind)
1218        };
1219        let has_date = matches!(l_kind, K::Date | K::Timestamp | K::TimestampTz)
1220            || matches!(r_kind, K::Date | K::Timestamp | K::TimestampTz);
1221        let to = if has_date {
1222            "timestamptz"
1223        } else {
1224            target_kind.as_tag()
1225        };
1226        return Err(Error::DatetimeConvertWithoutTz(
1227            from.as_tag().into(),
1228            to.into(),
1229        ));
1230    }
1231    let ord = match compare_datetime_kinds(&l_iso, l_kind, &r_iso, r_kind, use_tz) {
1232        Some(o) => o,
1233        None => return Ok(Truth::Unknown),
1234    };
1235    use CompareOp::*;
1236    Ok(match op {
1237        Eq => ord.is_eq(),
1238        Ne => !ord.is_eq(),
1239        Gt => ord.is_gt(),
1240        Ge => !ord.is_lt(),
1241        Lt => ord.is_lt(),
1242        Le => !ord.is_gt(),
1243    }
1244    .into())
1245}
1246
1247fn compare_datetime_kinds(
1248    l_iso: &str,
1249    l_kind: crate::datetime::DatetimeKind,
1250    r_iso: &str,
1251    r_kind: crate::datetime::DatetimeKind,
1252    use_tz: bool,
1253) -> Option<std::cmp::Ordering> {
1254    use crate::datetime::DatetimeKind as K;
1255    if l_kind == r_kind {
1256        match l_kind {
1257            K::Date | K::Timestamp => return cmp_date_or_ts(l_iso, l_kind, r_iso, r_kind),
1258            K::Time => return Some(l_iso.cmp(r_iso)),
1259            K::TimestampTz => {
1260                let l_inst = to_instant(l_iso, l_kind)?;
1261                let r_inst = to_instant(r_iso, r_kind)?;
1262                return Some(l_inst.cmp(&r_inst));
1263            }
1264            K::TimeTz => return cmp_timetz_pair(l_iso, l_kind, r_iso, r_kind),
1265        }
1266    }
1267    if matches!(
1268        (l_kind, r_kind),
1269        (K::Date, K::Timestamp) | (K::Timestamp, K::Date)
1270    ) {
1271        return cmp_date_or_ts(l_iso, l_kind, r_iso, r_kind);
1272    }
1273    let l_is_time = matches!(l_kind, K::Time | K::TimeTz);
1274    let r_is_time = matches!(r_kind, K::Time | K::TimeTz);
1275    let l_is_dated = matches!(l_kind, K::Date | K::Timestamp | K::TimestampTz);
1276    let r_is_dated = matches!(r_kind, K::Date | K::Timestamp | K::TimestampTz);
1277    if (l_is_time && r_is_dated) || (l_is_dated && r_is_time) {
1278        return None;
1279    }
1280    // Time <-> TimeTz: PG casts the Time to TimeTz at session TZ then
1281    // compares as TimeTz (primary by UTC instant, tiebreak by offset).
1282    if matches!(
1283        (l_kind, r_kind),
1284        (K::Time, K::TimeTz) | (K::TimeTz, K::Time) | (K::TimeTz, K::TimeTz) | (K::Time, K::Time)
1285    ) {
1286        if !use_tz
1287            && matches!(
1288                (l_kind, r_kind),
1289                (K::Time, K::TimeTz) | (K::TimeTz, K::Time)
1290            )
1291        {
1292            return None;
1293        }
1294        return cmp_timetz_pair(l_iso, l_kind, r_iso, r_kind);
1295    }
1296    // Date/Timestamp/TimestampTz cross-comparisons: same general rule.
1297    if !use_tz {
1298        return None;
1299    }
1300    // Wide-year (> 4 digits) exceeds jiff's range; fall back to numeric
1301    // Y/M/D + lexical time-suffix compare. Pathological "both wide-year
1302    // TimestampTz with asymmetric offsets at same Y/M/D" is out of scope.
1303    if has_wide_year(l_iso) || has_wide_year(r_iso) {
1304        return cmp_date_or_ts(l_iso, l_kind, r_iso, r_kind);
1305    }
1306    let l_inst = to_instant(l_iso, l_kind)?;
1307    let r_inst = to_instant(r_iso, r_kind)?;
1308    Some(l_inst.cmp(&r_inst))
1309}
1310
1311fn has_wide_year(iso: &str) -> bool {
1312    match iso.find('-') {
1313        Some(idx) => idx > 4,
1314        None => false,
1315    }
1316}
1317
1318fn cmp_date_or_ts(
1319    l_iso: &str,
1320    l_kind: crate::datetime::DatetimeKind,
1321    r_iso: &str,
1322    r_kind: crate::datetime::DatetimeKind,
1323) -> Option<std::cmp::Ordering> {
1324    use crate::datetime::DatetimeKind as K;
1325    let (ly, lm, ld, l_time) = parse_ymd_and_time(l_iso)?;
1326    let (ry, rm, rd, r_time) = parse_ymd_and_time(r_iso)?;
1327    match (ly, lm, ld).cmp(&(ry, rm, rd)) {
1328        std::cmp::Ordering::Equal => {}
1329        ord => return Some(ord),
1330    }
1331    let l_t = if l_kind == K::Date {
1332        "T00:00:00"
1333    } else {
1334        l_time
1335    };
1336    let r_t = if r_kind == K::Date {
1337        "T00:00:00"
1338    } else {
1339        r_time
1340    };
1341    Some(l_t.cmp(r_t))
1342}
1343
1344fn parse_ymd_and_time(iso: &str) -> Option<(u64, u32, u32, &str)> {
1345    let dash1 = iso.find('-')?;
1346    let year: u64 = iso[..dash1].parse().ok()?;
1347    let rest = &iso[dash1 + 1..];
1348    let dash2 = rest.find('-')?;
1349    let month: u32 = rest[..dash2].parse().ok()?;
1350    let after_dash = &rest[dash2 + 1..];
1351    let day_end = after_dash
1352        .find(|c: char| !c.is_ascii_digit())
1353        .unwrap_or(after_dash.len());
1354    let day: u32 = after_dash[..day_end].parse().ok()?;
1355    let time_part = &after_dash[day_end..];
1356    Some((year, month, day, time_part))
1357}
1358
1359fn cmp_timetz_pair(
1360    l_iso: &str,
1361    l_kind: crate::datetime::DatetimeKind,
1362    r_iso: &str,
1363    r_kind: crate::datetime::DatetimeKind,
1364) -> Option<std::cmp::Ordering> {
1365    let (l_wall, l_off) = parse_time_pair(l_iso, l_kind)?;
1366    let (r_wall, r_off) = parse_time_pair(r_iso, r_kind)?;
1367    let l_utc = l_wall - l_off;
1368    let r_utc = r_wall - r_off;
1369    let ord = l_utc.cmp(&r_utc);
1370    if ord != std::cmp::Ordering::Equal {
1371        return Some(ord);
1372    }
1373    Some(r_off.cmp(&l_off))
1374}
1375
1376fn parse_time_pair(iso: &str, kind: crate::datetime::DatetimeKind) -> Option<(i64, i64)> {
1377    use crate::datetime::DatetimeKind as K;
1378    match kind {
1379        K::Time => {
1380            let t: jiff::civil::Time = iso.parse().ok()?;
1381            Some((time_to_seconds(t), 0))
1382        }
1383        K::TimeTz => {
1384            let (time_part, off_part) = split_offset(iso)?;
1385            let t: jiff::civil::Time = time_part.parse().ok()?;
1386            let off = parse_offset(off_part)?.seconds() as i64;
1387            Some((time_to_seconds(t), off))
1388        }
1389        _ => None,
1390    }
1391}
1392
1393fn time_to_seconds(t: jiff::civil::Time) -> i64 {
1394    i64::from(t.hour()) * 3600 + i64::from(t.minute()) * 60 + i64::from(t.second())
1395}
1396
1397fn to_instant(iso: &str, kind: crate::datetime::DatetimeKind) -> Option<jiff::Timestamp> {
1398    use crate::datetime::DatetimeKind as K;
1399    match kind {
1400        K::Date => {
1401            let d: jiff::civil::Date = iso.parse().ok()?;
1402            let dt = d.at(0, 0, 0, 0);
1403            dt.to_zoned(jiff::tz::TimeZone::UTC)
1404                .ok()
1405                .map(|z| z.timestamp())
1406        }
1407        K::Time => {
1408            // Promote to today's date at this time, UTC.
1409            let t: jiff::civil::Time = iso.parse().ok()?;
1410            let today = jiff::civil::date(1970, 1, 1);
1411            let dt = today.at(t.hour(), t.minute(), t.second(), t.subsec_nanosecond());
1412            dt.to_zoned(jiff::tz::TimeZone::UTC)
1413                .ok()
1414                .map(|z| z.timestamp())
1415        }
1416        K::TimeTz => {
1417            // ISO form "HH:MM:SS+HH:MM" — split offset and parse time.
1418            let (time_part, off_part) = split_offset(iso)?;
1419            let t: jiff::civil::Time = time_part.parse().ok()?;
1420            let off = parse_offset(off_part)?;
1421            let today = jiff::civil::date(1970, 1, 1);
1422            let dt = today.at(t.hour(), t.minute(), t.second(), t.subsec_nanosecond());
1423            let zoned = dt.to_zoned(jiff::tz::TimeZone::fixed(off)).ok()?;
1424            Some(zoned.timestamp())
1425        }
1426        K::Timestamp => {
1427            let dt: jiff::civil::DateTime = iso.parse().ok()?;
1428            dt.to_zoned(jiff::tz::TimeZone::UTC)
1429                .ok()
1430                .map(|z| z.timestamp())
1431        }
1432        K::TimestampTz => {
1433            let (dt_part, off_part) = split_offset(iso)?;
1434            let dt: jiff::civil::DateTime = dt_part.parse().ok()?;
1435            let off = parse_offset(off_part)?;
1436            let zoned = dt.to_zoned(jiff::tz::TimeZone::fixed(off)).ok()?;
1437            Some(zoned.timestamp())
1438        }
1439    }
1440}
1441
1442fn split_offset(s: &str) -> Option<(&str, &str)> {
1443    // Look for last `+`/`-` (skipping the leading negative-year sign).
1444    let bytes = s.as_bytes();
1445    for i in (1..bytes.len()).rev() {
1446        if bytes[i] == b'+' || bytes[i] == b'-' {
1447            return Some((&s[..i], &s[i..]));
1448        }
1449    }
1450    None
1451}
1452
1453fn parse_offset(s: &str) -> Option<jiff::tz::Offset> {
1454    // "+HH:MM" or "-HH:MM" — already normalized by our renderer.
1455    let bytes = s.as_bytes();
1456    if bytes.len() != 6 || (bytes[0] != b'+' && bytes[0] != b'-') {
1457        return None;
1458    }
1459    let sign = if bytes[0] == b'-' { -1 } else { 1 };
1460    let h: i8 = std::str::from_utf8(&bytes[1..3]).ok()?.parse().ok()?;
1461    let m: i8 = std::str::from_utf8(&bytes[4..6]).ok()?.parse().ok()?;
1462    let total_min = sign * (i32::from(h) * 60 + i32::from(m));
1463    jiff::tz::Offset::from_seconds(total_min * 60).ok()
1464}
1465
1466/// Evaluate the unary operator.
1467fn eval_unary_op<T: Json>(op: UnaryOp, value: T::Borrowed<'_>) -> Result<T> {
1468    let n = value.as_number().ok_or(Error::UnaryOperandNotNumeric(op))?;
1469    Ok(match op {
1470        UnaryOp::Plus => value.to_owned(),
1471        UnaryOp::Minus => T::from_number(n.neg()),
1472    })
1473}
1474
1475/// Evaluate the binary operator.
1476fn eval_binary_op<T: Json>(
1477    op: BinaryOp,
1478    left: T::Borrowed<'_>,
1479    right: T::Borrowed<'_>,
1480) -> Result<T> {
1481    let left = left.as_number().ok_or(Error::LeftOperandNotNumeric(op))?;
1482    let right = right.as_number().ok_or(Error::RightOperandNotNumeric(op))?;
1483    Ok(T::from_number(match op {
1484        BinaryOp::Add => left.add(&right),
1485        BinaryOp::Sub => left.sub(&right),
1486        BinaryOp::Mul => left.mul(&right),
1487        BinaryOp::Div => left.div(&right)?,
1488        BinaryOp::Rem => left.rem(&right)?,
1489    }))
1490}
1491
1492/// Compare two values that implement `Ord`.
1493fn compare_ord<T: Ord>(op: CompareOp, left: T, right: T) -> bool {
1494    use CompareOp::*;
1495    match op {
1496        Eq => left == right,
1497        Ne => left != right,
1498        Gt => left > right,
1499        Ge => left >= right,
1500        Lt => left < right,
1501        Le => left <= right,
1502    }
1503}
1504
1505/// Extension methods for `Number`.
1506pub trait NumberExt: Sized {
1507    fn equal(&self, other: &Self) -> bool;
1508    fn less_than(&self, other: &Self) -> bool;
1509    fn neg(&self) -> Self;
1510    fn add(&self, other: &Self) -> Self;
1511    fn sub(&self, other: &Self) -> Self;
1512    fn mul(&self, other: &Self) -> Self;
1513    fn div(&self, other: &Self) -> Result<Self>;
1514    fn rem(&self, other: &Self) -> Result<Self>;
1515    fn ceil(&self) -> Self;
1516    fn floor(&self) -> Self;
1517    fn abs(&self) -> Self;
1518    fn to_i64(&self) -> Option<i64>;
1519}
1520
1521impl NumberExt for Number {
1522    fn equal(&self, other: &Self) -> bool {
1523        // The original `Eq` implementation of `Number` does not work
1524        // if the two numbers have different types. (i64, u64, f64)
1525        self.as_f64().unwrap() == other.as_f64().unwrap()
1526    }
1527
1528    fn less_than(&self, other: &Self) -> bool {
1529        self.as_f64().unwrap() < other.as_f64().unwrap()
1530    }
1531
1532    fn neg(&self) -> Self {
1533        if let Some(n) = self.as_i64() {
1534            Number::from(-n)
1535        } else if let Some(n) = self.as_f64() {
1536            Number::from_f64(-n).unwrap()
1537        } else {
1538            // `as_f64` should always return a value
1539            unreachable!()
1540        }
1541    }
1542
1543    fn add(&self, other: &Self) -> Self {
1544        if let (Some(a), Some(b)) = (self.as_i64(), other.as_i64()) {
1545            Number::from(a + b)
1546        } else if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
1547            Number::from_f64(a + b).unwrap()
1548        } else {
1549            unreachable!()
1550        }
1551    }
1552
1553    fn sub(&self, other: &Self) -> Self {
1554        if let (Some(a), Some(b)) = (self.as_i64(), other.as_i64()) {
1555            Number::from(a - b)
1556        } else if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
1557            Number::from_f64(a - b).unwrap()
1558        } else {
1559            unreachable!()
1560        }
1561    }
1562
1563    fn mul(&self, other: &Self) -> Self {
1564        if let (Some(a), Some(b)) = (self.as_i64(), other.as_i64()) {
1565            Number::from(a * b)
1566        } else if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
1567            Number::from_f64(a * b).unwrap()
1568        } else {
1569            unreachable!()
1570        }
1571    }
1572
1573    fn div(&self, other: &Self) -> Result<Self> {
1574        if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
1575            if b == 0.0 {
1576                return Err(Error::DivisionByZero);
1577            }
1578            Ok(Number::from_f64(a / b).unwrap())
1579        } else {
1580            unreachable!()
1581        }
1582    }
1583
1584    fn rem(&self, other: &Self) -> Result<Self> {
1585        if let (Some(a), Some(b)) = (self.as_i64(), other.as_i64()) {
1586            if b == 0 {
1587                return Err(Error::DivisionByZero);
1588            }
1589            return Ok(Number::from(a % b));
1590        }
1591        if let Some(r) = exact_decimal_rem(self, other) {
1592            return Ok(r);
1593        }
1594        if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
1595            if b == 0.0 {
1596                return Err(Error::DivisionByZero);
1597            }
1598            Ok(Number::from_f64(a % b).unwrap())
1599        } else {
1600            unreachable!()
1601        }
1602    }
1603
1604    fn ceil(&self) -> Self {
1605        if self.is_f64() {
1606            Number::from(self.as_f64().unwrap().ceil() as i64)
1607        } else {
1608            self.clone()
1609        }
1610    }
1611
1612    fn floor(&self) -> Self {
1613        if self.is_f64() {
1614            Number::from(self.as_f64().unwrap().floor() as i64)
1615        } else {
1616            self.clone()
1617        }
1618    }
1619
1620    fn abs(&self) -> Self {
1621        if let Some(n) = self.as_i64() {
1622            Number::from(n.abs())
1623        } else if let Some(n) = self.as_f64() {
1624            Number::from_f64(n.abs()).unwrap()
1625        } else {
1626            unreachable!()
1627        }
1628    }
1629
1630    /// Converts to json integer if possible.
1631    /// Float values are truncated.
1632    /// Returns `None` if the value is out of range.
1633    /// Range: [-2^53 + 1, 2^53 - 1]
1634    fn to_i64(&self) -> Option<i64> {
1635        const INT_MIN: i64 = -(1 << 53) + 1;
1636        const INT_MAX: i64 = (1 << 53) - 1;
1637        if let Some(i) = self.as_i64() {
1638            if (INT_MIN..=INT_MAX).contains(&i) {
1639                Some(i)
1640            } else {
1641                None
1642            }
1643        } else if let Some(f) = self.as_f64() {
1644            if (INT_MIN as f64..=INT_MAX as f64).contains(&f) {
1645                Some(f as i64)
1646            } else {
1647                None
1648            }
1649        } else {
1650            unreachable!()
1651        }
1652    }
1653}
1654
1655fn exact_decimal_rem(a: &Number, b: &Number) -> Option<Number> {
1656    let (a_int, a_scale) = decimal_parts(&a.to_string())?;
1657    let (b_int, b_scale) = decimal_parts(&b.to_string())?;
1658    let scale = a_scale.max(b_scale);
1659    let a_pow = 10_i128.checked_pow((scale - a_scale) as u32)?;
1660    let b_pow = 10_i128.checked_pow((scale - b_scale) as u32)?;
1661    let a_scaled = a_int.checked_mul(a_pow)?;
1662    let b_scaled = b_int.checked_mul(b_pow)?;
1663    if b_scaled == 0 {
1664        return None;
1665    }
1666    let r = a_scaled % b_scaled;
1667    let s = render_decimal(r, scale);
1668    if scale == 0 {
1669        Some(Number::from(s.parse::<i64>().ok()?))
1670    } else {
1671        Number::from_f64(s.parse::<f64>().ok()?)
1672    }
1673}
1674
1675fn decimal_parts(s: &str) -> Option<(i128, usize)> {
1676    if s.contains('e') || s.contains('E') {
1677        return None;
1678    }
1679    let (sign, body) = match s.strip_prefix('-') {
1680        Some(rest) => (-1_i128, rest),
1681        None => (1_i128, s),
1682    };
1683    let (int_str, frac_str) = match body.split_once('.') {
1684        Some((i, f)) => (i, f),
1685        None => (body, ""),
1686    };
1687    let scale = frac_str.len();
1688    let int_part: i128 = if int_str.is_empty() {
1689        0
1690    } else {
1691        int_str.parse().ok()?
1692    };
1693    let frac_part: i128 = if frac_str.is_empty() {
1694        0
1695    } else {
1696        frac_str.parse().ok()?
1697    };
1698    let pow = 10_i128.checked_pow(scale as u32)?;
1699    let scaled = int_part.checked_mul(pow)?.checked_add(frac_part)?;
1700    Some((sign * scaled, scale))
1701}
1702
1703fn render_decimal(r: i128, scale: usize) -> String {
1704    if scale == 0 {
1705        return r.to_string();
1706    }
1707    let neg = r < 0;
1708    let abs = r.unsigned_abs().to_string();
1709    let padded = if abs.len() <= scale {
1710        format!("0.{:0>width$}", abs, width = scale)
1711    } else {
1712        let dot = abs.len() - scale;
1713        format!("{}.{}", &abs[..dot], &abs[dot..])
1714    };
1715    let mut trimmed = padded.trim_end_matches('0').to_string();
1716    if trimmed.ends_with('.') {
1717        trimmed.pop();
1718    }
1719    if neg && trimmed != "0" {
1720        format!("-{trimmed}")
1721    } else {
1722        trimmed
1723    }
1724}