#[macro_export]
macro_rules! filter {
(cont; $f:ident, ORDER $value:tt $($tt:tt)*) => ({
$crate::filter_order!($f, $value);
});
(cont; $f:ident, LIMIT $value:tt $($tt:tt)*) => ({
$crate::filter_limit!($f, $value);
});
(cont; $f:ident, OFFSET $value:tt $($tt:tt)*) => ({
$crate::filter_offset!($f, $value);
});
(cont; $f:ident, $($tt:tt)*) => ({
$crate::filter_inner!($f, $($tt)*);
});
($($tt:tt)*) => ({
#[allow(unused_mut)]
let mut f = $crate::filter::Filter::new();
$crate::filter!(cont; f, $($tt)*);
f
});
}
#[macro_export]
macro_rules! whr {
($($tt:tt)*) => ({
#[allow(unused_mut)]
let mut f = $crate::filter::WhereFilter::new();
$crate::filter_inner!(f, $($tt)*);
f
});
}
#[doc(hidden)]
#[macro_export]
macro_rules! filter_inner {
($f:ident,) => ();
($f:ident, ($($tt:tt)+) $($rest:tt)*) => ({
let mut prev_where = std::mem::take(&mut $f.whr);
$crate::filter_inner!($f, $($tt)*);
std::mem::swap(&mut $f.whr, &mut prev_where);
$f.whr.push($crate::filter::WherePart::Nested(prev_where));
$crate::whr_log!($f, $($rest)*);
});
($f:ident, &$id:ident $($tt:tt)*) => (
$crate::whr_comp!($f, stringify!($id), Eq, &$id $($tt)*);
);
($f:ident, $id:ident $($tt:tt)*) => (
$crate::whr_comp!($f, stringify!($id), Eq, $id $($tt)*);
);
($f:ident, $name:literal = $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Eq, $($tt)*);
);
($f:ident, $name:literal != $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Ne, $($tt)*);
);
($f:ident, $name:literal < $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Lt, $($tt)*);
);
($f:ident, $name:literal <= $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Lte, $($tt)*);
);
($f:ident, $name:literal > $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Gt, $($tt)*);
);
($f:ident, $name:literal >= $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Gte, $($tt)*);
);
($f:ident, $name:literal LIKE $($tt:tt)+) => (
$crate::whr_comp!($f, $name, Like, $($tt)*);
);
($f:ident, $name:literal ~ $($tt:tt)+) => (
$crate::whr_comp!($f, $name, ~, $($tt)*);
);
($f:ident, $name:literal ~= $($tt:tt)+) => (
$crate::whr_comp!($f, $name, ~=, $($tt)*);
);
($f:ident, $name:literal =~ $($tt:tt)+) => (
$crate::whr_comp!($f, $name, =~, $($tt)*);
);
($f:ident, $name:literal IN $($tt:tt)+) => (
$crate::whr_comp_in!($f, $name, $($tt)*);
);
}
#[doc(hidden)]
#[macro_export]
macro_rules! whr_comp {
($f:ident, $name:expr, $symb:tt, &$value:tt $($tt:tt)*) => (
$crate::whr_comp!(symb; $f, $name, $symb, &$value, $($tt)*);
);
($f:ident, $name:expr, $symb:tt, $value:tt $($tt:tt)*) => (
$crate::whr_comp!(symb; $f, $name, $symb, $value, $($tt)*);
);
(symb; $f:ident, $name:expr, ~, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new_owned($name, format!("%{}%", $value));
$crate::whr_comp!(fin; $f, param, Like, $($tt)*);
);
(symb; $f:ident, $name:expr, ~=, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new_owned($name, format!("%{}", $value));
$crate::whr_comp!(fin; $f, param, Like, $($tt)*);
);
(symb; $f:ident, $name:expr, =~, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new_owned($name, format!("{}%", $value));
$crate::whr_comp!(fin; $f, param, Like, $($tt)*);
);
(symb; $f:ident, $name:expr, $symb:ident, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new($name, $value);
$crate::whr_comp!(fin; $f, param, $symb, $($tt)*);
);
(fin; $f:ident, $param:expr, $symb:ident, $($tt:tt)*) => (
let symb = $crate::filter::Operator::$symb;
let mut cont = true;
if $param.is_null() {
match symb {
$crate::filter::Operator::Eq => {
$f.whr.push($crate::filter::WhereOperation {
kind: $crate::filter::Operator::IsNull,
column: $param.name.into()
});
cont = false;
},
$crate::filter::Operator::Ne => {
$f.whr.push($crate::filter::WhereOperation {
kind: $crate::filter::Operator::IsNotNull,
column: $param.name.into()
});
cont = false;
},
_ => {}
}
}
if cont {
$f.whr.push($crate::filter::WhereOperation {
kind: symb,
column: $param.name.into()
});
$f.params.push($param);
}
$crate::whr_log!($f, $($tt)*);
);
}
#[doc(hidden)]
#[macro_export]
macro_rules! whr_comp_in {
($f:ident, $name:expr, &$value:tt $($tt:tt)*) => (
$crate::whr_comp_in!(two; $f, $name, &$value, $($tt)*);
);
($f:ident, $name:expr, $value:tt $($tt:tt)*) => (
$crate::whr_comp_in!(two; $f, $name, $value, $($tt)*);
);
(two; $f:ident, $name:expr, $value:expr, $($tt:tt)*) => (
{
let mut c = 0;
for val in $value {
c += 1;
let param = $crate::filter::Param::new($name, val);
$f.params.push(param);
}
$f.whr.push($crate::filter::WhereOperation {
kind: $crate::filter::Operator::In { length: c },
column: $name.into()
});
}
$crate::whr_log!($f, $($tt)*);
);
}
#[doc(hidden)]
#[macro_export]
macro_rules! whr_log {
($f:ident, AND $($tt:tt)+) => (
$f.whr.push($crate::filter::WherePart::And);
$crate::filter_inner!($f, $($tt)+);
);
($f:ident, OR $($tt:tt)+) => (
$f.whr.push($crate::filter::WherePart::Or);
$crate::filter_inner!($f, $($tt)+);
);
($f:ident, ORDER $($tt:tt)+) => (
$crate::filter_order!($f, $($tt)+);
);
($f:ident, LIMIT $($tt:tt)+) => (
$crate::filter_limit!($f, $($tt)+);
);
($f:ident, OFFSET $($tt:tt)+) => (
$crate::filter_offset!($f, $($tt)+);
);
($f:ident,) => ();
}
#[doc(hidden)]
#[macro_export]
macro_rules! filter_order {
($f:ident, $name:literal DESC $($tt:tt)*) => (
$f.order_by.push_desc($name);
$crate::filter_order!($f, $($tt)*);
);
($f:ident, $name:literal ASC $($tt:tt)*) => (
$f.order_by.push_asc($name);
$crate::filter_order!($f, $($tt)*);
);
($f:ident, LIMIT $($tt:tt)+) => (
$crate::filter_limit!($f, $($tt)+);
);
($f:ident, OFFSET $($tt:tt)+) => (
$crate::filter_offset!($f, $($tt)+);
);
($f:ident,) => ();
}
#[doc(hidden)]
#[macro_export]
macro_rules! filter_limit {
($f:ident, &$value:ident $($tt:tt)*) => (
$crate::filter_limit!(val; $f, stringify!($value), &$value, $($tt)*);
);
($f:ident, $value:ident $($tt:tt)*) => (
$crate::filter_limit!(val; $f, stringify!($value), $value, $($tt)*);
);
($f:ident, $value:literal $($tt:tt)*) => (
$f.limit.set_fixed($value);
$crate::filter_limit!(next; $f, $($tt)*);
);
(val; $f:ident, $name:expr, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new($name, $value);
$f.limit.set_param();
$f.params.push(param);
$crate::filter_limit!(next; $f, $($tt)*);
);
(next; $f:ident, OFFSET $($tt:tt)+) => (
$crate::filter_offset!($f, $($tt)*);
);
(next; $f:ident,) => ();
}
#[doc(hidden)]
#[macro_export]
macro_rules! filter_offset {
($f:ident, &$value:ident $($tt:tt)*) => (
$crate::filter_offset!(val; $f, stringify!($value), &$value, $($tt)*);
);
($f:ident, $value:ident $($tt:tt)*) => (
$crate::filter_offset!(val; $f, stringify!($value), $value, $($tt)*);
);
($f:ident, $value:literal $($tt:tt)*) => (
$f.offset.set_fixed($value);
$crate::filter_offset!(next; $f, $($tt)*);
);
(val; $f:ident, $name:literal, $value:expr, $($tt:tt)*) => (
let param = $crate::filter::Param::new($name, $value);
$f.offset.set_param();
$f.params.push(param);
$crate::filter_offset!(next; $f, $($tt)*);
);
(next; $f:ident,) => ();
}
#[cfg(test)]
mod tests {
use crate::UniqueId;
#[test]
fn test_simple_eq() {
let id = &UniqueId::new();
let id2 = &UniqueId::new();
let query = filter!(id OR "id" != &id2);
assert_eq!(query.to_string(), r#" WHERE "id" = $1 OR "id" != $2"#);
}
#[test]
fn test_simple_like() {
let id = "str";
let query = filter!("id" ~ id);
assert_eq!(query.to_string(), r#" WHERE "id" LIKE $1"#);
}
#[test]
fn test_limit() {
let id = &UniqueId::new();
let limit = 10;
let query = filter!(id LIMIT &limit);
assert_eq!(query.to_string(), " WHERE \"id\" = $1 LIMIT $2");
}
#[test]
fn test_and_or() {
let user_id = &UniqueId::new();
let id1 = &UniqueId::new();
let id2 = &UniqueId::new();
let id3 = &UniqueId::new();
let query =
filter!(user_id AND ("id" != &id1 OR "id" = &id2) OR "id" = &id3);
assert_eq!(
query.to_string(),
r#" WHERE "user_id" = $1 AND ("id" != $2 OR "id" = $3) OR "id" = $4"#
);
}
}