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}