@@ -23,12 +23,14 @@ use std::sync::atomic::{AtomicU32, Ordering};
23
23
#[ serde( untagged) ]
24
24
pub enum Rule {
25
25
Numeric ( NumericRule ) ,
26
+ String ( StringRule ) ,
26
27
}
27
28
28
29
impl Rule {
29
30
pub ( super ) fn resolves ( & self , event : & serde_json:: Value ) -> bool {
30
31
match self {
31
32
Rule :: Numeric ( rule) => rule. resolves ( event) ,
33
+ Rule :: String ( rule) => rule. resolves ( event) ,
32
34
}
33
35
}
34
36
@@ -51,6 +53,10 @@ impl Rule {
51
53
) ,
52
54
None => false ,
53
55
} ,
56
+ Rule :: String ( StringRule { column, .. } ) => match schema. column_with_name ( column) {
57
+ Some ( ( _, column) ) => matches ! ( column. data_type( ) , arrow_schema:: DataType :: Utf8 ) ,
58
+ None => false ,
59
+ } ,
54
60
}
55
61
}
56
62
@@ -88,6 +94,19 @@ impl Rule {
88
94
column, value, repeats
89
95
) ,
90
96
} ,
97
+ Rule :: String ( StringRule {
98
+ column,
99
+ operator,
100
+ value,
101
+ ..
102
+ } ) => match operator {
103
+ StringOperator :: Exact => format ! ( "{} column value is {}" , column, value) ,
104
+ StringOperator :: NotExact => format ! ( "{} column value is not {}" , column, value) ,
105
+ StringOperator :: Contains => format ! ( "{} column contains {}" , column, value) ,
106
+ StringOperator :: NotContains => {
107
+ format ! ( "{} column does not contains {}" , column, value)
108
+ }
109
+ } ,
91
110
}
92
111
}
93
112
}
@@ -149,6 +168,44 @@ impl NumericRule {
149
168
}
150
169
}
151
170
171
+ #[ derive( Debug , Serialize , Deserialize ) ]
172
+ #[ serde( rename_all = "camelCase" ) ]
173
+ pub struct StringRule {
174
+ pub column : String ,
175
+ #[ serde( default ) ]
176
+ pub operator : StringOperator ,
177
+ pub ignore_case : Option < bool > ,
178
+ pub value : String ,
179
+ }
180
+
181
+ impl StringRule {
182
+ pub fn resolves ( & self , event : & serde_json:: Value ) -> bool {
183
+ let string = match event. get ( & self . column ) . expect ( "column exists" ) {
184
+ serde_json:: Value :: String ( s) => s,
185
+ _ => unreachable ! ( "right rule is set for right column type" ) ,
186
+ } ;
187
+
188
+ if self . ignore_case . unwrap_or_default ( ) {
189
+ match self . operator {
190
+ StringOperator :: Exact => string. eq_ignore_ascii_case ( & self . value ) ,
191
+ StringOperator :: NotExact => !string. eq_ignore_ascii_case ( & self . value ) ,
192
+ StringOperator :: Contains => string
193
+ . to_ascii_lowercase ( )
194
+ . contains ( & self . value . to_ascii_lowercase ( ) ) ,
195
+ StringOperator :: NotContains => !string
196
+ . to_ascii_lowercase ( )
197
+ . contains ( & self . value . to_ascii_lowercase ( ) ) ,
198
+ }
199
+ } else {
200
+ match self . operator {
201
+ StringOperator :: Exact => string. eq ( & self . value ) ,
202
+ StringOperator :: NotExact => !string. eq ( & self . value ) ,
203
+ StringOperator :: Contains => string. contains ( & self . value ) ,
204
+ StringOperator :: NotContains => !string. contains ( & self . value ) ,
205
+ }
206
+ }
207
+ }
208
+ }
152
209
// Operator for comparing values
153
210
154
211
#[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
@@ -173,3 +230,20 @@ impl Default for NumericOperator {
173
230
Self :: EqualTo
174
231
}
175
232
}
233
+
234
+ #[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
235
+ #[ serde( rename_all = "camelCase" ) ]
236
+ pub enum StringOperator {
237
+ #[ serde( alias = "=" ) ]
238
+ Exact ,
239
+ #[ serde( alias = "!=" ) ]
240
+ NotExact ,
241
+ Contains ,
242
+ NotContains ,
243
+ }
244
+
245
+ impl Default for StringOperator {
246
+ fn default ( ) -> Self {
247
+ Self :: Contains
248
+ }
249
+ }
0 commit comments