use crate::{
num::JsonInt, str::JsonString, Comparable, ComparisonExpr, ComparisonOp, Index, JsonPathQuery, Literal,
LogicalExpr, Segment, Selector, Selectors, SingularJsonPathQuery, SingularSegment, Slice, TestExpr,
};
pub struct JsonPathQueryBuilder {
segments: Vec<Segment>,
}
pub struct JsonPathSelectorsBuilder {
selectors: Vec<Selector>,
}
impl JsonPathQueryBuilder {
#[must_use]
#[inline(always)]
pub fn new() -> Self {
Self { segments: vec![] }
}
#[inline]
pub fn child<F>(&mut self, selectors_builder: F) -> &mut Self
where
F: FnOnce(&mut JsonPathSelectorsBuilder) -> &mut JsonPathSelectorsBuilder,
{
let mut builder = JsonPathSelectorsBuilder::new();
selectors_builder(&mut builder);
self.segments.push(Segment::Child(builder.build()));
self
}
#[inline]
pub fn descendant<F>(&mut self, selectors_builder: F) -> &mut Self
where
F: FnOnce(&mut JsonPathSelectorsBuilder) -> &mut JsonPathSelectorsBuilder,
{
let mut builder = JsonPathSelectorsBuilder::new();
selectors_builder(&mut builder);
self.segments.push(Segment::Descendant(builder.build()));
self
}
#[inline(always)]
pub fn child_name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
self.child(|x| x.name(name))
}
#[inline(always)]
pub fn child_wildcard(&mut self) -> &mut Self {
self.child(|x| x.wildcard())
}
#[inline(always)]
pub fn child_index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
self.child(|x| x.index(idx))
}
#[inline(always)]
pub fn child_slice<F>(&mut self, slice_builder: F) -> &mut Self
where
F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
{
self.child(|x| x.slice(slice_builder))
}
#[inline(always)]
pub fn child_filter<F>(&mut self, filter_builder: F) -> &mut Self
where
F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
{
self.child(|x| x.filter(filter_builder))
}
#[inline(always)]
pub fn descendant_name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
self.descendant(|x| x.name(name))
}
#[inline(always)]
pub fn descendant_wildcard(&mut self) -> &mut Self {
self.descendant(|x| x.wildcard())
}
#[inline(always)]
pub fn descendant_index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
self.descendant(|x| x.index(idx))
}
#[inline(always)]
pub fn descendant_slice<F>(&mut self, slice_builder: F) -> &mut Self
where
F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
{
self.descendant(|x| x.slice(slice_builder))
}
#[inline(always)]
pub fn descendant_filter<F>(&mut self, filter_builder: F) -> &mut Self
where
F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
{
self.descendant(|x| x.filter(filter_builder))
}
#[must_use]
#[inline]
pub fn to_query(&mut self) -> JsonPathQuery {
JsonPathQuery {
segments: self.segments.clone(),
}
}
#[must_use]
#[inline]
pub fn into_query(self) -> JsonPathQuery {
JsonPathQuery {
segments: self.segments,
}
}
}
impl JsonPathSelectorsBuilder {
fn new() -> Self {
Self { selectors: vec![] }
}
fn build(self) -> Selectors {
assert!(!self.selectors.is_empty(), "there must be at least one selector");
Selectors::many(self.selectors)
}
#[inline(always)]
pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
self.selectors.push(Selector::Name(name.into()));
self
}
#[inline(always)]
pub fn index<N: Into<JsonInt>>(&mut self, idx: N) -> &mut Self {
let json_int: JsonInt = idx.into();
self.selectors.push(Selector::Index(Index::from(json_int)));
self
}
#[inline(always)]
pub fn slice<F>(&mut self, slice_builder: F) -> &mut Self
where
F: FnOnce(&mut SliceBuilder) -> &mut SliceBuilder,
{
let mut slice = SliceBuilder::new();
slice_builder(&mut slice);
let slice = slice.into();
self.selectors.push(Selector::Slice(slice));
self
}
#[inline(always)]
pub fn wildcard(&mut self) -> &mut Self {
self.selectors.push(Selector::Wildcard);
self
}
#[inline]
pub fn filter<F>(&mut self, filter_builder: F) -> &mut Self
where
F: FnOnce(EmptyLogicalExprBuilder) -> LogicalExprBuilder,
{
let filter = filter_builder(EmptyLogicalExprBuilder);
let logical_expr = filter.into();
self.selectors.push(Selector::Filter(logical_expr));
self
}
}
impl Default for JsonPathQueryBuilder {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl From<JsonPathQueryBuilder> for JsonPathQuery {
#[inline(always)]
fn from(value: JsonPathQueryBuilder) -> Self {
Self {
segments: value.segments,
}
}
}
pub struct SliceBuilder {
inner: Slice,
start_was_explicitly_given: bool,
}
impl SliceBuilder {
#[inline]
#[must_use]
pub fn new() -> Self {
Self {
inner: Slice::default(),
start_was_explicitly_given: false,
}
}
#[inline]
pub fn with_start<N: Into<JsonInt>>(&mut self, start: N) -> &mut Self {
self.inner.start = start.into().into();
self.start_was_explicitly_given = true;
self
}
#[inline]
pub fn with_end<N: Into<JsonInt>>(&mut self, end: N) -> &mut Self {
self.inner.end = Some(end.into().into());
self
}
#[inline]
pub fn with_step<N: Into<JsonInt>>(&mut self, step: N) -> &mut Self {
self.inner.step = step.into().into();
self
}
#[inline]
#[must_use]
pub fn to_slice(&mut self) -> Slice {
if !self.start_was_explicitly_given {
if self.inner.step.is_forward() {
self.inner.start = Slice::DEFAULT_START_FORWARDS;
} else {
self.inner.start = Slice::default_start_backwards();
}
}
self.inner.clone()
}
}
impl From<SliceBuilder> for Slice {
#[inline]
fn from(mut value: SliceBuilder) -> Self {
value.to_slice()
}
}
impl Default for SliceBuilder {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
pub struct EmptyLogicalExprBuilder;
pub struct EmptyComparisonExprBuilder;
pub struct ComparisonWithLhsBuilder {
lhs: Comparable,
}
pub struct ComparisonWithLhsAndOpBuilder {
lhs: Comparable,
op: ComparisonOp,
}
pub struct LogicalExprBuilder {
current: LogicalExpr,
}
pub struct SingularJsonPathQueryBuilder {
segments: Vec<SingularSegment>,
}
impl SingularJsonPathQueryBuilder {
#[inline]
#[must_use]
pub fn new() -> Self {
Self { segments: vec![] }
}
#[inline]
pub fn name<S: Into<JsonString>>(&mut self, name: S) -> &mut Self {
self.segments.push(SingularSegment::Name(name.into()));
self
}
#[inline]
pub fn index<N: Into<Index>>(&mut self, n: N) -> &mut Self {
self.segments.push(SingularSegment::Index(n.into()));
self
}
}
impl Default for SingularJsonPathQueryBuilder {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl From<SingularJsonPathQueryBuilder> for SingularJsonPathQuery {
#[inline]
fn from(value: SingularJsonPathQueryBuilder) -> Self {
Self {
segments: value.segments,
}
}
}
impl EmptyLogicalExprBuilder {
#[inline]
#[must_use]
pub fn comparison<F>(self, cf: F) -> LogicalExprBuilder
where
F: FnOnce(EmptyComparisonExprBuilder) -> ComparisonExpr,
{
let comparison = cf(EmptyComparisonExprBuilder);
LogicalExprBuilder {
current: LogicalExpr::Comparison(comparison),
}
}
#[inline]
pub fn test_absolute<F>(self, tf: F) -> LogicalExprBuilder
where
F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
{
let mut query = JsonPathQueryBuilder::new();
tf(&mut query);
LogicalExprBuilder {
current: LogicalExpr::Test(TestExpr::Absolute(query.into_query())),
}
}
#[inline]
pub fn test_relative<F>(self, tf: F) -> LogicalExprBuilder
where
F: FnOnce(&mut JsonPathQueryBuilder) -> &mut JsonPathQueryBuilder,
{
let mut query = JsonPathQueryBuilder::new();
tf(&mut query);
LogicalExprBuilder {
current: LogicalExpr::Test(TestExpr::Relative(query.into_query())),
}
}
#[inline]
pub fn not<F>(self, tf: F) -> LogicalExprBuilder
where
F: FnOnce(Self) -> LogicalExprBuilder,
{
let inner = tf(Self).into();
LogicalExprBuilder {
current: LogicalExpr::Not(Box::new(inner)),
}
}
}
impl EmptyComparisonExprBuilder {
#[inline]
#[must_use]
pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonWithLhsBuilder {
ComparisonWithLhsBuilder {
lhs: Comparable::Literal(l.into()),
}
}
#[inline]
#[must_use]
pub fn query_absolute<F>(self, qf: F) -> ComparisonWithLhsBuilder
where
F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
{
let mut query = SingularJsonPathQueryBuilder::new();
qf(&mut query);
ComparisonWithLhsBuilder {
lhs: Comparable::AbsoluteSingularQuery(query.into()),
}
}
#[inline]
#[must_use]
pub fn query_relative<F>(self, qf: F) -> ComparisonWithLhsBuilder
where
F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
{
let mut query = SingularJsonPathQueryBuilder::new();
qf(&mut query);
ComparisonWithLhsBuilder {
lhs: Comparable::RelativeSingularQuery(query.into()),
}
}
}
impl ComparisonWithLhsBuilder {
#[inline]
#[must_use]
pub fn equal_to(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::EqualTo,
}
}
#[inline]
#[must_use]
pub fn not_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::NotEqualTo,
}
}
#[inline]
#[must_use]
pub fn less_than(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::LessThan,
}
}
#[inline]
#[must_use]
pub fn lesser_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::LesserOrEqualTo,
}
}
#[inline]
#[must_use]
pub fn greater_than(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::GreaterThan,
}
}
#[inline]
#[must_use]
pub fn greater_or_equal_to(self) -> ComparisonWithLhsAndOpBuilder {
ComparisonWithLhsAndOpBuilder {
lhs: self.lhs,
op: ComparisonOp::GreaterOrEqualTo,
}
}
}
impl ComparisonWithLhsAndOpBuilder {
#[inline]
pub fn literal<L: Into<Literal>>(self, l: L) -> ComparisonExpr {
ComparisonExpr {
lhs: self.lhs,
op: self.op,
rhs: Comparable::Literal(l.into()),
}
}
#[inline]
#[must_use]
pub fn query_absolute<F>(self, qf: F) -> ComparisonExpr
where
F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
{
let mut query = SingularJsonPathQueryBuilder::new();
qf(&mut query);
ComparisonExpr {
lhs: self.lhs,
op: self.op,
rhs: Comparable::AbsoluteSingularQuery(query.into()),
}
}
#[inline]
#[must_use]
pub fn query_relative<F>(self, qf: F) -> ComparisonExpr
where
F: FnOnce(&mut SingularJsonPathQueryBuilder) -> &mut SingularJsonPathQueryBuilder,
{
let mut query = SingularJsonPathQueryBuilder::new();
qf(&mut query);
ComparisonExpr {
lhs: self.lhs,
op: self.op,
rhs: Comparable::RelativeSingularQuery(query.into()),
}
}
}
impl LogicalExprBuilder {
#[inline]
pub fn and<F>(self, f: F) -> Self
where
F: FnOnce(EmptyLogicalExprBuilder) -> Self,
{
let lhs = Box::new(self.current);
let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
Self {
current: LogicalExpr::And(lhs, rhs),
}
}
#[inline]
pub fn or<F>(self, f: F) -> Self
where
F: FnOnce(EmptyLogicalExprBuilder) -> Self,
{
let lhs = Box::new(self.current);
let rhs = Box::new(f(EmptyLogicalExprBuilder).into());
Self {
current: LogicalExpr::Or(lhs, rhs),
}
}
}
impl From<LogicalExprBuilder> for LogicalExpr {
#[inline(always)]
fn from(value: LogicalExprBuilder) -> Self {
value.current
}
}
#[cfg(test)]
mod tests {
use super::SliceBuilder;
use crate::{Index, Slice, Step};
#[test]
fn slice_builder_default_start_forward() {
let mut builder = SliceBuilder::new();
builder.with_end(3).with_step(4);
let slice: Slice = builder.into();
assert_eq!(slice.start(), Index::FromStart(0.into()));
assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
assert_eq!(slice.step(), Step::Forward(4.into()));
}
#[test]
fn slice_builder_default_start_backward() {
let mut builder = SliceBuilder::new();
builder.with_end(3).with_step(-4);
let slice: Slice = builder.into();
assert_eq!(slice.start(), Index::FromEnd(1.try_into().unwrap()));
assert_eq!(slice.end(), Some(Index::FromStart(3.into())));
assert_eq!(slice.step(), Step::Backward(4.try_into().unwrap()));
}
}