entity_async_graphql/filter/
primitive.rs

1use crate::GqlValue;
2use async_graphql::InputObject;
3use entity::{Id, Predicate};
4use paste::paste;
5use std::collections::HashSet;
6
7macro_rules! impl_pred {
8    ($name:ident; $type:ty; $($attrs:tt)*) => {
9        paste! {
10            #[derive(Clone, InputObject)]
11            #[graphql(rename_fields = "snake_case")]
12            #[allow(non_camel_case_types)]
13            pub struct [<GqlPredicate_ $name _RangeArgs>] {
14                start: $type,
15                end: $type,
16            }
17
18            #[derive(Clone, InputObject)]
19            #[graphql(rename_fields = "snake_case")]
20            #[allow(non_camel_case_types)]
21            pub struct [<GqlPredicate_ $name _HasKeyWhereValueArgs>] {
22                key: String,
23                predicate: Box<[<GqlPredicate_ $name>]>,
24            }
25
26            /// Represents a wrapper around an ent query [`TypedPredicate`] that
27            /// exposes a GraphQL API.
28            #[derive(Clone, Default, InputObject)]
29            #[graphql(rename_fields = "snake_case")]
30            #[allow(non_camel_case_types)]
31            pub struct [<GqlPredicate_ $name>] {
32                #[doc = "Checks if multiple predicates pass"] and: Option<Vec<Self>>,
33                #[doc = "Checks if any predicate passes"] or: Option<Vec<Self>>,
34                #[doc = "Checks if exactly one predicate passes"] xor: Option<Vec<Self>>,
35                #[doc = "Checks if any value in collection passes predicate"] any: Option<Box<Self>>,
36                #[doc = "Checks if collection contains value"] contains: Option<$type>,
37                #[doc = "Checks if collection contains all values"] contains_all: Option<Vec<$type>>,
38                #[doc = "Checks if collection contains any of the values"] contains_any: Option<Vec<$type>>,
39                #[doc = "Checks if equals value"] equals: Option<$type>,
40                #[doc = "Checks if greater than value"] greater_than: Option<$type>,
41                #[doc = "Checks if greater than or equals value"] greater_than_or_equals: Option<$type>,
42                #[doc = "Checks if collection contains key"] has_key: Option<String>,
43                #[doc = "Checks if collection has key where associated value passes predicate"] has_key_where_value: Option<[<GqlPredicate_ $name _HasKeyWhereValueArgs>]>,
44                #[doc = "Checks if value in range"] in_range: Option<[<GqlPredicate_ $name _RangeArgs>]>,
45                #[doc = "Checks if value in set"] in_set: Option<HashSet<$type>>,
46                #[doc = "Checks if value is null"] is_none: Option<bool>,
47                #[doc = "Checks if less than value"] less_than: Option<$type>,
48                #[doc = "Checks if less than or equals value"] less_than_or_equals: Option<$type>,
49                #[doc = "Checks if does not pass predicate"] not: Option<Box<Self>>,
50                #[doc = "Checks if does not equal value"] not_equals: Option<$type>,
51                #[doc = "Checks if value not in range"] not_in_range: Option<[<GqlPredicate_ $name _RangeArgs>]>,
52                #[doc = "Checks if value not in set"] not_in_set: Option<HashSet<$type>>,
53                #[doc = "Checks if ends with specified text"] text_ends_with: Option<String>,
54                #[doc = "Checks if ends with specified text (case insensitive)"] text_ends_with_case_insensitive: Option<String>,
55                #[doc = "Checks if equals specified text (case insensitive)"] text_equals_case_insensitive: Option<String>,
56                #[doc = "Checks if text is in set (case insensitive)"] text_in_set_case_insensitive: Option<HashSet<String>>,
57                #[doc = "Checks if not equals specified text (case insensitive)"] text_not_equals_case_insensitive: Option<String>,
58                #[doc = "Checks if starts with specified text"] text_starts_with: Option<String>,
59                #[doc = "Checks if starts with specified text (case insensitive)"] text_starts_with_case_insensitive: Option<String>,
60                #[doc = "Checks if text is contained within specified text"] text_contained_in: Option<String>,
61                #[doc = "Checks if text is contained within specified text (case insensitive)"] text_contained_in_case_insensitive: Option<String>,
62                #[doc = "Checks if text contains all of the specified text within it"] text_contains_all: Option<Vec<String>>,
63                #[doc = "Checks if text contains all of the specified text within it (case insensitive)"] text_contains_all_case_insensitive: Option<Vec<String>>,
64                #[doc = "Checks if text contains any of the specified text within it"] text_contains_any: Option<Vec<String>>,
65                #[doc = "Checks if text contains any of the specified text within it (case insensitive)"] text_contains_any_case_insensitive: Option<Vec<String>>,
66                #[doc = "Checks if text ends with any of the specified text"] text_ends_with_any: Option<Vec<String>>,
67                #[doc = "Checks if text ends with any of the specified text (case insensitive)"] text_ends_with_any_case_insensitive: Option<Vec<String>>,
68                #[doc = "Checks if text starts with any of the specified text"] text_starts_with_any: Option<Vec<String>>,
69                #[doc = "Checks if text starts with any of the specified text (case insensitive)"] text_starts_with_any_case_insensitive: Option<Vec<String>>,
70            }
71
72            impl From<Box<[<GqlPredicate_ $name>]>> for Predicate {
73                fn from(x: Box<[<GqlPredicate_ $name>]>) -> Self {
74                    Self::from(x.as_ref().clone())
75                }
76            }
77
78            impl From<[<GqlPredicate_ $name>]> for Predicate {
79                /// Converts into a predicate based on criteria in GraphQL
80                /// predicate
81                fn from(x: [<GqlPredicate_ $name>]) -> Self {
82                    let mut criteria = Vec::new();
83
84                    impl_pred!(@criteria x; criteria; $name; $type; $($attrs)*);
85
86                    Self::and(criteria)
87                }
88            }
89        }
90    };
91    (@criteria $self:ident; $vec:ident; $name:ident; $type:ty; @core $($tail:tt)*) => {
92        paste! {
93            impl_pred!(@criteria_push $self; $vec; and; |v| Self::and(v));
94            impl_pred!(@criteria_push $self; $vec; or; |v| Self::or(v));
95            impl_pred!(@criteria_push $self; $vec; xor; |v| Self::xor(v));
96            impl_pred!(
97                @criteria_push $self; $vec; any;
98                |v: Box<[<GqlPredicate_ $name>]>| Self::any(v.as_ref().clone())
99            );
100            impl_pred!(@criteria_push $self; $vec; contains; |v| Self::contains(v));
101            impl_pred!(@criteria_push $self; $vec; contains_all; |v| Self::contains_all(v));
102            impl_pred!(@criteria_push $self; $vec; contains_any; |v| Self::contains_any(v));
103            impl_pred!(@criteria_push $self; $vec; equals; |v| Self::equals(v));
104            impl_pred!(@criteria_push $self; $vec; greater_than; |v| Self::greater_than(v));
105            impl_pred!(@criteria_push $self; $vec; greater_than_or_equals; |v| Self::greater_than_or_equals(v));
106            impl_pred!(@criteria_push $self; $vec; has_key; |v| Self::has_key(v));
107            impl_pred!(
108                @criteria_push $self; $vec; has_key_where_value;
109                |v: [<GqlPredicate_ $name _HasKeyWhereValueArgs>]|
110                Self::has_key_where_value(v.key, v.predicate.as_ref().clone())
111            );
112            impl_pred!(
113                @criteria_push $self; $vec; in_range;
114                |v: [<GqlPredicate_ $name _RangeArgs>]| Self::in_range(v.start..=v.end)
115            );
116            impl_pred!(@criteria_push $self; $vec; in_set; |v| Self::in_set(v));
117            impl_pred!(@criteria_push $self; $vec; is_none; |v| if v { Self::IsNone } else { Self::not(Self::IsNone) });
118            impl_pred!(@criteria_push $self; $vec; less_than; |v| Self::less_than(v));
119            impl_pred!(@criteria_push $self; $vec; less_than_or_equals; |v| Self::less_than_or_equals(v));
120            impl_pred!(
121                @criteria_push $self; $vec; not;
122                |v: Box<[<GqlPredicate_ $name>]>| Self::not(v.as_ref().clone())
123            );
124            impl_pred!(@criteria_push $self; $vec; not_equals; |v| Self::not_equals(v));
125            impl_pred!(
126                @criteria_push $self; $vec; not_in_range;
127                |v: [<GqlPredicate_ $name _RangeArgs>]| Self::not_in_range(v.start..=v.end)
128            );
129            impl_pred!(@criteria_push $self; $vec; not_in_set; |v| Self::not_in_set(v));
130            impl_pred!(@criteria $self; $vec; $name; $type; $($tail)*);
131        }
132    };
133    (@criteria $self:ident; $vec:ident; $name:ident; $type:ty; @text $($tail:tt)*) => {
134        impl_pred!(@criteria_push $self; $vec; text_ends_with; |v| Self::TextEndsWith(v));
135        impl_pred!(@criteria_push $self; $vec; text_ends_with_case_insensitive; |v| Self::TextEndsWithCaseInsensitive(v));
136        impl_pred!(@criteria_push $self; $vec; text_equals_case_insensitive; |v| Self::TextEqualsCaseInsensitive(v));
137        impl_pred!(@criteria_push $self; $vec; text_in_set_case_insensitive; |v| Self::TextInSetCaseInsensitive(v));
138        impl_pred!(@criteria_push $self; $vec; text_not_equals_case_insensitive; |v| Self::TextNotEqualsCaseInsensitive(v));
139        impl_pred!(@criteria_push $self; $vec; text_starts_with; |v| Self::TextStartsWith(v));
140        impl_pred!(@criteria_push $self; $vec; text_starts_with_case_insensitive; |v| Self::TextStartsWithCaseInsensitive(v));
141        impl_pred!(@criteria_push $self; $vec; text_contained_in; |v| Self::TextContainedIn(v));
142        impl_pred!(@criteria_push $self; $vec; text_contained_in_case_insensitive; |v| Self::TextContainedInCaseInsensitive(v));
143        impl_pred!(@criteria_push $self; $vec; text_contains_all; |v| Self::TextContainsAll(v));
144        impl_pred!(@criteria_push $self; $vec; text_contains_all_case_insensitive; |v| Self::TextContainsAllCaseInsensitive(v));
145        impl_pred!(@criteria_push $self; $vec; text_contains_any; |v| Self::TextContainsAny(v));
146        impl_pred!(@criteria_push $self; $vec; text_contains_any_case_insensitive; |v| Self::TextContainsAnyCaseInsensitive(v));
147        impl_pred!(@criteria_push $self; $vec; text_ends_with_any; |v| Self::TextEndsWithAny(v));
148        impl_pred!(@criteria_push $self; $vec; text_ends_with_any_case_insensitive; |v| Self::TextEndsWithAnyCaseInsensitive(v));
149        impl_pred!(@criteria_push $self; $vec; text_starts_with_any; |v| Self::TextStartsWithAny(v));
150        impl_pred!(@criteria_push $self; $vec; text_starts_with_any_case_insensitive; |v| Self::TextStartsWithAnyCaseInsensitive(v));
151        impl_pred!(@criteria $self; $vec; $name; $type; $($tail)*);
152    };
153    (@criteria $self:ident; $vec:ident; $name:ident; $type:ty;) => {};
154    (@criteria_push $self:ident; $vec:ident; $name:ident; $make_pred:expr) => {
155        if let Some(v) = $self.$name {
156            let f = $make_pred;
157            let p = f(v);
158            $vec.push(p);
159        }
160    };
161}
162
163impl_pred!(Value; GqlValue; @core @text);
164impl_pred!(String; String; @core @text);
165
166impl_pred!(Id; Id; @core);
167impl_pred!(bool; bool; @core);
168impl_pred!(char; char; @core);
169
170// NOTE: async-graphql does not support i128
171impl_pred!(isize; isize; @core);
172impl_pred!(i64; i64; @core);
173impl_pred!(i32; i32; @core);
174impl_pred!(i16; i16; @core);
175impl_pred!(i8; i8; @core);
176
177// NOTE: async-graphql does not support u128
178impl_pred!(usize; usize; @core);
179impl_pred!(u64; u64; @core);
180impl_pred!(u32; u32; @core);
181impl_pred!(u16; u16; @core);
182impl_pred!(u8; u8; @core);