1#[macro_export]
17macro_rules! filter {
18 (cont; $f:ident, ORDER $value:tt $($tt:tt)*) => ({
20 $crate::filter_order!($f, $value);
21 });
22 (cont; $f:ident, LIMIT $value:tt $($tt:tt)*) => ({
24 $crate::filter_limit!($f, $value);
25 });
26 (cont; $f:ident, OFFSET $value:tt $($tt:tt)*) => ({
28 $crate::filter_offset!($f, $value);
29 });
30 (cont; $f:ident, $($tt:tt)*) => ({
31 $crate::filter_inner!($f, $($tt)*);
32 });
33
34 ($($tt:tt)*) => ({
35 #[allow(unused_mut)]
36 let mut f = $crate::filter::Filter::new();
37 $crate::filter!(cont; f, $($tt)*);
38
39 f
40 });
41}
42
43#[macro_export]
59macro_rules! whr {
60 ($($tt:tt)*) => ({
61 #[allow(unused_mut)]
62 let mut f = $crate::filter::WhereFilter::new();
63 $crate::filter_inner!(f, $($tt)*);
64
65 f
66 });
67}
68
69#[doc(hidden)]
70#[macro_export]
71macro_rules! filter_inner {
72 ($f:ident,) => ();
73
74 ($f:ident, ($($tt:tt)+) $($rest:tt)*) => ({
76 let mut prev_where = std::mem::take(&mut $f.whr);
78 $crate::filter_inner!($f, $($tt)*);
79 std::mem::swap(&mut $f.whr, &mut prev_where);
80 $f.whr.push($crate::filter::WherePart::Nested(prev_where));
81 $crate::whr_log!($f, $($rest)*);
82 });
83
84 ($f:ident, &$id:ident $($tt:tt)*) => (
86 $crate::whr_comp!($f, stringify!($id), Eq, &$id $($tt)*);
87 );
88 ($f:ident, $id:ident $($tt:tt)*) => (
90 $crate::whr_comp!($f, stringify!($id), Eq, $id $($tt)*);
91 );
92
93 ($f:ident, $name:literal = $($tt:tt)+) => (
95 $crate::whr_comp!($f, $name, Eq, $($tt)*);
96 );
97 ($f:ident, $name:literal != $($tt:tt)+) => (
99 $crate::whr_comp!($f, $name, Ne, $($tt)*);
100 );
101 ($f:ident, $name:literal < $($tt:tt)+) => (
103 $crate::whr_comp!($f, $name, Lt, $($tt)*);
104 );
105 ($f:ident, $name:literal <= $($tt:tt)+) => (
107 $crate::whr_comp!($f, $name, Lte, $($tt)*);
108 );
109 ($f:ident, $name:literal > $($tt:tt)+) => (
111 $crate::whr_comp!($f, $name, Gt, $($tt)*);
112 );
113 ($f:ident, $name:literal >= $($tt:tt)+) => (
115 $crate::whr_comp!($f, $name, Gte, $($tt)*);
116 );
117 ($f:ident, $name:literal LIKE $($tt:tt)+) => (
119 $crate::whr_comp!($f, $name, Like, $($tt)*);
120 );
121 ($f:ident, $name:literal ~ $($tt:tt)+) => (
123 $crate::whr_comp!($f, $name, ~, $($tt)*);
124 );
125 ($f:ident, $name:literal ~= $($tt:tt)+) => (
127 $crate::whr_comp!($f, $name, ~=, $($tt)*);
128 );
129 ($f:ident, $name:literal =~ $($tt:tt)+) => (
131 $crate::whr_comp!($f, $name, =~, $($tt)*);
132 );
133 ($f:ident, $name:literal IN $($tt:tt)+) => (
135 $crate::whr_comp_in!($f, $name, $($tt)*);
136 );
137}
138
139#[doc(hidden)]
140#[macro_export]
141macro_rules! whr_comp {
142 ($f:ident, $name:expr, $symb:tt, &$value:tt $($tt:tt)*) => (
143 $crate::whr_comp!(symb; $f, $name, $symb, &$value, $($tt)*);
144 );
145 ($f:ident, $name:expr, $symb:tt, $value:tt $($tt:tt)*) => (
146 $crate::whr_comp!(symb; $f, $name, $symb, $value, $($tt)*);
147 );
148
149 (symb; $f:ident, $name:expr, ~, $value:expr, $($tt:tt)*) => (
150 let param = $crate::filter::Param::new_owned($name, format!("%{}%", $value));
151 $crate::whr_comp!(fin; $f, param, Like, $($tt)*);
152 );
153 (symb; $f:ident, $name:expr, ~=, $value:expr, $($tt:tt)*) => (
154 let param = $crate::filter::Param::new_owned($name, format!("%{}", $value));
155 $crate::whr_comp!(fin; $f, param, Like, $($tt)*);
156 );
157 (symb; $f:ident, $name:expr, =~, $value:expr, $($tt:tt)*) => (
158 let param = $crate::filter::Param::new_owned($name, format!("{}%", $value));
159 $crate::whr_comp!(fin; $f, param, Like, $($tt)*);
160 );
161 (symb; $f:ident, $name:expr, $symb:ident, $value:expr, $($tt:tt)*) => (
162 let param = $crate::filter::Param::new($name, $value);
163 $crate::whr_comp!(fin; $f, param, $symb, $($tt)*);
164 );
165 (fin; $f:ident, $param:expr, $symb:ident, $($tt:tt)*) => (
166 let symb = $crate::filter::Operator::$symb;
167
168 let mut cont = true;
169
170 if $param.is_null() {
172 match symb {
173 $crate::filter::Operator::Eq => {
174 $f.whr.push($crate::filter::WhereOperation {
175 kind: $crate::filter::Operator::IsNull,
176 column: $param.name.into()
177 });
178 cont = false;
179 },
180 $crate::filter::Operator::Ne => {
181 $f.whr.push($crate::filter::WhereOperation {
182 kind: $crate::filter::Operator::IsNotNull,
183 column: $param.name.into()
184 });
185 cont = false;
186 },
187 _ => {}
188 }
189 }
190
191 if cont {
192 $f.whr.push($crate::filter::WhereOperation {
193 kind: symb,
194 column: $param.name.into()
195 });
196 $f.params.push($param);
197 }
198
199 $crate::whr_log!($f, $($tt)*);
200 );
201 }
203
204#[doc(hidden)]
205#[macro_export]
206macro_rules! whr_comp_in {
207 ($f:ident, $name:expr, &$value:tt $($tt:tt)*) => (
208 $crate::whr_comp_in!(two; $f, $name, &$value, $($tt)*);
209 );
210 ($f:ident, $name:expr, $value:tt $($tt:tt)*) => (
211 $crate::whr_comp_in!(two; $f, $name, $value, $($tt)*);
212 );
213
214 (two; $f:ident, $name:expr, $value:expr, $($tt:tt)*) => (
215 {
216 let mut c = 0;
217 for val in $value {
218 c += 1;
219 let param = $crate::filter::Param::new($name, val);
220 $f.params.push(param);
221 }
222
223 $f.whr.push($crate::filter::WhereOperation {
224 kind: $crate::filter::Operator::In { length: c },
225 column: $name.into()
226 });
227 }
228
229 $crate::whr_log!($f, $($tt)*);
230 );
231}
232
233#[doc(hidden)]
234#[macro_export]
235macro_rules! whr_log {
236 ($f:ident, AND $($tt:tt)+) => (
237 $f.whr.push($crate::filter::WherePart::And);
238 $crate::filter_inner!($f, $($tt)+);
239 );
240 ($f:ident, OR $($tt:tt)+) => (
241 $f.whr.push($crate::filter::WherePart::Or);
242 $crate::filter_inner!($f, $($tt)+);
243 );
244
245 ($f:ident, ORDER $($tt:tt)+) => (
246 $crate::filter_order!($f, $($tt)+);
247 );
248 ($f:ident, LIMIT $($tt:tt)+) => (
249 $crate::filter_limit!($f, $($tt)+);
250 );
251 ($f:ident, OFFSET $($tt:tt)+) => (
252 $crate::filter_offset!($f, $($tt)+);
253 );
254 ($f:ident,) => ();
255}
256
257#[doc(hidden)]
258#[macro_export]
259macro_rules! filter_order {
260 ($f:ident, $name:literal DESC $($tt:tt)*) => (
261 $f.order_by.push_desc($name);
262 $crate::filter_order!($f, $($tt)*);
263 );
264 ($f:ident, $name:literal ASC $($tt:tt)*) => (
265 $f.order_by.push_asc($name);
266 $crate::filter_order!($f, $($tt)*);
267 );
268 ($f:ident, LIMIT $($tt:tt)+) => (
269 $crate::filter_limit!($f, $($tt)+);
270 );
271 ($f:ident, OFFSET $($tt:tt)+) => (
272 $crate::filter_offset!($f, $($tt)+);
273 );
274 ($f:ident,) => ();
275}
276
277#[doc(hidden)]
278#[macro_export]
279macro_rules! filter_limit {
280 ($f:ident, &$value:ident $($tt:tt)*) => (
281 $crate::filter_limit!(val; $f, stringify!($value), &$value, $($tt)*);
282 );
283 ($f:ident, $value:ident $($tt:tt)*) => (
284 $crate::filter_limit!(val; $f, stringify!($value), $value, $($tt)*);
285 );
286 ($f:ident, $value:literal $($tt:tt)*) => (
287 $f.limit.set_fixed($value);
288
289 $crate::filter_limit!(next; $f, $($tt)*);
290 );
291
292 (val; $f:ident, $name:expr, $value:expr, $($tt:tt)*) => (
293 let param = $crate::filter::Param::new($name, $value);
294 $f.limit.set_param();
295 $f.params.push(param);
296
297 $crate::filter_limit!(next; $f, $($tt)*);
298 );
299
300 (next; $f:ident, OFFSET $($tt:tt)+) => (
301 $crate::filter_offset!($f, $($tt)*);
302 );
303 (next; $f:ident,) => ();
304}
305
306#[doc(hidden)]
307#[macro_export]
308macro_rules! filter_offset {
309 ($f:ident, &$value:ident $($tt:tt)*) => (
310 $crate::filter_offset!(val; $f, stringify!($value), &$value, $($tt)*);
311 );
312 ($f:ident, $value:ident $($tt:tt)*) => (
313 $crate::filter_offset!(val; $f, stringify!($value), $value, $($tt)*);
314 );
315 ($f:ident, $value:literal $($tt:tt)*) => (
316 $f.offset.set_fixed($value);
317
318 $crate::filter_offset!(next; $f, $($tt)*);
319 );
320
321 (val; $f:ident, $name:literal, $value:expr, $($tt:tt)*) => (
322 let param = $crate::filter::Param::new($name, $value);
323 $f.offset.set_param();
324 $f.params.push(param);
325
326 $crate::filter_offset!(next; $f, $($tt)*);
327 );
328
329 (next; $f:ident,) => ();
330}
331
332#[cfg(test)]
333mod tests {
334 use crate::UniqueId;
335
336 #[test]
337 fn test_simple_eq() {
338 let id = &UniqueId::new();
339 let id2 = &UniqueId::new();
340 let query = filter!(id OR "id" != &id2);
341 assert_eq!(query.to_string(), r#" WHERE "id" = $1 OR "id" != $2"#);
342 }
343
344 #[test]
345 fn test_simple_like() {
346 let id = "str";
347 let query = filter!("id" ~ id);
348 assert_eq!(query.to_string(), r#" WHERE "id" LIKE $1"#);
349 }
350
351 #[test]
352 fn test_limit() {
353 let id = &UniqueId::new();
354 let limit = 10;
355 let query = filter!(id LIMIT &limit);
356 assert_eq!(query.to_string(), " WHERE \"id\" = $1 LIMIT $2");
357 }
358
359 #[test]
360 fn test_and_or() {
361 let user_id = &UniqueId::new();
362 let id1 = &UniqueId::new();
363 let id2 = &UniqueId::new();
364 let id3 = &UniqueId::new();
365 let query =
366 filter!(user_id AND ("id" != &id1 OR "id" = &id2) OR "id" = &id3);
367 assert_eq!(
368 query.to_string(),
369 r#" WHERE "user_id" = $1 AND ("id" != $2 OR "id" = $3) OR "id" = $4"#
370 );
371 }
372
373 }