summary refs log tree commit diff stats
path: root/lib/noun_query.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-01-16 18:02:50 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-01-16 18:02:50 -0500
commit6746da6edd7d9d50efe374eabbb79a3cac882d81 (patch)
treeff20917e08b08d36b9541c1371106596e7bec442 /lib/noun_query.cpp
parent4af7e55733098ca42f75a4ffaca1b0f6bab4dd36 (diff)
downloadverbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.tar.gz
verbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.tar.bz2
verbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.zip
Started structural rewrite
The new object structure was designed to build on the existing WordNet
structure, while also adding in all of the data that we get from other sources.
More information about this can be found on the project wiki.

The generator has already been completely rewritten to generate a
datafile that uses the new structure. In addition, a number of indexes
are created, which does double the size of the datafile, but also allows
for much faster lookups. Finally, the new generator is written modularly
and is a lot more readable than the old one.

The verbly interface to the new object structure has mostly been
completed, but has not been tested fully. There is a completely new
search API which utilizes a lot of operator overloading; documentation
on how to use it should go up at some point.

Token processing and verb frames are currently unimplemented. Source for
these have been left in the repository for now.
Diffstat (limited to 'lib/noun_query.cpp')
-rw-r--r--lib/noun_query.cpp2013
1 files changed, 0 insertions, 2013 deletions
diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp deleted file mode 100644 index 8648227..0000000 --- a/lib/noun_query.cpp +++ /dev/null
@@ -1,2013 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 noun_query::noun_query(const data& _data) : _data(_data)
6 {
7
8 }
9
10 noun_query& noun_query::limit(int _limit)
11 {
12 if ((_limit > 0) || (_limit == unlimited))
13 {
14 this->_limit = _limit;
15 }
16
17 return *this;
18 }
19
20 noun_query& noun_query::random()
21 {
22 this->_random = true;
23
24 return *this;
25 }
26
27 noun_query& noun_query::except(const noun& _word)
28 {
29 _except.push_back(_word);
30
31 return *this;
32 }
33
34 noun_query& noun_query::rhymes_with(const word& _word)
35 {
36 for (auto rhyme : _word.get_rhymes())
37 {
38 _rhymes.push_back(rhyme);
39 }
40
41 if (dynamic_cast<const noun*>(&_word) != nullptr)
42 {
43 _except.push_back(dynamic_cast<const noun&>(_word));
44 }
45
46 return *this;
47 }
48
49 noun_query& noun_query::rhymes_with(rhyme _r)
50 {
51 _rhymes.push_back(_r);
52
53 return *this;
54 }
55
56 noun_query& noun_query::has_pronunciation()
57 {
58 this->_has_prn = true;
59
60 return *this;
61 }
62
63 noun_query& noun_query::has_rhyming_noun()
64 {
65 _has_rhyming_noun = true;
66
67 return *this;
68 }
69
70 noun_query& noun_query::has_rhyming_adjective()
71 {
72 _has_rhyming_adjective = true;
73
74 return *this;
75 }
76
77 noun_query& noun_query::has_rhyming_adverb()
78 {
79 _has_rhyming_adverb = true;
80
81 return *this;
82 }
83
84 noun_query& noun_query::has_rhyming_verb()
85 {
86 _has_rhyming_verb = true;
87
88 return *this;
89 }
90
91 noun_query& noun_query::with_stress(filter<std::vector<bool>> _arg)
92 {
93 _stress = _arg;
94
95 return *this;
96 }
97
98 noun_query& noun_query::with_singular_form(std::string _arg)
99 {
100 _with_singular_form.push_back(_arg);
101
102 return *this;
103 }
104
105 noun_query& noun_query::with_prefix(filter<std::string> _f)
106 {
107 _f.clean();
108 _with_prefix = _f;
109
110 return *this;
111 }
112
113 noun_query& noun_query::with_suffix(filter<std::string> _f)
114 {
115 _f.clean();
116 _with_suffix = _f;
117
118 return *this;
119 }
120
121 noun_query& noun_query::requires_plural_form()
122 {
123 _requires_plural_form = true;
124
125 return *this;
126 }
127
128 noun_query& noun_query::with_complexity(int _arg)
129 {
130 _with_complexity = _arg;
131
132 return *this;
133 }
134
135 noun_query& noun_query::is_hypernym()
136 {
137 _is_hypernym = true;
138
139 return *this;
140 }
141
142 noun_query& noun_query::hypernym_of(filter<noun> _f)
143 {
144 _f.clean();
145 _hypernym_of = _f;
146
147 return *this;
148 }
149
150 noun_query& noun_query::full_hypernym_of(filter<noun> _f)
151 {
152 _f.clean();
153 _full_hypernym_of = _f;
154
155 return *this;
156 }
157
158 noun_query& noun_query::is_hyponym()
159 {
160 _is_hyponym = true;
161
162 return *this;
163 }
164
165 noun_query& noun_query::hyponym_of(filter<noun> _f)
166 {
167 _f.clean();
168 _hyponym_of = _f;
169
170 return *this;
171 }
172
173 noun_query& noun_query::full_hyponym_of(filter<noun> _f)
174 {
175 _f.clean();
176 _full_hyponym_of = _f;
177
178 return *this;
179 }
180
181 noun_query& noun_query::is_part_meronym()
182 {
183 _is_part_meronym = true;
184
185 return *this;
186 }
187
188 noun_query& noun_query::part_meronym_of(filter<noun> _f)
189 {
190 _f.clean();
191 _part_meronym_of = _f;
192
193 return *this;
194 }
195
196 noun_query& noun_query::full_part_meronym_of(filter<noun> _f)
197 {
198 _f.clean();
199 _full_part_meronym_of = _f;
200
201 return *this;
202 }
203
204 noun_query& noun_query::is_part_holonym()
205 {
206 _is_part_holonym = true;
207
208 return *this;
209 }
210
211 noun_query& noun_query::part_holonym_of(filter<noun> _f)
212 {
213 _f.clean();
214 _part_holonym_of = _f;
215
216 return *this;
217 }
218
219 noun_query& noun_query::full_part_holonym_of(filter<noun> _f)
220 {
221 _f.clean();
222 _full_part_holonym_of = _f;
223
224 return *this;
225 }
226
227 noun_query& noun_query::is_substance_meronym()
228 {
229 _is_substance_meronym = true;
230
231 return *this;
232 }
233
234 noun_query& noun_query::substance_meronym_of(filter<noun> _f)
235 {
236 _f.clean();
237 _substance_meronym_of = _f;
238
239 return *this;
240 }
241
242 noun_query& noun_query::full_substance_meronym_of(filter<noun> _f)
243 {
244 _f.clean();
245 _full_substance_meronym_of = _f;
246
247 return *this;
248 }
249
250 noun_query& noun_query::is_substance_holonym()
251 {
252 _is_substance_holonym = true;
253
254 return *this;
255 }
256
257 noun_query& noun_query::substance_holonym_of(filter<noun> _f)
258 {
259 _f.clean();
260 _substance_holonym_of = _f;
261
262 return *this;
263 }
264
265 noun_query& noun_query::full_substance_holonym_of(filter<noun> _f)
266 {
267 _f.clean();
268 _full_substance_holonym_of = _f;
269
270 return *this;
271 }
272
273 noun_query& noun_query::is_member_meronym()
274 {
275 _is_member_meronym = true;
276
277 return *this;
278 }
279
280 noun_query& noun_query::member_meronym_of(filter<noun> _f)
281 {
282 _f.clean();
283 _member_meronym_of = _f;
284
285 return *this;
286 }
287
288 noun_query& noun_query::full_member_meronym_of(filter<noun> _f)
289 {
290 _f.clean();
291 _full_member_meronym_of = _f;
292
293 return *this;
294 }
295
296 noun_query& noun_query::is_member_holonym()
297 {
298 _is_member_holonym = true;
299
300 return *this;
301 }
302
303 noun_query& noun_query::member_holonym_of(filter<noun> _f)
304 {
305 _f.clean();
306 _member_holonym_of = _f;
307
308 return *this;
309 }
310
311 noun_query& noun_query::full_member_holonym_of(filter<noun> _f)
312 {
313 _f.clean();
314 _full_member_holonym_of = _f;
315
316 return *this;
317 }
318
319 noun_query& noun_query::is_proper()
320 {
321 _is_proper = true;
322
323 return *this;
324 }
325
326 noun_query& noun_query::is_not_proper()
327 {
328 _is_not_proper = true;
329
330 return *this;
331 }
332
333 noun_query& noun_query::is_instance()
334 {
335 _is_instance = true;
336
337 return *this;
338 }
339
340 noun_query& noun_query::instance_of(filter<noun> _f)
341 {
342 _f.clean();
343 _instance_of = _f;
344
345 return *this;
346 }
347
348 noun_query& noun_query::is_class()
349 {
350 _is_class = true;
351
352 return *this;
353 }
354
355 noun_query& noun_query::class_of(filter<noun> _f)
356 {
357 _f.clean();
358 _class_of = _f;
359
360 return *this;
361 }
362
363 noun_query& noun_query::has_synonyms()
364 {
365 _has_synonyms = true;
366
367 return *this;
368 }
369
370 noun_query& noun_query::synonym_of(filter<noun> _f)
371 {
372 _f.clean();
373 _synonym_of = _f;
374
375 return *this;
376 }
377
378 noun_query& noun_query::has_antonyms()
379 {
380 _has_antonyms = true;
381
382 return *this;
383 }
384
385 noun_query& noun_query::antonym_of(filter<noun> _f)
386 {
387 _f.clean();
388 _antonym_of = _f;
389
390 return *this;
391 }
392
393 noun_query& noun_query::has_pertainym()
394 {
395 _has_pertainym = true;
396
397 return *this;
398 }
399
400 noun_query& noun_query::anti_pertainym_of(filter<adjective> _f)
401 {
402 _f.clean();
403 _anti_pertainym_of = _f;
404
405 return *this;
406 }
407
408 noun_query& noun_query::is_attribute()
409 {
410 _is_attribute = true;
411
412 return *this;
413 }
414
415 noun_query& noun_query::attribute_of(filter<adjective> _f)
416 {
417 _f.clean();
418 _attribute_of = _f;
419
420 return *this;
421 }
422
423 noun_query& noun_query::at_least_n_images(int _arg)
424 {
425 _at_least_n_images = _arg;
426
427 return *this;
428 }
429
430 noun_query& noun_query::with_wnid(int _arg)
431 {
432 _with_wnid.insert(_arg);
433
434 return *this;
435 }
436
437 /*
438 noun_query& noun_query::derived_from(const word& _w)
439 {
440 if (dynamic_cast<const adjective*>(&_w) != nullptr)
441 {
442 _derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
443 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
444 {
445 _derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
446 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
447 {
448 _derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
449 }
450
451 return *this;
452 }
453
454 noun_query& noun_query::not_derived_from(const word& _w)
455 {
456 if (dynamic_cast<const adjective*>(&_w) != nullptr)
457 {
458 _not_derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
459 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
460 {
461 _not_derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
462 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
463 {
464 _not_derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
465 }
466
467 return *this;
468 }*/
469
470 std::list<noun> noun_query::run() const
471 {
472 std::stringstream construct;
473
474 if (!_full_hypernym_of.empty() || !_full_hyponym_of.empty() || !_full_part_meronym_of.empty() || !_full_part_holonym_of.empty() || !_full_substance_meronym_of.empty() || !_full_substance_holonym_of.empty() || !_full_member_meronym_of.empty() || !_full_member_holonym_of.empty())
475 {
476 construct << "WITH RECURSIVE ";
477
478 std::list<std::string> ctes;
479
480 for (auto hyponym : _full_hypernym_of.uniq_flatten())
481 {
482 ctes.push_back("hypernym_tree_" + std::to_string(hyponym._id) + " AS (SELECT hypernym_id FROM hypernymy WHERE hyponym_id = " + std::to_string(hyponym._id) + " UNION SELECT h.hypernym_id FROM hypernym_tree_" + std::to_string(hyponym._id) + " AS t INNER JOIN hypernymy AS h ON t.hypernym_id = h.hyponym_id)");
483 }
484
485 for (auto hypernym : _full_hyponym_of.uniq_flatten())
486 {
487 ctes.push_back("hyponym_tree_" + std::to_string(hypernym._id) + " AS (SELECT hyponym_id FROM hypernymy WHERE hypernym_id = " + std::to_string(hypernym._id) + " UNION SELECT h.hyponym_id FROM hyponym_tree_" + std::to_string(hypernym._id) + " AS t INNER JOIN hypernymy AS h ON t.hyponym_id = h.hypernym_id)");
488 }
489
490 for (auto holonym : _full_part_meronym_of.uniq_flatten())
491 {
492 ctes.push_back("part_meronym_tree_" + std::to_string(holonym._id) + " AS (SELECT meronym_id FROM part_meronymy WHERE holonym_id = " + std::to_string(holonym._id) + " UNION SELECT h.meronym_id FROM part_meronym_tree_" + std::to_string(holonym._id) + " AS t INNER JOIN part_meronymy AS h ON t.meronym_id = h.holonym_id)");
493 }
494
495 for (auto meronym : _full_part_holonym_of.uniq_flatten())
496 {
497 ctes.push_back("part_holonym_tree_" + std::to_string(meronym._id) + " AS (SELECT holonym_id FROM part_meronymy WHERE meronym_id = " + std::to_string(meronym._id) + " UNION SELECT h.holonym_id FROM part_holonym_tree_" + std::to_string(meronym._id) + " AS t INNER JOIN part_meronymy AS h ON t.holonym_id = h.meronym_id)");
498 }
499
500 for (auto holonym : _full_substance_meronym_of.uniq_flatten())
501 {
502 ctes.push_back("substance_meronym_tree_" + std::to_string(holonym._id) + " AS (SELECT meronym_id FROM substance_meronymy WHERE holonym_id = " + std::to_string(holonym._id) + " UNION SELECT h.meronym_id FROM substance_meronym_tree_" + std::to_string(holonym._id) + " AS t INNER JOIN substance_meronymy AS h ON t.meronym_id = h.holonym_id)");
503 }
504
505 for (auto meronym : _full_substance_holonym_of.uniq_flatten())
506 {
507 ctes.push_back("substance_holonym_tree_" + std::to_string(meronym._id) + " AS (SELECT holonym_id FROM substance_meronymy WHERE meronym_id = " + std::to_string(meronym._id) + " UNION SELECT h.holonym_id FROM substance_holonym_tree_" + std::to_string(meronym._id) + " AS t INNER JOIN substance_meronymy AS h ON t.holonym_id = h.meronym_id)");
508 }
509
510 for (auto holonym : _full_member_meronym_of.uniq_flatten())
511 {
512 ctes.push_back("member_meronym_tree_" + std::to_string(holonym._id) + " AS (SELECT meronym_id FROM member_meronymy WHERE holonym_id = " + std::to_string(holonym._id) + " UNION SELECT h.meronym_id FROM member_meronym_tree_" + std::to_string(holonym._id) + " AS t INNER JOIN member_meronymy AS h ON t.meronym_id = h.holonym_id)");
513 }
514
515 for (auto meronym : _full_member_holonym_of.uniq_flatten())
516 {
517 ctes.push_back("member_holonym_tree_" + std::to_string(meronym._id) + " AS (SELECT holonym_id FROM member_meronymy WHERE meronym_id = " + std::to_string(meronym._id) + " UNION SELECT h.holonym_id FROM member_holonym_tree_" + std::to_string(meronym._id) + " AS t INNER JOIN member_meronymy AS h ON t.holonym_id = h.meronym_id)");
518 }
519
520 construct << verbly::implode(std::begin(ctes), std::end(ctes), ", ");
521 construct << " ";
522 }
523
524 construct << "SELECT noun_id, singular, plural, wnid FROM nouns";
525 std::list<std::string> conditions;
526 std::list<binding> bindings;
527
528 if (_has_prn)
529 {
530 conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)");
531 }
532
533 if (!_rhymes.empty())
534 {
535 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
536 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
537 conditions.push_back(cond);
538
539 for (auto rhy : _rhymes)
540 {
541 bindings.emplace_back(rhy.get_prerhyme());
542 bindings.emplace_back(rhy.get_rhyme());
543 }
544 }
545
546 if (_has_rhyming_noun)
547 {
548 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.noun_id != curp.noun_id)");
549 }
550
551 if (_has_rhyming_adjective)
552 {
553 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
554 }
555
556 if (_has_rhyming_adverb)
557 {
558 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
559 }
560
561 if (_has_rhyming_verb)
562 {
563 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
564 }
565
566 if (!_stress.empty())
567 {
568 std::stringstream cond;
569 if (_stress.get_notlogic())
570 {
571 cond << "noun_id NOT IN";
572 } else {
573 cond << "noun_id IN";
574 }
575
576 cond << "(SELECT noun_id FROM noun_pronunciations WHERE ";
577
578 std::function<std::string (filter<std::vector<bool>>, bool)> recur = [&] (filter<std::vector<bool>> f, bool notlogic) -> std::string {
579 switch (f.get_type())
580 {
581 case filter<std::vector<bool>>::type::singleton:
582 {
583 std::ostringstream _val;
584 for (auto syl : f.get_elem())
585 {
586 if (syl)
587 {
588 _val << "1";
589 } else {
590 _val << "0";
591 }
592 }
593
594 bindings.emplace_back(_val.str());
595
596 if (notlogic == f.get_notlogic())
597 {
598 return "stress = ?";
599 } else {
600 return "stress != ?";
601 }
602 }
603
604 case filter<std::vector<bool>>::type::group:
605 {
606 bool truelogic = notlogic != f.get_notlogic();
607
608 std::list<std::string> clauses;
609 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::vector<bool>> f2) {
610 return recur(f2, truelogic);
611 });
612
613 if (truelogic == f.get_orlogic())
614 {
615 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
616 } else {
617 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
618 }
619 }
620 }
621 };
622
623 cond << recur(_stress, _stress.get_notlogic());
624 cond << ")";
625 conditions.push_back(cond.str());
626 }
627
628 for (auto except : _except)
629 {
630 conditions.push_back("noun_id != ?");
631 bindings.emplace_back(except._id);
632 }
633
634 if (!_with_singular_form.empty())
635 {
636 std::list<std::string> clauses(_with_singular_form.size(), "singular = ?");
637 std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
638 conditions.push_back(cond);
639
640 for (auto form : _with_singular_form)
641 {
642 bindings.emplace_back(form);
643 }
644 }
645
646 if (_requires_plural_form)
647 {
648 conditions.push_back("plural IS NOT NULL");
649 }
650
651 if (!_with_prefix.empty())
652 {
653 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
654 switch (f.get_type())
655 {
656 case filter<std::string>::type::singleton:
657 {
658 bindings.emplace_back(f.get_elem() + "%");
659
660 if (notlogic == f.get_notlogic())
661 {
662 return "singular LIKE ?";
663 } else {
664 return "singular NOT LIKE ?";
665 }
666 }
667
668 case filter<std::string>::type::group:
669 {
670 bool truelogic = notlogic != f.get_notlogic();
671
672 std::list<std::string> clauses;
673 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
674 return recur(f2, truelogic);
675 });
676
677 if (truelogic == f.get_orlogic())
678 {
679 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
680 } else {
681 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
682 }
683 }
684 }
685 };
686
687 conditions.push_back(recur(_with_prefix, false));
688 }
689
690 if (!_with_suffix.empty())
691 {
692 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
693 switch (f.get_type())
694 {
695 case filter<std::string>::type::singleton:
696 {
697 bindings.emplace_back("%" + f.get_elem());
698
699 if (notlogic == f.get_notlogic())
700 {
701 return "singular LIKE ?";
702 } else {
703 return "singular NOT LIKE ?";
704 }
705 }
706
707 case filter<std::string>::type::group:
708 {
709 bool truelogic = notlogic != f.get_notlogic();
710
711 std::list<std::string> clauses;
712 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
713 return recur(f2, truelogic);
714 });
715
716 if (truelogic == f.get_orlogic())
717 {
718 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
719 } else {
720 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
721 }
722 }
723 }
724 };
725
726 conditions.push_back(recur(_with_suffix, false));
727 }
728
729 if (_with_complexity != unlimited)
730 {
731 conditions.push_back("complexity = ?");
732 bindings.emplace_back(_with_complexity);
733 }
734
735 if (_is_hypernym)
736 {
737 conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)");
738 }
739
740 if (!_hypernym_of.empty())
741 {
742 std::stringstream cond;
743 if (_hypernym_of.get_notlogic())
744 {
745 cond << "noun_id NOT IN";
746 } else {
747 cond << "noun_id IN";
748 }
749
750 cond << "(SELECT hypernym_id FROM hypernymy WHERE ";
751
752 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
753 switch (f.get_type())
754 {
755 case filter<noun>::type::singleton:
756 {
757 bindings.emplace_back(f.get_elem()._id);
758
759 if (notlogic == f.get_notlogic())
760 {
761 return "hyponym_id = ?";
762 } else {
763 return "hyponym_id != ?";
764 }
765 }
766
767 case filter<noun>::type::group:
768 {
769 bool truelogic = notlogic != f.get_notlogic();
770
771 std::list<std::string> clauses;
772 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
773 return recur(f2, truelogic);
774 });
775
776 if (truelogic == f.get_orlogic())
777 {
778 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
779 } else {
780 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
781 }
782 }
783 }
784 };
785
786 cond << recur(_hypernym_of, _hypernym_of.get_notlogic());
787 cond << ")";
788 conditions.push_back(cond.str());
789 }
790
791 if (!_full_hypernym_of.empty())
792 {
793 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
794 switch (f.get_type())
795 {
796 case filter<noun>::type::singleton:
797 {
798 if (notlogic == f.get_notlogic())
799 {
800 return "noun_id IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")";
801 } else {
802 return "noun_id NOT IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")";
803 }
804 }
805
806 case filter<noun>::type::group:
807 {
808 bool truelogic = notlogic != f.get_notlogic();
809
810 std::list<std::string> clauses;
811 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
812 return recur(f2, truelogic);
813 });
814
815 if (truelogic == f.get_orlogic())
816 {
817 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
818 } else {
819 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
820 }
821 }
822 }
823 };
824
825 conditions.push_back(recur(_full_hypernym_of, false));
826 }
827
828 if (!_full_hyponym_of.empty())
829 {
830 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
831 switch (f.get_type())
832 {
833 case filter<noun>::type::singleton:
834 {
835 if (notlogic == f.get_notlogic())
836 {
837 return "noun_id IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")";
838 } else {
839 return "noun_id NOT IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")";
840 }
841 }
842
843 case filter<noun>::type::group:
844 {
845 bool truelogic = notlogic != f.get_notlogic();
846
847 std::list<std::string> clauses;
848 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
849 return recur(f2, truelogic);
850 });
851
852 if (truelogic == f.get_orlogic())
853 {
854 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
855 } else {
856 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
857 }
858 }
859 }
860 };
861
862 conditions.push_back(recur(_full_hyponym_of, false));
863 }
864
865 if (_is_hyponym)
866 {
867 conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)");
868 }
869
870 if (!_hyponym_of.empty())
871 {
872 std::stringstream cond;
873 if (_hyponym_of.get_notlogic())
874 {
875 cond << "noun_id NOT IN";
876 } else {
877 cond << "noun_id IN";
878 }
879
880 cond << "(SELECT hyponym_id FROM hypernymy WHERE ";
881
882 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
883 switch (f.get_type())
884 {
885 case filter<noun>::type::singleton:
886 {
887 bindings.emplace_back(f.get_elem()._id);
888
889 if (notlogic == f.get_notlogic())
890 {
891 return "hypernym_id = ?";
892 } else {
893 return "hypernym_id != ?";
894 }
895 }
896
897 case filter<noun>::type::group:
898 {
899 bool truelogic = notlogic != f.get_notlogic();
900
901 std::list<std::string> clauses;
902 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
903 return recur(f2, truelogic);
904 });
905
906 if (truelogic == f.get_orlogic())
907 {
908 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
909 } else {
910 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
911 }
912 }
913 }
914 };
915
916 cond << recur(_hyponym_of, _hyponym_of.get_notlogic());
917 cond << ")";
918 conditions.push_back(cond.str());
919 }
920
921 if (_is_part_meronym)
922 {
923 conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)");
924 }
925
926 if (!_part_meronym_of.empty())
927 {
928 std::stringstream cond;
929 if (_part_meronym_of.get_notlogic())
930 {
931 cond << "noun_id NOT IN";
932 } else {
933 cond << "noun_id IN";
934 }
935
936 cond << "(SELECT meronym_id FROM part_meronymy WHERE ";
937
938 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
939 switch (f.get_type())
940 {
941 case filter<noun>::type::singleton:
942 {
943 bindings.emplace_back(f.get_elem()._id);
944
945 if (notlogic == f.get_notlogic())
946 {
947 return "holonym_id = ?";
948 } else {
949 return "holonym_id != ?";
950 }
951 }
952
953 case filter<noun>::type::group:
954 {
955 bool truelogic = notlogic != f.get_notlogic();
956
957 std::list<std::string> clauses;
958 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
959 return recur(f2, truelogic);
960 });
961
962 if (truelogic == f.get_orlogic())
963 {
964 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
965 } else {
966 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
967 }
968 }
969 }
970 };
971
972 cond << recur(_part_meronym_of, _part_meronym_of.get_notlogic());
973 cond << ")";
974 conditions.push_back(cond.str());
975 }
976
977 if (!_full_part_meronym_of.empty())
978 {
979 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
980 switch (f.get_type())
981 {
982 case filter<noun>::type::singleton:
983 {
984 if (notlogic == f.get_notlogic())
985 {
986 return "noun_id IN (SELECT meronym_id FROM part_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
987 } else {
988 return "noun_id NOT IN (SELECT meronym_id FROM part_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
989 }
990 }
991
992 case filter<noun>::type::group:
993 {
994 bool truelogic = notlogic != f.get_notlogic();
995
996 std::list<std::string> clauses;
997 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
998 return recur(f2, truelogic);
999 });
1000
1001 if (truelogic == f.get_orlogic())
1002 {
1003 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1004 } else {
1005 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1006 }
1007 }
1008 }
1009 };
1010
1011 conditions.push_back(recur(_full_part_meronym_of, false));
1012 }
1013
1014 if (_is_part_holonym)
1015 {
1016 conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)");
1017 }
1018
1019 if (!_part_holonym_of.empty())
1020 {
1021 std::stringstream cond;
1022 if (_part_holonym_of.get_notlogic())
1023 {
1024 cond << "noun_id NOT IN";
1025 } else {
1026 cond << "noun_id IN";
1027 }
1028
1029 cond << "(SELECT holonym_id FROM part_meronymy WHERE ";
1030
1031 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1032 switch (f.get_type())
1033 {
1034 case filter<noun>::type::singleton:
1035 {
1036 bindings.emplace_back(f.get_elem()._id);
1037
1038 if (notlogic == f.get_notlogic())
1039 {
1040 return "meronym_id = ?";
1041 } else {
1042 return "meronym_id != ?";
1043 }
1044 }
1045
1046 case filter<noun>::type::group:
1047 {
1048 bool truelogic = notlogic != f.get_notlogic();
1049
1050 std::list<std::string> clauses;
1051 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1052 return recur(f2, truelogic);
1053 });
1054
1055 if (truelogic == f.get_orlogic())
1056 {
1057 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1058 } else {
1059 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1060 }
1061 }
1062 }
1063 };
1064
1065 cond << recur(_part_holonym_of, _part_holonym_of.get_notlogic());
1066 cond << ")";
1067 conditions.push_back(cond.str());
1068 }
1069
1070 if (!_full_part_holonym_of.empty())
1071 {
1072 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1073 switch (f.get_type())
1074 {
1075 case filter<noun>::type::singleton:
1076 {
1077 if (notlogic == f.get_notlogic())
1078 {
1079 return "noun_id IN (SELECT holonym_id FROM part_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1080 } else {
1081 return "noun_id NOT IN (SELECT holonym_id FROM part_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1082 }
1083 }
1084
1085 case filter<noun>::type::group:
1086 {
1087 bool truelogic = notlogic != f.get_notlogic();
1088
1089 std::list<std::string> clauses;
1090 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1091 return recur(f2, truelogic);
1092 });
1093
1094 if (truelogic == f.get_orlogic())
1095 {
1096 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1097 } else {
1098 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1099 }
1100 }
1101 }
1102 };
1103
1104 conditions.push_back(recur(_full_part_holonym_of, false));
1105 }
1106
1107 if (_is_substance_meronym)
1108 {
1109 conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)");
1110 }
1111
1112 if (!_substance_meronym_of.empty())
1113 {
1114 std::stringstream cond;
1115 if (_substance_meronym_of.get_notlogic())
1116 {
1117 cond << "noun_id NOT IN";
1118 } else {
1119 cond << "noun_id IN";
1120 }
1121
1122 cond << "(SELECT meronym_id FROM substance_meronymy WHERE ";
1123
1124 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1125 switch (f.get_type())
1126 {
1127 case filter<noun>::type::singleton:
1128 {
1129 bindings.emplace_back(f.get_elem()._id);
1130
1131 if (notlogic == f.get_notlogic())
1132 {
1133 return "holonym_id = ?";
1134 } else {
1135 return "holonym_id != ?";
1136 }
1137 }
1138
1139 case filter<noun>::type::group:
1140 {
1141 bool truelogic = notlogic != f.get_notlogic();
1142
1143 std::list<std::string> clauses;
1144 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1145 return recur(f2, truelogic);
1146 });
1147
1148 if (truelogic == f.get_orlogic())
1149 {
1150 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1151 } else {
1152 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1153 }
1154 }
1155 }
1156 };
1157
1158 cond << recur(_substance_meronym_of, _substance_meronym_of.get_notlogic());
1159 cond << ")";
1160 conditions.push_back(cond.str());
1161 }
1162
1163 if (!_full_substance_meronym_of.empty())
1164 {
1165 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1166 switch (f.get_type())
1167 {
1168 case filter<noun>::type::singleton:
1169 {
1170 if (notlogic == f.get_notlogic())
1171 {
1172 return "noun_id IN (SELECT meronym_id FROM substance_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
1173 } else {
1174 return "noun_id NOT IN (SELECT meronym_id FROM substance_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
1175 }
1176 }
1177
1178 case filter<noun>::type::group:
1179 {
1180 bool truelogic = notlogic != f.get_notlogic();
1181
1182 std::list<std::string> clauses;
1183 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1184 return recur(f2, truelogic);
1185 });
1186
1187 if (truelogic == f.get_orlogic())
1188 {
1189 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1190 } else {
1191 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1192 }
1193 }
1194 }
1195 };
1196
1197 conditions.push_back(recur(_full_substance_meronym_of, false));
1198 }
1199
1200 if (_is_substance_holonym)
1201 {
1202 conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)");
1203 }
1204
1205 if (!_substance_holonym_of.empty())
1206 {
1207 std::stringstream cond;
1208 if (_substance_holonym_of.get_notlogic())
1209 {
1210 cond << "noun_id NOT IN";
1211 } else {
1212 cond << "noun_id IN";
1213 }
1214
1215 cond << "(SELECT holonym_id FROM substance_meronymy WHERE ";
1216
1217 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1218 switch (f.get_type())
1219 {
1220 case filter<noun>::type::singleton:
1221 {
1222 bindings.emplace_back(f.get_elem()._id);
1223
1224 if (notlogic == f.get_notlogic())
1225 {
1226 return "meronym_id = ?";
1227 } else {
1228 return "meronym_id != ?";
1229 }
1230 }
1231
1232 case filter<noun>::type::group:
1233 {
1234 bool truelogic = notlogic != f.get_notlogic();
1235
1236 std::list<std::string> clauses;
1237 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1238 return recur(f2, truelogic);
1239 });
1240
1241 if (truelogic == f.get_orlogic())
1242 {
1243 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1244 } else {
1245 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1246 }
1247 }
1248 }
1249 };
1250
1251 cond << recur(_substance_holonym_of, _substance_holonym_of.get_notlogic());
1252 cond << ")";
1253 conditions.push_back(cond.str());
1254 }
1255
1256 if (!_full_substance_holonym_of.empty())
1257 {
1258 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1259 switch (f.get_type())
1260 {
1261 case filter<noun>::type::singleton:
1262 {
1263 if (notlogic == f.get_notlogic())
1264 {
1265 return "noun_id IN (SELECT holonym_id FROM substance_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1266 } else {
1267 return "noun_id NOT IN (SELECT holonym_id FROM substance_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1268 }
1269 }
1270
1271 case filter<noun>::type::group:
1272 {
1273 bool truelogic = notlogic != f.get_notlogic();
1274
1275 std::list<std::string> clauses;
1276 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1277 return recur(f2, truelogic);
1278 });
1279
1280 if (truelogic == f.get_orlogic())
1281 {
1282 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1283 } else {
1284 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1285 }
1286 }
1287 }
1288 };
1289
1290 conditions.push_back(recur(_full_substance_holonym_of, false));
1291 }
1292
1293 if (_is_member_meronym)
1294 {
1295 conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)");
1296 }
1297
1298 if (!_member_meronym_of.empty())
1299 {
1300 std::stringstream cond;
1301 if (_member_meronym_of.get_notlogic())
1302 {
1303 cond << "noun_id NOT IN";
1304 } else {
1305 cond << "noun_id IN";
1306 }
1307
1308 cond << "(SELECT meronym_id FROM member_meronymy WHERE ";
1309
1310 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1311 switch (f.get_type())
1312 {
1313 case filter<noun>::type::singleton:
1314 {
1315 bindings.emplace_back(f.get_elem()._id);
1316
1317 if (notlogic == f.get_notlogic())
1318 {
1319 return "holonym_id = ?";
1320 } else {
1321 return "holonym_id != ?";
1322 }
1323 }
1324
1325 case filter<noun>::type::group:
1326 {
1327 bool truelogic = notlogic != f.get_notlogic();
1328
1329 std::list<std::string> clauses;
1330 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1331 return recur(f2, truelogic);
1332 });
1333
1334 if (truelogic == f.get_orlogic())
1335 {
1336 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1337 } else {
1338 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1339 }
1340 }
1341 }
1342 };
1343
1344 cond << recur(_member_meronym_of, _member_meronym_of.get_notlogic());
1345 cond << ")";
1346 conditions.push_back(cond.str());
1347 }
1348
1349 if (!_full_member_meronym_of.empty())
1350 {
1351 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1352 switch (f.get_type())
1353 {
1354 case filter<noun>::type::singleton:
1355 {
1356 if (notlogic == f.get_notlogic())
1357 {
1358 return "noun_id IN (SELECT meronym_id FROM member_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
1359 } else {
1360 return "noun_id NOT IN (SELECT meronym_id FROM member_meronym_tree_" + std::to_string(f.get_elem()._id) + ")";
1361 }
1362 }
1363
1364 case filter<noun>::type::group:
1365 {
1366 bool truelogic = notlogic != f.get_notlogic();
1367
1368 std::list<std::string> clauses;
1369 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1370 return recur(f2, truelogic);
1371 });
1372
1373 if (truelogic == f.get_orlogic())
1374 {
1375 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1376 } else {
1377 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1378 }
1379 }
1380 }
1381 };
1382
1383 conditions.push_back(recur(_full_member_meronym_of, false));
1384 }
1385
1386 if (_is_member_holonym)
1387 {
1388 conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)");
1389 }
1390
1391 if (!_member_holonym_of.empty())
1392 {
1393 std::stringstream cond;
1394 if (_member_holonym_of.get_notlogic())
1395 {
1396 cond << "noun_id NOT IN";
1397 } else {
1398 cond << "noun_id IN";
1399 }
1400
1401 cond << "(SELECT holonym_id FROM member_meronymy WHERE ";
1402
1403 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1404 switch (f.get_type())
1405 {
1406 case filter<noun>::type::singleton:
1407 {
1408 bindings.emplace_back(f.get_elem()._id);
1409
1410 if (notlogic == f.get_notlogic())
1411 {
1412 return "meronym_id = ?";
1413 } else {
1414 return "meronym_id != ?";
1415 }
1416 }
1417
1418 case filter<noun>::type::group:
1419 {
1420 bool truelogic = notlogic != f.get_notlogic();
1421
1422 std::list<std::string> clauses;
1423 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1424 return recur(f2, truelogic);
1425 });
1426
1427 if (truelogic == f.get_orlogic())
1428 {
1429 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1430 } else {
1431 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1432 }
1433 }
1434 }
1435 };
1436
1437 cond << recur(_member_holonym_of, _member_holonym_of.get_notlogic());
1438 cond << ")";
1439 conditions.push_back(cond.str());
1440 }
1441
1442 if (!_full_member_holonym_of.empty())
1443 {
1444 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1445 switch (f.get_type())
1446 {
1447 case filter<noun>::type::singleton:
1448 {
1449 if (notlogic == f.get_notlogic())
1450 {
1451 return "noun_id IN (SELECT holonym_id FROM member_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1452 } else {
1453 return "noun_id NOT IN (SELECT holonym_id FROM member_holonym_tree_" + std::to_string(f.get_elem()._id) + ")";
1454 }
1455 }
1456
1457 case filter<noun>::type::group:
1458 {
1459 bool truelogic = notlogic != f.get_notlogic();
1460
1461 std::list<std::string> clauses;
1462 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1463 return recur(f2, truelogic);
1464 });
1465
1466 if (truelogic == f.get_orlogic())
1467 {
1468 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1469 } else {
1470 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1471 }
1472 }
1473 }
1474 };
1475
1476 conditions.push_back(recur(_full_member_holonym_of, false));
1477 }
1478
1479 if (_is_proper)
1480 {
1481 conditions.push_back("proper = 1");
1482 }
1483
1484 if (_is_not_proper)
1485 {
1486 conditions.push_back("proper = 0");
1487 }
1488
1489 if (_is_instance)
1490 {
1491 conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)");
1492 }
1493
1494 if (!_instance_of.empty())
1495 {
1496 std::stringstream cond;
1497 if (_instance_of.get_notlogic())
1498 {
1499 cond << "noun_id NOT IN";
1500 } else {
1501 cond << "noun_id IN";
1502 }
1503
1504 cond << "(SELECT instance_id FROM instantiation WHERE ";
1505
1506 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1507 switch (f.get_type())
1508 {
1509 case filter<noun>::type::singleton:
1510 {
1511 bindings.emplace_back(f.get_elem()._id);
1512
1513 if (notlogic == f.get_notlogic())
1514 {
1515 return "class_id = ?";
1516 } else {
1517 return "class_id != ?";
1518 }
1519 }
1520
1521 case filter<noun>::type::group:
1522 {
1523 bool truelogic = notlogic != f.get_notlogic();
1524
1525 std::list<std::string> clauses;
1526 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1527 return recur(f2, truelogic);
1528 });
1529
1530 if (truelogic == f.get_orlogic())
1531 {
1532 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1533 } else {
1534 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1535 }
1536 }
1537 }
1538 };
1539
1540 cond << recur(_instance_of, _instance_of.get_notlogic());
1541 cond << ")";
1542 conditions.push_back(cond.str());
1543 }
1544
1545 if (_is_class)
1546 {
1547 conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)");
1548 }
1549
1550 if (!_class_of.empty())
1551 {
1552 std::stringstream cond;
1553 if (_class_of.get_notlogic())
1554 {
1555 cond << "noun_id NOT IN";
1556 } else {
1557 cond << "noun_id IN";
1558 }
1559
1560 cond << "(SELECT class_id FROM instantiation WHERE ";
1561
1562 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1563 switch (f.get_type())
1564 {
1565 case filter<noun>::type::singleton:
1566 {
1567 bindings.emplace_back(f.get_elem()._id);
1568
1569 if (notlogic == f.get_notlogic())
1570 {
1571 return "instance_id = ?";
1572 } else {
1573 return "instance_id != ?";
1574 }
1575 }
1576
1577 case filter<noun>::type::group:
1578 {
1579 bool truelogic = notlogic != f.get_notlogic();
1580
1581 std::list<std::string> clauses;
1582 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1583 return recur(f2, truelogic);
1584 });
1585
1586 if (truelogic == f.get_orlogic())
1587 {
1588 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1589 } else {
1590 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1591 }
1592 }
1593 }
1594 };
1595
1596 cond << recur(_class_of, _class_of.get_notlogic());
1597 cond << ")";
1598 conditions.push_back(cond.str());
1599 }
1600
1601 if (_has_synonyms)
1602 {
1603 conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_synonymy)");
1604 }
1605
1606 if (!_synonym_of.empty())
1607 {
1608 std::stringstream cond;
1609 if (_synonym_of.get_notlogic())
1610 {
1611 cond << "noun_id NOT IN";
1612 } else {
1613 cond << "noun_id IN";
1614 }
1615
1616 cond << "(SELECT noun_2_id FROM noun_synonymy WHERE ";
1617
1618 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1619 switch (f.get_type())
1620 {
1621 case filter<noun>::type::singleton:
1622 {
1623 bindings.emplace_back(f.get_elem()._id);
1624
1625 if (notlogic == f.get_notlogic())
1626 {
1627 return "noun_1_id = ?";
1628 } else {
1629 return "noun_1_id != ?";
1630 }
1631 }
1632
1633 case filter<noun>::type::group:
1634 {
1635 bool truelogic = notlogic != f.get_notlogic();
1636
1637 std::list<std::string> clauses;
1638 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1639 return recur(f2, truelogic);
1640 });
1641
1642 if (truelogic == f.get_orlogic())
1643 {
1644 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1645 } else {
1646 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1647 }
1648 }
1649 }
1650 };
1651
1652 cond << recur(_synonym_of, _synonym_of.get_notlogic());
1653 cond << ")";
1654 conditions.push_back(cond.str());
1655 }
1656
1657 if (_has_antonyms)
1658 {
1659 conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_antonymy)");
1660 }
1661
1662 if (!_antonym_of.empty())
1663 {
1664 std::stringstream cond;
1665 if (_antonym_of.get_notlogic())
1666 {
1667 cond << "noun_id NOT IN";
1668 } else {
1669 cond << "noun_id IN";
1670 }
1671
1672 cond << "(SELECT noun_2_id FROM noun_antonymy WHERE ";
1673
1674 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1675 switch (f.get_type())
1676 {
1677 case filter<noun>::type::singleton:
1678 {
1679 bindings.emplace_back(f.get_elem()._id);
1680
1681 if (notlogic == f.get_notlogic())
1682 {
1683 return "noun_1_id = ?";
1684 } else {
1685 return "noun_1_id != ?";
1686 }
1687 }
1688
1689 case filter<noun>::type::group:
1690 {
1691 bool truelogic = notlogic != f.get_notlogic();
1692
1693 std::list<std::string> clauses;
1694 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1695 return recur(f2, truelogic);
1696 });
1697
1698 if (truelogic == f.get_orlogic())
1699 {
1700 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1701 } else {
1702 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1703 }
1704 }
1705 }
1706 };
1707
1708 cond << recur(_antonym_of, _antonym_of.get_notlogic());
1709 cond << ")";
1710 conditions.push_back(cond.str());
1711 }
1712
1713 if (_has_pertainym)
1714 {
1715 conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)");
1716 }
1717
1718 if (!_anti_pertainym_of.empty())
1719 {
1720 std::stringstream cond;
1721 if (_anti_pertainym_of.get_notlogic())
1722 {
1723 cond << "noun_id NOT IN";
1724 } else {
1725 cond << "noun_id IN";
1726 }
1727
1728 cond << "(SELECT noun_id FROM pertainymy WHERE ";
1729
1730 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
1731 switch (f.get_type())
1732 {
1733 case filter<adjective>::type::singleton:
1734 {
1735 bindings.emplace_back(f.get_elem()._id);
1736
1737 if (notlogic == f.get_notlogic())
1738 {
1739 return "pertainym_id = ?";
1740 } else {
1741 return "pertainym_id != ?";
1742 }
1743 }
1744
1745 case filter<adjective>::type::group:
1746 {
1747 bool truelogic = notlogic != f.get_notlogic();
1748
1749 std::list<std::string> clauses;
1750 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
1751 return recur(f2, truelogic);
1752 });
1753
1754 if (truelogic == f.get_orlogic())
1755 {
1756 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1757 } else {
1758 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1759 }
1760 }
1761 }
1762 };
1763
1764 cond << recur(_anti_pertainym_of, _anti_pertainym_of.get_notlogic());
1765 cond << ")";
1766 conditions.push_back(cond.str());
1767 }
1768
1769 if (_is_attribute)
1770 {
1771 conditions.push_back("noun_id IN (SELECT noun_id FROM variation)");
1772 }
1773
1774 if (!_attribute_of.empty())
1775 {
1776 std::stringstream cond;
1777 if (_attribute_of.get_notlogic())
1778 {
1779 cond << "noun_id NOT IN";
1780 } else {
1781 cond << "noun_id IN";
1782 }
1783
1784 cond << "(SELECT noun_id FROM variation WHERE ";
1785
1786 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
1787 switch (f.get_type())
1788 {
1789 case filter<adjective>::type::singleton:
1790 {
1791 bindings.emplace_back(f.get_elem()._id);
1792
1793 if (notlogic == f.get_notlogic())
1794 {
1795 return "adjective_id = ?";
1796 } else {
1797 return "adjective_id != ?";
1798 }
1799 }
1800
1801 case filter<adjective>::type::group:
1802 {
1803 bool truelogic = notlogic != f.get_notlogic();
1804
1805 std::list<std::string> clauses;
1806 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
1807 return recur(f2, truelogic);
1808 });
1809
1810 if (truelogic == f.get_orlogic())
1811 {
1812 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1813 } else {
1814 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1815 }
1816 }
1817 }
1818 };
1819
1820 cond << recur(_attribute_of, _attribute_of.get_notlogic());
1821 cond << ")";
1822 conditions.push_back(cond.str());
1823 }
1824
1825 if (_at_least_n_images != unlimited)
1826 {
1827 conditions.push_back("images >= ?");
1828 bindings.emplace_back(_at_least_n_images);
1829 }
1830
1831 if (!_with_wnid.empty())
1832 {
1833 std::vector<std::string> clauses(_with_wnid.size(), "wnid = ?");
1834 std::string cond = verbly::implode(std::begin(clauses), std::end(clauses), " OR ");
1835 conditions.push_back("(" + cond + ")");
1836
1837 for (auto wnid : _with_wnid)
1838 {
1839 bindings.emplace_back(wnid);
1840 }
1841 }
1842
1843 /*
1844 if (!_derived_from_adjective.empty())
1845 {
1846 std::list<std::string> clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ");
1847 std::string cond = "noun_id IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1848 conditions.push_back(cond);
1849 }
1850
1851 if (!_not_derived_from_adjective.empty())
1852 {
1853 std::list<std::string> clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ");
1854 std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1855 conditions.push_back(cond);
1856 }
1857
1858 if (!_derived_from_adverb.empty())
1859 {
1860 std::list<std::string> clauses(_derived_from_adverb.size(), "adverb_id = @DERADV");
1861 std::string cond = "noun_id IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1862 conditions.push_back(cond);
1863 }
1864
1865 if (!_not_derived_from_adverb.empty())
1866 {
1867 std::list<std::string> clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV");
1868 std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1869 conditions.push_back(cond);
1870 }
1871
1872 if (!_derived_from_noun.empty())
1873 {
1874 std::list<std::string> clauses(_derived_from_noun.size(), "noun_2_id = @DERN");
1875 std::string cond = "noun_id IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1876 conditions.push_back(cond);
1877 }
1878
1879 if (!_not_derived_from_noun.empty())
1880 {
1881 std::list<std::string> clauses(_not_derived_from_noun.size(), "noun_2_id = @NDERN");
1882 std::string cond = "noun_id NOT IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1883 conditions.push_back(cond);
1884 }
1885 */
1886 if (!conditions.empty())
1887 {
1888 construct << " WHERE ";
1889 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
1890 }
1891
1892 if (_random)
1893 {
1894 construct << " ORDER BY RANDOM()";
1895 }
1896
1897 if (_limit != unlimited)
1898 {
1899 construct << " LIMIT " << _limit;
1900 }
1901
1902 sqlite3_stmt* ppstmt;
1903 std::string query = construct.str();
1904 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1905 {
1906 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1907 }
1908
1909 int i = 1;
1910 for (auto& binding : bindings)
1911 {
1912 switch (binding.get_type())
1913 {
1914 case binding::type::integer:
1915 {
1916 sqlite3_bind_int(ppstmt, i, binding.get_integer());
1917
1918 break;
1919 }
1920
1921 case binding::type::string:
1922 {
1923 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
1924
1925 break;
1926 }
1927 }
1928
1929 i++;
1930 }
1931
1932 /*
1933 for (auto adj : _derived_from_adjective)
1934 {
1935 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id);
1936 }
1937
1938 for (auto adj : _not_derived_from_adjective)
1939 {
1940 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id);
1941 }
1942
1943 for (auto adv : _derived_from_adverb)
1944 {
1945 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id);
1946 }
1947
1948 for (auto adv : _not_derived_from_adverb)
1949 {
1950 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id);
1951 }
1952
1953 for (auto n : _derived_from_noun)
1954 {
1955 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id);
1956 }
1957
1958 for (auto n : _not_derived_from_noun)
1959 {
1960 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id);
1961 }
1962*/
1963 std::list<noun> output;
1964 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1965 {
1966 noun tnc {_data, sqlite3_column_int(ppstmt, 0)};
1967 tnc._singular = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1968
1969 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
1970 {
1971 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1972 }
1973
1974 tnc._wnid = sqlite3_column_int(ppstmt, 3);
1975
1976 output.push_back(tnc);
1977 }
1978
1979 sqlite3_finalize(ppstmt);
1980
1981 for (auto& noun : output)
1982 {
1983 query = "SELECT pronunciation, prerhyme, rhyme FROM noun_pronunciations WHERE noun_id = ?";
1984 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1985 {
1986 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1987 }
1988
1989 sqlite3_bind_int(ppstmt, 1, noun._id);
1990
1991 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1992 {
1993 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
1994 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
1995
1996 noun.pronunciations.push_back(phonemes);
1997
1998 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
1999 {
2000 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
2001 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
2002
2003 noun.rhymes.emplace_back(prerhyme, rhyming);
2004 }
2005 }
2006
2007 sqlite3_finalize(ppstmt);
2008 }
2009
2010 return output;
2011 }
2012
2013};