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}