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}