1mod bnf_approach;
2mod regex_approach;
3
4use crate::regex_approach::layered_query::LayeredQueries;
5use crate::regex_approach::query::Query;
6use eyre::Result;
7use serde::Serialize;
8
9pub fn parse_query_to_condition(query: &str) -> Result<Condition> {
10 LayeredQueries::parse(Query::new(query.into()))?.to_condition()
11}
12
13#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
14pub enum Condition {
15 None,
16 Keyword(String),
17 PhraseKeyword(String),
18 Not(Box<Condition>),
19 Operator(Operator, Vec<Condition>),
20}
21
22#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
23pub enum Operator {
24 And,
25 Or,
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31 use crate::{Condition, Operator};
32
33 mod normal_query {
34 use super::*;
35
36 #[test]
37 fn test_keywords_concat_with_spaces() {
38 let actual = parse_query_to_condition("word1 word2").unwrap();
39 assert_eq!(
40 actual,
41 Condition::Operator(
42 Operator::And,
43 vec![
44 Condition::Keyword("word1".into()),
45 Condition::Keyword("word2".into())
46 ]
47 )
48 )
49 }
50
51 #[test]
52 fn test_keywords_concat_with_and_or() {
53 let actual = parse_query_to_condition("word1 OR word2 AND word3").unwrap();
54 assert_eq!(
55 actual,
56 Condition::Operator(
57 Operator::Or,
58 vec![
59 Condition::Keyword("word1".into()),
60 Condition::Operator(
61 Operator::And,
62 vec![
63 Condition::Keyword("word2".into()),
64 Condition::Keyword("word3".into()),
65 ]
66 )
67 ]
68 )
69 )
70 }
71
72 #[test]
73 fn test_brackets() {
74 let actual = parse_query_to_condition("word1 AND (word2 OR word3)").unwrap();
75 assert_eq!(
76 actual,
77 Condition::Operator(
78 Operator::And,
79 vec![
80 Condition::Keyword("word1".into()),
81 Condition::Operator(
82 Operator::Or,
83 vec![
84 Condition::Keyword("word2".into()),
85 Condition::Keyword("word3".into()),
86 ]
87 )
88 ]
89 )
90 )
91 }
92
93 #[test]
94 fn test_double_quote() {
95 let actual = parse_query_to_condition("\"word1 AND (word2 OR word3)\" word4").unwrap();
96 assert_eq!(
97 actual,
98 Condition::Operator(
99 Operator::And,
100 vec![
101 Condition::PhraseKeyword("word1 AND (word2 OR word3)".into()),
102 Condition::Keyword("word4".into()),
103 ]
104 )
105 )
106 }
107
108 #[test]
109 fn test_minus() {
110 let actual = parse_query_to_condition("-word1 -\"word2\" -(word3 OR word4)").unwrap();
111 assert_eq!(
112 actual,
113 Condition::Operator(
114 Operator::And,
115 vec![
116 Condition::Not(Box::new(Condition::Keyword("word1".into()))),
117 Condition::Not(Box::new(Condition::PhraseKeyword("word2".into()))),
118 Condition::Not(Box::new(Condition::Operator(
119 Operator::Or,
120 vec![
121 Condition::Keyword("word3".into()),
122 Condition::Keyword("word4".into())
123 ]
124 ))),
125 ]
126 )
127 )
128 }
129
130 #[test]
131 fn test_full_pattern() {
132 let actual = parse_query_to_condition(
133 "(word1 and -word2) or ((\"phrase word 1\" or -\"phrase word 2\") and -(\" a long phrase word \" or word3))",
134 )
135 .unwrap();
136 assert_eq!(
137 actual,
138 Condition::Operator(
139 Operator::Or,
140 vec![
141 Condition::Operator(
142 Operator::And,
143 vec![
144 Condition::Keyword("word1".into()),
145 Condition::Not(Box::new(Condition::Keyword("word2".into()))),
146 ]
147 ),
148 Condition::Operator(
149 Operator::And,
150 vec![
151 Condition::Operator(
152 Operator::Or,
153 vec![
154 Condition::PhraseKeyword("phrase word 1".into()),
155 Condition::Not(Box::new(Condition::PhraseKeyword(
156 "phrase word 2".into()
157 )))
158 ]
159 ),
160 Condition::Not(Box::new(Condition::Operator(
161 Operator::Or,
162 vec![
163 Condition::PhraseKeyword(" a long phrase word ".into()),
164 Condition::Keyword("word3".into())
165 ]
166 )))
167 ]
168 ),
169 ]
170 )
171 )
172 }
173 }
174
175 mod invalid_query {
176 use super::*;
177
178 #[test]
179 fn test_empty_brackets() {
180 let actual = parse_query_to_condition("A AND () AND B").unwrap();
181 assert_eq!(
182 actual,
183 Condition::Operator(
184 Operator::And,
185 vec![
186 Condition::Keyword("A".into()),
187 Condition::Keyword("B".into()),
188 ]
189 )
190 )
191 }
192
193 #[test]
194 fn test_reverse_brackets() {
195 let actual = parse_query_to_condition("A OR B) AND (C OR D").unwrap();
196 assert_eq!(
197 actual,
198 Condition::Operator(
199 Operator::Or,
200 vec![
201 Condition::Keyword("A".into()),
202 Condition::Operator(
203 Operator::And,
204 vec![
205 Condition::Keyword("B".into()),
206 Condition::Keyword("C".into()),
207 ]
208 ),
209 Condition::Keyword("D".into()),
210 ]
211 )
212 )
213 }
214
215 #[test]
216 fn test_missing_brackets() {
217 let actual = parse_query_to_condition("(A OR B) AND (C").unwrap();
218 assert_eq!(
219 actual,
220 Condition::Operator(
221 Operator::And,
222 vec![
223 Condition::Operator(
224 Operator::Or,
225 vec![
226 Condition::Keyword("A".into()),
227 Condition::Keyword("B".into()),
228 ]
229 ),
230 Condition::Keyword("C".into()),
231 ]
232 )
233 )
234 }
235
236 #[test]
237 fn test_invalid_nest_brackets() {
238 let actual = parse_query_to_condition("(((A OR B)) AND C").unwrap();
239 assert_eq!(
240 actual,
241 Condition::Operator(
242 Operator::And,
243 vec![
244 Condition::Operator(
245 Operator::Or,
246 vec![
247 Condition::Keyword("A".into()),
248 Condition::Keyword("B".into()),
249 ]
250 ),
251 Condition::Keyword("C".into()),
252 ]
253 )
254 )
255 }
256
257 #[test]
258 fn test_no_keyword_in_brackets() {
259 let actual = parse_query_to_condition("A AND (\"\" OR \"\") AND B").unwrap();
260 assert_eq!(
261 actual,
262 Condition::Operator(
263 Operator::And,
264 vec![
265 Condition::Keyword("A".into()),
266 Condition::Keyword("B".into()),
267 ]
268 )
269 )
270 }
271
272 #[test]
273 fn test_empty_phrase_keywords() {
274 let actual = parse_query_to_condition("A AND \"\" AND B").unwrap();
275 assert_eq!(
276 actual,
277 Condition::Operator(
278 Operator::And,
279 vec![
280 Condition::Keyword("A".into()),
281 Condition::Keyword("B".into()),
282 ]
283 )
284 )
285 }
286
287 #[test]
288 fn test_invalid_double_quote() {
289 let actual = parse_query_to_condition("\"A\" OR \"B OR C").unwrap();
290 assert_eq!(
291 actual,
292 Condition::Operator(
293 Operator::Or,
294 vec![
295 Condition::PhraseKeyword("A".into()),
296 Condition::Keyword("B".into()),
297 Condition::Keyword("C".into()),
298 ]
299 )
300 )
301 }
302
303 #[test]
304 fn test_invalid_and_or() {
305 let actual = parse_query_to_condition("A AND OR B").unwrap();
306 assert_eq!(
307 actual,
308 Condition::Operator(
309 Operator::Or,
310 vec![
311 Condition::Keyword("A".into()),
312 Condition::Keyword("B".into()),
313 ]
314 )
315 )
316 }
317 }
318
319 mod effective_query {
320 use super::*;
321
322 #[test]
323 fn test_unnecessary_nest_brackets() {
324 let actual = parse_query_to_condition("(A OR (B OR C)) AND D").unwrap();
325 assert_eq!(
326 actual,
327 Condition::Operator(
328 Operator::And,
329 vec![
330 Condition::Operator(
331 Operator::Or,
332 vec![
333 Condition::Keyword("A".into()),
334 Condition::Keyword("B".into()),
335 Condition::Keyword("C".into()),
336 ]
337 ),
338 Condition::Keyword("D".into()),
339 ]
340 )
341 )
342 }
343
344 #[test]
345 fn test_concat_brackets_without_space() {
346 let actual = parse_query_to_condition("A(B OR C)D").unwrap();
347 assert_eq!(
348 actual,
349 Condition::Operator(
350 Operator::And,
351 vec![
352 Condition::Keyword("A".into()),
353 Condition::Operator(
354 Operator::Or,
355 vec![
356 Condition::Keyword("B".into()),
357 Condition::Keyword("C".into()),
358 ]
359 ),
360 Condition::Keyword("D".into()),
361 ]
362 )
363 )
364 }
365
366 #[test]
367 fn test_concat_phrase_keywords_without_space() {
368 let actual = parse_query_to_condition("A\"B\"C").unwrap();
369 assert_eq!(
370 actual,
371 Condition::Operator(
372 Operator::And,
373 vec![
374 Condition::Keyword("A".into()),
375 Condition::PhraseKeyword("B".into()),
376 Condition::Keyword("C".into()),
377 ]
378 )
379 )
380 }
381 }
382}