diff options
Diffstat (limited to 'lib/filter.cpp')
-rw-r--r-- | lib/filter.cpp | 1365 |
1 files changed, 1365 insertions, 0 deletions
diff --git a/lib/filter.cpp b/lib/filter.cpp new file mode 100644 index 0000000..959fa05 --- /dev/null +++ b/lib/filter.cpp | |||
@@ -0,0 +1,1365 @@ | |||
1 | #include "filter.h" | ||
2 | #include <stdexcept> | ||
3 | #include <map> | ||
4 | #include "notion.h" | ||
5 | #include "word.h" | ||
6 | #include "group.h" | ||
7 | #include "frame.h" | ||
8 | #include "lemma.h" | ||
9 | #include "form.h" | ||
10 | #include "pronunciation.h" | ||
11 | |||
12 | namespace verbly { | ||
13 | |||
14 | filter::filter(const filter& other) | ||
15 | { | ||
16 | type_ = other.type_; | ||
17 | |||
18 | switch (type_) | ||
19 | { | ||
20 | case type::empty: | ||
21 | { | ||
22 | break; | ||
23 | } | ||
24 | |||
25 | case type::singleton: | ||
26 | { | ||
27 | new(&singleton_.filterField) field(other.singleton_.filterField); | ||
28 | singleton_.filterType = other.singleton_.filterType; | ||
29 | |||
30 | switch (singleton_.filterType) | ||
31 | { | ||
32 | case comparison::int_equals: | ||
33 | case comparison::int_does_not_equal: | ||
34 | case comparison::int_is_at_least: | ||
35 | case comparison::int_is_greater_than: | ||
36 | case comparison::int_is_at_most: | ||
37 | case comparison::int_is_less_than: | ||
38 | { | ||
39 | singleton_.intValue = other.singleton_.intValue; | ||
40 | |||
41 | break; | ||
42 | } | ||
43 | |||
44 | case comparison::boolean_equals: | ||
45 | { | ||
46 | singleton_.boolValue = other.singleton_.boolValue; | ||
47 | |||
48 | break; | ||
49 | } | ||
50 | |||
51 | case comparison::string_equals: | ||
52 | case comparison::string_does_not_equal: | ||
53 | case comparison::string_is_like: | ||
54 | case comparison::string_is_not_like: | ||
55 | { | ||
56 | new(&singleton_.stringValue) std::string(other.singleton_.stringValue); | ||
57 | |||
58 | break; | ||
59 | } | ||
60 | |||
61 | case comparison::is_null: | ||
62 | case comparison::is_not_null: | ||
63 | { | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | case comparison::matches: | ||
68 | case comparison::does_not_match: | ||
69 | case comparison::hierarchally_matches: | ||
70 | case comparison::does_not_hierarchally_match: | ||
71 | { | ||
72 | new(&singleton_.join) std::unique_ptr<filter>(new filter(*other.singleton_.join)); | ||
73 | |||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | break; | ||
79 | } | ||
80 | |||
81 | case type::group: | ||
82 | { | ||
83 | new(&group_.children) std::list<filter>(other.group_.children); | ||
84 | group_.orlogic = other.group_.orlogic; | ||
85 | |||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | filter::filter(filter&& other) : filter() | ||
92 | { | ||
93 | swap(*this, other); | ||
94 | } | ||
95 | |||
96 | filter& filter::operator=(filter other) | ||
97 | { | ||
98 | swap(*this, other); | ||
99 | |||
100 | return *this; | ||
101 | } | ||
102 | |||
103 | void swap(filter& first, filter& second) | ||
104 | { | ||
105 | using type = filter::type; | ||
106 | using comparison = filter::comparison; | ||
107 | |||
108 | type tempType = first.type_; | ||
109 | field tempField; | ||
110 | comparison tempComparison; | ||
111 | std::unique_ptr<filter> tempJoin; | ||
112 | std::string tempStringValue; | ||
113 | int tempIntValue; | ||
114 | bool tempBoolValue; | ||
115 | std::list<filter> tempChildren; | ||
116 | bool tempOrlogic; | ||
117 | |||
118 | switch (tempType) | ||
119 | { | ||
120 | case type::empty: | ||
121 | { | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | case type::singleton: | ||
126 | { | ||
127 | tempField = std::move(first.singleton_.filterField); | ||
128 | tempComparison = first.singleton_.filterType; | ||
129 | |||
130 | switch (tempComparison) | ||
131 | { | ||
132 | case comparison::int_equals: | ||
133 | case comparison::int_does_not_equal: | ||
134 | case comparison::int_is_at_least: | ||
135 | case comparison::int_is_greater_than: | ||
136 | case comparison::int_is_at_most: | ||
137 | case comparison::int_is_less_than: | ||
138 | { | ||
139 | tempIntValue = first.singleton_.intValue; | ||
140 | |||
141 | break; | ||
142 | } | ||
143 | |||
144 | case comparison::boolean_equals: | ||
145 | { | ||
146 | tempBoolValue = first.singleton_.boolValue; | ||
147 | |||
148 | break; | ||
149 | } | ||
150 | |||
151 | case comparison::string_equals: | ||
152 | case comparison::string_does_not_equal: | ||
153 | case comparison::string_is_like: | ||
154 | case comparison::string_is_not_like: | ||
155 | { | ||
156 | tempStringValue = std::move(first.singleton_.stringValue); | ||
157 | |||
158 | break; | ||
159 | } | ||
160 | |||
161 | case comparison::is_null: | ||
162 | case comparison::is_not_null: | ||
163 | { | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | case comparison::matches: | ||
168 | case comparison::does_not_match: | ||
169 | case comparison::hierarchally_matches: | ||
170 | case comparison::does_not_hierarchally_match: | ||
171 | { | ||
172 | tempJoin = std::move(first.singleton_.join); | ||
173 | |||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | break; | ||
179 | } | ||
180 | |||
181 | case type::group: | ||
182 | { | ||
183 | tempChildren = std::move(first.group_.children); | ||
184 | tempOrlogic = first.group_.orlogic; | ||
185 | |||
186 | break; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | first.~filter(); | ||
191 | |||
192 | first.type_ = second.type_; | ||
193 | |||
194 | switch (first.type_) | ||
195 | { | ||
196 | case type::empty: | ||
197 | { | ||
198 | break; | ||
199 | } | ||
200 | |||
201 | case type::singleton: | ||
202 | { | ||
203 | new(&first.singleton_.filterField) field(std::move(second.singleton_.filterField)); | ||
204 | first.singleton_.filterType = second.singleton_.filterType; | ||
205 | |||
206 | switch (first.singleton_.filterType) | ||
207 | { | ||
208 | case comparison::int_equals: | ||
209 | case comparison::int_does_not_equal: | ||
210 | case comparison::int_is_at_least: | ||
211 | case comparison::int_is_greater_than: | ||
212 | case comparison::int_is_at_most: | ||
213 | case comparison::int_is_less_than: | ||
214 | { | ||
215 | first.singleton_.intValue = second.singleton_.intValue; | ||
216 | |||
217 | break; | ||
218 | } | ||
219 | |||
220 | case comparison::boolean_equals: | ||
221 | { | ||
222 | first.singleton_.boolValue = second.singleton_.boolValue; | ||
223 | |||
224 | break; | ||
225 | } | ||
226 | |||
227 | case comparison::string_equals: | ||
228 | case comparison::string_does_not_equal: | ||
229 | case comparison::string_is_like: | ||
230 | case comparison::string_is_not_like: | ||
231 | { | ||
232 | new(&first.singleton_.stringValue) std::string(std::move(second.singleton_.stringValue)); | ||
233 | |||
234 | break; | ||
235 | } | ||
236 | |||
237 | case comparison::is_null: | ||
238 | case comparison::is_not_null: | ||
239 | { | ||
240 | break; | ||
241 | } | ||
242 | |||
243 | case comparison::matches: | ||
244 | case comparison::does_not_match: | ||
245 | case comparison::hierarchally_matches: | ||
246 | case comparison::does_not_hierarchally_match: | ||
247 | { | ||
248 | new(&first.singleton_.join) std::unique_ptr<filter>(std::move(second.singleton_.join)); | ||
249 | |||
250 | break; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | break; | ||
255 | } | ||
256 | |||
257 | case type::group: | ||
258 | { | ||
259 | new(&first.group_.children) std::list<filter>(std::move(second.group_.children)); | ||
260 | first.group_.orlogic = second.group_.orlogic; | ||
261 | |||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | second.~filter(); | ||
267 | |||
268 | second.type_ = tempType; | ||
269 | |||
270 | switch (second.type_) | ||
271 | { | ||
272 | case type::empty: | ||
273 | { | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | case type::singleton: | ||
278 | { | ||
279 | new(&second.singleton_.filterField) field(std::move(tempField)); | ||
280 | second.singleton_.filterType = tempComparison; | ||
281 | |||
282 | switch (second.singleton_.filterType) | ||
283 | { | ||
284 | case comparison::int_equals: | ||
285 | case comparison::int_does_not_equal: | ||
286 | case comparison::int_is_at_least: | ||
287 | case comparison::int_is_greater_than: | ||
288 | case comparison::int_is_at_most: | ||
289 | case comparison::int_is_less_than: | ||
290 | { | ||
291 | second.singleton_.intValue = tempIntValue; | ||
292 | |||
293 | break; | ||
294 | } | ||
295 | |||
296 | case comparison::boolean_equals: | ||
297 | { | ||
298 | second.singleton_.boolValue = tempBoolValue; | ||
299 | |||
300 | break; | ||
301 | } | ||
302 | |||
303 | case comparison::string_equals: | ||
304 | case comparison::string_does_not_equal: | ||
305 | case comparison::string_is_like: | ||
306 | case comparison::string_is_not_like: | ||
307 | { | ||
308 | new(&second.singleton_.stringValue) std::string(std::move(tempStringValue)); | ||
309 | |||
310 | break; | ||
311 | } | ||
312 | |||
313 | case comparison::is_null: | ||
314 | case comparison::is_not_null: | ||
315 | { | ||
316 | break; | ||
317 | } | ||
318 | |||
319 | case comparison::matches: | ||
320 | case comparison::does_not_match: | ||
321 | case comparison::hierarchally_matches: | ||
322 | case comparison::does_not_hierarchally_match: | ||
323 | { | ||
324 | new(&second.singleton_.join) std::unique_ptr<filter>(std::move(tempJoin)); | ||
325 | |||
326 | break; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | break; | ||
331 | } | ||
332 | |||
333 | case type::group: | ||
334 | { | ||
335 | new(&second.group_.children) std::list<filter>(std::move(tempChildren)); | ||
336 | second.group_.orlogic = tempOrlogic; | ||
337 | |||
338 | break; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | filter::~filter() | ||
344 | { | ||
345 | switch (type_) | ||
346 | { | ||
347 | case type::empty: | ||
348 | { | ||
349 | break; | ||
350 | } | ||
351 | |||
352 | case type::singleton: | ||
353 | { | ||
354 | singleton_.filterField.~field(); | ||
355 | |||
356 | switch (singleton_.filterType) | ||
357 | { | ||
358 | case comparison::int_equals: | ||
359 | case comparison::int_does_not_equal: | ||
360 | case comparison::int_is_at_least: | ||
361 | case comparison::int_is_greater_than: | ||
362 | case comparison::int_is_at_most: | ||
363 | case comparison::int_is_less_than: | ||
364 | case comparison::boolean_equals: | ||
365 | case comparison::is_null: | ||
366 | case comparison::is_not_null: | ||
367 | { | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | case comparison::string_equals: | ||
372 | case comparison::string_does_not_equal: | ||
373 | case comparison::string_is_like: | ||
374 | case comparison::string_is_not_like: | ||
375 | { | ||
376 | using string_type = std::string; | ||
377 | |||
378 | singleton_.stringValue.~string_type(); | ||
379 | |||
380 | break; | ||
381 | } | ||
382 | |||
383 | case comparison::matches: | ||
384 | case comparison::does_not_match: | ||
385 | case comparison::hierarchally_matches: | ||
386 | case comparison::does_not_hierarchally_match: | ||
387 | { | ||
388 | using ptr_type = std::unique_ptr<filter>; | ||
389 | |||
390 | singleton_.join.~ptr_type(); | ||
391 | |||
392 | break; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | break; | ||
397 | } | ||
398 | |||
399 | case type::group: | ||
400 | { | ||
401 | using list_type = std::list<filter>; | ||
402 | |||
403 | group_.children.~list_type(); | ||
404 | |||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | |||
410 | filter::filter() | ||
411 | { | ||
412 | } | ||
413 | |||
414 | filter::filter( | ||
415 | field filterField, | ||
416 | comparison filterType, | ||
417 | int filterValue) : | ||
418 | type_(type::singleton) | ||
419 | { | ||
420 | if (filterField.getType() == field::type::integer) | ||
421 | { | ||
422 | switch (filterType) | ||
423 | { | ||
424 | case comparison::int_equals: | ||
425 | case comparison::int_does_not_equal: | ||
426 | case comparison::int_is_at_least: | ||
427 | case comparison::int_is_greater_than: | ||
428 | case comparison::int_is_at_most: | ||
429 | case comparison::int_is_less_than: | ||
430 | { | ||
431 | new(&singleton_.filterField) field(std::move(filterField)); | ||
432 | singleton_.filterType = filterType; | ||
433 | singleton_.intValue = filterValue; | ||
434 | |||
435 | break; | ||
436 | } | ||
437 | |||
438 | case comparison::boolean_equals: | ||
439 | case comparison::string_equals: | ||
440 | case comparison::string_does_not_equal: | ||
441 | case comparison::string_is_like: | ||
442 | case comparison::string_is_not_like: | ||
443 | case comparison::is_null: | ||
444 | case comparison::is_not_null: | ||
445 | case comparison::matches: | ||
446 | case comparison::does_not_match: | ||
447 | case comparison::hierarchally_matches: | ||
448 | case comparison::does_not_hierarchally_match: | ||
449 | { | ||
450 | throw std::invalid_argument("Invalid comparison for integer field"); | ||
451 | } | ||
452 | } | ||
453 | } else { | ||
454 | throw std::domain_error("Cannot match a non-integer field against an integer value"); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | filter::filter( | ||
459 | field filterField, | ||
460 | comparison filterType, | ||
461 | std::string filterValue) : | ||
462 | type_(type::singleton) | ||
463 | { | ||
464 | if (filterField.getType() == field::type::string) | ||
465 | { | ||
466 | switch (filterType) | ||
467 | { | ||
468 | case comparison::string_equals: | ||
469 | case comparison::string_does_not_equal: | ||
470 | case comparison::string_is_like: | ||
471 | case comparison::string_is_not_like: | ||
472 | { | ||
473 | new(&singleton_.filterField) field(std::move(filterField)); | ||
474 | singleton_.filterType = filterType; | ||
475 | new(&singleton_.stringValue) std::string(std::move(filterValue)); | ||
476 | |||
477 | break; | ||
478 | } | ||
479 | |||
480 | case comparison::int_equals: | ||
481 | case comparison::int_does_not_equal: | ||
482 | case comparison::int_is_at_least: | ||
483 | case comparison::int_is_greater_than: | ||
484 | case comparison::int_is_at_most: | ||
485 | case comparison::int_is_less_than: | ||
486 | case comparison::boolean_equals: | ||
487 | case comparison::is_null: | ||
488 | case comparison::is_not_null: | ||
489 | case comparison::matches: | ||
490 | case comparison::does_not_match: | ||
491 | case comparison::hierarchally_matches: | ||
492 | case comparison::does_not_hierarchally_match: | ||
493 | { | ||
494 | throw std::invalid_argument("Invalid comparison for string field"); | ||
495 | } | ||
496 | } | ||
497 | } else { | ||
498 | throw std::domain_error("Cannot match a non-string field against an string value"); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | filter::filter( | ||
503 | field filterField, | ||
504 | comparison filterType, | ||
505 | bool filterValue) : | ||
506 | type_(type::singleton) | ||
507 | { | ||
508 | if (filterField.getType() == field::type::boolean) | ||
509 | { | ||
510 | switch (filterType) | ||
511 | { | ||
512 | case comparison::boolean_equals: | ||
513 | { | ||
514 | new(&singleton_.filterField) field(std::move(filterField)); | ||
515 | singleton_.filterType = filterType; | ||
516 | singleton_.boolValue = filterValue; | ||
517 | |||
518 | break; | ||
519 | } | ||
520 | |||
521 | case comparison::string_equals: | ||
522 | case comparison::string_does_not_equal: | ||
523 | case comparison::string_is_like: | ||
524 | case comparison::string_is_not_like: | ||
525 | case comparison::int_equals: | ||
526 | case comparison::int_does_not_equal: | ||
527 | case comparison::int_is_at_least: | ||
528 | case comparison::int_is_greater_than: | ||
529 | case comparison::int_is_at_most: | ||
530 | case comparison::int_is_less_than: | ||
531 | case comparison::is_null: | ||
532 | case comparison::is_not_null: | ||
533 | case comparison::matches: | ||
534 | case comparison::does_not_match: | ||
535 | case comparison::hierarchally_matches: | ||
536 | case comparison::does_not_hierarchally_match: | ||
537 | { | ||
538 | throw std::invalid_argument("Invalid comparison for boolean field"); | ||
539 | } | ||
540 | } | ||
541 | } else { | ||
542 | throw std::domain_error("Cannot match a non-boolean field against a boolean value"); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | filter::filter( | ||
547 | field filterField, | ||
548 | comparison filterType) : | ||
549 | type_(type::singleton) | ||
550 | { | ||
551 | if (filterField.isNullable()) | ||
552 | { | ||
553 | switch (filterType) | ||
554 | { | ||
555 | case comparison::is_null: | ||
556 | case comparison::is_not_null: | ||
557 | { | ||
558 | new(&singleton_.filterField) field(std::move(filterField)); | ||
559 | singleton_.filterType = filterType; | ||
560 | |||
561 | break; | ||
562 | } | ||
563 | |||
564 | case comparison::string_equals: | ||
565 | case comparison::string_does_not_equal: | ||
566 | case comparison::string_is_like: | ||
567 | case comparison::string_is_not_like: | ||
568 | case comparison::int_equals: | ||
569 | case comparison::int_does_not_equal: | ||
570 | case comparison::int_is_at_least: | ||
571 | case comparison::int_is_greater_than: | ||
572 | case comparison::int_is_at_most: | ||
573 | case comparison::int_is_less_than: | ||
574 | case comparison::boolean_equals: | ||
575 | case comparison::matches: | ||
576 | case comparison::does_not_match: | ||
577 | case comparison::hierarchally_matches: | ||
578 | case comparison::does_not_hierarchally_match: | ||
579 | { | ||
580 | throw std::invalid_argument("Incorrect constructor for given comparison"); | ||
581 | } | ||
582 | } | ||
583 | } else { | ||
584 | throw std::domain_error("Cannot check nullity/non-nullity of non-nullable field"); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | filter::filter( | ||
589 | field joinOn, | ||
590 | comparison filterType, | ||
591 | filter joinCondition) : | ||
592 | type_(type::singleton) | ||
593 | { | ||
594 | switch (joinOn.getType()) | ||
595 | { | ||
596 | case field::type::join: | ||
597 | case field::type::join_through: | ||
598 | { | ||
599 | switch (filterType) | ||
600 | { | ||
601 | case comparison::matches: | ||
602 | case comparison::does_not_match: | ||
603 | { | ||
604 | new(&singleton_.filterField) field(std::move(joinOn)); | ||
605 | singleton_.filterType = filterType; | ||
606 | new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getJoinObject()))); | ||
607 | |||
608 | break; | ||
609 | } | ||
610 | |||
611 | case comparison::int_equals: | ||
612 | case comparison::int_does_not_equal: | ||
613 | case comparison::int_is_at_least: | ||
614 | case comparison::int_is_greater_than: | ||
615 | case comparison::int_is_at_most: | ||
616 | case comparison::int_is_less_than: | ||
617 | case comparison::boolean_equals: | ||
618 | case comparison::string_equals: | ||
619 | case comparison::string_does_not_equal: | ||
620 | case comparison::string_is_like: | ||
621 | case comparison::string_is_not_like: | ||
622 | case comparison::is_null: | ||
623 | case comparison::is_not_null: | ||
624 | case comparison::hierarchally_matches: | ||
625 | case comparison::does_not_hierarchally_match: | ||
626 | { | ||
627 | throw std::invalid_argument("Incorrect constructor for given comparison"); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | break; | ||
632 | } | ||
633 | |||
634 | case field::type::hierarchal_join: | ||
635 | { | ||
636 | switch (filterType) | ||
637 | { | ||
638 | case comparison::hierarchally_matches: | ||
639 | case comparison::does_not_hierarchally_match: | ||
640 | { | ||
641 | new(&singleton_.filterField) field(std::move(joinOn)); | ||
642 | singleton_.filterType = filterType; | ||
643 | new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getObject()))); | ||
644 | |||
645 | break; | ||
646 | } | ||
647 | |||
648 | case comparison::int_equals: | ||
649 | case comparison::int_does_not_equal: | ||
650 | case comparison::int_is_at_least: | ||
651 | case comparison::int_is_greater_than: | ||
652 | case comparison::int_is_at_most: | ||
653 | case comparison::int_is_less_than: | ||
654 | case comparison::boolean_equals: | ||
655 | case comparison::string_equals: | ||
656 | case comparison::string_does_not_equal: | ||
657 | case comparison::string_is_like: | ||
658 | case comparison::string_is_not_like: | ||
659 | case comparison::is_null: | ||
660 | case comparison::is_not_null: | ||
661 | case comparison::matches: | ||
662 | case comparison::does_not_match: | ||
663 | { | ||
664 | throw std::invalid_argument("Incorrect constructor for given comparison"); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | break; | ||
669 | } | ||
670 | |||
671 | case field::type::undefined: | ||
672 | case field::type::string: | ||
673 | case field::type::integer: | ||
674 | case field::type::boolean: | ||
675 | { | ||
676 | throw std::domain_error("Matching field must be a join field"); | ||
677 | } | ||
678 | } | ||
679 | } | ||
680 | |||
681 | field filter::getField() const | ||
682 | { | ||
683 | if (type_ == type::singleton) | ||
684 | { | ||
685 | return singleton_.filterField; | ||
686 | } else { | ||
687 | throw std::domain_error("This filter does not have a field"); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | filter::comparison filter::getComparison() const | ||
692 | { | ||
693 | if (type_ == type::singleton) | ||
694 | { | ||
695 | return singleton_.filterType; | ||
696 | } else { | ||
697 | throw std::domain_error("This filter does not have a comparison"); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | filter filter::getJoinCondition() const | ||
702 | { | ||
703 | if (type_ == type::singleton) | ||
704 | { | ||
705 | switch (singleton_.filterType) | ||
706 | { | ||
707 | case comparison::matches: | ||
708 | case comparison::does_not_match: | ||
709 | case comparison::hierarchally_matches: | ||
710 | case comparison::does_not_hierarchally_match: | ||
711 | { | ||
712 | return *singleton_.join; | ||
713 | } | ||
714 | |||
715 | case comparison::string_equals: | ||
716 | case comparison::string_does_not_equal: | ||
717 | case comparison::string_is_like: | ||
718 | case comparison::string_is_not_like: | ||
719 | case comparison::int_equals: | ||
720 | case comparison::int_does_not_equal: | ||
721 | case comparison::int_is_at_least: | ||
722 | case comparison::int_is_greater_than: | ||
723 | case comparison::int_is_at_most: | ||
724 | case comparison::int_is_less_than: | ||
725 | case comparison::boolean_equals: | ||
726 | case comparison::is_null: | ||
727 | case comparison::is_not_null: | ||
728 | { | ||
729 | throw std::domain_error("This filter does not have a join condition"); | ||
730 | } | ||
731 | } | ||
732 | } else { | ||
733 | throw std::domain_error("This filter does not have a join condition"); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | std::string filter::getStringArgument() const | ||
738 | { | ||
739 | if (type_ == type::singleton) | ||
740 | { | ||
741 | switch (singleton_.filterType) | ||
742 | { | ||
743 | case comparison::string_equals: | ||
744 | case comparison::string_does_not_equal: | ||
745 | case comparison::string_is_like: | ||
746 | case comparison::string_is_not_like: | ||
747 | { | ||
748 | return singleton_.stringValue; | ||
749 | } | ||
750 | |||
751 | case comparison::int_equals: | ||
752 | case comparison::int_does_not_equal: | ||
753 | case comparison::int_is_at_least: | ||
754 | case comparison::int_is_greater_than: | ||
755 | case comparison::int_is_at_most: | ||
756 | case comparison::int_is_less_than: | ||
757 | case comparison::boolean_equals: | ||
758 | case comparison::is_null: | ||
759 | case comparison::is_not_null: | ||
760 | case comparison::matches: | ||
761 | case comparison::does_not_match: | ||
762 | case comparison::hierarchally_matches: | ||
763 | case comparison::does_not_hierarchally_match: | ||
764 | { | ||
765 | throw std::domain_error("This filter does not have a string argument"); | ||
766 | } | ||
767 | } | ||
768 | } else { | ||
769 | throw std::domain_error("This filter does not have a string argument"); | ||
770 | } | ||
771 | } | ||
772 | |||
773 | int filter::getIntegerArgument() const | ||
774 | { | ||
775 | if (type_ == type::singleton) | ||
776 | { | ||
777 | switch (singleton_.filterType) | ||
778 | { | ||
779 | case comparison::int_equals: | ||
780 | case comparison::int_does_not_equal: | ||
781 | case comparison::int_is_at_least: | ||
782 | case comparison::int_is_greater_than: | ||
783 | case comparison::int_is_at_most: | ||
784 | case comparison::int_is_less_than: | ||
785 | { | ||
786 | return singleton_.intValue; | ||
787 | } | ||
788 | |||
789 | case comparison::string_equals: | ||
790 | case comparison::string_does_not_equal: | ||
791 | case comparison::string_is_like: | ||
792 | case comparison::string_is_not_like: | ||
793 | case comparison::boolean_equals: | ||
794 | case comparison::is_null: | ||
795 | case comparison::is_not_null: | ||
796 | case comparison::matches: | ||
797 | case comparison::does_not_match: | ||
798 | case comparison::hierarchally_matches: | ||
799 | case comparison::does_not_hierarchally_match: | ||
800 | { | ||
801 | throw std::domain_error("This filter does not have an integer argument"); | ||
802 | } | ||
803 | } | ||
804 | } else { | ||
805 | throw std::domain_error("This filter does not have an integer argument"); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | bool filter::getBooleanArgument() const | ||
810 | { | ||
811 | if ((type_ == type::singleton) && (singleton_.filterType == comparison::boolean_equals)) | ||
812 | { | ||
813 | return singleton_.boolValue; | ||
814 | } else { | ||
815 | throw std::domain_error("This filter does not have a boolean argument"); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | filter::filter(bool orlogic) : type_(type::group) | ||
820 | { | ||
821 | new(&group_.children) std::list<filter>(); | ||
822 | group_.orlogic = orlogic; | ||
823 | } | ||
824 | |||
825 | bool filter::getOrlogic() const | ||
826 | { | ||
827 | if (type_ == type::group) | ||
828 | { | ||
829 | return group_.orlogic; | ||
830 | } else { | ||
831 | throw std::domain_error("This filter is not a group filter"); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | filter filter::operator+(filter condition) const | ||
836 | { | ||
837 | filter result(*this); | ||
838 | result += std::move(condition); | ||
839 | |||
840 | return result; | ||
841 | } | ||
842 | |||
843 | filter& filter::operator+=(filter condition) | ||
844 | { | ||
845 | if (type_ == type::group) | ||
846 | { | ||
847 | group_.children.push_back(std::move(condition)); | ||
848 | |||
849 | return *this; | ||
850 | } else { | ||
851 | throw std::domain_error("Children can only be added to group filters"); | ||
852 | } | ||
853 | } | ||
854 | |||
855 | filter::const_iterator filter::begin() const | ||
856 | { | ||
857 | if (type_ == type::group) | ||
858 | { | ||
859 | return std::begin(group_.children); | ||
860 | } else { | ||
861 | throw std::domain_error("This filter has no children"); | ||
862 | } | ||
863 | } | ||
864 | |||
865 | filter::const_iterator filter::end() const | ||
866 | { | ||
867 | if (type_ == type::group) | ||
868 | { | ||
869 | return std::end(group_.children); | ||
870 | } else { | ||
871 | throw std::domain_error("This filter has no children"); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | filter filter::operator!() const | ||
876 | { | ||
877 | switch (type_) | ||
878 | { | ||
879 | case type::empty: | ||
880 | { | ||
881 | return {}; | ||
882 | } | ||
883 | |||
884 | case type::singleton: | ||
885 | { | ||
886 | switch (singleton_.filterType) | ||
887 | { | ||
888 | case comparison::int_equals: | ||
889 | { | ||
890 | return filter(singleton_.filterField, comparison::int_does_not_equal, singleton_.intValue); | ||
891 | } | ||
892 | |||
893 | case comparison::int_does_not_equal: | ||
894 | { | ||
895 | return filter(singleton_.filterField, comparison::int_equals, singleton_.intValue); | ||
896 | } | ||
897 | |||
898 | case comparison::int_is_at_least: | ||
899 | { | ||
900 | return filter(singleton_.filterField, comparison::int_is_less_than, singleton_.intValue); | ||
901 | } | ||
902 | |||
903 | case comparison::int_is_greater_than: | ||
904 | { | ||
905 | return filter(singleton_.filterField, comparison::int_is_at_most, singleton_.intValue); | ||
906 | } | ||
907 | |||
908 | case comparison::int_is_at_most: | ||
909 | { | ||
910 | return filter(singleton_.filterField, comparison::int_is_greater_than, singleton_.intValue); | ||
911 | } | ||
912 | |||
913 | case comparison::int_is_less_than: | ||
914 | { | ||
915 | return filter(singleton_.filterField, comparison::int_is_at_least, singleton_.intValue); | ||
916 | } | ||
917 | |||
918 | case comparison::boolean_equals: | ||
919 | { | ||
920 | return filter(singleton_.filterField, comparison::boolean_equals, !singleton_.boolValue); | ||
921 | } | ||
922 | |||
923 | case comparison::string_equals: | ||
924 | { | ||
925 | return filter(singleton_.filterField, comparison::string_does_not_equal, singleton_.stringValue); | ||
926 | } | ||
927 | |||
928 | case comparison::string_does_not_equal: | ||
929 | { | ||
930 | return filter(singleton_.filterField, comparison::string_equals, singleton_.stringValue); | ||
931 | } | ||
932 | |||
933 | case comparison::string_is_like: | ||
934 | { | ||
935 | return filter(singleton_.filterField, comparison::string_is_not_like, singleton_.stringValue); | ||
936 | } | ||
937 | |||
938 | case comparison::string_is_not_like: | ||
939 | { | ||
940 | return filter(singleton_.filterField, comparison::string_is_like, singleton_.stringValue); | ||
941 | } | ||
942 | |||
943 | case comparison::is_null: | ||
944 | { | ||
945 | return filter(singleton_.filterField, comparison::is_not_null); | ||
946 | } | ||
947 | |||
948 | case comparison::is_not_null: | ||
949 | { | ||
950 | return filter(singleton_.filterField, comparison::is_null); | ||
951 | } | ||
952 | |||
953 | case comparison::matches: | ||
954 | { | ||
955 | return filter(singleton_.filterField, comparison::does_not_match, *singleton_.join); | ||
956 | } | ||
957 | |||
958 | case comparison::does_not_match: | ||
959 | { | ||
960 | return filter(singleton_.filterField, comparison::matches, *singleton_.join); | ||
961 | } | ||
962 | |||
963 | case comparison::hierarchally_matches: | ||
964 | { | ||
965 | return filter(singleton_.filterField, comparison::does_not_hierarchally_match, *singleton_.join); | ||
966 | } | ||
967 | |||
968 | case comparison::does_not_hierarchally_match: | ||
969 | { | ||
970 | return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join); | ||
971 | } | ||
972 | } | ||
973 | } | ||
974 | |||
975 | case type::group: | ||
976 | { | ||
977 | filter result(!group_.orlogic); | ||
978 | |||
979 | for (const filter& child : group_.children) | ||
980 | { | ||
981 | result += !child; | ||
982 | } | ||
983 | |||
984 | return result; | ||
985 | } | ||
986 | } | ||
987 | } | ||
988 | |||
989 | filter& filter::operator&=(filter condition) | ||
990 | { | ||
991 | return (*this = (*this && std::move(condition))); | ||
992 | } | ||
993 | |||
994 | filter& filter::operator|=(filter condition) | ||
995 | { | ||
996 | return (*this = (*this || std::move(condition))); | ||
997 | } | ||
998 | |||
999 | filter filter::operator&&(filter condition) const | ||
1000 | { | ||
1001 | switch (type_) | ||
1002 | { | ||
1003 | case type::empty: | ||
1004 | { | ||
1005 | return condition; | ||
1006 | } | ||
1007 | |||
1008 | case type::singleton: | ||
1009 | { | ||
1010 | filter result(false); | ||
1011 | result.group_.children.push_back(*this); | ||
1012 | result.group_.children.push_back(std::move(condition)); | ||
1013 | |||
1014 | return result; | ||
1015 | } | ||
1016 | |||
1017 | case type::group: | ||
1018 | { | ||
1019 | if (group_.orlogic) | ||
1020 | { | ||
1021 | filter result(false); | ||
1022 | result.group_.children.push_back(*this); | ||
1023 | result.group_.children.push_back(std::move(condition)); | ||
1024 | |||
1025 | return result; | ||
1026 | } else { | ||
1027 | filter result(*this); | ||
1028 | result.group_.children.push_back(std::move(condition)); | ||
1029 | |||
1030 | return result; | ||
1031 | } | ||
1032 | } | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | filter filter::operator||(filter condition) const | ||
1037 | { | ||
1038 | switch (type_) | ||
1039 | { | ||
1040 | case type::empty: | ||
1041 | { | ||
1042 | return condition; | ||
1043 | } | ||
1044 | |||
1045 | case type::singleton: | ||
1046 | { | ||
1047 | filter result(true); | ||
1048 | result.group_.children.push_back(*this); | ||
1049 | result.group_.children.push_back(std::move(condition)); | ||
1050 | |||
1051 | return result; | ||
1052 | } | ||
1053 | |||
1054 | case type::group: | ||
1055 | { | ||
1056 | if (!group_.orlogic) | ||
1057 | { | ||
1058 | filter result(true); | ||
1059 | result.group_.children.push_back(*this); | ||
1060 | result.group_.children.push_back(std::move(condition)); | ||
1061 | |||
1062 | return result; | ||
1063 | } else { | ||
1064 | filter result(*this); | ||
1065 | result.group_.children.push_back(std::move(condition)); | ||
1066 | |||
1067 | return result; | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | filter filter::normalize(object context) const | ||
1074 | { | ||
1075 | { | ||
1076 | switch (type_) | ||
1077 | { | ||
1078 | case type::empty: | ||
1079 | { | ||
1080 | return *this; | ||
1081 | } | ||
1082 | |||
1083 | case type::singleton: | ||
1084 | { | ||
1085 | // First, switch on the normalized context, and then switch on the | ||
1086 | // current context. We recursively recontextualize by using the | ||
1087 | // current filter as a subquery for a join such that the context of | ||
1088 | // the subquery is one step closer to the context of the current | ||
1089 | // filter, and then letting the filter constructor normalize the | ||
1090 | // subquery. | ||
1091 | switch (context) | ||
1092 | { | ||
1093 | case object::undefined: | ||
1094 | { | ||
1095 | // An undefined object indicates no participation in | ||
1096 | // recontexualization. | ||
1097 | return *this; | ||
1098 | } | ||
1099 | |||
1100 | case object::notion: | ||
1101 | { | ||
1102 | switch (singleton_.filterField.getObject()) | ||
1103 | { | ||
1104 | case object::undefined: | ||
1105 | case object::notion: | ||
1106 | { | ||
1107 | return *this; | ||
1108 | } | ||
1109 | |||
1110 | case object::word: | ||
1111 | case object::group: | ||
1112 | case object::frame: | ||
1113 | case object::lemma: | ||
1114 | case object::form: | ||
1115 | case object::pronunciation: | ||
1116 | { | ||
1117 | return (verbly::notion::word %= *this); | ||
1118 | } | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | case object::word: | ||
1123 | { | ||
1124 | switch (singleton_.filterField.getObject()) | ||
1125 | { | ||
1126 | case object::notion: | ||
1127 | { | ||
1128 | return (verbly::word::notion %= *this); | ||
1129 | } | ||
1130 | |||
1131 | case object::undefined: | ||
1132 | case object::word: | ||
1133 | { | ||
1134 | return *this; | ||
1135 | } | ||
1136 | |||
1137 | case object::group: | ||
1138 | case object::frame: | ||
1139 | { | ||
1140 | return (verbly::word::group %= *this); | ||
1141 | } | ||
1142 | |||
1143 | case object::lemma: | ||
1144 | case object::form: | ||
1145 | case object::pronunciation: | ||
1146 | { | ||
1147 | return (verbly::word::lemma %= *this); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | case object::group: | ||
1152 | { | ||
1153 | switch (singleton_.filterField.getObject()) | ||
1154 | { | ||
1155 | case object::undefined: | ||
1156 | case object::group: | ||
1157 | { | ||
1158 | return *this; | ||
1159 | } | ||
1160 | |||
1161 | case object::notion: | ||
1162 | case object::word: | ||
1163 | case object::lemma: | ||
1164 | case object::form: | ||
1165 | case object::pronunciation: | ||
1166 | { | ||
1167 | return (verbly::group::word %= *this); | ||
1168 | } | ||
1169 | |||
1170 | case object::frame: | ||
1171 | { | ||
1172 | return (verbly::group::frame %= *this); | ||
1173 | } | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | case object::frame: | ||
1178 | { | ||
1179 | switch (singleton_.filterField.getObject()) | ||
1180 | { | ||
1181 | case object::undefined: | ||
1182 | case object::frame: | ||
1183 | { | ||
1184 | return *this; | ||
1185 | } | ||
1186 | |||
1187 | case object::notion: | ||
1188 | case object::word: | ||
1189 | case object::group: | ||
1190 | case object::lemma: | ||
1191 | case object::form: | ||
1192 | case object::pronunciation: | ||
1193 | { | ||
1194 | return (verbly::frame::group %= *this); | ||
1195 | } | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | case object::lemma: | ||
1200 | { | ||
1201 | switch (singleton_.filterField.getObject()) | ||
1202 | { | ||
1203 | case object::notion: | ||
1204 | case object::word: | ||
1205 | case object::group: | ||
1206 | case object::frame: | ||
1207 | { | ||
1208 | return verbly::lemma::word %= *this; | ||
1209 | } | ||
1210 | |||
1211 | case object::undefined: | ||
1212 | case object::lemma: | ||
1213 | { | ||
1214 | return *this; | ||
1215 | } | ||
1216 | |||
1217 | case object::form: | ||
1218 | case object::pronunciation: | ||
1219 | { | ||
1220 | return (verbly::lemma::form(inflection::base) %= *this); | ||
1221 | } | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | case object::form: | ||
1226 | { | ||
1227 | switch (singleton_.filterField.getObject()) | ||
1228 | { | ||
1229 | case object::notion: | ||
1230 | case object::word: | ||
1231 | case object::group: | ||
1232 | case object::frame: | ||
1233 | case object::lemma: | ||
1234 | { | ||
1235 | return verbly::form::lemma(inflection::base) %= *this; | ||
1236 | } | ||
1237 | |||
1238 | case object::undefined: | ||
1239 | case object::form: | ||
1240 | { | ||
1241 | return *this; | ||
1242 | } | ||
1243 | |||
1244 | case object::pronunciation: | ||
1245 | { | ||
1246 | return (verbly::form::pronunciation %= *this); | ||
1247 | } | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | case object::pronunciation: | ||
1252 | { | ||
1253 | switch (singleton_.filterField.getObject()) | ||
1254 | { | ||
1255 | case object::notion: | ||
1256 | case object::word: | ||
1257 | case object::group: | ||
1258 | case object::frame: | ||
1259 | case object::lemma: | ||
1260 | case object::form: | ||
1261 | { | ||
1262 | return verbly::pronunciation::form %= *this; | ||
1263 | } | ||
1264 | |||
1265 | case object::undefined: | ||
1266 | case object::pronunciation: | ||
1267 | { | ||
1268 | return *this; | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||
1272 | } | ||
1273 | } | ||
1274 | } | ||
1275 | |||
1276 | case type::group: | ||
1277 | { | ||
1278 | filter result(group_.orlogic); | ||
1279 | std::map<field, filter> joins; | ||
1280 | |||
1281 | for (const filter& child : group_.children) | ||
1282 | { | ||
1283 | filter normalized = child.normalize(context); | ||
1284 | |||
1285 | // Notably, this does not attempt to merge hierarchal matches. | ||
1286 | switch (normalized.getType()) | ||
1287 | { | ||
1288 | case type::singleton: | ||
1289 | { | ||
1290 | switch (normalized.getComparison()) | ||
1291 | { | ||
1292 | case comparison::matches: | ||
1293 | { | ||
1294 | if (!joins.count(normalized.singleton_.filterField)) | ||
1295 | { | ||
1296 | joins[normalized.getField()] = filter(group_.orlogic); | ||
1297 | } | ||
1298 | |||
1299 | joins.at(normalized.getField()) += std::move(*normalized.singleton_.join); | ||
1300 | |||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | case comparison::does_not_match: | ||
1305 | { | ||
1306 | if (!joins.count(normalized.singleton_.filterField)) | ||
1307 | { | ||
1308 | joins[normalized.getField()] = filter(group_.orlogic); | ||
1309 | } | ||
1310 | |||
1311 | joins.at(normalized.getField()) += !*normalized.singleton_.join; | ||
1312 | |||
1313 | break; | ||
1314 | } | ||
1315 | |||
1316 | case comparison::int_equals: | ||
1317 | case comparison::int_does_not_equal: | ||
1318 | case comparison::int_is_at_least: | ||
1319 | case comparison::int_is_greater_than: | ||
1320 | case comparison::int_is_at_most: | ||
1321 | case comparison::int_is_less_than: | ||
1322 | case comparison::boolean_equals: | ||
1323 | case comparison::string_equals: | ||
1324 | case comparison::string_does_not_equal: | ||
1325 | case comparison::string_is_like: | ||
1326 | case comparison::string_is_not_like: | ||
1327 | case comparison::is_null: | ||
1328 | case comparison::is_not_null: | ||
1329 | case comparison::hierarchally_matches: | ||
1330 | case comparison::does_not_hierarchally_match: | ||
1331 | { | ||
1332 | result += std::move(normalized); | ||
1333 | |||
1334 | break; | ||
1335 | } | ||
1336 | } | ||
1337 | |||
1338 | break; | ||
1339 | } | ||
1340 | |||
1341 | case type::group: | ||
1342 | case type::empty: | ||
1343 | { | ||
1344 | result += std::move(normalized); | ||
1345 | |||
1346 | break; | ||
1347 | } | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | for (auto& mapping : joins) | ||
1352 | { | ||
1353 | const field& joinOn = mapping.first; | ||
1354 | filter& joinCondition = mapping.second; | ||
1355 | |||
1356 | result += (joinOn %= joinCondition.normalize(joinOn.getJoinObject())); | ||
1357 | } | ||
1358 | |||
1359 | return result; | ||
1360 | } | ||
1361 | } | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1365 | }; | ||