Skip to main content

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        assert!(!self.selectors.is_empty(), "there must be at least one selector");
244        Selectors::many(self.selectors)
245    }
246
247    /// Add a name selector with a given `name` string to the collection.
248    ///
249    /// ## Examples
250    ///
251    /// ```rust
252    /// # use rsonpath_syntax::prelude::*;
253    /// let mut builder = JsonPathQueryBuilder::new();
254    /// builder.child(|x| x.name("book").name("journal"));
255    /// let result = builder.into_query();
256    /// assert_eq!(result.segments().len(), 1);
257    /// let segment = &result.segments()[0];
258    /// assert_eq!(segment.selectors().as_slice(), &[
259    ///     Selector::Name(JsonString::new("book")),
260    ///     Selector::Name(JsonString::new("journal")),
261    /// ]);
262    /// ```
263    #[inline(always)]
264    pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
265        self.selectors.push(Selector::Name(name.into()));
266        self
267    }
268
269    /// Add an index selector based on a given JSON integer.
270    ///
271    /// The result is a [`Selector::Index`] with an [`Index::FromStart`]
272    /// if `idx` converts to a non-negative [`JsonInt`], and [`Index::FromEnd`]
273    /// otherwise.
274    ///
275    /// ## Examples
276    ///
277    /// ```rust
278    /// # use rsonpath_syntax::{prelude::*, num::JsonNonZeroUInt};
279    /// let mut builder = JsonPathQueryBuilder::new();
280    /// builder.child(|x| x.index(10).index(-20));
281    /// let result = builder.into_query();
282    /// assert_eq!(result.segments().len(), 1);
283    /// let segment = &result.segments()[0];
284    /// assert_eq!(segment.selectors().as_slice(), &[
285    ///     Selector::Index(Index::FromStart(JsonUInt::from(10))),
286    ///     Selector::Index(Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap())),
287    /// ]);
288    /// ```
289    #[inline(always)]
290    pub fn index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
291        let json_int: JsonInt = idx.into();
292        self.selectors.push(Selector::Index(Index::from(json_int)));
293        self
294    }
295
296    /// Add a slice selector based on a given start, end, and step integers.
297    ///
298    /// The result is a [`Selector::Slice`] with given `start`, `end`, and `step`.
299    ///
300    /// ## Examples
301    ///
302    /// ```rust
303    /// # use rsonpath_syntax::{prelude::*, num::JsonNonZeroUInt};
304    /// let mut builder = JsonPathQueryBuilder::new();
305    /// builder.child(|x| x
306    ///     .slice(|s| s.with_start(10).with_end(-20).with_step(5))
307    ///     .slice(|s| s.with_start(-20).with_step(-30)));
308    /// let result = builder.into_query();
309    ///
310    /// assert_eq!(result.segments().len(), 1);
311    /// let segment = &result.segments()[0];
312    /// let selectors = segment.selectors().as_slice();
313    /// match (&selectors[0], &selectors[1]) {
314    ///     (Selector::Slice(s1), Selector::Slice(s2)) => {
315    ///         assert_eq!(s1.start(), Index::FromStart(10.into()));
316    ///         assert_eq!(s1.end(), Some(Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap())));
317    ///         assert_eq!(s1.step(), Step::Forward(5.into()));
318    ///         assert_eq!(s2.start(), Index::FromEnd(JsonNonZeroUInt::try_from(20).unwrap()));
319    ///         assert_eq!(s2.end(), None);
320    ///         assert_eq!(s2.step(), Step::Backward(JsonNonZeroUInt::try_from(30).unwrap()));
321    ///     }
322    ///     _ => unreachable!()
323    /// }
324    /// ```
325    #[inline(always)]
326    pub fn slice<F>(&mut self, slice_builder: F) -> &mut Self
327    where
328        F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
329    {
330        let mut slice = SliceBuilder::new();
331        slice_builder(&mut slice);
332        let slice = slice.into();
333        self.selectors.push(Selector::Slice(slice));
334        self
335    }
336
337    /// Add a wildcard selector.
338    ///
339    /// ```rust
340    /// # use rsonpath_syntax::prelude::*;
341    /// let mut builder = JsonPathQueryBuilder::new();
342    /// builder.child(|x| {
343    ///     x.filter(|x| {
344    ///         x.comparison(|x| {
345    ///             x.query_relative(|x| x.name("price"))
346    ///              .less_than()
347    ///              .literal(JsonInt::from(10))
348    ///         })
349    ///     })
350    /// });
351    /// let result = builder.into_query();
352    /// assert_eq!(result.segments().len(), 1);
353    /// let segment = &result.segments()[0];
354    /// assert_eq!(segment.selectors().len(), 1);
355    /// let selector = segment.selectors().first();
356    ///
357    /// let Selector::Filter(LogicalExpr::Comparison(expr)) = selector else {
358    ///     panic!("expected comparison filter")
359    /// };
360    /// let Comparable::RelativeSingularQuery(lhs) = expr.lhs() else {
361    ///     panic!("expected lhs to be a relative singular query")
362    /// };
363    /// let lhs_segments: Vec<_> = lhs.segments().collect();
364    /// assert_eq!(&lhs_segments, &[
365    ///     &SingularSegment::Name(JsonString::new("price"))
366    /// ]);
367    /// assert_eq!(expr.op(), ComparisonOp::LessThan);
368    /// assert_eq!(expr.rhs(), &Comparable::Literal(JsonInt::from(10).into()));
369    ///
370    /// ```
371    #[inline(always)]
372    pub fn wildcard(&mut self) -> &mut Self {
373        self.selectors.push(Selector::Wildcard);
374        self
375    }
376
377    /// Add a filter selector.
378    #[inline]
379    pub fn filter<F>(&mut self, filter_builder: F) -> &mut Self
380    where
381        F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
382    {
383        let filter = filter_builder(EmptyLogicalExprBuilder);
384        let logical_expr = filter.into();
385        self.selectors.push(Selector::Filter(logical_expr));
386        self
387    }
388}
389
390impl Default for JsonPathQueryBuilder {
391    /// Return the empty builder.
392    #[inline(always)]
393    fn default() -> Self {
394        Self::new()
395    }
396}
397
398impl From<JsonPathQueryBuilder> for JsonPathQuery {
399    #[inline(always)]
400    fn from(value: JsonPathQueryBuilder) -> Self {
401        Self {
402            segments: value.segments,
403        }
404    }
405}
406
407/// Helper API for programmatically constructing [`Slice`] instances.
408///
409/// # Examples
410/// ```
411/// # use rsonpath_syntax::prelude::*;
412/// let mut builder = SliceBuilder::new();
413///
414/// builder.with_start(-3).with_end(1).with_step(-7);
415///
416/// let slice: Slice = builder.into();
417/// assert_eq!(slice.to_string(), "-3:1:-7");
418/// ```
419pub struct SliceBuilder {
420    inner: Slice,
421    /// We need to track if start is explicit because the default depends on step sign.
422    start_was_explicitly_given: bool,
423}
424
425impl SliceBuilder {
426    /// Create a new [`Slice`] configuration with default values.
427    ///
428    /// ```rust
429    /// # use rsonpath_syntax::prelude::*;
430    /// let slice: Slice = SliceBuilder::new().into();
431    /// assert_eq!(Slice::default(), slice);
432    /// ```
433    #[inline]
434    #[must_use]
435    pub fn new() -> Self {
436        Self {
437            inner: Slice::default(),
438            start_was_explicitly_given: false,
439        }
440    }
441
442    /// Set the start of the [`Slice`].
443    #[inline]
444    pub fn with_start<N: Into<JsonInt>>(&mut self, start: N) -> &mut Self {
445        self.inner.start = start.into().into();
446        self.start_was_explicitly_given = true;
447        self
448    }
449
450    /// Set the end of the [`Slice`].
451    #[inline]
452    pub fn with_end<N: Into<JsonInt>>(&mut self, end: N) -> &mut Self {
453        self.inner.end = Some(end.into().into());
454        self
455    }
456
457    /// Set the step of the [`Slice`].
458    #[inline]
459    pub fn with_step<N: Into<JsonInt>>(&mut self, step: N) -> &mut Self {
460        self.inner.step = step.into().into();
461        self
462    }
463
464    /// Get the configured [`Slice`] instance.
465    ///
466    /// This does not consume the builder. For a consuming variant use the `Into<Slice>` impl.
467    #[inline]
468    #[must_use]
469    pub fn to_slice(&mut self) -> Slice {
470        if !self.start_was_explicitly_given {
471            if self.inner.step.is_forward() {
472                self.inner.start = Slice::DEFAULT_START_FORWARDS;
473            } else {
474                self.inner.start = Slice::default_start_backwards();
475            }
476        }
477
478        self.inner.clone()
479    }
480}
481
482impl From<SliceBuilder> for Slice {
483    #[inline]
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    fn default() -> Self {
499        Self::new()
500    }
501}
502
503/// Starting point for building a filter [`LogicalExpr`].
504pub struct EmptyLogicalExprBuilder;
505
506/// Starting point for building a [`ComparisonExpr`].
507pub struct EmptyComparisonExprBuilder;
508
509/// Builder for [`ComparisonExpr`] with the [`lhs`](ComparisonExpr::lhs) already configured.
510pub struct ComparisonWithLhsBuilder {
511    lhs: Comparable,
512}
513
514/// Builder for [`ComparisonExpr`] with the [`lhs`](ComparisonExpr::lhs)
515/// and [`op`](ComparisonExpr::op) already configured.
516pub struct ComparisonWithLhsAndOpBuilder {
517    lhs: Comparable,
518    op: ComparisonOp,
519}
520
521/// Builder for a [`LogicalExpr`] that can be finalized,
522/// or boolean-combined with another [`LogicalExpr`].
523///
524/// # Examples
525/// ```rust
526/// # use rsonpath_syntax::prelude::*;
527/// let mut builder = JsonPathQueryBuilder::new();
528/// builder.child_filter(|fb|
529///     fb.test_relative(|qb| qb.child_name("book"))
530///     // We could finish here, but we can also chain another expression.
531///       .or(|fb2| fb2.test_relative(|qb2| qb2.child_name("journal")))
532/// );
533///
534/// assert_eq!(builder.to_query().to_string(), "$[?@['book'] || @['journal']]");
535/// ```
536pub struct LogicalExprBuilder {
537    current: LogicalExpr,
538}
539
540/// Builder for a [`SingularJsonPathQuery`].
541pub struct SingularJsonPathQueryBuilder {
542    segments: Vec<SingularSegment>,
543}
544
545impl SingularJsonPathQueryBuilder {
546    /// Create a new, empty builder.
547    #[inline]
548    #[must_use]
549    pub fn new() -> Self {
550        Self { segments: vec![] }
551    }
552
553    /// Add a child name segment.
554    #[inline]
555    pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
556        self.segments.push(SingularSegment::Name(name.into()));
557        self
558    }
559
560    /// Add a child index segment.
561    #[inline]
562    pub fn index<N: Into<Index>>(&mut self, n: N) -> &mut Self {
563        self.segments.push(SingularSegment::Index(n.into()));
564        self
565    }
566}
567
568impl Default for SingularJsonPathQueryBuilder {
569    #[inline]
570    fn default() -> Self {
571        Self::new()
572    }
573}
574
575impl From<SingularJsonPathQueryBuilder> for SingularJsonPathQuery {
576    #[inline]
577    fn from(value: SingularJsonPathQueryBuilder) -> Self {
578        Self {
579            segments: value.segments,
580        }
581    }
582}
583
584impl EmptyLogicalExprBuilder {
585    /// Start building a [`ComparisonExpr`] logical expression.
586    #[inline]
587    #[must_use]
588    pub fn comparison<F>(self, cf: F) -> LogicalExprBuilder
589    where
590        F: FnOnce(EmptyComparisonExprBuilder) -> ComparisonExpr,
591    {
592        let comparison = cf(EmptyComparisonExprBuilder);
593        LogicalExprBuilder {
594            current: LogicalExpr::Comparison(comparison),
595        }
596    }
597
598    /// Start building a test query from the root.
599    #[inline]
600    pub fn test_absolute<F>(self, tf: F) -> LogicalExprBuilder
601    where
602        F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
603    {
604        let mut query = JsonPathQueryBuilder::new();
605        tf(&mut query);
606        LogicalExprBuilder {
607            current: LogicalExpr::Test(TestExpr::Absolute(query.into_query())),
608        }
609    }
610
611    /// Start building a test query from the current node.
612    #[inline]
613    pub fn test_relative<F>(self, tf: F) -> LogicalExprBuilder
614    where
615        F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
616    {
617        let mut query = JsonPathQueryBuilder::new();
618        tf(&mut query);
619        LogicalExprBuilder {
620            current: LogicalExpr::Test(TestExpr::Relative(query.into_query())),
621        }
622    }
623
624    /// Build a logical expression by negating the one created in the inner function.
625    #[inline]
626    pub fn not<F>(self, tf: F) -> LogicalExprBuilder
627    where
628        F: FnOnce(Self) -> LogicalExprBuilder,
629    {
630        let inner = tf(Self).into();
631        LogicalExprBuilder {
632            current: LogicalExpr::Not(Box::new(inner)),
633        }
634    }
635}
636
637impl EmptyComparisonExprBuilder {
638    /// Set the left-hand side of the comparison to a literal.
639    #[inline]
640    #[must_use]
641    pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonWithLhsBuilder {
642        ComparisonWithLhsBuilder {
643            lhs: Comparable::Literal(l.into()),
644        }
645    }
646
647    /// Set the left-hand side of the comparison to a root-based singular query.
648    #[inline]
649    #[must_use]
650    pub fn query_absolute<F>(self, qf: F) -> ComparisonWithLhsBuilder
651    where
652        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
653    {
654        let mut query = SingularJsonPathQueryBuilder::new();
655        qf(&mut query);
656        ComparisonWithLhsBuilder {
657            lhs: Comparable::AbsoluteSingularQuery(query.into()),
658        }
659    }
660
661    /// Set the left-hand side of the comparison to a current-node-based singular query.
662    #[inline]
663    #[must_use]
664    pub fn query_relative<F>(self, qf: F) -> ComparisonWithLhsBuilder
665    where
666        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
667    {
668        let mut query = SingularJsonPathQueryBuilder::new();
669        qf(&mut query);
670        ComparisonWithLhsBuilder {
671            lhs: Comparable::RelativeSingularQuery(query.into()),
672        }
673    }
674}
675
676impl ComparisonWithLhsBuilder {
677    /// Use the equality operator `==`.
678    #[inline]
679    #[must_use]
680    pub fn equal_to(self) -> ComparisonWithLhsAndOpBuilder {
681        ComparisonWithLhsAndOpBuilder {
682            lhs: self.lhs,
683            op: ComparisonOp::EqualTo,
684        }
685    }
686
687    /// Use the inequality operator `!=`.
688    #[inline]
689    #[must_use]
690    pub fn not_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
691        ComparisonWithLhsAndOpBuilder {
692            lhs: self.lhs,
693            op: ComparisonOp::NotEqualTo,
694        }
695    }
696
697    /// Use the less-than operator `<`.
698    #[inline]
699    #[must_use]
700    pub fn less_than(self) -> ComparisonWithLhsAndOpBuilder {
701        ComparisonWithLhsAndOpBuilder {
702            lhs: self.lhs,
703            op: ComparisonOp::LessThan,
704        }
705    }
706
707    /// Use the less-than-or-equal operator `<=`.
708    #[inline]
709    #[must_use]
710    pub fn lesser_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
711        ComparisonWithLhsAndOpBuilder {
712            lhs: self.lhs,
713            op: ComparisonOp::LesserOrEqualTo,
714        }
715    }
716
717    /// Use the greater-than operator `>`.
718    #[inline]
719    #[must_use]
720    pub fn greater_than(self) -> ComparisonWithLhsAndOpBuilder {
721        ComparisonWithLhsAndOpBuilder {
722            lhs: self.lhs,
723            op: ComparisonOp::GreaterThan,
724        }
725    }
726
727    /// Use the greater-than-or-equal operator `>=`.
728    #[inline]
729    #[must_use]
730    pub fn greater_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
731        ComparisonWithLhsAndOpBuilder {
732            lhs: self.lhs,
733            op: ComparisonOp::GreaterOrEqualTo,
734        }
735    }
736}
737
738impl ComparisonWithLhsAndOpBuilder {
739    /// Set the right-hand side of the comparison to a literal and finalize the expression.
740    #[inline]
741    pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonExpr {
742        ComparisonExpr {
743            lhs: self.lhs,
744            op: self.op,
745            rhs: Comparable::Literal(l.into()),
746        }
747    }
748
749    /// Set the right-hand side of the comparison to a root-based singular query and finalize the expression.
750    #[inline]
751    #[must_use]
752    pub fn query_absolute<F>(self, qf: F) -> ComparisonExpr
753    where
754        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
755    {
756        let mut query = SingularJsonPathQueryBuilder::new();
757        qf(&mut query);
758        ComparisonExpr {
759            lhs: self.lhs,
760            op: self.op,
761            rhs: Comparable::AbsoluteSingularQuery(query.into()),
762        }
763    }
764
765    /// Set the right-hand side of the comparison to a current-node-based singular query and finalize the expression.
766    #[inline]
767    #[must_use]
768    pub fn query_relative<F>(self, qf: F) -> ComparisonExpr
769    where
770        F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
771    {
772        let mut query = SingularJsonPathQueryBuilder::new();
773        qf(&mut query);
774        ComparisonExpr {
775            lhs: self.lhs,
776            op: self.op,
777            rhs: Comparable::RelativeSingularQuery(query.into()),
778        }
779    }
780}
781
782impl LogicalExprBuilder {
783    /// Combine the entire expression built thus far with the one built in the inner function
784    /// by using the boolean conjunction operator `&&`.
785    #[inline]
786    pub fn and<F>(self, f: F) -> Self
787    where
788        F: FnOnce(EmptyLogicalExprBuilder) -> Self,
789    {
790        let lhs = Box::new(self.current);
791        let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
792        Self {
793            current: LogicalExpr::And(lhs, rhs),
794        }
795    }
796
797    /// Combine the entire expression built thus far with the one built in the inner function
798    /// by using the boolean disjunction operator `||`.
799    #[inline]
800    pub fn or<F>(self, f: F) -> Self
801    where
802        F: FnOnce(EmptyLogicalExprBuilder) -> Self,
803    {
804        let lhs = Box::new(self.current);
805        let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
806        Self {
807            current: LogicalExpr::Or(lhs, rhs),
808        }
809    }
810}
811
812impl From<LogicalExprBuilder> for LogicalExpr {
813    #[inline(always)]
814    fn from(value: LogicalExprBuilder) -> Self {
815        value.current
816    }
817}
818
819#[cfg(test)]
820mod tests {
821    use super::SliceBuilder;
822    use crate::{Index, Slice, Step};
823
824    #[test]
825    fn slice_builder_default_start_forward() {
826        let mut builder = SliceBuilder::new();
827        builder.with_end(3).with_step(4);
828        let slice: Slice = builder.into();
829
830        assert_eq!(slice.start(), Index::FromStart(0.into()));
831        assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
832        assert_eq!(slice.step(), Step::Forward(4.into()));
833    }
834
835    #[test]
836    fn slice_builder_default_start_backward() {
837        let mut builder = SliceBuilder::new();
838        builder.with_end(3).with_step(-4);
839        let slice: Slice = builder.into();
840
841        assert_eq!(slice.start(), Index::FromEnd(1.try_into().unwrap()));
842        assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
843        assert_eq!(slice.step(), Step::Backward(4.try_into().unwrap()));
844    }
845}