Skip to main content

yo_doc/
query.rs

1//! The half of JSONPath that names more than one place.
2//!
3//! [`Value::path`] answers one value and is the fast way to ask for one field,
4//! and it refuses `[*]` and `..` on purpose because it has nowhere to put a
5//! second answer. This is the other half. `$..price` and `$.items[*].sku` and
6//! `$.a[0:10:2]` each name a set, and the `JSON.*` surface is written against
7//! sets rather than against single values: `JSON.GET $..price` on a document
8//! with four prices answers four numbers, and `JSON.SET` with the same path
9//! writes four times.
10//!
11//! ```
12//! use yo_doc::{Path, Value, from_json};
13//!
14//! let doc = from_json(br#"{"items":[{"sku":"a","price":3},{"sku":"b","price":5}]}"#)?;
15//! let v = Value::new(&doc).expect("readable");
16//!
17//! let mut hits = Vec::new();
18//! Path::parse(b"$..price")?.select(&v, &mut hits);
19//! let prices: Vec<i64> = hits.iter().filter_map(Value::as_int).collect();
20//! assert_eq!(prices, [3, 5]);
21//! # Ok::<(), yo_common::Error>(())
22//! ```
23//!
24//! # What is here
25//!
26//! The root `$`, a child by name written either way, `[*]` and `.*`, the
27//! descent `..`, an index counting from either end, a union of indices or names
28//! in one bracket, and a slice with an optional step. That is RFC 9535 without
29//! its filter selector.
30//!
31//! The filter, `[?(@.price < 10)]`, is here too. It is the only selector whose
32//! answer depends on the document rather than only on the path, and the only one
33//! that can look somewhere other than where it stands, because `$` inside an
34//! expression is the whole document.
35//!
36//! ```
37//! use yo_doc::{Path, Value, from_json};
38//!
39//! let doc = from_json(br#"{"items":[{"sku":"a","price":3},{"sku":"b","price":15}]}"#)?;
40//! let v = Value::new(&doc).expect("readable");
41//!
42//! let mut hits = Vec::new();
43//! Path::parse(b"$.items[?(@.price < 10)].sku")?.select(&v, &mut hits);
44//! let cheap: Vec<&str> = hits.iter().filter_map(Value::as_text).collect();
45//! assert_eq!(cheap, ["a"]);
46//! # Ok::<(), yo_common::Error>(())
47//! ```
48//!
49//! # What a filter's operators mean
50//!
51//! An operand is a path from the current node, a path from the root, or a
52//! literal, and a path answers a set rather than one value. A comparison is true
53//! when some pair drawn from the two sides satisfies it, so `@.tags[*] == "x"`
54//! asks whether any tag is `x`. A side that answers nothing satisfies nothing,
55//! which is why `@.missing == 1` and `@.missing < 1` are both false, and `!=` is
56//! the negation of the whole comparison rather than a comparison of its own,
57//! which is why `@.missing != 1` is true.
58//!
59//! An ordering comparison only arises between two values of the same sort.
60//! Numbers order as numbers, strings order by their characters, `false` is below
61//! `true`, and two nulls are equal, so `null >= null` is true and `null < null`
62//! is not. Everything else is false: a string is not below a number, and an
63//! array or an object is not below anything at all, not even an equal one.
64//! Equality is the whole value, and it crosses the integer and float split so
65//! `1 == 1.0`, but it crosses nothing else, so `0 == false` and `1 == "1"` are
66//! both false. All of that was read off RedisJSON 8.10.1 rather than off the
67//! RFC, which leaves most of it open.
68//!
69//! An expression with no operator in it asks whether the operand is there.
70//! `[?(@.price)]` keeps the members that have a price, including the ones whose
71//! price is `null` or `false`, because it is a question about the document and
72//! not about the value. The one thing that is false on its own is the literal
73//! `false`, so `[?(false)]` keeps nothing while `[?(0)]` and `[?(null)]` keep
74//! everything.
75//!
76//! `=~` is a regular expression, and the flavour is the one in
77//! [`yo_common::re`], which is what `ARGREP` uses. RedisJSON's is the Rust
78//! `regex` crate's, so the two agree on everything anyone writes by hand and
79//! part company on the corners, which is a row in the divergence register.
80//!
81//! The parentheses everyone writes around a filter are not part of it, so
82//! `[?@.a == 1]` and `[? (@.a == 1)]` are the same filter. A filter iterates the
83//! children of an array and of an object alike, and it works under a write as
84//! well as a read: `JSON.SET`, `JSON.DEL` and `JSON.NUMINCRBY` all take one.
85//!
86//! # The operators past the comparisons
87//!
88//! `in` asks whether the left value is one of the elements of the array on the
89//! right, and `nin` is its negation over both whole sides. `anyof` and `noneof`
90//! ask whether two arrays share an element, and `subsetof` asks whether every
91//! element of the left array is on the right, which makes `[]` a subset of
92//! anything. `size`, which is also spelled `sizeof`, takes a bare number and is
93//! the length of a string, an array or an object, and `empty` takes `true` or
94//! `false` over the same three, so a number has neither and satisfies neither.
95//! The right hand side of all five may be a path rather than a literal, and it
96//! is the values that path answered that are the collection, so `3 in @.list`
97//! and `@.tags anyof $.wanted` both read.
98//!
99//! The postfix methods are `.length()`, `.count()`, `.min()`, `.max()`, `.sum()`
100//! and `.avg()`. `count()` is how many values the operand answered and is a
101//! number even when that number is zero, so `@.nope.count() == 0` is true, and
102//! it is the only one of the six that answers for an operand that answered
103//! nothing. The four aggregates want an array of numbers and answer nothing for
104//! an empty one or for an array with anything else in it. A name that is not one
105//! of the six answers nothing rather than refusing the path, which is what
106//! `@.p.size()` does.
107//!
108//! Arithmetic is `+ - * / %` over numbers, `*` and `/` and `%` bind tighter than
109//! `+` and `-`, and parentheses group. Only `*` is an operator wherever it
110//! stands, so `@.p*2 == 6` reads the way it looks. The other four are name
111//! characters and need their spaces: `@.total-vat` is a key called `total-vat`,
112//! `@.a+1` is a key called `a+1`, and `@.total - vat` is the subtraction. The
113//! exception is straight after a `]`, where no name can be running, so
114//! `@.list[0]-1` is a subtraction with no spaces in it at all. A leading `-` or
115//! `+` is a sign, it answers a number or nothing so `-@.name` on a string
116//! answers nothing, and one is as many as go in a row: `--@.p` is refused and
117//! `-(-@.p)` is how a second one is written.
118//!
119//! Arithmetic and the methods want one node, which is the one place the set rule
120//! above does not hold. An operand that answered two answers nothing rather than
121//! a pair of sums, so `@.list[*] + 1` on a list of two is nothing and
122//! `@.list[*].length()` is nothing as well. `count()` is outside that because
123//! counting is what it is for. This is worth knowing before writing a wildcard
124//! into an arithmetic operand, because what comes back is nothing rather than
125//! what it looks like it asks for.
126//!
127//! The postfix `~` answers the key names of an object, one string each, and
128//! nothing at all for an array or a scalar. It is a set rather than an array
129//! value, so `@.p~ == "x"` is true of any object with an `x` in it, and the
130//! operators that want a collection read the whole set as one: `@.p~ size 2` is
131//! an object with two keys, and `@.p~ subsetof ["x","y"]` is an object with no
132//! other key. It is a collection on the right of those operators too, so
133//! `"x" in @.p~` asks whether the object has an `x`. `in` and `=~` do not take
134//! it on the left and are false whatever is on the other side, which is the
135//! reference's behaviour rather than a rule with a reason behind it.
136//!
137//! An object with no keys answers a set that is there and empty, and something
138//! that is not an object answers no set at all, and every one of the collection
139//! operators tells the two apart. On `{}` the tests `@.p~ subsetof ["x"]`,
140//! `@.p~ empty true` and `@.p~ size 0` are all true, and on a number or a
141//! missing key none of the three is.
142//!
143//! # A path that is an expression
144//!
145//! `JSON.GET`, `JSON.MGET` and `JSON.RESP` take a path that is not a way through
146//! a document at all but a sum over one. `$.a + $.b`, `$.list.length()` and
147//! `$.o~` are all projections, and what comes back is what the expression worked
148//! out rather than where it was found. Nothing else about them is different from
149//! the same expression inside a filter: the same operators, the same methods,
150//! the same one node rule. [`Path::is_projection`] tells the two apart and
151//! [`Path::project`] runs one.
152//!
153//! A projection never fails the way a path does. `$.nope + 1` answers `[]`
154//! rather than raising the "path does not exist" a legacy path would, and it
155//! answers an array even when it was written in the legacy syntax, so `.a + 1`
156//! is `[4]` and not `4`.
157//!
158//! The first thing at the top level is a path however it is written, which is
159//! how `.a + 1` and `2 + 3` both parse. The second is a member really called
160//! `2`, plus three, and answers `[]`. Inside parentheses the ordinary rules are
161//! back, so `(2)` is the number two. `@` is refused up here, since there is no
162//! current node outside a filter.
163//!
164//! The kind of number that comes out follows the reference and is not always the
165//! kind the arithmetic suggests. A whole number stays whole through `+`, `-`,
166//! `*` and `%`, `/` is always a fraction even when it divides evenly, `length()`
167//! and `count()` are whole, and `min()`, `max()`, `sum()` and `avg()` are
168//! fractions. Dividing or taking a remainder by zero answers nothing.
169//!
170//! Every other `JSON.*` command refuses a projection rather than reading it as a
171//! path, so `JSON.NUMINCRBY key "$.a + 1" 1` is an error and not a write
172//! somewhere nobody asked for.
173//!
174//! # Two orderings that are not Redis's
175//!
176//! Matches come back in document order, and for an object that is key order,
177//! because that is the order members are stored in. RedisJSON walks an object
178//! in the order the client wrote it. This is the same difference the JSON
179//! writer has and it is the same one row in the register.
180//!
181//! A descent walks a node before its children, which is what every JSONPath
182//! implementation does, so `$..a` on a document with an `a` inside an `a`
183//! answers the outer one first.
184
185use yo_common::{Code, Error, Result};
186
187use crate::filter::{Arith, Expr, Fun, Item, Num, Op, Operand, Pattern};
188use crate::head::{DEPTH_MAX, Kind};
189use crate::path::Step;
190use crate::read::Value;
191
192/// A parsed path.
193///
194/// Parsing is separate from matching because a path arrives once and is matched
195/// against every document a command touches, and because a path that does not
196/// parse should be an error before any document is read rather than an empty
197/// answer after all of them.
198#[derive(Debug, Clone)]
199pub struct Path<'a> {
200    sels: Vec<Sel<'a>>,
201    legacy: bool,
202    /// The expression this path is, when it is one rather than a way through
203    /// the document. A path with one has no selectors and names nothing.
204    proj: Option<Operand<'a>>,
205}
206
207/// One value a projection worked out.
208///
209/// A projection answers numbers and key names rather than places in a document,
210/// which is why it is not a [`Value`]. The two number kinds are apart because
211/// the reference writes `$.a + $.b` as `7` and `$.list.sum()` as `7.0`, and a
212/// client reading the reply back as JSON sees the difference.
213#[derive(Debug, Clone, Copy)]
214pub enum Computed<'d> {
215    /// A value the document holds.
216    Value(Value<'d>),
217    /// A key name, which is what `~` answers.
218    Name(&'d [u8]),
219    /// A whole number.
220    Int(i64),
221    /// A number that is not whole.
222    Float(f64),
223}
224
225impl Computed<'_> {
226    /// This as JSON text, appended to `out`, as if it sat `depth` levels inside
227    /// whatever the caller has already opened.
228    ///
229    /// # Errors
230    ///
231    /// A document that arrived damaged, and a number that is not finite, which
232    /// JSON has no way to write.
233    pub fn write_json_at(
234        &self,
235        f: &crate::Format<'_>,
236        out: &mut Vec<u8>,
237        depth: usize,
238    ) -> Result<()> {
239        match self {
240            Computed::Value(v) => v.write_json_at(f, out, depth),
241            Computed::Name(k) => {
242                crate::text::write_string(k, out);
243                Ok(())
244            }
245            Computed::Int(i) => {
246                crate::text::write_int(*i, out);
247                Ok(())
248            }
249            Computed::Float(x) => crate::text::write_float(*x, out),
250        }
251    }
252}
253
254/// One selector.
255#[derive(Debug, Clone, PartialEq, Eq)]
256pub(crate) enum Sel<'a> {
257    /// A member of an object, by name.
258    Key(&'a [u8]),
259    /// An element of an array, counting back from the end when negative.
260    Index(i64),
261    /// Every element of a container.
262    Wild,
263    /// This value and every value under it, which is what `..` is. The selector
264    /// after it is what actually picks, so `$..a` is a descent and then a name.
265    Descend,
266    /// Several of the above in one bracket, applied in the order written.
267    Union(Vec<Sel<'a>>),
268    /// A run of an array. The bounds count back from the end when negative and
269    /// the step may be negative, which walks it backwards.
270    Slice {
271        from: Option<i64>,
272        to: Option<i64>,
273        step: i64,
274    },
275    /// The children this expression is true of. Boxed because it is the one
276    /// selector that is more than a few words and every other selector would
277    /// otherwise pay for it.
278    Filter(Box<Expr<'a>>),
279}
280
281impl<'a> Path<'a> {
282    /// Parse `path`.
283    ///
284    /// A path that starts with `$` is a JSONPath and anything else is what
285    /// RedisJSON calls a legacy path, which is the older syntax that answers one
286    /// value. Both are matched the same way here and the difference is recorded
287    /// in [`Path::legacy`], because what it changes is the shape of the reply
288    /// and that is the dispatch layer's business rather than this one's.
289    pub fn parse(path: &'a [u8]) -> Result<Path<'a>> {
290        // A projection is tried first and falls through quietly when the path is
291        // an ordinary one, so nothing about an ordinary path goes through the
292        // expression grammar.
293        if let Some(proj) = projection(path) {
294            return Ok(Path {
295                sels: Vec::new(),
296                legacy: false,
297                proj: Some(proj),
298            });
299        }
300        let (rest, legacy) = match path.strip_prefix(b"$") {
301            Some(rest) => (rest, false),
302            None => (path, true),
303        };
304        let mut p = Parse {
305            rest,
306            at: 0,
307            legacy,
308            sels: Vec::new(),
309        };
310        p.run()?;
311        Ok(Path {
312            sels: p.sels,
313            legacy,
314            proj: None,
315        })
316    }
317
318    /// Whether this path is an expression rather than a way through the
319    /// document.
320    ///
321    /// A projection answers values that are nowhere in the document, so there
322    /// is nothing for a write to write to and nothing for `JSON.TYPE` to
323    /// describe. Only `JSON.GET`, `JSON.MGET` and `JSON.RESP` take one and the
324    /// rest refuse it, which is what this is for.
325    #[must_use]
326    pub fn is_projection(&self) -> bool {
327        self.proj.is_some()
328    }
329
330    /// What this projection works out against `root`, and nothing at all when
331    /// the path is not one.
332    #[must_use]
333    pub fn project<'d>(&'d self, root: &Value<'d>) -> Vec<Computed<'d>> {
334        let Some(o) = &self.proj else {
335            return Vec::new();
336        };
337        crate::filter::project(o, root)
338            .into_iter()
339            .map(|it| match it {
340                Item::Ref(v) => Computed::Value(v),
341                Item::Key(k) => Computed::Name(k),
342                Item::Num(Num::Int(i)) => Computed::Int(i),
343                Item::Num(Num::Float(x)) => Computed::Float(x),
344            })
345            .collect()
346    }
347
348    /// Whether this path was written in the older syntax, without a leading
349    /// `$`.
350    #[must_use]
351    pub fn legacy(&self) -> bool {
352        self.legacy
353    }
354
355    /// Whether this path is the root and nothing else.
356    ///
357    /// `$`, a bare `.` and the empty path are all it. `JSON.SET` needs to know,
358    /// because the root is the only place a whole document can be written to a
359    /// key that is not there yet, and `JSON.DEL` needs to know because deleting
360    /// the root is deleting the key.
361    #[must_use]
362    pub fn is_root(&self) -> bool {
363        self.sels.is_empty()
364    }
365
366    /// Whether this path names at most one place, whatever document it is
367    /// matched against.
368    ///
369    /// A path made only of names and indices does. Everything else can answer
370    /// more than one value on some document even if it answers one on this one,
371    /// and the difference decides what a command is allowed to do: `JSON.SET`
372    /// creating a field that is not there yet only makes sense when the path
373    /// says exactly where it goes.
374    #[must_use]
375    pub fn is_definite(&self) -> bool {
376        self.sels
377            .iter()
378            .all(|s| matches!(s, Sel::Key(_) | Sel::Index(_)))
379    }
380
381    /// Every value this path names in `root`, in document order, appended to
382    /// `out`.
383    ///
384    /// Appended rather than assigned, so that a command matching one path
385    /// against many documents keeps one buffer. Nothing here allocates except
386    /// that buffer and the frontier the walk carries.
387    pub fn select<'d>(&self, root: &Value<'d>, out: &mut Vec<Value<'d>>) {
388        select_from(&self.sels, root, root, out);
389    }
390
391    /// This path without its last selector, and that selector, when the last
392    /// one names one place.
393    ///
394    /// `JSON.SET` is what needs it. A path that matched nothing can still be a
395    /// place to write, as long as what would hold the new value is there and the
396    /// last step says exactly where in it the value goes, so `$.a.b` against a
397    /// document with an `a` and no `b` splits into the parent `$.a` and the step
398    /// `b`.
399    ///
400    /// `None` for the root, which has no last selector, and for a last selector
401    /// that is a wildcard, a descent, a union or a slice, because none of those
402    /// names a place that is not already there.
403    #[must_use]
404    pub fn split_last(&self) -> Option<(Path<'a>, Step<'a>)> {
405        let step = match self.sels.last()? {
406            Sel::Key(k) => Step::Key(k),
407            Sel::Index(i) => Step::Index(*i),
408            _ => return None,
409        };
410        let parent = Path {
411            sels: self.sels[..self.sels.len() - 1].to_vec(),
412            legacy: self.legacy,
413            proj: None,
414        };
415        Some((parent, step))
416    }
417
418    /// The one value this path names, for a caller that has already checked
419    /// [`Path::is_definite`] or that only wants the first of several.
420    ///
421    /// RedisJSON's older syntax answers the first match, which is what this is
422    /// for.
423    #[must_use]
424    pub fn first<'d>(&self, root: &Value<'d>) -> Option<Value<'d>> {
425        let mut out = Vec::new();
426        self.select(root, &mut out);
427        out.into_iter().next()
428    }
429}
430
431/// Walk `sels` from `start`, with everything they name appended to `out`.
432///
433/// `root` is carried the whole way down because a filter may say `$`, which is
434/// the document and not the value the filter stands on. It is the same value as
435/// `start` for a path a client sent and a different one for a path inside a
436/// filter.
437pub(crate) fn select_from<'d>(
438    sels: &[Sel<'_>],
439    start: &Value<'d>,
440    root: &Value<'d>,
441    out: &mut Vec<Value<'d>>,
442) {
443    let mut cur = vec![*start];
444    let mut next = Vec::new();
445    for sel in sels {
446        next.clear();
447        for v in &cur {
448            apply(sel, root, v, &mut next);
449        }
450        core::mem::swap(&mut cur, &mut next);
451        if cur.is_empty() {
452            return;
453        }
454    }
455    out.append(&mut cur);
456}
457
458/// One selector against one value, with everything it names pushed onto `out`.
459fn apply<'d>(sel: &Sel<'_>, root: &Value<'d>, v: &Value<'d>, out: &mut Vec<Value<'d>>) {
460    match sel {
461        Sel::Key(k) => out.extend(v.get(k)),
462        Sel::Index(i) => out.extend(index(v, *i)),
463        Sel::Wild => out.extend(v.iter()),
464        Sel::Descend => descend(v, out, 0),
465        Sel::Union(items) => {
466            for item in items {
467                apply(item, root, v, out);
468            }
469        }
470        Sel::Slice { from, to, step } => slice(v, *from, *to, *step, out),
471        // A filter is asked about the children and not about the value it
472        // stands on, so an array is filtered element by element and an object
473        // member by member, which is what `iter` walks for both.
474        Sel::Filter(e) => out.extend(v.iter().filter(|child| e.holds(root, child))),
475    }
476}
477
478/// An element of an array by an index that may count back from the end.
479fn index<'d>(v: &Value<'d>, i: i64) -> Option<Value<'d>> {
480    if v.kind() != Kind::Array {
481        return None;
482    }
483    v.at(place(i, v.len())?)
484}
485
486/// Where `i` lands in a container of `n`, or `None` when it lands outside.
487fn place(i: i64, n: usize) -> Option<usize> {
488    if i < 0 {
489        n.checked_sub(i.unsigned_abs() as usize)
490    } else {
491        let at = i as usize;
492        (at < n).then_some(at)
493    }
494}
495
496/// This value and everything under it, a node before its children.
497///
498/// The depth is counted here rather than left to the encoding, because this
499/// walks a document that may have arrived from anywhere and a damaged one can
500/// claim any shape it likes.
501fn descend<'d>(v: &Value<'d>, out: &mut Vec<Value<'d>>, depth: usize) {
502    out.push(*v);
503    if depth >= DEPTH_MAX {
504        return;
505    }
506    for child in v.iter() {
507        descend(&child, out, depth + 1);
508    }
509}
510
511/// The RFC 9535 slice, which is Python's slice with Python's defaults.
512fn slice<'d>(
513    v: &Value<'d>,
514    from: Option<i64>,
515    to: Option<i64>,
516    step: i64,
517    out: &mut Vec<Value<'d>>,
518) {
519    if v.kind() != Kind::Array || step == 0 {
520        return;
521    }
522    let n = v.len() as i64;
523    // A bound is clamped rather than wrapped, so `[0:1000]` is the whole array
524    // and not an error, which is what every other slice in every other language
525    // does and what a client writing one expects.
526    let bound = |i: i64, lo: i64, hi: i64| {
527        let i = if i < 0 { n + i } else { i };
528        i.clamp(lo, hi)
529    };
530    if step > 0 {
531        let mut at = bound(from.unwrap_or(0), 0, n);
532        let end = bound(to.unwrap_or(n), 0, n);
533        while at < end {
534            out.extend(v.at(at as usize));
535            at += step;
536        }
537    } else {
538        let mut at = bound(from.unwrap_or(n - 1), -1, n - 1);
539        let end = bound(to.unwrap_or(-n - 1), -1, n - 1);
540        while at > end {
541            out.extend(v.at(at as usize));
542            at += step;
543        }
544    }
545}
546
547// ---------------------------------------------------------------- the grammar
548
549struct Parse<'a> {
550    rest: &'a [u8],
551    at: usize,
552    legacy: bool,
553    sels: Vec<Sel<'a>>,
554}
555
556impl<'a> Parse<'a> {
557    fn run(&mut self) -> Result<()> {
558        // A legacy path of one dot is the root. It is the spelling the `JSON.*`
559        // commands fall back to when the client gave no path at all, and it is
560        // the only place a `.` is allowed to have nothing after it.
561        if self.legacy && self.rest == b"." {
562            return Ok(());
563        }
564        // A path with no `$` may start with a bare name, so that `a.b` means
565        // what `$.a.b` means. Only at the front of one of those: anywhere else,
566        // and in a path that did start with a `$`, a missing separator is a typo
567        // and reading it as a name would hide one.
568        if self.legacy && self.at < self.rest.len() && !matches!(self.rest[self.at], b'.' | b'[') {
569            let name = self.name()?;
570            self.sels.push(Sel::Key(name));
571        }
572        while self.at < self.rest.len() {
573            match self.rest[self.at] {
574                b'.' if self.rest.get(self.at + 1) == Some(&b'.') => {
575                    self.at += 2;
576                    self.sels.push(Sel::Descend);
577                    if self.at >= self.rest.len() {
578                        return Err(self.bad("a `..` with nothing after it"));
579                    }
580                    // A descent picks with whatever follows it, and a bracket
581                    // is handled by the next turn of this loop.
582                    if self.rest.get(self.at) == Some(&b'[') {
583                        continue;
584                    }
585                    let sel = self.after_dot()?;
586                    self.sels.push(sel);
587                }
588                b'.' => {
589                    self.at += 1;
590                    let sel = self.after_dot()?;
591                    self.sels.push(sel);
592                }
593                b'[' => {
594                    let sel = self.bracket()?;
595                    self.sels.push(sel);
596                }
597                _ => return Err(self.bad("a step that does not start with `.` or `[`")),
598            }
599        }
600        Ok(())
601    }
602
603    /// What follows a `.` or a `..`, which is a name or a `*`.
604    fn after_dot(&mut self) -> Result<Sel<'a>> {
605        if self.rest.get(self.at) == Some(&b'*') {
606            self.at += 1;
607            return Ok(Sel::Wild);
608        }
609        Ok(Sel::Key(self.name()?))
610    }
611
612    /// A bare name, which runs to the next separator.
613    ///
614    /// A name written without quotes may not have a space, a `~`, a `*` or a
615    /// comparison character in it, because the top level of a path is an
616    /// expression now and those are what it is made of. A member really called
617    /// `my key` is reached by `$["my key"]`, which is what the reference wants
618    /// too. The four arithmetic characters that are also name characters are
619    /// still name characters, so `$.total-vat` and `$.a+1` are members.
620    fn name(&mut self) -> Result<&'a [u8]> {
621        let from = self.at;
622        while self.at < self.rest.len()
623            && !matches!(self.rest[self.at], b'.' | b'[')
624            && !ends_name(self.rest[self.at])
625        {
626            self.at += 1;
627        }
628        if self.at == from {
629            return Err(self.bad("a `.` with no name after it"));
630        }
631        Ok(&self.rest[from..self.at])
632    }
633
634    /// Everything between one `[` and its `]`.
635    fn bracket(&mut self) -> Result<Sel<'a>> {
636        let body = &self.rest[self.at + 1..];
637        let Some(close) = closer(body, b']') else {
638            return Err(self.bad("a `[` with no `]` after it"));
639        };
640        let inner = &body[..close];
641        self.at += close + 2;
642        if let Some(rest) = inner.strip_prefix(b"?") {
643            return self.filter(rest);
644        }
645        if inner == b"*" {
646            return Ok(Sel::Wild);
647        }
648        if inner.contains(&b':') {
649            return self.slice(inner);
650        }
651        let mut items = Vec::new();
652        for part in inner.split(|&c| c == b',') {
653            items.push(self.one(trim(part))?);
654        }
655        match items.len() {
656            0 => Err(self.bad("an empty `[]`")),
657            1 => Ok(items.pop().expect("one item")),
658            _ => Ok(Sel::Union(items)),
659        }
660    }
661
662    /// One item of a bracket: a quoted name or an index.
663    fn one(&self, part: &'a [u8]) -> Result<Sel<'a>> {
664        if let Some(name) = quoted(part) {
665            return Ok(Sel::Key(name));
666        }
667        Ok(Sel::Index(self.int(part)?))
668    }
669
670    fn slice(&self, inner: &[u8]) -> Result<Sel<'a>> {
671        let mut parts = inner.split(|&c| c == b':');
672        let from = self.maybe(parts.next().unwrap_or(b""))?;
673        let to = self.maybe(parts.next().unwrap_or(b""))?;
674        let step = self.maybe(parts.next().unwrap_or(b""))?.unwrap_or(1);
675        if parts.next().is_some() {
676            return Err(self.bad("a slice has at most a start, an end and a step"));
677        }
678        if step == 0 {
679            return Err(self.bad("a slice with a step of zero"));
680        }
681        Ok(Sel::Slice { from, to, step })
682    }
683
684    /// A bound of a slice, which may be left out.
685    fn maybe(&self, part: &[u8]) -> Result<Option<i64>> {
686        let part = trim(part);
687        if part.is_empty() {
688            return Ok(None);
689        }
690        Ok(Some(self.int(part)?))
691    }
692
693    fn int(&self, part: &[u8]) -> Result<i64> {
694        core::str::from_utf8(part)
695            .ok()
696            .and_then(|t| t.parse().ok())
697            .ok_or_else(|| self.bad("an index that is not a number"))
698    }
699
700    /// Everything between `[?` and its `]`.
701    ///
702    /// The parentheses everyone writes around a filter are not part of it. They
703    /// are a group like any other group, which is why `[?@.a == 1]` and
704    /// `[? (@.a == 1)]` are both this and read the same.
705    fn filter(&mut self, body: &'a [u8]) -> Result<Sel<'a>> {
706        let mut f = Filter {
707            body,
708            at: 0,
709            of: self.at,
710            top: false,
711        };
712        let e = f.or()?;
713        f.spaces();
714        if f.at < f.body.len() {
715            return Err(f.bad("a filter with something left over at the end of it"));
716        }
717        Ok(Sel::Filter(Box::new(e)))
718    }
719
720    /// An error that says where in the path it happened, since a path is short
721    /// enough that the offset is the whole explanation.
722    fn bad(&self, what: &str) -> Error {
723        Error::fmt(
724            Code::Invalid,
725            format_args!("{what}, at byte {} of the path", self.at),
726        )
727    }
728}
729
730// ------------------------------------------------------------------ a filter
731
732/// The grammar inside `[?...]`.
733///
734/// Separate from [`Parse`] because it reads an expression rather than a run of
735/// selectors, and because it works over the one bracket rather than over the
736/// whole path. `of` is where that bracket started, so an error still says where
737/// in the path the client should look.
738struct Filter<'a> {
739    body: &'a [u8],
740    at: usize,
741    of: usize,
742    /// Whether the next atom read is the first one of a projection, where a
743    /// bare name is a path rather than a value. It is cleared by the atom that
744    /// reads it, so it only ever applies to one.
745    top: bool,
746}
747
748impl<'a> Filter<'a> {
749    /// `and` and then any number of `|| and`.
750    fn or(&mut self) -> Result<Expr<'a>> {
751        let mut e = self.and()?;
752        while self.word(b"||") {
753            e = Expr::Or(Box::new(e), Box::new(self.and()?));
754        }
755        Ok(e)
756    }
757
758    /// `unary` and then any number of `&& unary`, which is why `&&` binds
759    /// tighter than `||`.
760    fn and(&mut self) -> Result<Expr<'a>> {
761        let mut e = self.unary()?;
762        while self.word(b"&&") {
763            e = Expr::And(Box::new(e), Box::new(self.unary()?));
764        }
765        Ok(e)
766    }
767
768    /// A `!`, a group, or a comparison.
769    ///
770    /// A `(` is ambiguous, because `(@.a || @.b)` groups an expression and
771    /// `(1 + 2) * 3` groups arithmetic and the two are told apart only by what
772    /// comes after the `)`. This reads it as an expression, and if what follows
773    /// is an operator rather than the end of one, winds back and reads the whole
774    /// thing as a comparison instead.
775    fn unary(&mut self) -> Result<Expr<'a>> {
776        self.spaces();
777        if self.word(b"!") {
778            return Ok(Expr::Not(Box::new(self.unary()?)));
779        }
780        let from = self.at;
781        if self.word(b"(") {
782            let e = self.or()?;
783            if !self.word(b")") {
784                return Err(self.bad("a `(` in a filter with no `)` after it"));
785            }
786            if !self.operator_next() {
787                return Ok(e);
788            }
789            self.at = from;
790        }
791        self.cmp()
792    }
793
794    /// Whether what comes next is an operator, which is what says a `(...)` just
795    /// read was arithmetic and not a group.
796    fn operator_next(&mut self) -> bool {
797        self.spaces();
798        let rest = &self.body[self.at..];
799        if rest.first().is_some_and(|c| {
800            matches!(c, b'+' | b'-' | b'*' | b'/' | b'%' | b'<' | b'>' | b'=') || *c == b'!'
801        }) {
802            // A `!` is only an operator when it is a `!=`, since a `!` on its
803            // own after a group is not something a filter can mean.
804            return rest[0] != b'!' || rest.starts_with(b"!=");
805        }
806        WORD_OPS.iter().any(|(text, _)| word_at(rest, text))
807    }
808
809    /// One operand, and the other one when there is an operator between them.
810    fn cmp(&mut self) -> Result<Expr<'a>> {
811        let left = self.operand()?;
812        let Some(op) = self.op() else {
813            return Ok(Expr::Test(left));
814        };
815        let mut right = self.operand()?;
816        if op == Op::Re {
817            // A pattern is compiled here rather than once per value it is run
818            // against, which is the whole reason a path is parsed at all. One
819            // that will not compile is left as it was written, which makes it a
820            // right hand side that matches nothing, because that is what the
821            // reference does with `"["` rather than refusing the path.
822            if let Operand::Lit(bytes) = &right
823                && let Some(v) = Value::new(bytes)
824                && let Some(text) = v.text_bytes()
825                && let Ok(pat) = Pattern::new(text)
826            {
827                right = Operand::Re(pat);
828            }
829        }
830        Ok(Expr::Cmp(left, op, right))
831    }
832
833    /// The operator between two operands, if there is one.
834    ///
835    /// The two character ones are tried first, so that `<=` is not read as a
836    /// `<` with a stray `=` after it, and the ones written as words need a
837    /// boundary after them so that a `size` in `sizes` is not one.
838    fn op(&mut self) -> Option<Op> {
839        self.spaces();
840        for (text, op) in [
841            (&b"=="[..], Op::Eq),
842            (b"!=", Op::Ne),
843            (b"<=", Op::Le),
844            (b">=", Op::Ge),
845            (b"=~", Op::Re),
846            (b"<", Op::Lt),
847            (b">", Op::Gt),
848        ] {
849            if self.word(text) {
850                return Some(op);
851            }
852        }
853        for (text, op) in WORD_OPS {
854            if word_at(&self.body[self.at..], text) {
855                self.at += text.len();
856                return Some(*op);
857            }
858        }
859        None
860    }
861
862    /// One side of a comparison, which is a sum of products of atoms.
863    ///
864    /// Arithmetic binds tighter than a comparison and `*` binds tighter than
865    /// `+`, which is the ordering everybody expects and is the one the reference
866    /// has.
867    fn operand(&mut self) -> Result<Operand<'a>> {
868        let mut e = self.product()?;
869        loop {
870            self.spaces();
871            let op = match self.body.get(self.at) {
872                Some(b'+') => Arith::Add,
873                // A `-` is only ever subtraction when it is spaced, because a
874                // key really called `total-vat` is reachable and an operator
875                // nobody can write around is not worth it.
876                Some(b'-') => Arith::Sub,
877                _ => break,
878            };
879            self.at += 1;
880            e = Operand::Math(Box::new(e), op, Box::new(self.product()?));
881        }
882        Ok(e)
883    }
884
885    /// A signed atom and then any number of `* / %` and another one.
886    fn product(&mut self) -> Result<Operand<'a>> {
887        let mut e = self.signed()?;
888        loop {
889            self.spaces();
890            let op = match self.body.get(self.at) {
891                Some(b'*') => Arith::Mul,
892                Some(b'/') => Arith::Div,
893                Some(b'%') => Arith::Rem,
894                _ => break,
895            };
896            self.at += 1;
897            e = Operand::Math(Box::new(e), op, Box::new(self.signed()?));
898        }
899        Ok(e)
900    }
901
902    /// An atom with a `-` or a `+` in front of it, or an atom.
903    ///
904    /// One sign and no more, which is what the reference does: `--@.a` is
905    /// refused and `-(-@.a)` is not. A sign answers a number or nothing, so
906    /// `-@.name` on a string answers nothing rather than the string.
907    fn signed(&mut self) -> Result<Operand<'a>> {
908        self.spaces();
909        let neg = match self.body.get(self.at) {
910            Some(b'-') => true,
911            Some(b'+') => false,
912            _ => return self.atom(),
913        };
914        self.at += 1;
915        Ok(Operand::Sign(Box::new(self.atom()?), neg))
916    }
917
918    /// A path from `@` or from `$`, a value written into the path, or either of
919    /// those in parentheses, and then any postfix on it.
920    fn atom(&mut self) -> Result<Operand<'a>> {
921        self.spaces();
922        let Some(&c) = self.body.get(self.at) else {
923            return Err(self.bad("a filter that stops where a value was expected"));
924        };
925        let mut e = if c == b'(' {
926            // Only the first thing at the very top of a projection is a path
927            // however it is written. Inside parentheses the ordinary rules are
928            // back, so `(2)` is the number and `2 + 3` is a member called `2`.
929            self.top = false;
930            self.at += 1;
931            let inner = self.operand()?;
932            if !self.word(b")") {
933                return Err(self.bad("a `(` in a filter with no `)` after it"));
934            }
935            inner
936        } else if c == b'@' || c == b'$' {
937            self.top = false;
938            self.at += 1;
939            self.path(c == b'@', false)?
940        } else if core::mem::take(&mut self.top) {
941            // The first thing in a projection is a path however it is written,
942            // which is what makes `.a + 1` read and what makes `2 + 3` a member
943            // really called `2` rather than five.
944            self.path(false, true)?
945        } else {
946            self.literal()?
947        };
948        // One `~` and no more. Key names have no keys of their own, so `@.p~~`
949        // is a path that means nothing and the reference refuses it.
950        if self.body.get(self.at) == Some(&b'~') {
951            self.at += 1;
952            e = Operand::Keys(Box::new(e));
953        }
954        Ok(e)
955    }
956
957    /// The path that starts here, and the postfix method on the end of it when
958    /// there is one.
959    ///
960    /// `at` says the path started at `@` rather than at `$`, and `legacy` says
961    /// it started at neither, which only happens at the top of a projection.
962    fn path(&mut self, at: bool, legacy: bool) -> Result<Operand<'a>> {
963        let end = self.at + path_end(&self.body[self.at..]);
964        // A postfix method looks like the last name of the path, because the
965        // path stops at the `(` rather than at the `.` before it, so the name
966        // comes back off the end here.
967        let mut to = end;
968        let mut fun = None;
969        if self.body[end..].starts_with(b"()")
970            && let Some(dot) = self.body[self.at..end].iter().rposition(|&b| b == b'.')
971        {
972            fun = Some(Fun::named(&self.body[self.at + dot + 1..end]));
973            to = self.at + dot;
974        }
975        let mut p = Parse {
976            rest: &self.body[self.at..to],
977            at: 0,
978            legacy,
979            sels: Vec::new(),
980        };
981        p.run()?;
982        self.at = if fun.is_some() { end + 2 } else { end };
983        let path = Operand::Path { at, sels: p.sels };
984        Ok(match fun {
985            Some(f) => Operand::Call(Box::new(path), f),
986            None => path,
987        })
988    }
989
990    /// A number, a string, `true`, `false`, `null`, or a whole array or object.
991    fn literal(&mut self) -> Result<Operand<'a>> {
992        let from = self.at;
993        let text = match self.body[self.at] {
994            b'"' | b'\'' => self.string()?,
995            open @ (b'[' | b'{') => {
996                let body = &self.body[self.at + 1..];
997                let close = if open == b'[' { b']' } else { b'}' };
998                let Some(close) = closer(body, close) else {
999                    return Err(self.bad("a value in a filter that is not closed"));
1000                };
1001                self.at += close + 2;
1002                self.body[from..self.at].to_vec()
1003            }
1004            _ => {
1005                while self.at < self.body.len() && !stops(self.body[self.at]) {
1006                    self.at += 1;
1007                }
1008                if self.at == from {
1009                    return Err(self.bad("a filter with an operator where a value goes"));
1010                }
1011                self.body[from..self.at].to_vec()
1012            }
1013        };
1014        let bytes = crate::from_json(&text)
1015            .map_err(|_| self.bad("a value in a filter that is not a value"))?;
1016        Ok(Operand::Lit(bytes))
1017    }
1018
1019    /// A quoted string, as the JSON text of the same string.
1020    ///
1021    /// A filter may quote with either mark and JSON only knows the one, so a
1022    /// single quoted string is rewritten rather than parsed twice. What is
1023    /// inside it is left alone, escapes included, so `'A'` means what it
1024    /// means in JSON.
1025    fn string(&mut self) -> Result<Vec<u8>> {
1026        let quote = self.body[self.at];
1027        let mut out = vec![b'"'];
1028        let mut i = self.at + 1;
1029        while i < self.body.len() {
1030            let c = self.body[i];
1031            if c == b'\\' && i + 1 < self.body.len() {
1032                // A quote of the other kind was escaped to get past this
1033                // parser, and JSON has no escape for it, so the backslash goes
1034                // and the mark stays.
1035                let next = self.body[i + 1];
1036                if next == b'\'' {
1037                    out.push(b'\'');
1038                } else {
1039                    out.push(c);
1040                    out.push(next);
1041                }
1042                i += 2;
1043                continue;
1044            }
1045            if c == quote {
1046                out.push(b'"');
1047                self.at = i + 1;
1048                return Ok(out);
1049            }
1050            if c == b'"' {
1051                out.push(b'\\');
1052            }
1053            out.push(c);
1054            i += 1;
1055        }
1056        Err(self.bad("a string in a filter with no closing quote"))
1057    }
1058
1059    /// Take `text` if it is next, after any spaces.
1060    fn word(&mut self, text: &[u8]) -> bool {
1061        self.spaces();
1062        if self.body[self.at..].starts_with(text) {
1063            self.at += text.len();
1064            return true;
1065        }
1066        false
1067    }
1068
1069    fn spaces(&mut self) {
1070        while matches!(self.body.get(self.at), Some(b' ' | b'\t')) {
1071            self.at += 1;
1072        }
1073    }
1074
1075    fn bad(&self, what: &str) -> Error {
1076        Error::fmt(
1077            Code::Invalid,
1078            format_args!("{what}, at byte {} of the path", self.of + self.at),
1079        )
1080    }
1081}
1082
1083/// The expression a path is, when it is one rather than a way through the
1084/// document.
1085///
1086/// Redis 8.10 lets the top level of a path be arithmetic, a postfix method or a
1087/// `~`, so `$.a + $.b` answers a number that is nowhere in the document and
1088/// `$.o~` answers key names. It is told from an ordinary path by what it parses
1089/// into: a path on its own stays a path, and anything else is an expression. A
1090/// path in parentheses is an expression too, which is what the leading `(` here
1091/// is about.
1092///
1093/// Nothing here is an error. A body that does not read as an expression is left
1094/// to the ordinary parser, which is what says whether it is a path or a mistake.
1095fn projection(body: &[u8]) -> Option<Operand<'_>> {
1096    // The reference's top level starts at the first byte, so a leading space is
1097    // part of the first name rather than something to skip past, and nothing
1098    // that starts with one is an expression.
1099    if body.first().is_none_or(|c| matches!(c, b' ' | b'\t')) {
1100        return None;
1101    }
1102    let mut f = Filter {
1103        body,
1104        at: 0,
1105        of: 0,
1106        top: true,
1107    };
1108    let e = f.operand().ok()?;
1109    f.spaces();
1110    if f.at != body.len() || (body[0] != b'(' && matches!(e, Operand::Path { .. })) {
1111        return None;
1112    }
1113    // `@` is the node a filter stands on and there is no such node up here, so
1114    // a path that mentions one is not an expression. The reference refuses it
1115    // and this leaves it to the ordinary parser, which reads it as a member
1116    // really called `@` and answers nothing, which is the same thing to a
1117    // client.
1118    (!mentions_at(&e)).then_some(e)
1119}
1120
1121/// Whether an operand reads `@` anywhere inside it.
1122fn mentions_at(o: &Operand<'_>) -> bool {
1123    match o {
1124        Operand::Path { at, .. } => *at,
1125        Operand::Lit(_) | Operand::Re(_) => false,
1126        Operand::Keys(inner) | Operand::Call(inner, _) | Operand::Sign(inner, _) => {
1127            mentions_at(inner)
1128        }
1129        Operand::Math(l, _, r) => mentions_at(l) || mentions_at(r),
1130    }
1131}
1132
1133/// Where a path inside a filter ends.
1134///
1135/// A path there runs up against the expression around it, so it stops at the
1136/// first thing that cannot be part of one. Arithmetic is not read, so `+`, `-`
1137/// and the rest are not in that set and a member really called `total-vat` is
1138/// reachable, which matters more than an operator nobody can use.
1139fn path_end(body: &[u8]) -> usize {
1140    let mut depth = 0usize;
1141    let mut quote = 0u8;
1142    let mut i = 0;
1143    while i < body.len() {
1144        let c = body[i];
1145        if quote != 0 {
1146            if c == b'\\' {
1147                i += 2;
1148                continue;
1149            }
1150            if c == quote {
1151                quote = 0;
1152            }
1153        } else if depth == 0 && ends_path(body, i) {
1154            return i;
1155        } else {
1156            match c {
1157                b'"' | b'\'' => quote = c,
1158                b'[' => depth += 1,
1159                b']' => depth = depth.saturating_sub(1),
1160                _ => {}
1161            }
1162        }
1163        i += 1;
1164    }
1165    body.len()
1166}
1167
1168/// Whether this byte ends a bare value inside a filter.
1169///
1170/// A `-` is not one of these, because a number's sign is read before this runs
1171/// and a `1-2` with no spaces is not a value anybody meant.
1172fn stops(c: u8) -> bool {
1173    matches!(
1174        c,
1175        b' ' | b'\t'
1176            | b'('
1177            | b')'
1178            | b'!'
1179            | b'<'
1180            | b'>'
1181            | b'='
1182            | b'&'
1183            | b'|'
1184            | b','
1185            | b'~'
1186            | b'+'
1187            | b'*'
1188            | b'/'
1189            | b'%'
1190    )
1191}
1192
1193/// Whether the byte at `i` ends the path being read.
1194///
1195/// `+`, `-`, `/` and `%` are all characters a member name may have in it, so
1196/// `@.total-vat` and `@.p+1` are members and not arithmetic. They only end a
1197/// path where no name can be running, which is straight after a `]`, so
1198/// `@.list[0]-1` is a subtraction. A `*` is never a name character, because it
1199/// is the wildcard, so `@.p*2` is a product and a member really called `p*2` has
1200/// to be written `@["p*2"]`. All of that was read off RedisJSON 8.10.1.
1201fn ends_path(body: &[u8], i: usize) -> bool {
1202    if matches!(body[i], b'+' | b'-' | b'/' | b'%') {
1203        return i > 0 && body[i - 1] == b']';
1204    }
1205    ends_name(body[i])
1206}
1207
1208/// Whether this byte ends a bare member name.
1209///
1210/// The same set that ends a path, less the four arithmetic characters that are
1211/// also name characters, since a name is exactly where those are allowed.
1212fn ends_name(c: u8) -> bool {
1213    stops(c) && !matches!(c, b'+' | b'/' | b'%')
1214}
1215
1216/// The operators that are written as words rather than as symbols.
1217///
1218/// `nin` comes before `in` and `noneof` before `nin`, so that the longer one is
1219/// the one that matches.
1220const WORD_OPS: &[(&[u8], Op)] = &[
1221    (b"subsetof", Op::SubsetOf),
1222    (b"anyof", Op::AnyOf),
1223    (b"noneof", Op::NoneOf),
1224    (b"nin", Op::Nin),
1225    (b"in", Op::In),
1226    (b"sizeof", Op::Size),
1227    (b"size", Op::Size),
1228    (b"empty", Op::Empty),
1229];
1230
1231/// Whether `body` starts with `text` and then something that is not more of a
1232/// word, so that the `in` in `into` is not the operator.
1233fn word_at(body: &[u8], text: &[u8]) -> bool {
1234    body.starts_with(text)
1235        && !body[text.len()..]
1236            .first()
1237            .is_some_and(|c| c.is_ascii_alphanumeric() || *c == b'_')
1238}
1239
1240/// Where the `close` that matches an opener is, counting nesting and quotes.
1241///
1242/// The first `]` is the answer for `[0]` and for `['a']`, and it is the wrong
1243/// answer for `[?(@.a[0] == 1)]` and for `[?(@.a == "]")]`, which is why this
1244/// walks rather than searches. `close` is a parameter because a filter can hold
1245/// a whole value written out, and `{"a":1}` ends at a brace.
1246fn closer(body: &[u8], close: u8) -> Option<usize> {
1247    let mut depth = 0usize;
1248    let mut quote = 0u8;
1249    let mut i = 0;
1250    while i < body.len() {
1251        let c = body[i];
1252        if quote != 0 {
1253            if c == b'\\' {
1254                i += 2;
1255                continue;
1256            }
1257            if c == quote {
1258                quote = 0;
1259            }
1260        } else if c == close && depth == 0 {
1261            return Some(i);
1262        } else {
1263            match c {
1264                b'"' | b'\'' => quote = c,
1265                b'[' | b'{' => depth += 1,
1266                b']' | b'}' => depth = depth.saturating_sub(1),
1267                _ => {}
1268            }
1269        }
1270        i += 1;
1271    }
1272    None
1273}
1274
1275/// The bytes inside `"..."` or `'...'`, if that is what this is.
1276fn quoted(part: &[u8]) -> Option<&[u8]> {
1277    if part.len() >= 2 {
1278        let (first, last) = (part[0], part[part.len() - 1]);
1279        if (first == b'"' || first == b'\'') && last == first {
1280            return Some(&part[1..part.len() - 1]);
1281        }
1282    }
1283    None
1284}
1285
1286/// Spaces off both ends, because `[0, 1]` is a path a person types.
1287fn trim(part: &[u8]) -> &[u8] {
1288    let from = part.iter().position(|&c| c != b' ').unwrap_or(part.len());
1289    let to = part
1290        .iter()
1291        .rposition(|&c| c != b' ')
1292        .map_or(from, |i| i + 1);
1293    &part[from..to]
1294}
1295
1296#[cfg(test)]
1297mod tests {
1298    use super::*;
1299    use crate::from_json;
1300
1301    /// `{"store":{"book":[{"title":"a","price":8},{"title":"b","price":22}],
1302    ///   "bike":{"price":19}},"expensive":10}`
1303    ///
1304    /// The shape from the JSONPath paper, which is what every implementation is
1305    /// tested against, so a reader who knows the paper knows these documents.
1306    fn doc() -> Vec<u8> {
1307        from_json(
1308            br#"{"store":{"book":[{"title":"a","price":8},{"title":"b","price":22}],
1309                 "bike":{"price":19}},"expensive":10}"#,
1310        )
1311        .expect("the text parses")
1312    }
1313
1314    /// What `path` names in [`doc`], as JSON text, so a whole answer fits on a
1315    /// line and reads like the thing it is.
1316    fn ask(bytes: &[u8], path: &str) -> String {
1317        let v = Value::new(bytes).expect("readable");
1318        let mut hits = Vec::new();
1319        Path::parse(path.as_bytes())
1320            .expect("the path parses")
1321            .select(&v, &mut hits);
1322        let mut out = Vec::new();
1323        out.push(b'[');
1324        for (i, hit) in hits.iter().enumerate() {
1325            if i > 0 {
1326                out.push(b',');
1327            }
1328            hit.write_json(&mut out).expect("writable");
1329        }
1330        out.push(b']');
1331        String::from_utf8(out).expect("UTF-8")
1332    }
1333
1334    fn why(path: &str) -> String {
1335        Path::parse(path.as_bytes())
1336            .expect_err("this should not parse")
1337            .message()
1338            .to_string()
1339    }
1340
1341    /// The root has three spellings and one of them is a bare dot, which is
1342    /// what the `JSON.*` commands use when the client gave no path at all.
1343    #[test]
1344    fn a_bare_dot_is_the_root_and_is_the_only_dot_with_nothing_after_it() {
1345        for spelling in ["$", ".", ""] {
1346            let p = Path::parse(spelling.as_bytes()).expect("the path parses");
1347            assert!(p.is_root(), "{spelling} should be the root");
1348            assert!(p.is_definite(), "{spelling} names one place");
1349        }
1350        assert!(!Path::parse(b"$").expect("parses").legacy());
1351        assert!(Path::parse(b".").expect("parses").legacy());
1352        let d = doc();
1353        assert_eq!(
1354            ask(&d, "."),
1355            format!(
1356                "[{}]",
1357                String::from_utf8_lossy(
1358                    &Value::new(&d)
1359                        .expect("readable")
1360                        .to_json()
1361                        .expect("writable")
1362                )
1363            )
1364        );
1365        // Every other dot still has to be followed by something.
1366        assert!(why("..").contains("`..` with nothing after it"));
1367        assert!(why(".a.").contains("no name after it"));
1368        assert!(why("$.").contains("no name after it"));
1369    }
1370
1371    #[test]
1372    fn a_path_that_names_one_place_names_the_same_place_it_always_did() {
1373        let d = doc();
1374        assert_eq!(ask(&d, "$.expensive"), "[10]");
1375        assert_eq!(ask(&d, "$.store.bike.price"), "[19]");
1376        assert_eq!(ask(&d, "$.store.book[0].title"), r#"["a"]"#);
1377        assert_eq!(ask(&d, "$.store.book[-1].title"), r#"["b"]"#);
1378        assert_eq!(ask(&d, "$['store']['bike']['price']"), "[19]");
1379        assert_eq!(ask(&d, "store.bike.price"), "[19]", "the older syntax");
1380        // A bare name stops at a space, because the top level of a path is an
1381        // expression and a space is where one operand ends. A key with a space
1382        // in it is reached by quoting it.
1383        assert!(why("$.store.no such key").contains("does not start with"));
1384        assert_eq!(ask(&d, r#"$.store["no such key"]"#), "[]");
1385        assert_eq!(ask(&d, "$"), ask(&d, ""), "the root, both ways of asking");
1386    }
1387
1388    #[test]
1389    fn a_path_that_names_nothing_answers_nothing_rather_than_failing() {
1390        let d = doc();
1391        assert_eq!(ask(&d, "$.nope"), "[]");
1392        assert_eq!(ask(&d, "$.store.book[9]"), "[]");
1393        assert_eq!(ask(&d, "$.store.book[-9]"), "[]");
1394        assert_eq!(ask(&d, "$.expensive[0]"), "[]", "an index into a number");
1395        assert_eq!(ask(&d, "$.store.book.title"), "[]", "a name into an array");
1396        assert_eq!(ask(&d, "$.store[0]"), "[]", "an index into an object");
1397    }
1398
1399    #[test]
1400    fn a_wildcard_names_every_child_and_a_descent_names_every_one_below() {
1401        let d = doc();
1402        assert_eq!(ask(&d, "$.store.book[*].price"), "[8,22]");
1403        assert_eq!(ask(&d, "$.store.book[*].title"), r#"["a","b"]"#);
1404        assert_eq!(
1405            ask(&d, "$..price"),
1406            "[19,8,22]",
1407            "the bike sorts before the books"
1408        );
1409        assert_eq!(
1410            ask(&d, "$.store.*.price"),
1411            "[19]",
1412            "the bike and not the books"
1413        );
1414        assert_eq!(ask(&d, "$..book[0].price"), "[8]");
1415        assert_eq!(ask(&d, "$..[0].title"), r#"["a"]"#);
1416        // A wildcard over a scalar names nothing, which is what stops
1417        // `$..*.price` from being an error on a document with a number in it.
1418        assert_eq!(ask(&d, "$.expensive.*"), "[]");
1419    }
1420
1421    #[test]
1422    fn a_descent_walks_a_node_before_the_nodes_under_it() {
1423        let d = from_json(br#"{"a":{"b":1,"a":{"a":2}}}"#).expect("parses");
1424        assert_eq!(ask(&d, "$..a"), r#"[{"a":{"a":2},"b":1},{"a":2},2]"#);
1425    }
1426
1427    #[test]
1428    fn a_union_names_what_it_lists_in_the_order_it_lists_it() {
1429        let d = from_json(br#"{"a":1,"b":2,"c":3,"xs":[10,11,12,13]}"#).expect("parses");
1430        assert_eq!(ask(&d, "$.xs[0,2]"), "[10,12]");
1431        assert_eq!(ask(&d, "$.xs[2,0]"), "[12,10]", "and not in index order");
1432        assert_eq!(ask(&d, "$.xs[0, 2]"), "[10,12]", "spaces are allowed");
1433        assert_eq!(ask(&d, "$['b','a']"), "[2,1]");
1434        assert_eq!(ask(&d, "$.xs[0,9]"), "[10]", "one of them names nothing");
1435    }
1436
1437    #[test]
1438    fn a_slice_is_the_slice_every_other_language_has() {
1439        let d = from_json(br#"{"xs":[0,1,2,3,4,5]}"#).expect("parses");
1440        assert_eq!(ask(&d, "$.xs[1:3]"), "[1,2]");
1441        assert_eq!(ask(&d, "$.xs[:2]"), "[0,1]");
1442        assert_eq!(ask(&d, "$.xs[4:]"), "[4,5]");
1443        assert_eq!(ask(&d, "$.xs[:]"), "[0,1,2,3,4,5]");
1444        assert_eq!(ask(&d, "$.xs[-2:]"), "[4,5]");
1445        assert_eq!(ask(&d, "$.xs[:-4]"), "[0,1]");
1446        assert_eq!(ask(&d, "$.xs[0:6:2]"), "[0,2,4]");
1447        assert_eq!(ask(&d, "$.xs[::2]"), "[0,2,4]");
1448        assert_eq!(ask(&d, "$.xs[::-1]"), "[5,4,3,2,1,0]");
1449        assert_eq!(ask(&d, "$.xs[4:1:-1]"), "[4,3,2]");
1450        assert_eq!(
1451            ask(&d, "$.xs[0:1000]"),
1452            "[0,1,2,3,4,5]",
1453            "a bound is clamped"
1454        );
1455        assert_eq!(ask(&d, "$.xs[3:1]"), "[]", "an empty run is empty");
1456    }
1457
1458    #[test]
1459    fn a_path_says_whether_it_could_ever_name_two_places() {
1460        let definite = |p: &str| Path::parse(p.as_bytes()).expect("parses").is_definite();
1461        assert!(definite("$.a.b[0]"));
1462        assert!(definite("$['a'][-1]"));
1463        assert!(definite(""), "the root is one place");
1464        assert!(!definite("$.a[*]"));
1465        assert!(!definite("$..a"));
1466        assert!(!definite("$.a[0,1]"));
1467        assert!(!definite("$.a[0:2]"));
1468        assert!(!definite("$.*"));
1469    }
1470
1471    #[test]
1472    fn a_path_says_which_of_the_two_syntaxes_it_was_written_in() {
1473        let legacy = |p: &str| Path::parse(p.as_bytes()).expect("parses").legacy();
1474        assert!(!legacy("$.a"));
1475        assert!(!legacy("$"));
1476        assert!(legacy(".a"));
1477        assert!(legacy("a.b"));
1478    }
1479
1480    #[test]
1481    fn the_first_match_is_the_first_one_in_document_order() {
1482        let d = doc();
1483        let v = Value::new(&d).expect("readable");
1484        let p = Path::parse(b"$..price").expect("parses");
1485        assert_eq!(p.first(&v).expect("there").as_int(), Some(19));
1486        assert!(Path::parse(b"$.nope").expect("parses").first(&v).is_none());
1487    }
1488
1489    #[test]
1490    fn a_path_that_does_not_parse_says_so_and_says_where() {
1491        assert!(why("$.a[").contains("no `]`"));
1492        assert!(why("$.a[x]").contains("not a number"));
1493        assert!(why("$.a.").contains("no name after it"));
1494        assert!(why("$..").contains("nothing after it"));
1495        assert!(why("$.a[]").contains("not a number"));
1496        assert!(why("$.a[::0]").contains("step of zero"));
1497        assert!(why("$.a[1:2:3:4]").contains("at most a start"));
1498        assert!(why("$a").contains("does not start with"));
1499        assert!(why("$.a[x]").contains("at byte "));
1500        assert!(why("$.a[?(@.b > 1]").contains("no `)`"));
1501        assert!(why("$.a[?(@.b >)]").contains("where a value goes"));
1502        assert!(why("$.a[?(@.b > 1) 2]").contains("left over"));
1503        assert!(why("$.a[?(@.b == nope)]").contains("not a value"));
1504        assert!(why("$.a[?]").contains("where a value was expected"));
1505        // An operator with nothing after it, and a `~` on something that has no
1506        // keys to answer, which the reference refuses as well.
1507        assert!(why("$.a[?(@.b in)]").contains("where a value goes"));
1508        assert!(why("$.a[?(@.b size)]").contains("where a value goes"));
1509        assert!(why("$.a[?(@.b + )]").contains("where a value goes"));
1510        assert!(why("$.a[?(@.b~~)]").contains("no `)`"));
1511    }
1512
1513    #[test]
1514    fn the_walk_stops_at_the_depth_limit_rather_than_running_out_of_stack() {
1515        // A document at the limit, so the descent goes all the way down it and
1516        // the guard is the thing that is not tripped rather than the thing that
1517        // saves it.
1518        let text = format!("{}1{}", "[".repeat(DEPTH_MAX), "]".repeat(DEPTH_MAX));
1519        let d = from_json(text.as_bytes()).expect("parses");
1520        let v = Value::new(&d).expect("readable");
1521        let mut hits = Vec::new();
1522        Path::parse(b"$..*").expect("parses").select(&v, &mut hits);
1523        assert_eq!(hits.len(), DEPTH_MAX, "every level below the root, once");
1524    }
1525
1526    #[test]
1527    fn selecting_appends_so_that_one_buffer_serves_many_documents() {
1528        let one = from_json(br#"{"a":1}"#).expect("parses");
1529        let two = from_json(br#"{"a":2}"#).expect("parses");
1530        let p = Path::parse(b"$.a").expect("parses");
1531        let mut hits = Vec::new();
1532        p.select(&Value::new(&one).expect("readable"), &mut hits);
1533        p.select(&Value::new(&two).expect("readable"), &mut hits);
1534        let got: Vec<i64> = hits.iter().filter_map(Value::as_int).collect();
1535        assert_eq!(got, [1, 2]);
1536    }
1537
1538    /// One member per type a `p` can be, each with a name that says which, so
1539    /// that an answer reads as the list of types that survived rather than as a
1540    /// list of values.
1541    ///
1542    /// The last one has no `p` at all, which is the case most of the operators
1543    /// treat differently from the rest.
1544    fn types() -> Vec<u8> {
1545        from_json(
1546            br#"[{"p":1,"id":"i"},{"p":2.5,"id":"f"},{"p":"s","id":"t"},
1547                 {"p":null,"id":"n"},{"p":false,"id":"b"},{"p":[1],"id":"a"},
1548                 {"p":{"x":1},"id":"o"},{"q":9,"id":"m"}]"#,
1549        )
1550        .expect("the text parses")
1551    }
1552
1553    /// The ids of the members of [`types`] a filter keeps, as one string.
1554    fn kept(filter: &str) -> String {
1555        let d = types();
1556        ask(&d, &format!("$[?{filter}].id"))
1557            .replace(['[', ']', '"'], "")
1558            .replace(',', "")
1559    }
1560
1561    #[test]
1562    fn a_filter_keeps_the_children_its_expression_is_true_of() {
1563        let d = doc();
1564        assert_eq!(ask(&d, "$.store.book[?(@.price < 10)].title"), r#"["a"]"#);
1565        assert_eq!(ask(&d, "$.store.book[?(@.price > 10)].title"), r#"["b"]"#);
1566        // `$` inside a filter is the whole document rather than the member, so a
1567        // member can be compared against something somewhere else entirely.
1568        assert_eq!(
1569            ask(&d, "$.store.book[?(@.price < $.expensive)].title"),
1570            r#"["a"]"#
1571        );
1572        // The parentheses are a group like any other, so leaving them out and
1573        // padding them with spaces both read the same.
1574        assert_eq!(ask(&d, "$.store.book[?@.price<10].title"), r#"["a"]"#);
1575        assert_eq!(ask(&d, "$.store.book[? (@.price < 10) ].title"), r#"["a"]"#);
1576    }
1577
1578    /// An ordering comparison only arises between two values of the same sort,
1579    /// and where it does not arise the answer is no.
1580    #[test]
1581    fn ordering_is_within_a_type_and_not_across_one() {
1582        assert_eq!(kept("(@.p < 2)"), "i");
1583        assert_eq!(kept("(@.p > 2)"), "f");
1584        assert_eq!(kept("(@.p >= 1)"), "if");
1585        assert_eq!(kept("(@.p <= 2.5)"), "if");
1586        // Strings order by their characters, and a string is not below a number
1587        // however the two would sort if they were written out.
1588        assert_eq!(kept(r#"(@.p > "")"#), "t");
1589        assert_eq!(kept(r#"(@.p < "s")"#), "");
1590        assert_eq!(kept(r#"(@.p <= "s")"#), "t");
1591        assert_eq!(kept(r#"(@.p > "1")"#), "t");
1592        assert_eq!(kept(r#"(@.p < "1")"#), "");
1593        // `false` is below `true`, and two nulls are equal without either being
1594        // below the other.
1595        assert_eq!(kept("(@.p > false)"), "");
1596        assert_eq!(kept("(@.p >= false)"), "b");
1597        assert_eq!(kept("(@.p < true)"), "b");
1598        assert_eq!(kept("(@.p > null)"), "");
1599        assert_eq!(kept("(@.p >= null)"), "n");
1600        // An array and an object have no order at all, so even an equal one is
1601        // not below or above itself.
1602        assert_eq!(kept("(@.p >= [1])"), "");
1603        assert_eq!(kept("(@.p <= [1])"), "");
1604        assert_eq!(kept(r#"(@.p >= {"x":1})"#), "");
1605        assert_eq!(kept("(@.p > [])"), "");
1606        assert_eq!(kept("(@.p > {})"), "");
1607    }
1608
1609    /// Equality is the whole value, and the only line it crosses is the one
1610    /// between the two ways a number is held.
1611    #[test]
1612    fn equality_crosses_the_number_split_and_no_other() {
1613        assert_eq!(kept("(@.p == 1)"), "i");
1614        assert_eq!(kept("(@.p == 1.0)"), "i");
1615        assert_eq!(kept("(@.p == 2.5)"), "f");
1616        assert_eq!(kept(r#"(@.p == "s")"#), "t");
1617        assert_eq!(kept("(@.p == null)"), "n");
1618        assert_eq!(kept("(@.p == false)"), "b");
1619        assert_eq!(kept("(@.p == [1])"), "a");
1620        assert_eq!(kept(r#"(@.p == {"x":1})"#), "o");
1621        // A zero is not a false, a one is not a `"1"`, and an array of one is
1622        // not the thing it holds.
1623        assert_eq!(kept("(@.p == 0)"), "");
1624        assert_eq!(kept(r#"(@.p == "1")"#), "");
1625        assert_eq!(kept("(@.p == [2])"), "");
1626        assert_eq!(kept(r#"(@.p == {"x":2})"#), "");
1627    }
1628
1629    /// `!=` negates the comparison rather than being one, which is the whole
1630    /// difference: a member with no `p` satisfies it and satisfies nothing else.
1631    #[test]
1632    fn not_equal_is_the_negation_of_the_whole_comparison() {
1633        assert_eq!(kept("(@.p != 1)"), "ftnbaom");
1634        assert_eq!(kept("(@.p != 9)"), "iftnbaom");
1635        // Two sides that both answer nothing are equal to nothing, so this keeps
1636        // every member and its opposite keeps none.
1637        assert_eq!(kept("(@.zz == @.yy)"), "");
1638        assert_eq!(kept("(@.zz != @.yy)"), "iftnbaom");
1639    }
1640
1641    /// An operand on its own asks whether the document has it, so a `p` that is
1642    /// there is true whatever it holds.
1643    #[test]
1644    fn a_bare_operand_asks_whether_it_is_there() {
1645        assert_eq!(kept("(@.p)"), "iftnbao");
1646        assert_eq!(kept("(!@.p)"), "m");
1647        assert_eq!(kept("!@.p"), "m");
1648        assert_eq!(kept("(@.q)"), "m");
1649        // A literal is itself, and the only one that is false is the one that
1650        // says so.
1651        assert_eq!(kept("(false)"), "");
1652        assert_eq!(kept("(0)"), "iftnbaom");
1653        assert_eq!(kept(r#"("")"#), "iftnbaom");
1654        assert_eq!(kept("(null)"), "iftnbaom");
1655        assert_eq!(kept("(true)"), "iftnbaom");
1656    }
1657
1658    #[test]
1659    fn and_binds_tighter_than_or() {
1660        // Read the other way round this would keep nothing, because no member is
1661        // both an `i` and dearer than a hundred.
1662        assert_eq!(kept(r#"(@.id == "i" || @.id == "f" && @.p > 100)"#), "i");
1663        assert_eq!(kept(r#"(@.id == "i" && @.p == 1 || @.id == "t")"#), "it");
1664        assert_eq!(kept(r#"((@.id == "i" || @.id == "f") && @.p > 2)"#), "f");
1665        assert_eq!(kept(r#"(!(@.id == "i") && @.p == 2.5)"#), "f");
1666    }
1667
1668    /// A path answers a set, so a comparison asks whether any pair out of the
1669    /// two sets satisfies it.
1670    #[test]
1671    fn a_comparison_holds_when_any_pair_of_answers_does() {
1672        let d = from_json(br#"[{"t":["x","y"]},{"t":["z"]},{"t":[]}]"#).expect("parses");
1673        assert_eq!(ask(&d, r#"$[?(@.t[*] == "y")].t"#), r#"[["x","y"]]"#);
1674        assert_eq!(ask(&d, r#"$[?(@.t[*] == "q")].t"#), "[]");
1675        // An empty set satisfies nothing, and `!=` is the one operator that
1676        // reads that as true.
1677        assert_eq!(ask(&d, r#"$[?(@.t[*] != "z")].t"#), r#"[["x","y"],[]]"#);
1678        // A path under `@` is a path like any other, `*` and `..` included.
1679        assert_eq!(kept("(@..x == 1)"), "o");
1680        // `[*]` is every child of a container and an object is a container, so
1681        // the object whose only member is a one is kept alongside the array.
1682        assert_eq!(kept("(@.p[*] == 1)"), "ao");
1683    }
1684
1685    #[test]
1686    fn a_pattern_is_unanchored_and_minds_its_case() {
1687        assert_eq!(kept(r#"(@.p =~ "s")"#), "t");
1688        assert_eq!(kept(r#"(@.p =~ "^s$")"#), "t");
1689        assert_eq!(kept(r#"(@.p =~ "S")"#), "");
1690        assert_eq!(kept(r#"(@.p =~ "^x")"#), "");
1691        // A pattern that is not a string, and a pattern that is not a pattern,
1692        // both answer no rather than refusing the path.
1693        assert_eq!(kept("(@.p =~ 1)"), "");
1694        assert_eq!(kept("(@.p =~ null)"), "");
1695        assert_eq!(kept(r#"(@.p =~ "[")"#), "");
1696    }
1697
1698    /// A filter walks the children of whatever it is applied to, and an object
1699    /// has children too.
1700    #[test]
1701    fn a_filter_reads_an_object_the_same_way_it_reads_an_array() {
1702        let d = from_json(br#"{"one":{"p":1},"two":{"p":9}}"#).expect("parses");
1703        assert_eq!(ask(&d, "$[?(@.p < 5)]"), r#"[{"p":1}]"#);
1704        assert_eq!(ask(&d, "$.*[?(@.p < 5)]"), "[]");
1705        // Nothing that is not a container has children, so a filter over one
1706        // answers nothing rather than answering it.
1707        let flat = from_json(br#"[1,"a",null]"#).expect("parses");
1708        assert_eq!(ask(&flat, "$[*][?(@.p)]"), "[]");
1709    }
1710
1711    /// A filter is a selector, so it composes with the rest of them and a path
1712    /// can go on after it or hold more than one.
1713    #[test]
1714    fn a_filter_is_a_selector_like_the_others() {
1715        let d = from_json(
1716            br#"{"runs":[{"ok":true,"steps":[{"ms":9},{"ms":31}]},
1717                        {"ok":false,"steps":[{"ms":2}]}]}"#,
1718        )
1719        .expect("parses");
1720        assert_eq!(
1721            ask(&d, "$.runs[?(@.ok == true)].steps[?(@.ms > 10)].ms"),
1722            "[31]"
1723        );
1724        assert_eq!(ask(&d, "$..steps[?(@.ms < 10)].ms"), "[9,2]");
1725        // A filter is not one place, so it is not somewhere a value can be
1726        // grown, which is what `JSON.SET` asks about.
1727        assert!(
1728            !Path::parse(b"$.runs[?(@.ok)]")
1729                .expect("parses")
1730                .is_definite()
1731        );
1732    }
1733
1734    /// `in` is membership in the elements of the right side, and `anyof`,
1735    /// `noneof` and `subsetof` are all about two arrays rather than about a
1736    /// value and an array.
1737    #[test]
1738    fn the_membership_operators_read_an_array_on_the_right() {
1739        assert_eq!(kept("(@.p in [1,2])"), "i");
1740        assert_eq!(kept("(@.p nin [1,2])"), "ftnbaom");
1741        // Membership is the same equality as `==`, so it reaches every type.
1742        assert_eq!(kept(r#"(@.p in [[1],{"x":1},null,false,"s"])"#), "tnbao");
1743        // These three want an array on the left as well, which only `a` has.
1744        assert_eq!(kept("(@.p anyof [1,9])"), "a");
1745        assert_eq!(kept("(@.p noneof [1,9])"), "iftnbom");
1746        assert_eq!(kept("(@.p subsetof [1,2,3])"), "a");
1747        // `nin` and `noneof` negate the whole comparison, so the member with no
1748        // `p` at all satisfies them and satisfies nothing else here.
1749        assert_eq!(kept("(@.p subsetof [])"), "");
1750    }
1751
1752    /// `size` and `empty` are the one length a string, an array and an object
1753    /// each have, and nothing else has one.
1754    #[test]
1755    fn size_and_empty_are_about_the_three_types_with_a_length() {
1756        assert_eq!(kept("(@.p size 1)"), "tao");
1757        assert_eq!(kept("(@.p size 0)"), "");
1758        assert_eq!(kept("(@.p empty false)"), "tao");
1759        assert_eq!(kept("(@.p empty true)"), "");
1760        let d = from_json(br#"[{"p":"","id":"s"},{"p":[],"id":"a"},{"p":{},"id":"o"}]"#)
1761            .expect("parses");
1762        assert_eq!(ask(&d, "$[?(@.p empty true)].id"), r#"["s","a","o"]"#);
1763        assert_eq!(ask(&d, "$[?(@.p size 0)].id"), r#"["s","a","o"]"#);
1764    }
1765
1766    /// The six postfix methods, and the one thing that separates `count()` from
1767    /// the rest of them.
1768    #[test]
1769    fn a_method_answers_something_the_document_does_not_hold() {
1770        assert_eq!(kept("(@.p.length() == 1)"), "tao");
1771        // `count()` is how many values the operand answered, so it answers a
1772        // number for an operand that answered nothing, which none of the others
1773        // do.
1774        assert_eq!(kept("(@.p.count() == 1)"), "iftnbao");
1775        assert_eq!(kept("(@.p.count() == 0)"), "m");
1776        // The aggregates want an array of numbers, and `[1]` is the only one.
1777        assert_eq!(kept("(@.p.min() == 1)"), "a");
1778        assert_eq!(kept("(@.p.max() == 1)"), "a");
1779        assert_eq!(kept("(@.p.sum() == 1)"), "a");
1780        assert_eq!(kept("(@.p.avg() == 1)"), "a");
1781        // A name that is not one of the six answers nothing rather than being a
1782        // path that will not parse.
1783        assert_eq!(kept("(@.p.size() == 1)"), "");
1784        assert_eq!(kept("(@.p.nope() == 1)"), "");
1785    }
1786
1787    /// Arithmetic is over numbers, it binds the way it does everywhere else,
1788    /// and it composes with a method on either side.
1789    #[test]
1790    fn arithmetic_is_numbers_and_the_usual_precedence() {
1791        assert_eq!(kept("(@.p + 1 == 2)"), "i");
1792        assert_eq!(kept("(@.p - 1 == 0)"), "i");
1793        assert_eq!(kept("(@.p * 2 == 5)"), "f");
1794        assert_eq!(kept("(@.p / 2 == 0.5)"), "i");
1795        assert_eq!(kept("(@.p % 2 == 1)"), "i");
1796        assert_eq!(kept("(@.p + @.p == 2)"), "i");
1797        assert_eq!(kept("(@.p.length() + 1 == 2)"), "tao");
1798        // Everything is kept when the expression has no operand in it at all,
1799        // which is what makes these two about precedence and nothing else.
1800        assert_eq!(kept("(1 + 2 * 3 == 7)"), "iftnbaom");
1801        assert_eq!(kept("((1 + 2) * 3 == 9)"), "iftnbaom");
1802        assert_eq!(kept("(1 + 2 * 3 == 9)"), "");
1803        // `*` is the one that does not need its spaces. The other four are
1804        // characters a key name can hold, so without spaces they are part of the
1805        // name and the member they name is not there.
1806        assert_eq!(kept("(@.p*2==2)"), "i");
1807        assert_eq!(kept("(@.p+1==2)"), "");
1808        assert_eq!(kept("(@.p/2==0.5)"), "");
1809        assert_eq!(kept("(@.p%2==1)"), "");
1810        let d = from_json(br#"[{"a-b":1,"a+b":2,"a/b":3,"id":"k"}]"#).expect("parses");
1811        assert_eq!(ask(&d, r#"$[?(@.a-b == 1)].id"#), r#"["k"]"#);
1812        assert_eq!(ask(&d, r#"$[?(@.a+b == 2)].id"#), r#"["k"]"#);
1813        assert_eq!(ask(&d, r#"$[?(@.a/b == 3)].id"#), r#"["k"]"#);
1814        // Straight after a `]` no name can be running, so there the four are
1815        // operators with no spaces around them.
1816        let d = from_json(br#"[{"l":[4],"id":"k"}]"#).expect("parses");
1817        assert_eq!(ask(&d, r#"$[?(@.l[0]-1 == 3)].id"#), r#"["k"]"#);
1818        assert_eq!(ask(&d, r#"$[?(@.l[0]+1 == 5)].id"#), r#"["k"]"#);
1819    }
1820
1821    /// Arithmetic and the methods want one node and answer nothing for two,
1822    /// which is the one place a filter is not written against sets. `count()`
1823    /// is outside the rule.
1824    #[test]
1825    fn arithmetic_and_the_methods_want_one_node() {
1826        let d = from_json(
1827            br#"[{"l":[1,2],"s":["ab","cd"],"id":"two"},{"l":[1],"s":["a"],"id":"one"}]"#,
1828        )
1829        .expect("parses");
1830        assert_eq!(ask(&d, "$[?(@.l[*] + 1 == 2)].id"), r#"["one"]"#);
1831        assert_eq!(ask(&d, "$[?(@.s[*].length() == 1)].id"), r#"["one"]"#);
1832        assert_eq!(ask(&d, "$[?(-@.l[*] == -1)].id"), r#"["one"]"#);
1833        assert_eq!(ask(&d, "$[?(@.l[*].count() == 2)].id"), r#"["two"]"#);
1834    }
1835
1836    /// `~` answers the key names of an object, as a set of strings rather than
1837    /// as an array value.
1838    #[test]
1839    fn the_keys_operator_answers_a_name_at_a_time() {
1840        assert_eq!(kept("(@.p~)"), "o");
1841        assert_eq!(kept(r#"(@.p~ == "x")"#), "o");
1842        assert_eq!(kept(r#"(@.p~ != "x")"#), "iftnbam");
1843        // The operators that want a collection read the whole set as one, so
1844        // `size` is how many keys there are and not how long a key is.
1845        assert_eq!(kept("(@.p~ size 1)"), "o");
1846        assert_eq!(kept(r#"(@.p~ subsetof ["x"])"#), "o");
1847        assert_eq!(kept(r#"(@.p~ anyof ["x"])"#), "o");
1848        assert_eq!(kept(r#"(@.p~ noneof ["x"])"#), "iftnbam");
1849        assert_eq!(kept("(@.p~ empty false)"), "o");
1850        assert_eq!(kept("(@.p~ empty true)"), "");
1851        // `in` and `=~` do not take a key name, which is the reference's
1852        // behaviour and not a rule with a reason behind it.
1853        assert_eq!(kept(r#"(@.p~ in ["x"])"#), "");
1854        assert_eq!(kept(r#"(@.p~ =~ "x")"#), "");
1855        assert_eq!(kept(r#"(@.p~ nin ["x"])"#), "iftnbaom");
1856        // A two key object counts as two, and nothing that is not an object
1857        // answers at all.
1858        let d = from_json(br#"[{"p":{"abc":1},"id":"one"},{"p":{"a":1,"b":2},"id":"two"}]"#)
1859            .expect("parses");
1860        assert_eq!(ask(&d, "$[?(@.p~ size 1)].id"), r#"["one"]"#);
1861        assert_eq!(ask(&d, "$[?(@.p~ size 2)].id"), r#"["two"]"#);
1862        assert_eq!(ask(&d, "$[?(@.p~ size 3)].id"), "[]");
1863    }
1864
1865    /// A set of key names is a collection wherever a collection goes, including
1866    /// on the right of one of the collection operators.
1867    #[test]
1868    fn a_key_set_reads_as_a_collection_on_either_side() {
1869        assert_eq!(kept(r#"("x" in @.p~)"#), "o");
1870        assert_eq!(kept(r#"("q" in @.p~)"#), "");
1871        assert_eq!(kept("(@.p~ anyof @.p~)"), "o");
1872        assert_eq!(kept("(@.p~ subsetof @.p~)"), "o");
1873        assert_eq!(kept("(@.p~ noneof @.p~)"), "iftnbam");
1874        assert_eq!(kept(r#"(["x"] subsetof @.p~)"#), "o");
1875        // A path is a collection on the right too, so a value can be looked for
1876        // in an array the member itself holds.
1877        assert_eq!(kept("(1 in @.p)"), "a");
1878        assert_eq!(kept("(2 in @.p)"), "");
1879    }
1880
1881    /// An object with no keys answers a set that is there and empty, and
1882    /// something that is not an object answers no set at all. Every collection
1883    /// operator can tell the two apart.
1884    #[test]
1885    fn an_empty_object_has_a_key_set_and_a_scalar_has_none() {
1886        let d = from_json(br#"[{"p":{},"id":"e"},{"p":1,"id":"s"},{"id":"m"}]"#).expect("parses");
1887        for (path, want) in [
1888            (r#"$[?(@.p~ subsetof ["x"])].id"#, r#"["e"]"#),
1889            (r#"$[?(@.p~ anyof ["x"])].id"#, "[]"),
1890            // `noneof` is the negation of the whole comparison, so a side that
1891            // answers no set at all makes it true.
1892            (r#"$[?(@.p~ noneof ["x"])].id"#, r#"["e","s","m"]"#),
1893            ("$[?(@.p~ empty true)].id", r#"["e"]"#),
1894            ("$[?(@.p~ empty false)].id", "[]"),
1895            ("$[?(@.p~ size 0)].id", r#"["e"]"#),
1896            // The bare test is about answering a name, and an empty set answers
1897            // none, so it is the one place the two read alike.
1898            ("$[?(@.p~)].id", "[]"),
1899        ] {
1900            assert_eq!(ask(&d, path), want, "{path}");
1901        }
1902    }
1903
1904    /// `sizeof` is another spelling of `size`, and a leading `-` or `+` is a
1905    /// number or nothing at all.
1906    #[test]
1907    fn the_alias_and_the_signs_read_the_way_the_reference_reads_them() {
1908        assert_eq!(kept("(@.p sizeof 1)"), "tao");
1909        assert_eq!(kept("(@.p size 1)"), "tao");
1910        assert_eq!(kept("(-@.p == -1)"), "i");
1911        assert_eq!(kept("(+@.p == 1)"), "i");
1912        assert_eq!(kept("(@.p == +1)"), "i");
1913        assert_eq!(kept("(@.p > -1)"), "if");
1914        assert_eq!(kept("(@.p - -1 == 2)"), "i");
1915        // A sign is a number and nothing else, so it drops a string rather than
1916        // passing it along, and the bare test on it is that number's own test.
1917        assert_eq!(kept("(-@.p)"), "if");
1918        // One sign and no more, and a group is how a second one is written.
1919        assert_eq!(kept("(-(-@.p) == 1)"), "i");
1920        assert!(why("$[?(--@.p == 1)]").contains("not a value"));
1921    }
1922
1923    /// What a projection answers over [`doc`], as JSON text, the same way
1924    /// [`ask`] reads a path.
1925    fn sum(bytes: &[u8], path: &str) -> String {
1926        let v = Value::new(bytes).expect("readable");
1927        let p = Path::parse(path.as_bytes()).expect("the path parses");
1928        assert!(p.is_projection(), "{path} should be a projection");
1929        let mut out = Vec::new();
1930        out.push(b'[');
1931        for (i, got) in p.project(&v).iter().enumerate() {
1932            if i > 0 {
1933                out.push(b',');
1934            }
1935            got.write_json_at(&crate::Format::default(), &mut out, 0)
1936                .expect("writable");
1937        }
1938        out.push(b']');
1939        String::from_utf8(out).expect("UTF-8")
1940    }
1941
1942    /// A path that is an expression rather than a way through the document.
1943    #[test]
1944    fn a_projection_works_something_out_rather_than_naming_a_place() {
1945        let d = doc();
1946        assert_eq!(sum(&d, "$.expensive + 1"), "[11]");
1947        assert_eq!(sum(&d, "$.expensive * 2"), "[20]");
1948        assert_eq!(sum(&d, "-$.expensive"), "[-10]");
1949        assert_eq!(sum(&d, "$.store.book.length()"), "[2]");
1950        assert_eq!(sum(&d, "$.store.book[*].count()"), "[2]");
1951        assert_eq!(sum(&d, "$.store.bike~"), r#"["price"]"#);
1952        // A division is a fraction however evenly it divides, and the four
1953        // aggregates are fractions too, which is the reference's doing rather
1954        // than anything the arithmetic asks for.
1955        assert_eq!(sum(&d, "$.expensive / 1"), "[10.0]");
1956        assert_eq!(sum(&d, "$.store.book[*].price.sum()"), "[]");
1957        // Nothing at all rather than the error a path would raise, and an array
1958        // even when the path was written the legacy way.
1959        assert_eq!(sum(&d, "$.nope + 1"), "[]");
1960        assert_eq!(sum(&d, "$.nope.count()"), "[0]");
1961        assert_eq!(sum(&d, "$.expensive / 0"), "[]");
1962        assert_eq!(sum(&d, ".expensive + 1"), "[11]");
1963        assert_eq!(sum(&d, ".store.book.length()"), "[2]");
1964        // The first thing up here is a path however it is written, so this is a
1965        // member really called `2` and not the number. Inside a group the
1966        // ordinary rules are back.
1967        assert_eq!(sum(&d, "2 + 3"), "[]");
1968        assert_eq!(sum(&d, "(2) + 3"), "[5]");
1969        // A path is a path and not a projection, which is what keeps every
1970        // other `JSON.*` command working.
1971        for path in ["$.expensive", "$..price", "$.store.book[?(@.price < 10)]"] {
1972            let p = Path::parse(path.as_bytes()).expect("parses");
1973            assert!(!p.is_projection(), "{path} is a path");
1974        }
1975        // `@` has no meaning outside a filter, so a projection that mentions one
1976        // is not a projection and does not parse as a path either.
1977        assert!(why("@.expensive + 1").contains("does not start with"));
1978    }
1979}