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) => {{ $crate::filter::Filter::Not(Box::new($filter)) }};
263}
264
265#[cfg(test)]
266mod tests {
267 use crate::filter::{Filter, FilterValue};
268
269 #[test]
270 fn test_filter_eq_macro() {
271 let f = filter!(id == 42);
272 match f {
273 Filter::Equals(field, FilterValue::Int(42)) => {
274 assert_eq!(field.as_ref(), "id");
275 }
276 _ => panic!("Expected Equals filter"),
277 }
278 }
279
280 #[test]
281 fn test_filter_ne_macro() {
282 let f = filter!(status != "deleted");
283 assert!(matches!(f, Filter::NotEquals(_, _)));
284 }
285
286 #[test]
287 fn test_filter_gt_macro() {
288 let f = filter!(age > 18);
289 assert!(matches!(f, Filter::Gt(_, FilterValue::Int(18))));
290 }
291
292 #[test]
293 fn test_filter_gte_macro() {
294 let f = filter!(score >= 100);
295 assert!(matches!(f, Filter::Gte(_, FilterValue::Int(100))));
296 }
297
298 #[test]
299 fn test_filter_lt_macro() {
300 let f = filter!(price < 50);
301 assert!(matches!(f, Filter::Lt(_, FilterValue::Int(50))));
302 }
303
304 #[test]
305 fn test_filter_lte_macro() {
306 let f = filter!(quantity <= 10);
307 assert!(matches!(f, Filter::Lte(_, FilterValue::Int(10))));
308 }
309
310 #[test]
311 fn test_filter_is_null_macro() {
312 let f = filter!(deleted_at is null);
313 match f {
314 Filter::IsNull(field) => {
315 assert_eq!(field.as_ref(), "deleted_at");
316 }
317 _ => panic!("Expected IsNull filter"),
318 }
319 }
320
321 #[test]
322 fn test_filter_is_not_null_macro() {
323 let f = filter!(verified_at is not null);
324 match f {
325 Filter::IsNotNull(field) => {
326 assert_eq!(field.as_ref(), "verified_at");
327 }
328 _ => panic!("Expected IsNotNull filter"),
329 }
330 }
331
332 #[test]
333 fn test_filter_contains_macro() {
334 let f = filter!(email contains "@example.com");
335 assert!(matches!(f, Filter::Contains(_, _)));
336 }
337
338 #[test]
339 fn test_filter_starts_with_macro() {
340 let f = filter!(name starts_with "John");
341 assert!(matches!(f, Filter::StartsWith(_, _)));
342 }
343
344 #[test]
345 fn test_filter_ends_with_macro() {
346 let f = filter!(email ends_with ".com");
347 assert!(matches!(f, Filter::EndsWith(_, _)));
348 }
349
350 #[test]
351 fn test_filter_in_macro() {
352 let f = filter!(status in ["active", "pending", "processing"]);
353 match f {
354 Filter::In(field, values) => {
355 assert_eq!(field.as_ref(), "status");
356 assert_eq!(values.len(), 3);
357 }
358 _ => panic!("Expected In filter"),
359 }
360 }
361
362 #[test]
363 fn test_filter_not_in_macro() {
364 let f = filter!(role not in ["admin", "superuser"]);
365 match f {
366 Filter::NotIn(field, values) => {
367 assert_eq!(field.as_ref(), "role");
368 assert_eq!(values.len(), 2);
369 }
370 _ => panic!("Expected NotIn filter"),
371 }
372 }
373
374 #[test]
375 fn test_and_filter_macro() {
376 let f = and_filter!(filter!(active == true), filter!(score > 100));
377 match f {
378 Filter::And(filters) => {
379 assert_eq!(filters.len(), 2);
380 }
381 _ => panic!("Expected And filter"),
382 }
383 }
384
385 #[test]
386 fn test_or_filter_macro() {
387 let f = or_filter!(
388 filter!(status == "pending"),
389 filter!(status == "processing")
390 );
391 match f {
392 Filter::Or(filters) => {
393 assert_eq!(filters.len(), 2);
394 }
395 _ => panic!("Expected Or filter"),
396 }
397 }
398
399 #[test]
400 fn test_not_filter_macro() {
401 let f = not_filter!(filter!(deleted == true));
402 assert!(matches!(f, Filter::Not(_)));
403 }
404
405 #[test]
406 fn test_complex_filter_macro() {
407 let f = and_filter!(
409 filter!(active == true),
410 or_filter!(filter!(role == "admin"), filter!(role == "moderator")),
411 filter!(age >= 18)
412 );
413 assert!(matches!(f, Filter::And(_)));
414 }
415}