summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-01-23 11:20:20 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-01-23 11:20:20 -0500
commitd19c329607d611901540e5d3d746c1a94a0b6210 (patch)
tree05c845164e3f3df9dc38668a0278d15d0caaacfe
parent71064d07ad84b1d31471298f8cc5b497cbe85505 (diff)
downloadverbly-d19c329607d611901540e5d3d746c1a94a0b6210.tar.gz
verbly-d19c329607d611901540e5d3d746c1a94a0b6210.tar.bz2
verbly-d19c329607d611901540e5d3d746c1a94a0b6210.zip
Fixed normalization of negative join filters
Previously, negative join filters were folded in with positive joins by
AND/ORing them together and negating the negative joins. Checking for
the existence of something that doesn't match a condition is different
from checking for the non-existence of something that does match a
condition, so now normalization considers positive and negative join
filters to be distinct classes of filters and does not fold them
together.

Also made some whitespace changes.
-rw-r--r--lib/filter.cpp375
1 files changed, 192 insertions, 183 deletions
diff --git a/lib/filter.cpp b/lib/filter.cpp index 959fa05..1af7314 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp
@@ -14,19 +14,19 @@ namespace verbly {
14 filter::filter(const filter& other) 14 filter::filter(const filter& other)
15 { 15 {
16 type_ = other.type_; 16 type_ = other.type_;
17 17
18 switch (type_) 18 switch (type_)
19 { 19 {
20 case type::empty: 20 case type::empty:
21 { 21 {
22 break; 22 break;
23 } 23 }
24 24
25 case type::singleton: 25 case type::singleton:
26 { 26 {
27 new(&singleton_.filterField) field(other.singleton_.filterField); 27 new(&singleton_.filterField) field(other.singleton_.filterField);
28 singleton_.filterType = other.singleton_.filterType; 28 singleton_.filterType = other.singleton_.filterType;
29 29
30 switch (singleton_.filterType) 30 switch (singleton_.filterType)
31 { 31 {
32 case comparison::int_equals: 32 case comparison::int_equals:
@@ -37,74 +37,74 @@ namespace verbly {
37 case comparison::int_is_less_than: 37 case comparison::int_is_less_than:
38 { 38 {
39 singleton_.intValue = other.singleton_.intValue; 39 singleton_.intValue = other.singleton_.intValue;
40 40
41 break; 41 break;
42 } 42 }
43 43
44 case comparison::boolean_equals: 44 case comparison::boolean_equals:
45 { 45 {
46 singleton_.boolValue = other.singleton_.boolValue; 46 singleton_.boolValue = other.singleton_.boolValue;
47 47
48 break; 48 break;
49 } 49 }
50 50
51 case comparison::string_equals: 51 case comparison::string_equals:
52 case comparison::string_does_not_equal: 52 case comparison::string_does_not_equal:
53 case comparison::string_is_like: 53 case comparison::string_is_like:
54 case comparison::string_is_not_like: 54 case comparison::string_is_not_like:
55 { 55 {
56 new(&singleton_.stringValue) std::string(other.singleton_.stringValue); 56 new(&singleton_.stringValue) std::string(other.singleton_.stringValue);
57 57
58 break; 58 break;
59 } 59 }
60 60
61 case comparison::is_null: 61 case comparison::is_null:
62 case comparison::is_not_null: 62 case comparison::is_not_null:
63 { 63 {
64 break; 64 break;
65 } 65 }
66 66
67 case comparison::matches: 67 case comparison::matches:
68 case comparison::does_not_match: 68 case comparison::does_not_match:
69 case comparison::hierarchally_matches: 69 case comparison::hierarchally_matches:
70 case comparison::does_not_hierarchally_match: 70 case comparison::does_not_hierarchally_match:
71 { 71 {
72 new(&singleton_.join) std::unique_ptr<filter>(new filter(*other.singleton_.join)); 72 new(&singleton_.join) std::unique_ptr<filter>(new filter(*other.singleton_.join));
73 73
74 break; 74 break;
75 } 75 }
76 } 76 }
77 77
78 break; 78 break;
79 } 79 }
80 80
81 case type::group: 81 case type::group:
82 { 82 {
83 new(&group_.children) std::list<filter>(other.group_.children); 83 new(&group_.children) std::list<filter>(other.group_.children);
84 group_.orlogic = other.group_.orlogic; 84 group_.orlogic = other.group_.orlogic;
85 85
86 break; 86 break;
87 } 87 }
88 } 88 }
89 } 89 }
90 90
91 filter::filter(filter&& other) : filter() 91 filter::filter(filter&& other) : filter()
92 { 92 {
93 swap(*this, other); 93 swap(*this, other);
94 } 94 }
95 95
96 filter& filter::operator=(filter other) 96 filter& filter::operator=(filter other)
97 { 97 {
98 swap(*this, other); 98 swap(*this, other);
99 99
100 return *this; 100 return *this;
101 } 101 }
102 102
103 void swap(filter& first, filter& second) 103 void swap(filter& first, filter& second)
104 { 104 {
105 using type = filter::type; 105 using type = filter::type;
106 using comparison = filter::comparison; 106 using comparison = filter::comparison;
107 107
108 type tempType = first.type_; 108 type tempType = first.type_;
109 field tempField; 109 field tempField;
110 comparison tempComparison; 110 comparison tempComparison;
@@ -114,19 +114,19 @@ namespace verbly {
114 bool tempBoolValue; 114 bool tempBoolValue;
115 std::list<filter> tempChildren; 115 std::list<filter> tempChildren;
116 bool tempOrlogic; 116 bool tempOrlogic;
117 117
118 switch (tempType) 118 switch (tempType)
119 { 119 {
120 case type::empty: 120 case type::empty:
121 { 121 {
122 break; 122 break;
123 } 123 }
124 124
125 case type::singleton: 125 case type::singleton:
126 { 126 {
127 tempField = std::move(first.singleton_.filterField); 127 tempField = std::move(first.singleton_.filterField);
128 tempComparison = first.singleton_.filterType; 128 tempComparison = first.singleton_.filterType;
129 129
130 switch (tempComparison) 130 switch (tempComparison)
131 { 131 {
132 case comparison::int_equals: 132 case comparison::int_equals:
@@ -137,72 +137,72 @@ namespace verbly {
137 case comparison::int_is_less_than: 137 case comparison::int_is_less_than:
138 { 138 {
139 tempIntValue = first.singleton_.intValue; 139 tempIntValue = first.singleton_.intValue;
140 140
141 break; 141 break;
142 } 142 }
143 143
144 case comparison::boolean_equals: 144 case comparison::boolean_equals:
145 { 145 {
146 tempBoolValue = first.singleton_.boolValue; 146 tempBoolValue = first.singleton_.boolValue;
147 147
148 break; 148 break;
149 } 149 }
150 150
151 case comparison::string_equals: 151 case comparison::string_equals:
152 case comparison::string_does_not_equal: 152 case comparison::string_does_not_equal:
153 case comparison::string_is_like: 153 case comparison::string_is_like:
154 case comparison::string_is_not_like: 154 case comparison::string_is_not_like:
155 { 155 {
156 tempStringValue = std::move(first.singleton_.stringValue); 156 tempStringValue = std::move(first.singleton_.stringValue);
157 157
158 break; 158 break;
159 } 159 }
160 160
161 case comparison::is_null: 161 case comparison::is_null:
162 case comparison::is_not_null: 162 case comparison::is_not_null:
163 { 163 {
164 break; 164 break;
165 } 165 }
166 166
167 case comparison::matches: 167 case comparison::matches:
168 case comparison::does_not_match: 168 case comparison::does_not_match:
169 case comparison::hierarchally_matches: 169 case comparison::hierarchally_matches:
170 case comparison::does_not_hierarchally_match: 170 case comparison::does_not_hierarchally_match:
171 { 171 {
172 tempJoin = std::move(first.singleton_.join); 172 tempJoin = std::move(first.singleton_.join);
173 173
174 break; 174 break;
175 } 175 }
176 } 176 }
177 177
178 break; 178 break;
179 } 179 }
180 180
181 case type::group: 181 case type::group:
182 { 182 {
183 tempChildren = std::move(first.group_.children); 183 tempChildren = std::move(first.group_.children);
184 tempOrlogic = first.group_.orlogic; 184 tempOrlogic = first.group_.orlogic;
185 185
186 break; 186 break;
187 } 187 }
188 } 188 }
189 189
190 first.~filter(); 190 first.~filter();
191 191
192 first.type_ = second.type_; 192 first.type_ = second.type_;
193 193
194 switch (first.type_) 194 switch (first.type_)
195 { 195 {
196 case type::empty: 196 case type::empty:
197 { 197 {
198 break; 198 break;
199 } 199 }
200 200
201 case type::singleton: 201 case type::singleton:
202 { 202 {
203 new(&first.singleton_.filterField) field(std::move(second.singleton_.filterField)); 203 new(&first.singleton_.filterField) field(std::move(second.singleton_.filterField));
204 first.singleton_.filterType = second.singleton_.filterType; 204 first.singleton_.filterType = second.singleton_.filterType;
205 205
206 switch (first.singleton_.filterType) 206 switch (first.singleton_.filterType)
207 { 207 {
208 case comparison::int_equals: 208 case comparison::int_equals:
@@ -213,72 +213,72 @@ namespace verbly {
213 case comparison::int_is_less_than: 213 case comparison::int_is_less_than:
214 { 214 {
215 first.singleton_.intValue = second.singleton_.intValue; 215 first.singleton_.intValue = second.singleton_.intValue;
216 216
217 break; 217 break;
218 } 218 }
219 219
220 case comparison::boolean_equals: 220 case comparison::boolean_equals:
221 { 221 {
222 first.singleton_.boolValue = second.singleton_.boolValue; 222 first.singleton_.boolValue = second.singleton_.boolValue;
223 223
224 break; 224 break;
225 } 225 }
226 226
227 case comparison::string_equals: 227 case comparison::string_equals:
228 case comparison::string_does_not_equal: 228 case comparison::string_does_not_equal:
229 case comparison::string_is_like: 229 case comparison::string_is_like:
230 case comparison::string_is_not_like: 230 case comparison::string_is_not_like:
231 { 231 {
232 new(&first.singleton_.stringValue) std::string(std::move(second.singleton_.stringValue)); 232 new(&first.singleton_.stringValue) std::string(std::move(second.singleton_.stringValue));
233 233
234 break; 234 break;
235 } 235 }
236 236
237 case comparison::is_null: 237 case comparison::is_null:
238 case comparison::is_not_null: 238 case comparison::is_not_null:
239 { 239 {
240 break; 240 break;
241 } 241 }
242 242
243 case comparison::matches: 243 case comparison::matches:
244 case comparison::does_not_match: 244 case comparison::does_not_match:
245 case comparison::hierarchally_matches: 245 case comparison::hierarchally_matches:
246 case comparison::does_not_hierarchally_match: 246 case comparison::does_not_hierarchally_match:
247 { 247 {
248 new(&first.singleton_.join) std::unique_ptr<filter>(std::move(second.singleton_.join)); 248 new(&first.singleton_.join) std::unique_ptr<filter>(std::move(second.singleton_.join));
249 249
250 break; 250 break;
251 } 251 }
252 } 252 }
253 253
254 break; 254 break;
255 } 255 }
256 256
257 case type::group: 257 case type::group:
258 { 258 {
259 new(&first.group_.children) std::list<filter>(std::move(second.group_.children)); 259 new(&first.group_.children) std::list<filter>(std::move(second.group_.children));
260 first.group_.orlogic = second.group_.orlogic; 260 first.group_.orlogic = second.group_.orlogic;
261 261
262 break; 262 break;
263 } 263 }
264 } 264 }
265 265
266 second.~filter(); 266 second.~filter();
267 267
268 second.type_ = tempType; 268 second.type_ = tempType;
269 269
270 switch (second.type_) 270 switch (second.type_)
271 { 271 {
272 case type::empty: 272 case type::empty:
273 { 273 {
274 break; 274 break;
275 } 275 }
276 276
277 case type::singleton: 277 case type::singleton:
278 { 278 {
279 new(&second.singleton_.filterField) field(std::move(tempField)); 279 new(&second.singleton_.filterField) field(std::move(tempField));
280 second.singleton_.filterType = tempComparison; 280 second.singleton_.filterType = tempComparison;
281 281
282 switch (second.singleton_.filterType) 282 switch (second.singleton_.filterType)
283 { 283 {
284 case comparison::int_equals: 284 case comparison::int_equals:
@@ -289,57 +289,57 @@ namespace verbly {
289 case comparison::int_is_less_than: 289 case comparison::int_is_less_than:
290 { 290 {
291 second.singleton_.intValue = tempIntValue; 291 second.singleton_.intValue = tempIntValue;
292 292
293 break; 293 break;
294 } 294 }
295 295
296 case comparison::boolean_equals: 296 case comparison::boolean_equals:
297 { 297 {
298 second.singleton_.boolValue = tempBoolValue; 298 second.singleton_.boolValue = tempBoolValue;
299 299
300 break; 300 break;
301 } 301 }
302 302
303 case comparison::string_equals: 303 case comparison::string_equals:
304 case comparison::string_does_not_equal: 304 case comparison::string_does_not_equal:
305 case comparison::string_is_like: 305 case comparison::string_is_like:
306 case comparison::string_is_not_like: 306 case comparison::string_is_not_like:
307 { 307 {
308 new(&second.singleton_.stringValue) std::string(std::move(tempStringValue)); 308 new(&second.singleton_.stringValue) std::string(std::move(tempStringValue));
309 309
310 break; 310 break;
311 } 311 }
312 312
313 case comparison::is_null: 313 case comparison::is_null:
314 case comparison::is_not_null: 314 case comparison::is_not_null:
315 { 315 {
316 break; 316 break;
317 } 317 }
318 318
319 case comparison::matches: 319 case comparison::matches:
320 case comparison::does_not_match: 320 case comparison::does_not_match:
321 case comparison::hierarchally_matches: 321 case comparison::hierarchally_matches:
322 case comparison::does_not_hierarchally_match: 322 case comparison::does_not_hierarchally_match:
323 { 323 {
324 new(&second.singleton_.join) std::unique_ptr<filter>(std::move(tempJoin)); 324 new(&second.singleton_.join) std::unique_ptr<filter>(std::move(tempJoin));
325 325
326 break; 326 break;
327 } 327 }
328 } 328 }
329 329
330 break; 330 break;
331 } 331 }
332 332
333 case type::group: 333 case type::group:
334 { 334 {
335 new(&second.group_.children) std::list<filter>(std::move(tempChildren)); 335 new(&second.group_.children) std::list<filter>(std::move(tempChildren));
336 second.group_.orlogic = tempOrlogic; 336 second.group_.orlogic = tempOrlogic;
337 337
338 break; 338 break;
339 } 339 }
340 } 340 }
341 } 341 }
342 342
343 filter::~filter() 343 filter::~filter()
344 { 344 {
345 switch (type_) 345 switch (type_)
@@ -348,11 +348,11 @@ namespace verbly {
348 { 348 {
349 break; 349 break;
350 } 350 }
351 351
352 case type::singleton: 352 case type::singleton:
353 { 353 {
354 singleton_.filterField.~field(); 354 singleton_.filterField.~field();
355 355
356 switch (singleton_.filterType) 356 switch (singleton_.filterType)
357 { 357 {
358 case comparison::int_equals: 358 case comparison::int_equals:
@@ -367,50 +367,50 @@ namespace verbly {
367 { 367 {
368 break; 368 break;
369 } 369 }
370 370
371 case comparison::string_equals: 371 case comparison::string_equals:
372 case comparison::string_does_not_equal: 372 case comparison::string_does_not_equal:
373 case comparison::string_is_like: 373 case comparison::string_is_like:
374 case comparison::string_is_not_like: 374 case comparison::string_is_not_like:
375 { 375 {
376 using string_type = std::string; 376 using string_type = std::string;
377 377
378 singleton_.stringValue.~string_type(); 378 singleton_.stringValue.~string_type();
379 379
380 break; 380 break;
381 } 381 }
382 382
383 case comparison::matches: 383 case comparison::matches:
384 case comparison::does_not_match: 384 case comparison::does_not_match:
385 case comparison::hierarchally_matches: 385 case comparison::hierarchally_matches:
386 case comparison::does_not_hierarchally_match: 386 case comparison::does_not_hierarchally_match:
387 { 387 {
388 using ptr_type = std::unique_ptr<filter>; 388 using ptr_type = std::unique_ptr<filter>;
389 389
390 singleton_.join.~ptr_type(); 390 singleton_.join.~ptr_type();
391 391
392 break; 392 break;
393 } 393 }
394 } 394 }
395 395
396 break; 396 break;
397 } 397 }
398 398
399 case type::group: 399 case type::group:
400 { 400 {
401 using list_type = std::list<filter>; 401 using list_type = std::list<filter>;
402 402
403 group_.children.~list_type(); 403 group_.children.~list_type();
404 404
405 break; 405 break;
406 } 406 }
407 } 407 }
408 } 408 }
409 409
410 filter::filter() 410 filter::filter()
411 { 411 {
412 } 412 }
413 413
414 filter::filter( 414 filter::filter(
415 field filterField, 415 field filterField,
416 comparison filterType, 416 comparison filterType,
@@ -431,10 +431,10 @@ namespace verbly {
431 new(&singleton_.filterField) field(std::move(filterField)); 431 new(&singleton_.filterField) field(std::move(filterField));
432 singleton_.filterType = filterType; 432 singleton_.filterType = filterType;
433 singleton_.intValue = filterValue; 433 singleton_.intValue = filterValue;
434 434
435 break; 435 break;
436 } 436 }
437 437
438 case comparison::boolean_equals: 438 case comparison::boolean_equals:
439 case comparison::string_equals: 439 case comparison::string_equals:
440 case comparison::string_does_not_equal: 440 case comparison::string_does_not_equal:
@@ -454,7 +454,7 @@ namespace verbly {
454 throw std::domain_error("Cannot match a non-integer field against an integer value"); 454 throw std::domain_error("Cannot match a non-integer field against an integer value");
455 } 455 }
456 } 456 }
457 457
458 filter::filter( 458 filter::filter(
459 field filterField, 459 field filterField,
460 comparison filterType, 460 comparison filterType,
@@ -473,10 +473,10 @@ namespace verbly {
473 new(&singleton_.filterField) field(std::move(filterField)); 473 new(&singleton_.filterField) field(std::move(filterField));
474 singleton_.filterType = filterType; 474 singleton_.filterType = filterType;
475 new(&singleton_.stringValue) std::string(std::move(filterValue)); 475 new(&singleton_.stringValue) std::string(std::move(filterValue));
476 476
477 break; 477 break;
478 } 478 }
479 479
480 case comparison::int_equals: 480 case comparison::int_equals:
481 case comparison::int_does_not_equal: 481 case comparison::int_does_not_equal:
482 case comparison::int_is_at_least: 482 case comparison::int_is_at_least:
@@ -498,7 +498,7 @@ namespace verbly {
498 throw std::domain_error("Cannot match a non-string field against an string value"); 498 throw std::domain_error("Cannot match a non-string field against an string value");
499 } 499 }
500 } 500 }
501 501
502 filter::filter( 502 filter::filter(
503 field filterField, 503 field filterField,
504 comparison filterType, 504 comparison filterType,
@@ -514,10 +514,10 @@ namespace verbly {
514 new(&singleton_.filterField) field(std::move(filterField)); 514 new(&singleton_.filterField) field(std::move(filterField));
515 singleton_.filterType = filterType; 515 singleton_.filterType = filterType;
516 singleton_.boolValue = filterValue; 516 singleton_.boolValue = filterValue;
517 517
518 break; 518 break;
519 } 519 }
520 520
521 case comparison::string_equals: 521 case comparison::string_equals:
522 case comparison::string_does_not_equal: 522 case comparison::string_does_not_equal:
523 case comparison::string_is_like: 523 case comparison::string_is_like:
@@ -542,7 +542,7 @@ namespace verbly {
542 throw std::domain_error("Cannot match a non-boolean field against a boolean value"); 542 throw std::domain_error("Cannot match a non-boolean field against a boolean value");
543 } 543 }
544 } 544 }
545 545
546 filter::filter( 546 filter::filter(
547 field filterField, 547 field filterField,
548 comparison filterType) : 548 comparison filterType) :
@@ -557,10 +557,10 @@ namespace verbly {
557 { 557 {
558 new(&singleton_.filterField) field(std::move(filterField)); 558 new(&singleton_.filterField) field(std::move(filterField));
559 singleton_.filterType = filterType; 559 singleton_.filterType = filterType;
560 560
561 break; 561 break;
562 } 562 }
563 563
564 case comparison::string_equals: 564 case comparison::string_equals:
565 case comparison::string_does_not_equal: 565 case comparison::string_does_not_equal:
566 case comparison::string_is_like: 566 case comparison::string_is_like:
@@ -584,7 +584,7 @@ namespace verbly {
584 throw std::domain_error("Cannot check nullity/non-nullity of non-nullable field"); 584 throw std::domain_error("Cannot check nullity/non-nullity of non-nullable field");
585 } 585 }
586 } 586 }
587 587
588 filter::filter( 588 filter::filter(
589 field joinOn, 589 field joinOn,
590 comparison filterType, 590 comparison filterType,
@@ -604,10 +604,10 @@ namespace verbly {
604 new(&singleton_.filterField) field(std::move(joinOn)); 604 new(&singleton_.filterField) field(std::move(joinOn));
605 singleton_.filterType = filterType; 605 singleton_.filterType = filterType;
606 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getJoinObject()))); 606 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getJoinObject())));
607 607
608 break; 608 break;
609 } 609 }
610 610
611 case comparison::int_equals: 611 case comparison::int_equals:
612 case comparison::int_does_not_equal: 612 case comparison::int_does_not_equal:
613 case comparison::int_is_at_least: 613 case comparison::int_is_at_least:
@@ -627,10 +627,10 @@ namespace verbly {
627 throw std::invalid_argument("Incorrect constructor for given comparison"); 627 throw std::invalid_argument("Incorrect constructor for given comparison");
628 } 628 }
629 } 629 }
630 630
631 break; 631 break;
632 } 632 }
633 633
634 case field::type::hierarchal_join: 634 case field::type::hierarchal_join:
635 { 635 {
636 switch (filterType) 636 switch (filterType)
@@ -641,10 +641,10 @@ namespace verbly {
641 new(&singleton_.filterField) field(std::move(joinOn)); 641 new(&singleton_.filterField) field(std::move(joinOn));
642 singleton_.filterType = filterType; 642 singleton_.filterType = filterType;
643 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getObject()))); 643 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getObject())));
644 644
645 break; 645 break;
646 } 646 }
647 647
648 case comparison::int_equals: 648 case comparison::int_equals:
649 case comparison::int_does_not_equal: 649 case comparison::int_does_not_equal:
650 case comparison::int_is_at_least: 650 case comparison::int_is_at_least:
@@ -664,10 +664,10 @@ namespace verbly {
664 throw std::invalid_argument("Incorrect constructor for given comparison"); 664 throw std::invalid_argument("Incorrect constructor for given comparison");
665 } 665 }
666 } 666 }
667 667
668 break; 668 break;
669 } 669 }
670 670
671 case field::type::undefined: 671 case field::type::undefined:
672 case field::type::string: 672 case field::type::string:
673 case field::type::integer: 673 case field::type::integer:
@@ -677,7 +677,7 @@ namespace verbly {
677 } 677 }
678 } 678 }
679 } 679 }
680 680
681 field filter::getField() const 681 field filter::getField() const
682 { 682 {
683 if (type_ == type::singleton) 683 if (type_ == type::singleton)
@@ -687,7 +687,7 @@ namespace verbly {
687 throw std::domain_error("This filter does not have a field"); 687 throw std::domain_error("This filter does not have a field");
688 } 688 }
689 } 689 }
690 690
691 filter::comparison filter::getComparison() const 691 filter::comparison filter::getComparison() const
692 { 692 {
693 if (type_ == type::singleton) 693 if (type_ == type::singleton)
@@ -697,7 +697,7 @@ namespace verbly {
697 throw std::domain_error("This filter does not have a comparison"); 697 throw std::domain_error("This filter does not have a comparison");
698 } 698 }
699 } 699 }
700 700
701 filter filter::getJoinCondition() const 701 filter filter::getJoinCondition() const
702 { 702 {
703 if (type_ == type::singleton) 703 if (type_ == type::singleton)
@@ -711,7 +711,7 @@ namespace verbly {
711 { 711 {
712 return *singleton_.join; 712 return *singleton_.join;
713 } 713 }
714 714
715 case comparison::string_equals: 715 case comparison::string_equals:
716 case comparison::string_does_not_equal: 716 case comparison::string_does_not_equal:
717 case comparison::string_is_like: 717 case comparison::string_is_like:
@@ -733,7 +733,7 @@ namespace verbly {
733 throw std::domain_error("This filter does not have a join condition"); 733 throw std::domain_error("This filter does not have a join condition");
734 } 734 }
735 } 735 }
736 736
737 std::string filter::getStringArgument() const 737 std::string filter::getStringArgument() const
738 { 738 {
739 if (type_ == type::singleton) 739 if (type_ == type::singleton)
@@ -747,7 +747,7 @@ namespace verbly {
747 { 747 {
748 return singleton_.stringValue; 748 return singleton_.stringValue;
749 } 749 }
750 750
751 case comparison::int_equals: 751 case comparison::int_equals:
752 case comparison::int_does_not_equal: 752 case comparison::int_does_not_equal:
753 case comparison::int_is_at_least: 753 case comparison::int_is_at_least:
@@ -769,7 +769,7 @@ namespace verbly {
769 throw std::domain_error("This filter does not have a string argument"); 769 throw std::domain_error("This filter does not have a string argument");
770 } 770 }
771 } 771 }
772 772
773 int filter::getIntegerArgument() const 773 int filter::getIntegerArgument() const
774 { 774 {
775 if (type_ == type::singleton) 775 if (type_ == type::singleton)
@@ -785,7 +785,7 @@ namespace verbly {
785 { 785 {
786 return singleton_.intValue; 786 return singleton_.intValue;
787 } 787 }
788 788
789 case comparison::string_equals: 789 case comparison::string_equals:
790 case comparison::string_does_not_equal: 790 case comparison::string_does_not_equal:
791 case comparison::string_is_like: 791 case comparison::string_is_like:
@@ -805,7 +805,7 @@ namespace verbly {
805 throw std::domain_error("This filter does not have an integer argument"); 805 throw std::domain_error("This filter does not have an integer argument");
806 } 806 }
807 } 807 }
808 808
809 bool filter::getBooleanArgument() const 809 bool filter::getBooleanArgument() const
810 { 810 {
811 if ((type_ == type::singleton) && (singleton_.filterType == comparison::boolean_equals)) 811 if ((type_ == type::singleton) && (singleton_.filterType == comparison::boolean_equals))
@@ -815,13 +815,13 @@ namespace verbly {
815 throw std::domain_error("This filter does not have a boolean argument"); 815 throw std::domain_error("This filter does not have a boolean argument");
816 } 816 }
817 } 817 }
818 818
819 filter::filter(bool orlogic) : type_(type::group) 819 filter::filter(bool orlogic) : type_(type::group)
820 { 820 {
821 new(&group_.children) std::list<filter>(); 821 new(&group_.children) std::list<filter>();
822 group_.orlogic = orlogic; 822 group_.orlogic = orlogic;
823 } 823 }
824 824
825 bool filter::getOrlogic() const 825 bool filter::getOrlogic() const
826 { 826 {
827 if (type_ == type::group) 827 if (type_ == type::group)
@@ -831,27 +831,27 @@ namespace verbly {
831 throw std::domain_error("This filter is not a group filter"); 831 throw std::domain_error("This filter is not a group filter");
832 } 832 }
833 } 833 }
834 834
835 filter filter::operator+(filter condition) const 835 filter filter::operator+(filter condition) const
836 { 836 {
837 filter result(*this); 837 filter result(*this);
838 result += std::move(condition); 838 result += std::move(condition);
839 839
840 return result; 840 return result;
841 } 841 }
842 842
843 filter& filter::operator+=(filter condition) 843 filter& filter::operator+=(filter condition)
844 { 844 {
845 if (type_ == type::group) 845 if (type_ == type::group)
846 { 846 {
847 group_.children.push_back(std::move(condition)); 847 group_.children.push_back(std::move(condition));
848 848
849 return *this; 849 return *this;
850 } else { 850 } else {
851 throw std::domain_error("Children can only be added to group filters"); 851 throw std::domain_error("Children can only be added to group filters");
852 } 852 }
853 } 853 }
854 854
855 filter::const_iterator filter::begin() const 855 filter::const_iterator filter::begin() const
856 { 856 {
857 if (type_ == type::group) 857 if (type_ == type::group)
@@ -861,7 +861,7 @@ namespace verbly {
861 throw std::domain_error("This filter has no children"); 861 throw std::domain_error("This filter has no children");
862 } 862 }
863 } 863 }
864 864
865 filter::const_iterator filter::end() const 865 filter::const_iterator filter::end() const
866 { 866 {
867 if (type_ == type::group) 867 if (type_ == type::group)
@@ -880,7 +880,7 @@ namespace verbly {
880 { 880 {
881 return {}; 881 return {};
882 } 882 }
883 883
884 case type::singleton: 884 case type::singleton:
885 { 885 {
886 switch (singleton_.filterType) 886 switch (singleton_.filterType)
@@ -889,113 +889,113 @@ namespace verbly {
889 { 889 {
890 return filter(singleton_.filterField, comparison::int_does_not_equal, singleton_.intValue); 890 return filter(singleton_.filterField, comparison::int_does_not_equal, singleton_.intValue);
891 } 891 }
892 892
893 case comparison::int_does_not_equal: 893 case comparison::int_does_not_equal:
894 { 894 {
895 return filter(singleton_.filterField, comparison::int_equals, singleton_.intValue); 895 return filter(singleton_.filterField, comparison::int_equals, singleton_.intValue);
896 } 896 }
897 897
898 case comparison::int_is_at_least: 898 case comparison::int_is_at_least:
899 { 899 {
900 return filter(singleton_.filterField, comparison::int_is_less_than, singleton_.intValue); 900 return filter(singleton_.filterField, comparison::int_is_less_than, singleton_.intValue);
901 } 901 }
902 902
903 case comparison::int_is_greater_than: 903 case comparison::int_is_greater_than:
904 { 904 {
905 return filter(singleton_.filterField, comparison::int_is_at_most, singleton_.intValue); 905 return filter(singleton_.filterField, comparison::int_is_at_most, singleton_.intValue);
906 } 906 }
907 907
908 case comparison::int_is_at_most: 908 case comparison::int_is_at_most:
909 { 909 {
910 return filter(singleton_.filterField, comparison::int_is_greater_than, singleton_.intValue); 910 return filter(singleton_.filterField, comparison::int_is_greater_than, singleton_.intValue);
911 } 911 }
912 912
913 case comparison::int_is_less_than: 913 case comparison::int_is_less_than:
914 { 914 {
915 return filter(singleton_.filterField, comparison::int_is_at_least, singleton_.intValue); 915 return filter(singleton_.filterField, comparison::int_is_at_least, singleton_.intValue);
916 } 916 }
917 917
918 case comparison::boolean_equals: 918 case comparison::boolean_equals:
919 { 919 {
920 return filter(singleton_.filterField, comparison::boolean_equals, !singleton_.boolValue); 920 return filter(singleton_.filterField, comparison::boolean_equals, !singleton_.boolValue);
921 } 921 }
922 922
923 case comparison::string_equals: 923 case comparison::string_equals:
924 { 924 {
925 return filter(singleton_.filterField, comparison::string_does_not_equal, singleton_.stringValue); 925 return filter(singleton_.filterField, comparison::string_does_not_equal, singleton_.stringValue);
926 } 926 }
927 927
928 case comparison::string_does_not_equal: 928 case comparison::string_does_not_equal:
929 { 929 {
930 return filter(singleton_.filterField, comparison::string_equals, singleton_.stringValue); 930 return filter(singleton_.filterField, comparison::string_equals, singleton_.stringValue);
931 } 931 }
932 932
933 case comparison::string_is_like: 933 case comparison::string_is_like:
934 { 934 {
935 return filter(singleton_.filterField, comparison::string_is_not_like, singleton_.stringValue); 935 return filter(singleton_.filterField, comparison::string_is_not_like, singleton_.stringValue);
936 } 936 }
937 937
938 case comparison::string_is_not_like: 938 case comparison::string_is_not_like:
939 { 939 {
940 return filter(singleton_.filterField, comparison::string_is_like, singleton_.stringValue); 940 return filter(singleton_.filterField, comparison::string_is_like, singleton_.stringValue);
941 } 941 }
942 942
943 case comparison::is_null: 943 case comparison::is_null:
944 { 944 {
945 return filter(singleton_.filterField, comparison::is_not_null); 945 return filter(singleton_.filterField, comparison::is_not_null);
946 } 946 }
947 947
948 case comparison::is_not_null: 948 case comparison::is_not_null:
949 { 949 {
950 return filter(singleton_.filterField, comparison::is_null); 950 return filter(singleton_.filterField, comparison::is_null);
951 } 951 }
952 952
953 case comparison::matches: 953 case comparison::matches:
954 { 954 {
955 return filter(singleton_.filterField, comparison::does_not_match, *singleton_.join); 955 return filter(singleton_.filterField, comparison::does_not_match, *singleton_.join);
956 } 956 }
957 957
958 case comparison::does_not_match: 958 case comparison::does_not_match:
959 { 959 {
960 return filter(singleton_.filterField, comparison::matches, *singleton_.join); 960 return filter(singleton_.filterField, comparison::matches, *singleton_.join);
961 } 961 }
962 962
963 case comparison::hierarchally_matches: 963 case comparison::hierarchally_matches:
964 { 964 {
965 return filter(singleton_.filterField, comparison::does_not_hierarchally_match, *singleton_.join); 965 return filter(singleton_.filterField, comparison::does_not_hierarchally_match, *singleton_.join);
966 } 966 }
967 967
968 case comparison::does_not_hierarchally_match: 968 case comparison::does_not_hierarchally_match:
969 { 969 {
970 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join); 970 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join);
971 } 971 }
972 } 972 }
973 } 973 }
974 974
975 case type::group: 975 case type::group:
976 { 976 {
977 filter result(!group_.orlogic); 977 filter result(!group_.orlogic);
978 978
979 for (const filter& child : group_.children) 979 for (const filter& child : group_.children)
980 { 980 {
981 result += !child; 981 result += !child;
982 } 982 }
983 983
984 return result; 984 return result;
985 } 985 }
986 } 986 }
987 } 987 }
988 988
989 filter& filter::operator&=(filter condition) 989 filter& filter::operator&=(filter condition)
990 { 990 {
991 return (*this = (*this && std::move(condition))); 991 return (*this = (*this && std::move(condition)));
992 } 992 }
993 993
994 filter& filter::operator|=(filter condition) 994 filter& filter::operator|=(filter condition)
995 { 995 {
996 return (*this = (*this || std::move(condition))); 996 return (*this = (*this || std::move(condition)));
997 } 997 }
998 998
999 filter filter::operator&&(filter condition) const 999 filter filter::operator&&(filter condition) const
1000 { 1000 {
1001 switch (type_) 1001 switch (type_)
@@ -1004,16 +1004,16 @@ namespace verbly {
1004 { 1004 {
1005 return condition; 1005 return condition;
1006 } 1006 }
1007 1007
1008 case type::singleton: 1008 case type::singleton:
1009 { 1009 {
1010 filter result(false); 1010 filter result(false);
1011 result.group_.children.push_back(*this); 1011 result.group_.children.push_back(*this);
1012 result.group_.children.push_back(std::move(condition)); 1012 result.group_.children.push_back(std::move(condition));
1013 1013
1014 return result; 1014 return result;
1015 } 1015 }
1016 1016
1017 case type::group: 1017 case type::group:
1018 { 1018 {
1019 if (group_.orlogic) 1019 if (group_.orlogic)
@@ -1026,13 +1026,13 @@ namespace verbly {
1026 } else { 1026 } else {
1027 filter result(*this); 1027 filter result(*this);
1028 result.group_.children.push_back(std::move(condition)); 1028 result.group_.children.push_back(std::move(condition));
1029 1029
1030 return result; 1030 return result;
1031 } 1031 }
1032 } 1032 }
1033 } 1033 }
1034 } 1034 }
1035 1035
1036 filter filter::operator||(filter condition) const 1036 filter filter::operator||(filter condition) const
1037 { 1037 {
1038 switch (type_) 1038 switch (type_)
@@ -1041,16 +1041,16 @@ namespace verbly {
1041 { 1041 {
1042 return condition; 1042 return condition;
1043 } 1043 }
1044 1044
1045 case type::singleton: 1045 case type::singleton:
1046 { 1046 {
1047 filter result(true); 1047 filter result(true);
1048 result.group_.children.push_back(*this); 1048 result.group_.children.push_back(*this);
1049 result.group_.children.push_back(std::move(condition)); 1049 result.group_.children.push_back(std::move(condition));
1050 1050
1051 return result; 1051 return result;
1052 } 1052 }
1053 1053
1054 case type::group: 1054 case type::group:
1055 { 1055 {
1056 if (!group_.orlogic) 1056 if (!group_.orlogic)
@@ -1063,13 +1063,13 @@ namespace verbly {
1063 } else { 1063 } else {
1064 filter result(*this); 1064 filter result(*this);
1065 result.group_.children.push_back(std::move(condition)); 1065 result.group_.children.push_back(std::move(condition));
1066 1066
1067 return result; 1067 return result;
1068 } 1068 }
1069 } 1069 }
1070 } 1070 }
1071 } 1071 }
1072 1072
1073 filter filter::normalize(object context) const 1073 filter filter::normalize(object context) const
1074 { 1074 {
1075 { 1075 {
@@ -1096,7 +1096,7 @@ namespace verbly {
1096 // recontexualization. 1096 // recontexualization.
1097 return *this; 1097 return *this;
1098 } 1098 }
1099 1099
1100 case object::notion: 1100 case object::notion:
1101 { 1101 {
1102 switch (singleton_.filterField.getObject()) 1102 switch (singleton_.filterField.getObject())
@@ -1106,7 +1106,7 @@ namespace verbly {
1106 { 1106 {
1107 return *this; 1107 return *this;
1108 } 1108 }
1109 1109
1110 case object::word: 1110 case object::word:
1111 case object::group: 1111 case object::group:
1112 case object::frame: 1112 case object::frame:
@@ -1118,7 +1118,7 @@ namespace verbly {
1118 } 1118 }
1119 } 1119 }
1120 } 1120 }
1121 1121
1122 case object::word: 1122 case object::word:
1123 { 1123 {
1124 switch (singleton_.filterField.getObject()) 1124 switch (singleton_.filterField.getObject())
@@ -1127,19 +1127,19 @@ namespace verbly {
1127 { 1127 {
1128 return (verbly::word::notion %= *this); 1128 return (verbly::word::notion %= *this);
1129 } 1129 }
1130 1130
1131 case object::undefined: 1131 case object::undefined:
1132 case object::word: 1132 case object::word:
1133 { 1133 {
1134 return *this; 1134 return *this;
1135 } 1135 }
1136 1136
1137 case object::group: 1137 case object::group:
1138 case object::frame: 1138 case object::frame:
1139 { 1139 {
1140 return (verbly::word::group %= *this); 1140 return (verbly::word::group %= *this);
1141 } 1141 }
1142 1142
1143 case object::lemma: 1143 case object::lemma:
1144 case object::form: 1144 case object::form:
1145 case object::pronunciation: 1145 case object::pronunciation:
@@ -1147,7 +1147,7 @@ namespace verbly {
1147 return (verbly::word::lemma %= *this); 1147 return (verbly::word::lemma %= *this);
1148 } 1148 }
1149 } 1149 }
1150 1150
1151 case object::group: 1151 case object::group:
1152 { 1152 {
1153 switch (singleton_.filterField.getObject()) 1153 switch (singleton_.filterField.getObject())
@@ -1157,7 +1157,7 @@ namespace verbly {
1157 { 1157 {
1158 return *this; 1158 return *this;
1159 } 1159 }
1160 1160
1161 case object::notion: 1161 case object::notion:
1162 case object::word: 1162 case object::word:
1163 case object::lemma: 1163 case object::lemma:
@@ -1166,14 +1166,14 @@ namespace verbly {
1166 { 1166 {
1167 return (verbly::group::word %= *this); 1167 return (verbly::group::word %= *this);
1168 } 1168 }
1169 1169
1170 case object::frame: 1170 case object::frame:
1171 { 1171 {
1172 return (verbly::group::frame %= *this); 1172 return (verbly::group::frame %= *this);
1173 } 1173 }
1174 } 1174 }
1175 } 1175 }
1176 1176
1177 case object::frame: 1177 case object::frame:
1178 { 1178 {
1179 switch (singleton_.filterField.getObject()) 1179 switch (singleton_.filterField.getObject())
@@ -1183,7 +1183,7 @@ namespace verbly {
1183 { 1183 {
1184 return *this; 1184 return *this;
1185 } 1185 }
1186 1186
1187 case object::notion: 1187 case object::notion:
1188 case object::word: 1188 case object::word:
1189 case object::group: 1189 case object::group:
@@ -1195,7 +1195,7 @@ namespace verbly {
1195 } 1195 }
1196 } 1196 }
1197 } 1197 }
1198 1198
1199 case object::lemma: 1199 case object::lemma:
1200 { 1200 {
1201 switch (singleton_.filterField.getObject()) 1201 switch (singleton_.filterField.getObject())
@@ -1207,7 +1207,7 @@ namespace verbly {
1207 { 1207 {
1208 return verbly::lemma::word %= *this; 1208 return verbly::lemma::word %= *this;
1209 } 1209 }
1210 1210
1211 case object::undefined: 1211 case object::undefined:
1212 case object::lemma: 1212 case object::lemma:
1213 { 1213 {
@@ -1221,7 +1221,7 @@ namespace verbly {
1221 } 1221 }
1222 } 1222 }
1223 } 1223 }
1224 1224
1225 case object::form: 1225 case object::form:
1226 { 1226 {
1227 switch (singleton_.filterField.getObject()) 1227 switch (singleton_.filterField.getObject())
@@ -1234,7 +1234,7 @@ namespace verbly {
1234 { 1234 {
1235 return verbly::form::lemma(inflection::base) %= *this; 1235 return verbly::form::lemma(inflection::base) %= *this;
1236 } 1236 }
1237 1237
1238 case object::undefined: 1238 case object::undefined:
1239 case object::form: 1239 case object::form:
1240 { 1240 {
@@ -1247,7 +1247,7 @@ namespace verbly {
1247 } 1247 }
1248 } 1248 }
1249 } 1249 }
1250 1250
1251 case object::pronunciation: 1251 case object::pronunciation:
1252 { 1252 {
1253 switch (singleton_.filterField.getObject()) 1253 switch (singleton_.filterField.getObject())
@@ -1261,7 +1261,7 @@ namespace verbly {
1261 { 1261 {
1262 return verbly::pronunciation::form %= *this; 1262 return verbly::pronunciation::form %= *this;
1263 } 1263 }
1264 1264
1265 case object::undefined: 1265 case object::undefined:
1266 case object::pronunciation: 1266 case object::pronunciation:
1267 { 1267 {
@@ -1276,7 +1276,8 @@ namespace verbly {
1276 case type::group: 1276 case type::group:
1277 { 1277 {
1278 filter result(group_.orlogic); 1278 filter result(group_.orlogic);
1279 std::map<field, filter> joins; 1279 std::map<field, filter> positiveJoins;
1280 std::map<field, filter> negativeJoins;
1280 1281
1281 for (const filter& child : group_.children) 1282 for (const filter& child : group_.children)
1282 { 1283 {
@@ -1291,28 +1292,28 @@ namespace verbly {
1291 { 1292 {
1292 case comparison::matches: 1293 case comparison::matches:
1293 { 1294 {
1294 if (!joins.count(normalized.singleton_.filterField)) 1295 if (!positiveJoins.count(normalized.singleton_.filterField))
1295 { 1296 {
1296 joins[normalized.getField()] = filter(group_.orlogic); 1297 positiveJoins[normalized.getField()] = filter(group_.orlogic);
1297 } 1298 }
1298 1299
1299 joins.at(normalized.getField()) += std::move(*normalized.singleton_.join); 1300 positiveJoins.at(normalized.getField()) += std::move(*normalized.singleton_.join);
1300 1301
1301 break; 1302 break;
1302 } 1303 }
1303 1304
1304 case comparison::does_not_match: 1305 case comparison::does_not_match:
1305 { 1306 {
1306 if (!joins.count(normalized.singleton_.filterField)) 1307 if (!negativeJoins.count(normalized.singleton_.filterField))
1307 { 1308 {
1308 joins[normalized.getField()] = filter(group_.orlogic); 1309 negativeJoins[normalized.getField()] = filter(group_.orlogic);
1309 } 1310 }
1310 1311
1311 joins.at(normalized.getField()) += !*normalized.singleton_.join; 1312 negativeJoins.at(normalized.getField()) += std::move(*normalized.singleton_.join);
1312 1313
1313 break; 1314 break;
1314 } 1315 }
1315 1316
1316 case comparison::int_equals: 1317 case comparison::int_equals:
1317 case comparison::int_does_not_equal: 1318 case comparison::int_does_not_equal:
1318 case comparison::int_is_at_least: 1319 case comparison::int_is_at_least:
@@ -1330,25 +1331,25 @@ namespace verbly {
1330 case comparison::does_not_hierarchally_match: 1331 case comparison::does_not_hierarchally_match:
1331 { 1332 {
1332 result += std::move(normalized); 1333 result += std::move(normalized);
1333 1334
1334 break; 1335 break;
1335 } 1336 }
1336 } 1337 }
1337 1338
1338 break; 1339 break;
1339 } 1340 }
1340 1341
1341 case type::group: 1342 case type::group:
1342 case type::empty: 1343 case type::empty:
1343 { 1344 {
1344 result += std::move(normalized); 1345 result += std::move(normalized);
1345 1346
1346 break; 1347 break;
1347 } 1348 }
1348 } 1349 }
1349 } 1350 }
1350 1351
1351 for (auto& mapping : joins) 1352 for (auto& mapping : positiveJoins)
1352 { 1353 {
1353 const field& joinOn = mapping.first; 1354 const field& joinOn = mapping.first;
1354 filter& joinCondition = mapping.second; 1355 filter& joinCondition = mapping.second;
@@ -1356,6 +1357,14 @@ namespace verbly {
1356 result += (joinOn %= joinCondition.normalize(joinOn.getJoinObject())); 1357 result += (joinOn %= joinCondition.normalize(joinOn.getJoinObject()));
1357 } 1358 }
1358 1359
1360 for (auto& mapping : negativeJoins)
1361 {
1362 const field& joinOn = mapping.first;
1363 filter& joinCondition = mapping.second;
1364
1365 result += !(joinOn %= joinCondition.normalize(joinOn.getJoinObject()));
1366 }
1367
1359 return result; 1368 return result;
1360 } 1369 }
1361 } 1370 }