1#[macro_export]
70macro_rules! filter {
71 ($field:ident == $value:expr) => {{
73 $crate::filter::Filter::Equals(
74 ::std::borrow::Cow::Borrowed(stringify!($field)),
75 $value.into(),
76 )
77 }};
78
79 ($field:ident != $value:expr) => {{
81 $crate::filter::Filter::NotEquals(
82 ::std::borrow::Cow::Borrowed(stringify!($field)),
83 $value.into(),
84 )
85 }};
86
87 ($field:ident > $value:expr) => {{
89 $crate::filter::Filter::Gt(
90 ::std::borrow::Cow::Borrowed(stringify!($field)),
91 $value.into(),
92 )
93 }};
94
95 ($field:ident >= $value:expr) => {{
97 $crate::filter::Filter::Gte(
98 ::std::borrow::Cow::Borrowed(stringify!($field)),
99 $value.into(),
100 )
101 }};
102
103 ($field:ident < $value:expr) => {{
105 $crate::filter::Filter::Lt(
106 ::std::borrow::Cow::Borrowed(stringify!($field)),
107 $value.into(),
108 )
109 }};
110
111 ($field:ident <= $value:expr) => {{
113 $crate::filter::Filter::Lte(
114 ::std::borrow::Cow::Borrowed(stringify!($field)),
115 $value.into(),
116 )
117 }};
118
119 ($field:ident is null) => {{
121 $crate::filter::Filter::IsNull(
122 ::std::borrow::Cow::Borrowed(stringify!($field)),
123 )
124 }};
125
126 ($field:ident is not null) => {{
128 $crate::filter::Filter::IsNotNull(
129 ::std::borrow::Cow::Borrowed(stringify!($field)),
130 )
131 }};
132
133 ($field:ident contains $value:expr) => {{
135 $crate::filter::Filter::Contains(
136 ::std::borrow::Cow::Borrowed(stringify!($field)),
137 $value.into(),
138 )
139 }};
140
141 ($field:ident starts_with $value:expr) => {{
143 $crate::filter::Filter::StartsWith(
144 ::std::borrow::Cow::Borrowed(stringify!($field)),
145 $value.into(),
146 )
147 }};
148
149 ($field:ident ends_with $value:expr) => {{
151 $crate::filter::Filter::EndsWith(
152 ::std::borrow::Cow::Borrowed(stringify!($field)),
153 $value.into(),
154 )
155 }};
156
157 ($field:ident in [$($value:expr),* $(,)?]) => {{
159 $crate::filter::Filter::In(
160 ::std::borrow::Cow::Borrowed(stringify!($field)),
161 ::std::vec![$($value.into()),*],
162 )
163 }};
164
165 ($field:ident not in [$($value:expr),* $(,)?]) => {{
167 $crate::filter::Filter::NotIn(
168 ::std::borrow::Cow::Borrowed(stringify!($field)),
169 ::std::vec![$($value.into()),*],
170 )
171 }};
172}
173
174#[macro_export]
194macro_rules! and_filter {
195 ($a:expr, $b:expr $(,)?) => {{
197 $crate::filter::Filter::And(Box::new([$a, $b]))
198 }};
199
200 ($a:expr, $b:expr, $c:expr $(,)?) => {{
202 $crate::filter::Filter::And(Box::new([$a, $b, $c]))
203 }};
204
205 ($a:expr, $b:expr, $c:expr, $d:expr $(,)?) => {{
207 $crate::filter::Filter::And(Box::new([$a, $b, $c, $d]))
208 }};
209
210 ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr $(,)?) => {{
212 $crate::filter::Filter::And(Box::new([$a, $b, $c, $d, $e]))
213 }};
214
215 ($($filter:expr),+ $(,)?) => {{
217 $crate::filter::Filter::And(Box::new([$($filter),+]))
218 }};
219}
220
221#[macro_export]
234macro_rules! or_filter {
235 ($a:expr, $b:expr $(,)?) => {{
237 $crate::filter::Filter::Or(Box::new([$a, $b]))
238 }};
239
240 ($a:expr, $b:expr, $c:expr $(,)?) => {{
242 $crate::filter::Filter::Or(Box::new([$a, $b, $c]))
243 }};
244
245 ($($filter:expr),+ $(,)?) => {{
247 $crate::filter::Filter::Or(Box::new([$($filter),+]))
248 }};
249}
250
251#[macro_export]
261macro_rules! not_filter {
262 ($filter:expr) => {{
263 $crate::filter::Filter::Not(Box::new($filter))
264 }};
265}
266
267#[cfg(test)]
268mod tests {
269 use crate::filter::{Filter, FilterValue};
270
271 #[test]
272 fn test_filter_eq_macro() {
273 let f = filter!(id == 42);
274 match f {
275 Filter::Equals(field, FilterValue::Int(42)) => {
276 assert_eq!(field.as_ref(), "id");
277 }
278 _ => panic!("Expected Equals filter"),
279 }
280 }
281
282 #[test]
283 fn test_filter_ne_macro() {
284 let f = filter!(status != "deleted");
285 assert!(matches!(f, Filter::NotEquals(_, _)));
286 }
287
288 #[test]
289 fn test_filter_gt_macro() {
290 let f = filter!(age > 18);
291 assert!(matches!(f, Filter::Gt(_, FilterValue::Int(18))));
292 }
293
294 #[test]
295 fn test_filter_gte_macro() {
296 let f = filter!(score >= 100);
297 assert!(matches!(f, Filter::Gte(_, FilterValue::Int(100))));
298 }
299
300 #[test]
301 fn test_filter_lt_macro() {
302 let f = filter!(price < 50);
303 assert!(matches!(f, Filter::Lt(_, FilterValue::Int(50))));
304 }
305
306 #[test]
307 fn test_filter_lte_macro() {
308 let f = filter!(quantity <= 10);
309 assert!(matches!(f, Filter::Lte(_, FilterValue::Int(10))));
310 }
311
312 #[test]
313 fn test_filter_is_null_macro() {
314 let f = filter!(deleted_at is null);
315 match f {
316 Filter::IsNull(field) => {
317 assert_eq!(field.as_ref(), "deleted_at");
318 }
319 _ => panic!("Expected IsNull filter"),
320 }
321 }
322
323 #[test]
324 fn test_filter_is_not_null_macro() {
325 let f = filter!(verified_at is not null);
326 match f {
327 Filter::IsNotNull(field) => {
328 assert_eq!(field.as_ref(), "verified_at");
329 }
330 _ => panic!("Expected IsNotNull filter"),
331 }
332 }
333
334 #[test]
335 fn test_filter_contains_macro() {
336 let f = filter!(email contains "@example.com");
337 assert!(matches!(f, Filter::Contains(_, _)));
338 }
339
340 #[test]
341 fn test_filter_starts_with_macro() {
342 let f = filter!(name starts_with "John");
343 assert!(matches!(f, Filter::StartsWith(_, _)));
344 }
345
346 #[test]
347 fn test_filter_ends_with_macro() {
348 let f = filter!(email ends_with ".com");
349 assert!(matches!(f, Filter::EndsWith(_, _)));
350 }
351
352 #[test]
353 fn test_filter_in_macro() {
354 let f = filter!(status in ["active", "pending", "processing"]);
355 match f {
356 Filter::In(field, values) => {
357 assert_eq!(field.as_ref(), "status");
358 assert_eq!(values.len(), 3);
359 }
360 _ => panic!("Expected In filter"),
361 }
362 }
363
364 #[test]
365 fn test_filter_not_in_macro() {
366 let f = filter!(role not in ["admin", "superuser"]);
367 match f {
368 Filter::NotIn(field, values) => {
369 assert_eq!(field.as_ref(), "role");
370 assert_eq!(values.len(), 2);
371 }
372 _ => panic!("Expected NotIn filter"),
373 }
374 }
375
376 #[test]
377 fn test_and_filter_macro() {
378 let f = and_filter!(
379 filter!(active == true),
380 filter!(score > 100)
381 );
382 match f {
383 Filter::And(filters) => {
384 assert_eq!(filters.len(), 2);
385 }
386 _ => panic!("Expected And filter"),
387 }
388 }
389
390 #[test]
391 fn test_or_filter_macro() {
392 let f = or_filter!(
393 filter!(status == "pending"),
394 filter!(status == "processing")
395 );
396 match f {
397 Filter::Or(filters) => {
398 assert_eq!(filters.len(), 2);
399 }
400 _ => panic!("Expected Or filter"),
401 }
402 }
403
404 #[test]
405 fn test_not_filter_macro() {
406 let f = not_filter!(filter!(deleted == true));
407 assert!(matches!(f, Filter::Not(_)));
408 }
409
410 #[test]
411 fn test_complex_filter_macro() {
412 let f = and_filter!(
414 filter!(active == true),
415 or_filter!(
416 filter!(role == "admin"),
417 filter!(role == "moderator")
418 ),
419 filter!(age >= 18)
420 );
421 assert!(matches!(f, Filter::And(_)));
422 }
423}
424