use std::fmt::Display;
use std::fmt::Formatter;
use std::ops::Deref;
use serde_json::Number;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JsonPath {
pub(crate) mode: Mode,
pub(crate) expr: ExprOrPredicate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Lax,
Strict,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExprOrPredicate {
Expr(Expr),
Pred(Predicate),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr {
PathPrimary(PathPrimary),
Accessor(Box<Expr>, AccessorOp),
UnaryOp(UnaryOp, Box<Expr>),
BinaryOp(BinaryOp, Box<Expr>, Box<Expr>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Predicate {
Compare(CompareOp, Box<Expr>, Box<Expr>),
Exists(Box<Expr>),
And(Box<Predicate>, Box<Predicate>),
Or(Box<Predicate>, Box<Predicate>),
Not(Box<Predicate>),
IsUnknown(Box<Predicate>),
StartsWith(Box<Expr>, Value),
LikeRegex(Box<Expr>, Box<Regex>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PathPrimary {
Root,
Current,
Last,
Value(Value),
ExprOrPred(Box<ExprOrPredicate>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AccessorOp {
MemberWildcard,
DescendantMemberWildcard(LevelRange),
ElementWildcard,
Member(String),
Element(Vec<ArrayIndex>),
FilterExpr(Box<Predicate>),
Method(Method),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LevelRange {
All,
One(Level),
Range(Level, Level),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Level {
N(u32),
Last,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArrayIndex {
Index(Expr),
Slice(Expr, Expr),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
Null,
Boolean(bool),
Number(Number),
String(String),
Variable(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Plus,
Minus,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Rem,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Method {
Type,
Size,
Double,
Ceiling,
Floor,
Abs,
Keyvalue,
}
impl PathPrimary {
pub(crate) fn unnest(self) -> Self {
match self {
Self::ExprOrPred(expr) => match *expr {
ExprOrPredicate::Expr(Expr::PathPrimary(inner)) => inner,
other => Self::ExprOrPred(Box::new(other)),
},
_ => self,
}
}
}
impl LevelRange {
pub(crate) fn end(&self) -> u32 {
match self {
Self::One(Level::N(n)) => *n,
Self::Range(_, Level::N(end)) => *end,
_ => u32::MAX,
}
}
pub(crate) fn to_range(&self, last: usize) -> std::ops::Range<usize> {
match self {
Self::All => 0..last + 1,
Self::One(level) => {
level.to_usize(last).min(last + 1)..level.to_usize(last).min(last) + 1
}
Self::Range(start, end) => {
start.to_usize(last).min(last + 1)..end.to_usize(last).min(last) + 1
}
}
}
}
impl Level {
fn to_usize(&self, last: usize) -> usize {
match self {
Self::N(n) => *n as usize,
Self::Last => last,
}
}
}
impl Display for JsonPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.mode == Mode::Strict {
write!(f, "strict ")?;
}
write!(f, "{}", self.expr)
}
}
impl Display for Mode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Lax => write!(f, "lax"),
Self::Strict => write!(f, "strict"),
}
}
}
impl Display for ExprOrPredicate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Expr(expr) => match expr {
Expr::BinaryOp(_, _, _) => write!(f, "({})", expr),
_ => write!(f, "{}", expr),
},
Self::Pred(pred) => match pred {
Predicate::Compare(_, _, _) | Predicate::And(_, _) | Predicate::Or(_, _) => {
write!(f, "({})", pred)
}
_ => write!(f, "{}", pred),
},
}
}
}
impl Display for Predicate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Compare(op, left, right) => write!(f, "{left} {op} {right}"),
Self::Exists(expr) => write!(f, "exists ({expr})"),
Self::And(left, right) => {
match left.as_ref() {
Self::Or(_, _) => write!(f, "({left})")?,
_ => write!(f, "{left}")?,
}
write!(f, " && ")?;
match right.as_ref() {
Self::Or(_, _) => write!(f, "({right})"),
_ => write!(f, "{right}"),
}
}
Self::Or(left, right) => write!(f, "{left} || {right}"),
Self::Not(expr) => write!(f, "!({expr})"),
Self::IsUnknown(expr) => write!(f, "({expr}) is unknown"),
Self::StartsWith(expr, v) => write!(f, "{expr} starts with {v}"),
Self::LikeRegex(expr, regex) => {
write!(f, "{expr} like_regex \"{}\"", regex.pattern())?;
if let Some(flags) = regex.flags() {
write!(f, " flag \"{flags}\"")?;
}
Ok(())
}
}
}
}
impl Display for Expr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Expr::PathPrimary(primary) => write!(f, "{primary}"),
Expr::Accessor(base, op) => {
match base.as_ref() {
Expr::PathPrimary(PathPrimary::Value(Value::Number(_))) => {
write!(f, "({base})")?
}
Expr::PathPrimary(PathPrimary::ExprOrPred(expr)) => match expr.as_ref() {
ExprOrPredicate::Expr(Expr::UnaryOp(_, _)) => write!(f, "({base})")?,
_ => write!(f, "{base}")?,
},
_ => write!(f, "{base}")?,
}
write!(f, "{op}")?;
Ok(())
}
Expr::UnaryOp(op, expr) => match expr.as_ref() {
Expr::PathPrimary(_) | Expr::Accessor(_, _) => write!(f, "{op}{expr}"),
_ => write!(f, "{op}({expr})"),
},
Expr::BinaryOp(op, left, right) => write!(f, "{left} {op} {right}"),
}
}
}
impl Display for ArrayIndex {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Index(idx) => write!(f, "{idx}"),
Self::Slice(start, end) => write!(f, "{start} to {end}"),
}
}
}
impl Display for PathPrimary {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Root => write!(f, "$"),
Self::Current => write!(f, "@"),
Self::Value(v) => write!(f, "{v}"),
Self::Last => write!(f, "last"),
Self::ExprOrPred(expr) => write!(f, "{expr}"),
}
}
}
impl Display for AccessorOp {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::MemberWildcard => write!(f, ".*"),
Self::DescendantMemberWildcard(level) => write!(f, ".**{level}"),
Self::ElementWildcard => write!(f, "[*]"),
Self::Member(field) => write!(f, ".\"{field}\""),
Self::Element(indices) => {
write!(f, "[")?;
for (i, idx) in indices.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
write!(f, "{idx}")?;
}
write!(f, "]")
}
Self::FilterExpr(expr) => write!(f, "?({expr})"),
Self::Method(method) => write!(f, ".{method}()"),
}
}
}
impl Display for LevelRange {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::All => Ok(()),
Self::One(level) => write!(f, "{{{level}}}"),
Self::Range(start, end) => write!(f, "{{{start} to {end}}}"),
}
}
}
impl Display for Level {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::N(n) => write!(f, "{n}"),
Self::Last => write!(f, "last"),
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Null => write!(f, "null"),
Self::Boolean(v) => write!(f, "{v}"),
Self::Number(v) => write!(f, "{v}"),
Self::String(v) => write!(f, "\"{v}\""),
Self::Variable(v) => write!(f, "$\"{v}\""),
}
}
}
impl Display for UnaryOp {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Plus => write!(f, "+"),
Self::Minus => write!(f, "-"),
}
}
}
impl Display for CompareOp {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Eq => write!(f, "=="),
Self::Ne => write!(f, "!="),
Self::Lt => write!(f, "<"),
Self::Le => write!(f, "<="),
Self::Gt => write!(f, ">"),
Self::Ge => write!(f, ">="),
}
}
}
impl Display for BinaryOp {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Add => write!(f, "+"),
Self::Sub => write!(f, "-"),
Self::Mul => write!(f, "*"),
Self::Div => write!(f, "/"),
Self::Rem => write!(f, "%"),
}
}
}
impl Display for Method {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Type => write!(f, "type"),
Self::Size => write!(f, "size"),
Self::Double => write!(f, "double"),
Self::Ceiling => write!(f, "ceiling"),
Self::Floor => write!(f, "floor"),
Self::Abs => write!(f, "abs"),
Self::Keyvalue => write!(f, "keyvalue"),
}
}
}
#[derive(Debug, Clone)]
pub struct Regex {
regex: regex::Regex,
flags: String,
}
impl Regex {
pub(crate) fn with_flags(pattern: &str, flags: Option<String>) -> Result<Self, regex::Error> {
let mut builder = match flags.as_deref() {
Some(flags) if flags.contains('q') => regex::RegexBuilder::new(®ex::escape(pattern)),
_ => regex::RegexBuilder::new(pattern),
};
let mut out_flags = String::new();
if let Some(flags) = flags.as_deref() {
for c in flags.chars() {
match c {
'q' => {}
'i' => {
builder.case_insensitive(true);
}
'm' => {
builder.multi_line(true);
}
's' => {
builder.dot_matches_new_line(true);
}
'x' => {
return Err(regex::Error::Syntax(
"XQuery \"x\" flag (expanded regular expressions) is not implemented"
.to_string(),
))
}
_ => {
return Err(regex::Error::Syntax(format!(
"Unrecognized flag character \"{c}\" in LIKE_REGEX predicate."
)))
}
};
if !out_flags.contains(c) {
out_flags.push(c);
}
}
}
let regex = builder.build()?;
Ok(Self {
regex,
flags: out_flags,
})
}
pub fn pattern(&self) -> &str {
self.regex.as_str()
}
pub fn flags(&self) -> Option<&str> {
if self.flags.is_empty() {
None
} else {
Some(&self.flags)
}
}
}
impl Deref for Regex {
type Target = regex::Regex;
fn deref(&self) -> &Self::Target {
&self.regex
}
}
impl PartialEq for Regex {
fn eq(&self, other: &Self) -> bool {
self.pattern() == other.pattern() && self.flags() == other.flags()
}
}
impl Eq for Regex {}