use std::fmt::Display;
#[cfg(feature = "native")]
use chrono::{DateTime, Local};
use nom::Parser;
use nom::bytes::complete::tag_no_case;
use nom::{
IResult,
branch::alt,
bytes::complete::tag,
combinator::{map, value},
};
use super::number::NumberOperator;
use super::string::StringOperator;
#[cfg(feature = "native")]
#[derive(Debug, PartialEq, Clone, Eq)]
pub enum CompareExpression {
Partition(NumberOperator, i32),
OffsetTail(i64),
Offset(NumberOperator, i64),
Topic(StringOperator, String),
Key(StringOperator, String),
Value(Option<String>, StringOperator, String),
Header(String, StringOperator, String),
Size(NumberOperator, usize),
Timestamp(NumberOperator, DateTime<Local>),
TimestampBetween(DateTime<Local>, DateTime<Local>),
}
#[cfg(feature = "native")]
impl Display for CompareExpression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompareExpression::Partition(op, r) => write!(f, "partition {op} {r}"),
CompareExpression::OffsetTail(r) => write!(f, "offsetTail - {r}"),
CompareExpression::Offset(op, r) => write!(f, "offset {op} {r}"),
CompareExpression::Topic(op, r) => write!(f, "topic {op} {r}"),
CompareExpression::Key(op, r) => write!(f, "key {op} {r}"),
CompareExpression::Value(left, op, r) => write!(
f,
"value{} {} {}",
left.clone().unwrap_or(String::new()),
op,
r
),
CompareExpression::Header(left, op, r) => {
write!(f, "headers.{} {} {}", left.clone(), op, r)
}
CompareExpression::Size(op, r) => write!(f, "size {op} {r}"),
CompareExpression::Timestamp(op, r) => write!(
f,
r#"timestamp {} "{}""#,
op,
r.to_rfc3339_opts(chrono::SecondsFormat::Millis, false)
),
CompareExpression::TimestampBetween(l, r) => write!(
f,
r#"timestamp between "{}" and "{}"#,
l.to_rfc3339_opts(chrono::SecondsFormat::Millis, false),
r.to_rfc3339_opts(chrono::SecondsFormat::Millis, false)
),
}
}
}
#[cfg(feature = "native")]
pub fn parse_compare(input: &str) -> IResult<&str, CompareExpression> {
use crate::search::{
compare::{parse_equal, string::parse_string_operator},
number::parse_number,
string::parse_string,
symbol::{
Symbol, parse_header_symbol, parse_key, parse_offset, parse_partition, parse_size,
parse_timestamp_symbol, parse_topic, parse_value_symbol,
},
timestamp::parse_timestamp,
wsi::wsi,
};
use super::number::parse_number_operator;
alt((
map(
(parse_offset, wsi(parse_number_operator), wsi(parse_number)),
|(_, op, r)| CompareExpression::Offset(op, r),
),
map(
(parse_size, wsi(parse_number_operator), wsi(parse_number)),
|(_, op, r)| CompareExpression::Size(op, r),
),
map(
(
value(Symbol::OffsetTail, wsi(tag("offsetTail"))),
parse_equal,
wsi(parse_number),
),
|(_, _, r)| CompareExpression::OffsetTail(r),
),
map(
(
parse_partition,
wsi(parse_number_operator),
wsi(parse_number::<i32>),
),
|(_, op, partition)| CompareExpression::Partition(op, partition),
),
map(
(parse_topic, wsi(parse_string_operator), wsi(parse_string)),
|(_, op, r)| CompareExpression::Topic(op, r),
),
map(
(parse_key, wsi(parse_string_operator), wsi(parse_string)),
|(_, op, r)| CompareExpression::Key(op, r),
),
map(
(
parse_value_symbol,
wsi(parse_string_operator),
wsi(parse_string),
),
|(left, op, r)| CompareExpression::Value(left.1, op, r),
),
map(
(
parse_header_symbol,
wsi(parse_string_operator),
wsi(parse_string),
),
|(left, op, r)| CompareExpression::Header(left.1, op, r),
),
map(
(
parse_timestamp_symbol,
wsi(parse_number_operator),
wsi(parse_timestamp),
),
|(_, op, r)| CompareExpression::Timestamp(op, r),
),
map(
(
parse_timestamp_symbol,
wsi(tag_no_case("between")),
wsi(parse_timestamp),
wsi(tag_no_case("and")),
wsi(parse_timestamp),
),
|(_, _, from, _, to)| CompareExpression::TimestampBetween(from, to),
),
))
.parse(input)
}