summary refs log tree commit diff stats
path: root/lib/filter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/filter.cpp')
-rw-r--r--lib/filter.cpp1365
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
12namespace 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};