use crate::RawJsonb;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt::Display;
use std::fmt::Formatter;
use crate::number::Number;
#[derive(Debug, Clone, PartialEq)]
pub struct JsonPath<'a> {
pub paths: Vec<Path<'a>>,
}
impl JsonPath<'_> {
pub fn is_predicate(&self) -> bool {
self.paths.len() == 1 && matches!(self.paths[0], Path::Expr(_))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Path<'a> {
Root,
Current,
DotWildcard,
RecursiveDotWildcard(Option<RecursiveLevel>),
BracketWildcard,
DotField(Cow<'a, str>),
ColonField(Cow<'a, str>),
ObjectField(Cow<'a, str>),
ArrayIndices(Vec<ArrayIndex>),
FilterExpr(Box<Expr<'a>>),
Expr(Box<Expr<'a>>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Index {
Index(i32),
LastIndex(i32),
}
#[derive(Debug, Clone, PartialEq)]
pub enum ArrayIndex {
Index(Index),
Slice((Index, Index)),
}
impl ArrayIndex {
pub fn to_indices(&self, length: usize) -> HashSet<usize> {
let length = length as i32;
let mut indices = HashSet::new();
match self {
ArrayIndex::Index(idx) => {
let idx = Self::convert_index(idx, length);
if idx >= 0 && idx < length {
indices.insert(idx as usize);
}
}
ArrayIndex::Slice((start, end)) => {
let start_idx = Self::convert_index(start, length);
let end_idx = Self::convert_index(end, length);
let start_idx = if start_idx < 0 { 0 } else { start_idx as usize };
let end_idx = if end_idx >= length {
(length - 1) as usize
} else {
end_idx as usize
};
for idx in start_idx..=end_idx {
indices.insert(idx);
}
}
}
indices
}
fn convert_index(index: &Index, length: i32) -> i32 {
match index {
Index::Index(idx) => *idx,
Index::LastIndex(idx) => length + *idx - 1,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum RecursiveLevelEnd {
Index(u8),
Last,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RecursiveLevel {
pub start: u8,
pub end: Option<RecursiveLevelEnd>,
}
impl RecursiveLevel {
pub fn check_recursive_level(&self, level: u8) -> (bool, bool) {
if let Some(end) = &self.end {
match end {
RecursiveLevelEnd::Index(end) => {
if level < self.start && self.start <= *end {
(false, true)
} else if level >= self.start && level <= *end {
(true, true)
} else {
(false, false)
}
}
RecursiveLevelEnd::Last => {
if level < self.start {
(false, true)
} else {
(true, true)
}
}
}
} else if level < self.start {
(false, true)
} else if level == self.start {
(true, false)
} else {
(false, false)
}
}
}
#[derive(Debug, Clone)]
pub enum PathValue<'a> {
Null,
Boolean(bool),
Number(Number),
String(Cow<'a, str>),
Raw(RawJsonb<'a>),
}
impl PartialOrd for PathValue<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(PathValue::Null, PathValue::Null) => Some(Ordering::Equal),
(PathValue::Boolean(l), PathValue::Boolean(r)) => l.partial_cmp(r),
(PathValue::Number(l), PathValue::Number(r)) => l.partial_cmp(r),
(PathValue::String(l), PathValue::String(r)) => l.partial_cmp(r),
(_, _) => None,
}
}
}
impl PartialEq for PathValue<'_> {
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BinaryOperator {
And,
Or,
Eq,
NotEq,
Lt,
Lte,
Gt,
Gte,
StartsWith,
Add,
Subtract,
Multiply,
Divide,
Modulo,
}
#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOperator {
Add,
Subtract,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr<'a> {
Paths(Vec<Path<'a>>),
Value(Box<PathValue<'a>>),
BinaryOp {
op: BinaryOperator,
left: Box<Expr<'a>>,
right: Box<Expr<'a>>,
},
UnaryOp {
op: UnaryOperator,
operand: Box<Expr<'a>>,
},
ExistsFunc(Vec<Path<'a>>),
}
impl Display for JsonPath<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for path in &self.paths {
write!(f, "{path}")?;
}
Ok(())
}
}
impl Display for Index {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Index::Index(idx) => {
write!(f, "{idx}")?;
}
Index::LastIndex(idx) => {
write!(f, "last")?;
match idx.cmp(&0) {
Ordering::Greater => {
write!(f, "+{idx}")?;
}
Ordering::Less => {
write!(f, "{idx}")?;
}
Ordering::Equal => {}
}
}
}
Ok(())
}
}
impl Display for ArrayIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ArrayIndex::Index(idx) => {
write!(f, "{idx}")?;
}
ArrayIndex::Slice((start, end)) => {
write!(f, "{start} to {end}")?;
}
}
Ok(())
}
}
impl Display for RecursiveLevel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(end_index) = &self.end {
match end_index {
RecursiveLevelEnd::Index(end) => {
write!(f, "{} to {}", self.start, end)?;
}
RecursiveLevelEnd::Last => {
write!(f, "{} to last", self.start)?;
}
}
} else {
write!(f, "{}", self.start)?;
}
Ok(())
}
}
impl Display for Path<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Path::Root => {
write!(f, "$")?;
}
Path::Current => {
write!(f, "@")?;
}
Path::DotWildcard => {
write!(f, ".*")?;
}
Path::RecursiveDotWildcard(level_opt) => {
write!(f, ".**")?;
if let Some(level) = level_opt {
write!(f, "{{")?;
write!(f, "{level}")?;
write!(f, "}}")?;
}
}
Path::BracketWildcard => {
write!(f, "[*]")?;
}
Path::ColonField(field) => {
write!(f, ":{field}")?;
}
Path::DotField(field) => {
write!(f, ".{field}")?;
}
Path::ObjectField(field) => {
write!(f, "[\"{field}\"]")?;
}
Path::ArrayIndices(indices) => {
write!(f, "[")?;
for (i, index) in indices.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{index}")?;
}
write!(f, "]")?;
}
Path::FilterExpr(expr) => {
write!(f, "?({expr})")?;
}
Path::Expr(expr) => {
write!(f, "{expr}")?;
}
}
Ok(())
}
}
impl Display for PathValue<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PathValue::Null => {
write!(f, "null")
}
PathValue::Boolean(v) => {
if *v {
write!(f, "true")
} else {
write!(f, "false")
}
}
PathValue::Number(v) => {
write!(f, "{v}")
}
PathValue::String(v) => {
write!(f, "\"{v}\"")
}
PathValue::Raw(v) => {
write!(f, "{}", v.to_string())
}
}
}
}
impl Display for BinaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
BinaryOperator::And => {
write!(f, "&&")
}
BinaryOperator::Or => {
write!(f, "||")
}
BinaryOperator::Eq => {
write!(f, "==")
}
BinaryOperator::NotEq => {
write!(f, "!=")
}
BinaryOperator::Lt => {
write!(f, "<")
}
BinaryOperator::Lte => {
write!(f, "<=")
}
BinaryOperator::Gt => {
write!(f, ">")
}
BinaryOperator::Gte => {
write!(f, ">=")
}
BinaryOperator::StartsWith => {
write!(f, "starts with")
}
BinaryOperator::Add => {
write!(f, "+")
}
BinaryOperator::Subtract => {
write!(f, "-")
}
BinaryOperator::Multiply => {
write!(f, "*")
}
BinaryOperator::Divide => {
write!(f, "/")
}
BinaryOperator::Modulo => {
write!(f, "%")
}
}
}
}
impl Display for UnaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
UnaryOperator::Add => {
write!(f, "+")
}
UnaryOperator::Subtract => {
write!(f, "-")
}
}
}
}
impl Display for Expr<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Paths(paths) => {
for path in paths {
write!(f, "{path}")?;
}
}
Expr::Value(v) => {
write!(f, "{v}")?;
}
Expr::BinaryOp { op, left, right } => {
if let Expr::BinaryOp { op: left_op, .. } = &**left {
if left_op == &BinaryOperator::And || left_op == &BinaryOperator::Or {
write!(f, "({left})")?;
} else {
write!(f, "{left}")?;
}
} else {
write!(f, "{left}")?;
}
write!(f, " {op} ")?;
if let Expr::BinaryOp { op: right_op, .. } = &**right {
if right_op == &BinaryOperator::And || right_op == &BinaryOperator::Or {
write!(f, "({right})")?;
} else {
write!(f, "{right}")?;
}
} else {
write!(f, "{right}")?;
}
}
Expr::UnaryOp { op, operand } => {
write!(f, "{}{}", op, operand)?;
}
Expr::ExistsFunc(paths) => {
f.write_str("exists(")?;
for path in paths {
write!(f, "{path}")?;
}
f.write_str(")")?;
}
}
Ok(())
}
}