rsonpath_syntax/
builder.rs

1//! Utility for building a [`JsonPathQuery`](`crate::JsonPathQuery`)
2//! programmatically.
3//!
4//! The entrypoint is the [`JsonPathQueryBuilder`].
5//! Consult the structs documentation for details.
6
7use crate::{
8    num::JsonInt, str::JsonString, Comparable, ComparisonExpr, ComparisonOp, Index, JsonPathQuery, Literal,
9    LogicalExpr, Segment, Selector, Selectors, SingularJsonPathQuery, SingularSegment, Slice, TestExpr,
10};
11
12/// Builder for [`JsonPathQuery`] instances.
13///
14/// # Examples
15/// ```
16/// # use rsonpath_syntax::{JsonPathQuery, builder::JsonPathQueryBuilder, str::JsonString};
17/// let mut builder = JsonPathQueryBuilder::new();
18///     
19/// builder.child_name("a")
20///     .descendant_name("b")
21///     .child_wildcard()
22///     .child_name("c")
23///     .descendant_wildcard()
24///     .child_slice(|x| x.with_start(3).with_end(-7).with_step(2));
25///
26/// // Can also use `builder.build()` as a non-consuming version.
27/// let query: JsonPathQuery = builder.into();
28///
29/// assert_eq!(query.to_string(), "$['a']..['b'][*]['c']..[*][3:-7:2]");
30/// ```
31pub struct JsonPathQueryBuilder {
32    segments: Vec<Segment>,
33}
34
35/// Builder for a [`Selectors`] collection used by the [`JsonPathQueryBuilder`]
36/// to create multiple [`Selector`] instances within a [`Segment`].
37pub struct JsonPathSelectorsBuilder {
38    selectors: Vec<Selector>,
39}
40
41impl JsonPathQueryBuilder {
42    /// Initialize an empty builder.
43    ///
44    /// # Examples
45    /// ```
46    /// # use rsonpath_syntax::{JsonPathQuery, builder::JsonPathQueryBuilder};
47    /// let builder = JsonPathQueryBuilder::new();
48    /// let query: JsonPathQuery = builder.into();
49    ///
50    /// assert!(query.segments().is_empty());
51    /// ```
52    #[must_use]
53    #[inline(always)]
54    pub fn new() -> Self {
55        Self { segments: vec![] }
56    }
57
58    /// Add a child segment with selectors defined in the `selectors_builder` function.
59    ///
60    /// See the documentation of [`JsonPathSelectorsBuilder`] for selector building details.
61    ///
62    /// ## Examples
63    ///
64    /// ```rust
65    /// # use rsonpath_syntax::{Selector, Index, str::JsonString, num::JsonUInt, builder::JsonPathQueryBuilder};
66    /// let mut builder = JsonPathQueryBuilder::new();
67    /// builder.child(|x| x.name("abc").index(10).wildcard());
68    /// let result = builder.into_query();
69    /// assert_eq!(result.segments().len(), 1);
70    /// let segment = &result.segments()[0];
71    /// assert!(segment.is_child());
72    /// assert_eq!(&segment.selectors().as_slice(), &[
73    ///     Selector::Name(JsonString::new("abc")),
74    ///     Selector::Index(Index::FromStart(JsonUInt::from(10))),
75    ///     Selector::Wildcard,
76    /// ]);
77    /// ```
78    #[inline]
79    pub fn child<F>(&mut self, selectors_builder: F) -> &mut Self
80    where
81        F: FnOnce(&mut JsonPathSelectorsBuilder) -> &mut JsonPathSelectorsBuilder,
82    {
83        let mut builder = JsonPathSelectorsBuilder::new();
84        selectors_builder(&mut builder);
85        self.segments.push(Segment::Child(builder.build()));
86        self
87    }
88
89    /// Add a descendant segment with selectors defined in the `selectors_builder` function.
90    ///
91    /// See the documentation of [`JsonPathSelectorsBuilder`] for selector building details.
92    ///
93    /// ## Examples
94    ///
95    /// ```rust
96    /// # use rsonpath_syntax::{Selector, Index, str::JsonString, num::JsonUInt, builder::JsonPathQueryBuilder};
97    /// let mut builder = JsonPathQueryBuilder::new();
98    /// builder.descendant(|x| x.name("abc").index(10).wildcard());
99    /// let result = builder.into_query();
100    /// assert_eq!(result.segments().len(), 1);
101    /// let segment = &result.segments()[0];
102    /// assert!(segment.is_descendant());
103    /// assert_eq!(&segment.selectors().as_slice(), &[
104    ///     Selector::Name(JsonString::new("abc")),
105    ///     Selector::Index(Index::FromStart(JsonUInt::from(10))),
106    ///     Selector::Wildcard,
107    /// ]);
108    /// ```
109    #[inline]
110    pub fn descendant<F>(&mut self, selectors_builder: F) -> &mut Self
111    where
112        F: FnOnce(&mut JsonPathSelectorsBuilder) -> &mut JsonPathSelectorsBuilder,
113    {
114        let mut builder = JsonPathSelectorsBuilder::new();
115        selectors_builder(&mut builder);
116        self.segments.push(Segment::Descendant(builder.build()));
117        self
118    }
119
120    /// Add a child segment with a single name selector.
121    ///
122    /// This is a shorthand for `.child(|x| x.name(name))`.
123    #[inline(always)]
124    pub fn child_name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
125        self.child(|x| x.name(name))
126    }
127
128    /// Add a child segment with a single wildcard selector.
129    ///
130    /// This is a shorthand for `.child(|x| x.wildcard())`.
131    #[inline(always)]
132    pub fn child_wildcard(&mut self) -> &mut Self {
133        self.child(|x| x.wildcard())
134    }
135
136    /// Add a child segment with a single index selector.
137    ///
138    /// This is a shorthand for `.child(|x| x.index(idx))`.
139    #[inline(always)]
140    pub fn child_index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
141        self.child(|x| x.index(idx))
142    }
143
144    /// Add a child segment with a single slice selector.
145    ///
146    /// This is a shorthand for `.child(|x| x.slice(slice_builder))`.
147    #[inline(always)]
148    pub fn child_slice<F>(&mut self, slice_builder: F) -> &mut Self
149    where
150        F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
151    {
152        self.child(|x| x.slice(slice_builder))
153    }
154
155    /// Add a child segment with a single filter selector.
156    ///
157    /// This is a shorthand for `.child(|x| x.filter(filter_builder))`.
158    #[inline(always)]
159    pub fn child_filter<F>(&mut self, filter_builder: F) -> &mut Self
160    where
161        F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
162    {
163        self.child(|x| x.filter(filter_builder))
164    }
165
166    /// Add a descendant segment with a single name selector.
167    ///
168    /// This is a shorthand for `.descendant(|x| x.name(name))`.
169    #[inline(always)]
170    pub fn descendant_name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
171        self.descendant(|x| x.name(name))
172    }
173
174    /// Add a descendant segment with a single name selector.
175    ///
176    /// This is a shorthand for `.descendant(|x| x.wildcard())`.
177    #[inline(always)]
178    pub fn descendant_wildcard(&mut self) -> &mut Self {
179        self.descendant(|x| x.wildcard())
180    }
181
182    /// Add a descendant segment with a single name selector.
183    ///
184    /// This is a shorthand for `.descendant(|x| x.index(idx))`.
185    #[inline(always)]
186    pub fn descendant_index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
187        self.descendant(|x| x.index(idx))
188    }
189
190    /// Add a descendant segment with a single slice selector.
191    ///
192    /// This is a shorthand for `.descendant(|x| x.slice(slice_builder))`.
193    #[inline(always)]
194    pub fn descendant_slice<F>(&mut self, slice_builder: F) -> &mut Self
195    where
196        F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
197    {
198        self.descendant(|x| x.slice(slice_builder))
199    }
200
201    /// Add a descendant segment with a single filter selector.
202    ///
203    /// This is a shorthand for `.descendant(|x| x.filter(filter_builder))`.
204    #[inline(always)]
205    pub fn descendant_filter<F>(&mut self, filter_builder: F) -> &mut Self
206    where
207        F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
208    {
209        self.descendant(|x| x.filter(filter_builder))
210    }
211
212    /// Produce a [`JsonPathQuery`] from the builder.
213    ///
214    /// This clones all data in the builder to create the query.
215    /// If possible, use [`into_query`](JsonPathQueryBuilder::into_query)
216    /// to consume the builder and avoid a copy.
217    #[must_use]
218    #[inline]
219    pub fn to_query(&mut self) -> JsonPathQuery {
220        JsonPathQuery {
221            segments: self.segments.clone(),
222        }
223    }
224
225    /// Produce a [`JsonPathQuery`] by consuming this builder.
226    ///
227    /// To avoid consuming the builder use [`to_query`](JsonPathQueryBuilder::to_query).
228    #[must_use]
229    #[inline]
230    pub fn into_query(self) -> JsonPathQuery {
231        JsonPathQuery {
232            segments: self.segments,
233        }
234    }
235}
236
237impl JsonPathSelectorsBuilder {
238    fn new() -> Self {
239        Self { selectors: vec![] }
240    }
241
242    fn build(self) -> Selectors {
243        Selectors::many(self.selectors)
244    }
245
246    /// Add a name selector with a given `name` string to the collection.
247    ///
248    /// ## Examples
249    ///
250    /// ```rust
251    /// # use rsonpath_syntax::prelude::*;
252    /// let mut builder = JsonPathQueryBuilder::new();
253    /// builder.child(|x| x.name("book").name("journal"));
254    /// let result = builder.into_query();
255    /// assert_eq!(result.segments().len(), 1);
256    /// let segment = &result.segments()[0];
257    /// assert_eq!(segment.selectors().as_slice(), &[
258    ///     Selector::Name(JsonString::new("book")),
259    ///     Selector::Name(JsonString::new("journal")),
260    /// ]);
261    /// ```
262    #[inline(always)]
263    pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
264        self.selectors.push(Selector::Name(name.into()));
265        self
266    }
267
268    /// Add an index selector based on a given JSON integer.
269    ///
270    /// The result is a [`Selector::Index`] with an [`Index::FromStart`]
271    /// if `idx` converts to a non-negative [`JsonInt`], and [`Index::FromEnd`]
272    /// otherwise.
273    ///
274    /// ## Examples
275    ///
276    /// ```rust
277    /// # use rsonpath_syntax::{prelude::*, num::JsonNonZeroUInt};
278    /// let mut builder = JsonPathQueryBuilder::new();
279    /// builder.child(|x| x.index(10).index(-20));
280    /// let result = builder.into_query();
281    /// assert_eq!(result.segments().len(), 1);
282    /// let segment = &result.segments()[0];
283    /// assert_eq!(segment.selectors().as_slice(), &[
284    ///     Selector::Index(Index::FromStart(JsonUInt::from(10))),
285    ///     Selector::Index(Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap())),
286    /// ]);
287    /// ```
288    #[inline(always)]
289    pub fn index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
290        let json_int: JsonInt = idx.into();
291        self.selectors.push(Selector::Index(Index::from(json_int)));
292        self
293    }
294
295    /// Add a slice selector based on a given start, end, and step integers.
296    ///
297    /// The result is a [`Selector::Slice`] with given `start`, `end`, and `step`.
298    ///
299    /// ## Examples
300    ///
301    /// ```rust
302    /// # use rsonpath_syntax::{prelude::*, num::JsonNonZeroUInt};
303    /// let mut builder = JsonPathQueryBuilder::new();
304    /// builder.child(|x| x
305    ///     .slice(|s| s.with_start(10).with_end(-20).with_step(5))
306    ///     .slice(|s| s.with_start(-20).with_step(-30)));
307    /// let result = builder.into_query();
308    ///
309    /// assert_eq!(result.segments().len(), 1);
310    /// let segment = &result.segments()[0];
311    /// let selectors = segment.selectors().as_slice();
312    /// match (&selectors[0], &selectors[1]) {
313    ///     (Selector::Slice(s1), Selector::Slice(s2)) => {
314    ///         assert_eq!(s1.start(), Index::FromStart(10.into()));
315    ///         assert_eq!(s1.end(), Some(Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap())));
316    ///         assert_eq!(s1.step(), Step::Forward(5.into()));
317    ///         assert_eq!(s2.start(), Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap()));
318    ///         assert_eq!(s2.end(), None);
319    ///         assert_eq!(s2.step(), Step::Backward(JsonNonZeroUInt::try_from(30).unwrap()));
320    ///     }
321    ///     _ => unreachable!()
322    /// }
323    /// ```
324    #[inline(always)]
325    pub fn slice<F>(&mut self, slice_builder: F) -> &mut Self
326    where
327        F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
328    {
329        let mut slice = SliceBuilder::new();
330        slice_builder(&mut slice);
331        let slice = slice.into();
332        self.selectors.push(Selector::Slice(slice));
333        self
334    }
335
336    /// Add a wildcard selector.
337    ///
338    /// ```rust
339    /// # use rsonpath_syntax::prelude::*;
340    /// let mut builder = JsonPathQueryBuilder::new();
341    /// builder.child(|x| {
342    ///     x.filter(|x| {
343    ///         x.comparison(|x| {
344    ///             x.query_relative(|x| x.name("price"))
345    ///              .less_than()
346    ///              .literal(JsonInt::from(10))
347    ///         })
348    ///     })
349    /// });
350    /// let result = builder.into_query();
351    /// assert_eq!(result.segments().len(), 1);
352    /// let segment = &result.segments()[0];
353    /// assert_eq!(segment.selectors().len(), 1);
354    /// let selector = segment.selectors().first();
355    ///
356    /// let Selector::Filter(LogicalExpr::Comparison(expr)) = selector else {
357    ///     panic!("expected comparison filter")
358    /// };
359    /// let Comparable::RelativeSingularQuery(lhs) = expr.lhs() else {
360    ///     panic!("expected lhs to be a relative singular query")
361    /// };
362    /// let lhs_segments: Vec<_> = lhs.segments().collect();
363    /// assert_eq!(&lhs_segments, &[
364    ///     &SingularSegment::Name(JsonString::new("price"))
365    /// ]);
366    /// assert_eq!(expr.op(), ComparisonOp::LessThan);
367    /// assert_eq!(expr.rhs(), &Comparable::Literal(JsonInt::from(10).into()));
368    ///
369    /// ```
370    #[inline(always)]
371    pub fn wildcard(&mut self) -> &mut Self {
372        self.selectors.push(Selector::Wildcard);
373        self
374    }
375
376    /// Add a filter selector.
377    #[inline]
378    pub fn filter<F>(&mut self, filter_builder: F) -> &mut Self
379    where
380        F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
381    {
382        let filter = filter_builder(EmptyLogicalExprBuilder);
383        let logical_expr = filter.into();
384        self.selectors.push(Selector::Filter(logical_expr));
385        self
386    }
387}
388
389impl Default for JsonPathQueryBuilder {
390    /// Return the empty builder.
391    #[inline(always)]
392    fn default() -> Self {
393        Self::new()
394    }
395}
396
397impl From<JsonPathQueryBuilder> for JsonPathQuery {
398    #[inline(always)]
399    fn from(value: JsonPathQueryBuilder) -> Self {
400        Self {
401            segments: value.segments,
402        }
403    }
404}
405
406/// Helper API for programmatically constructing [`Slice`] instances.
407///
408/// # Examples
409/// ```
410/// # use rsonpath_syntax::prelude::*;
411/// let mut builder = SliceBuilder::new();
412///
413/// builder.with_start(-3).with_end(1).with_step(-7);
414///
415/// let slice: Slice = builder.into();
416/// assert_eq!(slice.to_string(), "-3:1:-7");
417/// ```
418pub struct SliceBuilder {
419    inner: Slice,
420    /// We need to track if start is explicit because the default depends on step sign.
421    start_was_explicitly_given: bool,
422}
423
424impl SliceBuilder {
425    /// Create a new [`Slice`] configuration with default values.
426    ///
427    /// ```rust
428    /// # use rsonpath_syntax::prelude::*;
429    /// let slice: Slice = SliceBuilder::new().into();
430    /// assert_eq!(Slice::default(), slice);
431    /// ```
432    #[inline]
433    #[must_use]
434    pub fn new() -> Self {
435        Self {
436            inner: Slice::default(),
437            start_was_explicitly_given: false,
438        }
439    }
440
441    /// Set the start of the [`Slice`].
442    #[inline]
443    pub fn with_start<N: Into<JsonInt>>(&mut self, start: N) -> &mut Self {
444        self.inner.start = start.into().into();
445        self.start_was_explicitly_given = true;
446        self
447    }
448
449    /// Set the end of the [`Slice`].
450    #[inline]
451    pub fn with_end<N: Into<JsonInt>>(&mut self, end: N) -> &mut Self {
452        self.inner.end = Some(end.into().into());
453        self
454    }
455
456    /// Set the step of the [`Slice`].
457    #[inline]
458    pub fn with_step<N: Into<JsonInt>>(&mut self, step: N) -> &mut Self {
459        self.inner.step = step.into().into();
460        self
461    }
462
463    /// Get the configured [`Slice`] instance.
464    ///
465    /// This does not consume the builder. For a consuming variant use the `Into<Slice>` impl.
466    #[inline]
467    #[must_use]
468    pub fn to_slice(&mut self) -> Slice {
469        if !self.start_was_explicitly_given {
470            if self.inner.step.is_forward() {
471                self.inner.start = Slice::DEFAULT_START_FORWARDS;
472            } else {
473                self.inner.start = Slice::default_start_backwards();
474            }
475        }
476
477        self.inner.clone()
478    }
479}
480
481impl From<SliceBuilder> for Slice {
482    #[inline]
483    #[must_use]
484    fn from(mut value: SliceBuilder) -> Self {
485        value.to_slice()
486    }
487}
488
489impl Default for SliceBuilder {
490    /// Create a builder configured with default values.
491    ///
492    /// ```rust
493    /// # use rsonpath_syntax::prelude::*;
494    /// let slice: Slice = SliceBuilder::default().into();
495    /// assert_eq!(Slice::default(), slice);
496    /// ```
497    #[inline(always)]
498    #[must_use]
499    fn default() -> Self {
500        Self::new()
501    }
502}
503
504/// Starting point for building a filter [`LogicalExpr`].
505pub struct EmptyLogicalExprBuilder;
506
507/// Starting point for building a [`ComparisonExpr`].
508pub struct EmptyComparisonExprBuilder;
509
510/// Builder for [`ComparisonExpr`] with the [`lhs`](ComparisonExpr::lhs) already configured.
511pub struct ComparisonWithLhsBuilder {
512    lhs: Comparable,
513}
514
515/// Builder for [`ComparisonExpr`] with the [`lhs`](ComparisonExpr::lhs)
516/// and [`op`](ComparisonExpr::op) already configured.
517pub struct ComparisonWithLhsAndOpBuilder {
518    lhs: Comparable,
519    op: ComparisonOp,
520}
521
522/// Builder for a [`LogicalExpr`] that can be finalized,
523/// or boolean-combined with another [`LogicalExpr`].
524///
525/// # Examples
526/// ```rust
527/// # use rsonpath_syntax::prelude::*;
528/// let mut builder = JsonPathQueryBuilder::new();
529/// builder.child_filter(|fb|
530///     fb.test_relative(|qb| qb.child_name("book"))
531///     // We could finish here, but we can also chain another expression.
532///       .or(|fb2| fb2.test_relative(|qb2| qb2.child_name("journal")))
533/// );
534///
535/// assert_eq!(builder.to_query().to_string(), "$[?@['book'] || @['journal']]");
536/// ```
537pub struct LogicalExprBuilder {
538    current: LogicalExpr,
539}
540
541/// Builder for a [`SingularJsonPathQuery`].
542pub struct SingularJsonPathQueryBuilder {
543    segments: Vec<SingularSegment>,
544}
545
546impl SingularJsonPathQueryBuilder {
547    /// Create a new, empty builder.
548    #[inline]
549    #[must_use]
550    pub fn new() -> Self {
551        Self { segments: vec![] }
552    }
553
554    /// Add a child name segment.
555    #[inline]
556    pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
557        self.segments.push(SingularSegment::Name(name.into()));
558        self
559    }
560
561    /// Add a child index segment.
562    #[inline]
563    pub fn index<N: Into<Index>>(&mut self, n: N) -> &mut Self {
564        self.segments.push(SingularSegment::Index(n.into()));
565        self
566    }
567}
568
569impl Default for SingularJsonPathQueryBuilder {
570    #[inline]
571    fn default() -> Self {
572        Self::new()
573    }
574}
575
576impl From<SingularJsonPathQueryBuilder> for SingularJsonPathQuery {
577    #[inline]
578    #[must_use]
579    fn from(value: SingularJsonPathQueryBuilder) -> Self {
580        Self {
581            segments: value.segments,
582        }
583    }
584}
585
586impl EmptyLogicalExprBuilder {
587    /// Start building a [`ComparisonExpr`] logical expression.
588    #[inline]
589    #[must_use]
590    pub fn comparison<F>(self, cf: F) -> LogicalExprBuilder
591    where
592        F: FnOnce(EmptyComparisonExprBuilder) -> ComparisonExpr,
593    {
594        let comparison = cf(EmptyComparisonExprBuilder);
595        LogicalExprBuilder {
596            current: LogicalExpr::Comparison(comparison),
597        }
598    }
599
600    /// Start building a test query from the root.
601    #[inline]
602    pub fn test_absolute<F>(self, tf: F) -> LogicalExprBuilder
603    where
604        F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
605    {
606        let mut query = JsonPathQueryBuilder::new();
607        tf(&mut query);
608        LogicalExprBuilder {
609            current: LogicalExpr::Test(TestExpr::Absolute(query.into_query())),
610        }
611    }
612
613    /// Start building a test query from the current node.
614    #[inline]
615    pub fn test_relative<F>(self, tf: F) -> LogicalExprBuilder
616    where
617        F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
618    {
619        let mut query = JsonPathQueryBuilder::new();
620        tf(&mut query);
621        LogicalExprBuilder {
622            current: LogicalExpr::Test(TestExpr::Relative(query.into_query())),
623        }
624    }
625
626    /// Build a logical expression by negating the one created in the inner function.
627    #[inline]
628    pub fn not<F>(self, tf: F) -> LogicalExprBuilder
629    where
630        F: FnOnce(Self) -> LogicalExprBuilder,
631    {
632        let inner = tf(Self).into();
633        LogicalExprBuilder {
634            current: LogicalExpr::Not(Box::new(inner)),
635        }
636    }
637}
638
639impl EmptyComparisonExprBuilder {
640    /// Set the left-hand side of the comparison to a literal.
641    #[inline]
642    #[must_use]
643    pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonWithLhsBuilder {
644        ComparisonWithLhsBuilder {
645            lhs: Comparable::Literal(l.into()),
646        }
647    }
648
649    /// Set the left-hand side of the comparison to a root-based singular query.
650    #[inline]
651    #[must_use]
652    pub fn query_absolute<F>(self, qf: F) -> ComparisonWithLhsBuilder
653    where
654        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
655    {
656        let mut query = SingularJsonPathQueryBuilder::new();
657        qf(&mut query);
658        ComparisonWithLhsBuilder {
659            lhs: Comparable::AbsoluteSingularQuery(query.into()),
660        }
661    }
662
663    /// Set the left-hand side of the comparison to a current-node-based singular query.
664    #[inline]
665    #[must_use]
666    pub fn query_relative<F>(self, qf: F) -> ComparisonWithLhsBuilder
667    where
668        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
669    {
670        let mut query = SingularJsonPathQueryBuilder::new();
671        qf(&mut query);
672        ComparisonWithLhsBuilder {
673            lhs: Comparable::RelativeSingularQuery(query.into()),
674        }
675    }
676}
677
678impl ComparisonWithLhsBuilder {
679    /// Use the equality operator `==`.
680    #[inline]
681    #[must_use]
682    pub fn equal_to(self) -> ComparisonWithLhsAndOpBuilder {
683        ComparisonWithLhsAndOpBuilder {
684            lhs: self.lhs,
685            op: ComparisonOp::EqualTo,
686        }
687    }
688
689    /// Use the inequality operator `!=`.
690    #[inline]
691    #[must_use]
692    pub fn not_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
693        ComparisonWithLhsAndOpBuilder {
694            lhs: self.lhs,
695            op: ComparisonOp::NotEqualTo,
696        }
697    }
698
699    /// Use the less-than operator `<`.
700    #[inline]
701    #[must_use]
702    pub fn less_than(self) -> ComparisonWithLhsAndOpBuilder {
703        ComparisonWithLhsAndOpBuilder {
704            lhs: self.lhs,
705            op: ComparisonOp::LessThan,
706        }
707    }
708
709    /// Use the less-than-or-equal operator `<=`.
710    #[inline]
711    #[must_use]
712    pub fn lesser_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
713        ComparisonWithLhsAndOpBuilder {
714            lhs: self.lhs,
715            op: ComparisonOp::LesserOrEqualTo,
716        }
717    }
718
719    /// Use the greater-than operator `>`.
720    #[inline]
721    #[must_use]
722    pub fn greater_than(self) -> ComparisonWithLhsAndOpBuilder {
723        ComparisonWithLhsAndOpBuilder {
724            lhs: self.lhs,
725            op: ComparisonOp::GreaterThan,
726        }
727    }
728
729    /// Use the greater-than-or-equal operator `>=`.
730    #[inline]
731    #[must_use]
732    pub fn greater_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
733        ComparisonWithLhsAndOpBuilder {
734            lhs: self.lhs,
735            op: ComparisonOp::GreaterOrEqualTo,
736        }
737    }
738}
739
740impl ComparisonWithLhsAndOpBuilder {
741    /// Set the right-hand side of the comparison to a literal and finalize the expression.
742    #[inline]
743    pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonExpr {
744        ComparisonExpr {
745            lhs: self.lhs,
746            op: self.op,
747            rhs: Comparable::Literal(l.into()),
748        }
749    }
750
751    /// Set the right-hand side of the comparison to a root-based singular query and finalize the expression.
752    #[inline]
753    #[must_use]
754    pub fn query_absolute<F>(self, qf: F) -> ComparisonExpr
755    where
756        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
757    {
758        let mut query = SingularJsonPathQueryBuilder::new();
759        qf(&mut query);
760        ComparisonExpr {
761            lhs: self.lhs,
762            op: self.op,
763            rhs: Comparable::AbsoluteSingularQuery(query.into()),
764        }
765    }
766
767    /// Set the right-hand side of the comparison to a current-node-based singular query and finalize the expression.
768    #[inline]
769    #[must_use]
770    pub fn query_relative<F>(self, qf: F) -> ComparisonExpr
771    where
772        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
773    {
774        let mut query = SingularJsonPathQueryBuilder::new();
775        qf(&mut query);
776        ComparisonExpr {
777            lhs: self.lhs,
778            op: self.op,
779            rhs: Comparable::RelativeSingularQuery(query.into()),
780        }
781    }
782}
783
784impl LogicalExprBuilder {
785    /// Combine the entire expression built thus far with the one built in the inner function
786    /// by using the boolean conjunction operator `&&`.
787    #[inline]
788    pub fn and<F>(self, f: F) -> Self
789    where
790        F: FnOnce(EmptyLogicalExprBuilder) -> Self,
791    {
792        let lhs = Box::new(self.current);
793        let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
794        Self {
795            current: LogicalExpr::And(lhs, rhs),
796        }
797    }
798
799    /// Combine the entire expression built thus far with the one built in the inner function
800    /// by using the boolean disjunction operator `||`.
801    #[inline]
802    pub fn or<F>(self, f: F) -> Self
803    where
804        F: FnOnce(EmptyLogicalExprBuilder) -> Self,
805    {
806        let lhs = Box::new(self.current);
807        let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
808        Self {
809            current: LogicalExpr::Or(lhs, rhs),
810        }
811    }
812}
813
814impl From<LogicalExprBuilder> for LogicalExpr {
815    #[inline(always)]
816    fn from(value: LogicalExprBuilder) -> Self {
817        value.current
818    }
819}
820
821#[cfg(test)]
822mod tests {
823    use super::SliceBuilder;
824    use crate::{Index, Slice, Step};
825
826    #[test]
827    fn slice_builder_default_start_forward() {
828        let mut builder = SliceBuilder::new();
829        builder.with_end(3).with_step(4);
830        let slice: Slice = builder.into();
831
832        assert_eq!(slice.start(), Index::FromStart(0.into()));
833        assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
834        assert_eq!(slice.step(), Step::Forward(4.into()));
835    }
836
837    #[test]
838    fn slice_builder_default_start_backward() {
839        let mut builder = SliceBuilder::new();
840        builder.with_end(3).with_step(-4);
841        let slice: Slice = builder.into();
842
843        assert_eq!(slice.start(), Index::FromEnd(1.try_into().unwrap()));
844        assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
845        assert_eq!(slice.step(), Step::Backward(4.try_into().unwrap()));
846    }
847}