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