summary refs log tree commit diff stats
path: root/lib/noun_query.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2016-03-24 23:16:07 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2016-03-24 23:16:07 -0400
commiteef5de613c75661e5d94baa086f6f2ddc26c7ed0 (patch)
tree180230f6a245c5bca94d894273f5d2b93ded3f04 /lib/noun_query.cpp
parentd5ee4e39e5b5b3b8daa85cd972802195ad35e965 (diff)
downloadverbly-eef5de613c75661e5d94baa086f6f2ddc26c7ed0.tar.gz
verbly-eef5de613c75661e5d94baa086f6f2ddc26c7ed0.tar.bz2
verbly-eef5de613c75661e5d94baa086f6f2ddc26c7ed0.zip
Added verb frames
In addition:
- Added prepositions.
- Rewrote a lot of the query interface. It now, for a lot of relationships, supports nested AND, OR, and NOT logic.
- Rewrote the token class. It is now a union-like class instead of being polymorphic, which means smart pointers are no longer necessary.
- Querying with regards to word derivation has been temporarily removed.
- Sentinel values are now supported for all word types.
- The VerbNet data retrieved from http://verbs.colorado.edu/~mpalmer/projects/verbnet/downloads.html was found to not be perfectly satisfactory in some regards, especially regarding adjective phrases. A patch file is now included in the repository describing the changes made to the VerbNet v3.2 download for the canonical verbly datafile.
Diffstat (limited to 'lib/noun_query.cpp')
-rw-r--r--lib/noun_query.cpp1453
1 files changed, 1453 insertions, 0 deletions
diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp new file mode 100644 index 0000000..cb11577 --- /dev/null +++ b/lib/noun_query.cpp
@@ -0,0 +1,1453 @@
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.rhyme_phonemes())
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::has_pronunciation()
50 {
51 this->_has_prn = true;
52
53 return *this;
54 }
55
56 noun_query& noun_query::with_singular_form(std::string _arg)
57 {
58 _with_singular_form.push_back(_arg);
59
60 return *this;
61 }
62
63 noun_query& noun_query::is_hypernym()
64 {
65 _is_hypernym = true;
66
67 return *this;
68 }
69
70 noun_query& noun_query::hypernym_of(filter<noun> _f)
71 {
72 _f.clean();
73 _hypernym_of = _f;
74
75 return *this;
76 }
77
78 noun_query& noun_query::full_hypernym_of(filter<noun> _f)
79 {
80 _f.clean();
81 _full_hypernym_of = _f;
82
83 return *this;
84 }
85
86 noun_query& noun_query::is_hyponym()
87 {
88 _is_hyponym = true;
89
90 return *this;
91 }
92
93 noun_query& noun_query::hyponym_of(filter<noun> _f)
94 {
95 _f.clean();
96 _hyponym_of = _f;
97
98 return *this;
99 }
100
101 noun_query& noun_query::full_hyponym_of(filter<noun> _f)
102 {
103 _f.clean();
104 _full_hyponym_of = _f;
105
106 return *this;
107 }
108
109 noun_query& noun_query::is_part_meronym()
110 {
111 _is_part_meronym = true;
112
113 return *this;
114 }
115
116 noun_query& noun_query::part_meronym_of(filter<noun> _f)
117 {
118 _f.clean();
119 _part_meronym_of = _f;
120
121 return *this;
122 }
123
124 noun_query& noun_query::is_part_holonym()
125 {
126 _is_part_holonym = true;
127
128 return *this;
129 }
130
131 noun_query& noun_query::part_holonym_of(filter<noun> _f)
132 {
133 _f.clean();
134 _part_holonym_of = _f;
135
136 return *this;
137 }
138
139 noun_query& noun_query::is_substance_meronym()
140 {
141 _is_substance_meronym = true;
142
143 return *this;
144 }
145
146 noun_query& noun_query::substance_meronym_of(filter<noun> _f)
147 {
148 _f.clean();
149 _substance_meronym_of = _f;
150
151 return *this;
152 }
153
154 noun_query& noun_query::is_substance_holonym()
155 {
156 _is_substance_holonym = true;
157
158 return *this;
159 }
160
161 noun_query& noun_query::substance_holonym_of(filter<noun> _f)
162 {
163 _f.clean();
164 _substance_holonym_of = _f;
165
166 return *this;
167 }
168
169 noun_query& noun_query::is_member_meronym()
170 {
171 _is_member_meronym = true;
172
173 return *this;
174 }
175
176 noun_query& noun_query::member_meronym_of(filter<noun> _f)
177 {
178 _f.clean();
179 _member_meronym_of = _f;
180
181 return *this;
182 }
183
184 noun_query& noun_query::is_member_holonym()
185 {
186 _is_member_holonym = true;
187
188 return *this;
189 }
190
191 noun_query& noun_query::member_holonym_of(filter<noun> _f)
192 {
193 _f.clean();
194 _member_holonym_of = _f;
195
196 return *this;
197 }
198
199 noun_query& noun_query::is_proper()
200 {
201 _is_proper = true;
202
203 return *this;
204 }
205
206 noun_query& noun_query::is_not_proper()
207 {
208 _is_not_proper = true;
209
210 return *this;
211 }
212
213 noun_query& noun_query::is_instance()
214 {
215 _is_instance = true;
216
217 return *this;
218 }
219
220 noun_query& noun_query::instance_of(filter<noun> _f)
221 {
222 _f.clean();
223 _instance_of = _f;
224
225 return *this;
226 }
227
228 noun_query& noun_query::is_class()
229 {
230 _is_class = true;
231
232 return *this;
233 }
234
235 noun_query& noun_query::class_of(filter<noun> _f)
236 {
237 _f.clean();
238 _class_of = _f;
239
240 return *this;
241 }
242
243 noun_query& noun_query::has_synonyms()
244 {
245 _has_synonyms = true;
246
247 return *this;
248 }
249
250 noun_query& noun_query::synonym_of(filter<noun> _f)
251 {
252 _f.clean();
253 _synonym_of = _f;
254
255 return *this;
256 }
257
258 noun_query& noun_query::has_antonyms()
259 {
260 _has_antonyms = true;
261
262 return *this;
263 }
264
265 noun_query& noun_query::antonym_of(filter<noun> _f)
266 {
267 _f.clean();
268 _antonym_of = _f;
269
270 return *this;
271 }
272
273 noun_query& noun_query::has_pertainym()
274 {
275 _has_pertainym = true;
276
277 return *this;
278 }
279
280 noun_query& noun_query::anti_pertainym_of(filter<adjective> _f)
281 {
282 _f.clean();
283 _anti_pertainym_of = _f;
284
285 return *this;
286 }
287
288 noun_query& noun_query::is_attribute()
289 {
290 _is_attribute = true;
291
292 return *this;
293 }
294
295 noun_query& noun_query::attribute_of(filter<adjective> _f)
296 {
297 _f.clean();
298 _attribute_of = _f;
299
300 return *this;
301 }
302 /*
303 noun_query& noun_query::derived_from(const word& _w)
304 {
305 if (dynamic_cast<const adjective*>(&_w) != nullptr)
306 {
307 _derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
308 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
309 {
310 _derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
311 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
312 {
313 _derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
314 }
315
316 return *this;
317 }
318
319 noun_query& noun_query::not_derived_from(const word& _w)
320 {
321 if (dynamic_cast<const adjective*>(&_w) != nullptr)
322 {
323 _not_derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
324 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
325 {
326 _not_derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
327 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
328 {
329 _not_derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
330 }
331
332 return *this;
333 }*/
334
335 std::list<noun> noun_query::run() const
336 {
337 std::stringstream construct;
338
339 if (!_full_hypernym_of.empty() || !_full_hyponym_of.empty())
340 {
341 construct << "WITH RECURSIVE ";
342
343 std::list<std::string> ctes;
344
345 for (auto hyponym : _full_hypernym_of.uniq_flatten())
346 {
347 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)");
348 }
349
350 for (auto hypernym : _full_hyponym_of.uniq_flatten())
351 {
352 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)");
353 }
354
355 construct << verbly::implode(std::begin(ctes), std::end(ctes), ", ");
356 construct << " ";
357 }
358
359 construct << "SELECT noun_id, singular, plural FROM nouns";
360 std::list<std::string> conditions;
361
362 if (_has_prn)
363 {
364 conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)");
365 }
366
367 if (!_rhymes.empty())
368 {
369 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
370 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
371 conditions.push_back(cond);
372 }
373
374 for (auto except : _except)
375 {
376 conditions.push_back("noun_id != @EXCID");
377 }
378
379 if (!_with_singular_form.empty())
380 {
381 std::list<std::string> clauses(_with_singular_form.size(), "singular = @SFORM");
382 std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
383 conditions.push_back(cond);
384 }
385
386 if (_is_hypernym)
387 {
388 conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)");
389 }
390
391 if (!_hypernym_of.empty())
392 {
393 std::stringstream cond;
394 if (_hypernym_of.get_notlogic())
395 {
396 cond << "noun_id NOT IN";
397 } else {
398 cond << "noun_id IN";
399 }
400
401 cond << "(SELECT hypernym_id FROM hypernymy WHERE ";
402
403 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
404 switch (f.get_type())
405 {
406 case filter<noun>::type::singleton:
407 {
408 if (notlogic == f.get_notlogic())
409 {
410 return "hyponym_id = @HYPO";
411 } else {
412 return "hyponym_id != @HYPO";
413 }
414 }
415
416 case filter<noun>::type::group:
417 {
418 bool truelogic = notlogic != f.get_notlogic();
419
420 std::list<std::string> clauses;
421 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
422 return recur(f2, truelogic);
423 });
424
425 if (truelogic == f.get_orlogic())
426 {
427 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
428 } else {
429 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
430 }
431 }
432 }
433 };
434
435 cond << recur(_hypernym_of, _hypernym_of.get_notlogic());
436 cond << ")";
437 conditions.push_back(cond.str());
438 }
439
440 if (!_full_hypernym_of.empty())
441 {
442 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
443 switch (f.get_type())
444 {
445 case filter<noun>::type::singleton:
446 {
447 if (notlogic == f.get_notlogic())
448 {
449 return "noun_id IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")";
450 } else {
451 return "noun_id NOT IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")";
452 }
453 }
454
455 case filter<noun>::type::group:
456 {
457 bool truelogic = notlogic != f.get_notlogic();
458
459 std::list<std::string> clauses;
460 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
461 return recur(f2, truelogic);
462 });
463
464 if (truelogic == f.get_orlogic())
465 {
466 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
467 } else {
468 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
469 }
470 }
471 }
472 };
473
474 conditions.push_back(recur(_full_hypernym_of, false));
475 }
476
477 if (!_full_hyponym_of.empty())
478 {
479 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
480 switch (f.get_type())
481 {
482 case filter<noun>::type::singleton:
483 {
484 if (notlogic == f.get_notlogic())
485 {
486 return "noun_id IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")";
487 } else {
488 return "noun_id NOT IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")";
489 }
490 }
491
492 case filter<noun>::type::group:
493 {
494 bool truelogic = notlogic != f.get_notlogic();
495
496 std::list<std::string> clauses;
497 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
498 return recur(f2, truelogic);
499 });
500
501 if (truelogic == f.get_orlogic())
502 {
503 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
504 } else {
505 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
506 }
507 }
508 }
509 };
510
511 conditions.push_back(recur(_full_hyponym_of, false));
512 }
513
514 if (_is_hyponym)
515 {
516 conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)");
517 }
518
519 if (!_hyponym_of.empty())
520 {
521 std::stringstream cond;
522 if (_hyponym_of.get_notlogic())
523 {
524 cond << "noun_id NOT IN";
525 } else {
526 cond << "noun_id IN";
527 }
528
529 cond << "(SELECT hyponym_id FROM hypernymy WHERE ";
530
531 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
532 switch (f.get_type())
533 {
534 case filter<noun>::type::singleton:
535 {
536 if (notlogic == f.get_notlogic())
537 {
538 return "hypernym_id = @HYPER";
539 } else {
540 return "hypernym_id != @HYPER";
541 }
542 }
543
544 case filter<noun>::type::group:
545 {
546 bool truelogic = notlogic != f.get_notlogic();
547
548 std::list<std::string> clauses;
549 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
550 return recur(f2, truelogic);
551 });
552
553 if (truelogic == f.get_orlogic())
554 {
555 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
556 } else {
557 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
558 }
559 }
560 }
561 };
562
563 cond << recur(_hyponym_of, _hyponym_of.get_notlogic());
564 cond << ")";
565 conditions.push_back(cond.str());
566 }
567
568 if (_is_part_meronym)
569 {
570 conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)");
571 }
572
573 if (!_part_meronym_of.empty())
574 {
575 std::stringstream cond;
576 if (_part_meronym_of.get_notlogic())
577 {
578 cond << "noun_id NOT IN";
579 } else {
580 cond << "noun_id IN";
581 }
582
583 cond << "(SELECT meronym_id FROM part_meronymy WHERE ";
584
585 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
586 switch (f.get_type())
587 {
588 case filter<noun>::type::singleton:
589 {
590 if (notlogic == f.get_notlogic())
591 {
592 return "holonym_id = @PHOLO";
593 } else {
594 return "holonym_id != @PHOLO";
595 }
596 }
597
598 case filter<noun>::type::group:
599 {
600 bool truelogic = notlogic != f.get_notlogic();
601
602 std::list<std::string> clauses;
603 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
604 return recur(f2, truelogic);
605 });
606
607 if (truelogic == f.get_orlogic())
608 {
609 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
610 } else {
611 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
612 }
613 }
614 }
615 };
616
617 cond << recur(_part_meronym_of, _part_meronym_of.get_notlogic());
618 cond << ")";
619 conditions.push_back(cond.str());
620 }
621
622 if (_is_part_holonym)
623 {
624 conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)");
625 }
626
627 if (!_part_holonym_of.empty())
628 {
629 std::stringstream cond;
630 if (_part_holonym_of.get_notlogic())
631 {
632 cond << "noun_id NOT IN";
633 } else {
634 cond << "noun_id IN";
635 }
636
637 cond << "(SELECT holonym_id FROM part_meronymy WHERE ";
638
639 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
640 switch (f.get_type())
641 {
642 case filter<noun>::type::singleton:
643 {
644 if (notlogic == f.get_notlogic())
645 {
646 return "meronym_id = @PMERO";
647 } else {
648 return "meronym_id != @PMERO";
649 }
650 }
651
652 case filter<noun>::type::group:
653 {
654 bool truelogic = notlogic != f.get_notlogic();
655
656 std::list<std::string> clauses;
657 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
658 return recur(f2, truelogic);
659 });
660
661 if (truelogic == f.get_orlogic())
662 {
663 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
664 } else {
665 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
666 }
667 }
668 }
669 };
670
671 cond << recur(_part_holonym_of, _part_holonym_of.get_notlogic());
672 cond << ")";
673 conditions.push_back(cond.str());
674 }
675
676 if (_is_substance_meronym)
677 {
678 conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)");
679 }
680
681 if (!_substance_meronym_of.empty())
682 {
683 std::stringstream cond;
684 if (_substance_meronym_of.get_notlogic())
685 {
686 cond << "noun_id NOT IN";
687 } else {
688 cond << "noun_id IN";
689 }
690
691 cond << "(SELECT meronym_id FROM substance_meronymy WHERE ";
692
693 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
694 switch (f.get_type())
695 {
696 case filter<noun>::type::singleton:
697 {
698 if (notlogic == f.get_notlogic())
699 {
700 return "holonym_id = @SHOLO";
701 } else {
702 return "holonym_id != @SHOLO";
703 }
704 }
705
706 case filter<noun>::type::group:
707 {
708 bool truelogic = notlogic != f.get_notlogic();
709
710 std::list<std::string> clauses;
711 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
712 return recur(f2, truelogic);
713 });
714
715 if (truelogic == f.get_orlogic())
716 {
717 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
718 } else {
719 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
720 }
721 }
722 }
723 };
724
725 cond << recur(_substance_meronym_of, _substance_meronym_of.get_notlogic());
726 cond << ")";
727 conditions.push_back(cond.str());
728 }
729
730 if (_is_substance_holonym)
731 {
732 conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)");
733 }
734
735 if (!_substance_holonym_of.empty())
736 {
737 std::stringstream cond;
738 if (_substance_holonym_of.get_notlogic())
739 {
740 cond << "noun_id NOT IN";
741 } else {
742 cond << "noun_id IN";
743 }
744
745 cond << "(SELECT holonym_id FROM substance_meronymy WHERE ";
746
747 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
748 switch (f.get_type())
749 {
750 case filter<noun>::type::singleton:
751 {
752 if (notlogic == f.get_notlogic())
753 {
754 return "meronym_id = @SMERO";
755 } else {
756 return "meronym_id != @SMERO";
757 }
758 }
759
760 case filter<noun>::type::group:
761 {
762 bool truelogic = notlogic != f.get_notlogic();
763
764 std::list<std::string> clauses;
765 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
766 return recur(f2, truelogic);
767 });
768
769 if (truelogic == f.get_orlogic())
770 {
771 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
772 } else {
773 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
774 }
775 }
776 }
777 };
778
779 cond << recur(_substance_holonym_of, _substance_holonym_of.get_notlogic());
780 cond << ")";
781 conditions.push_back(cond.str());
782 }
783
784 if (_is_member_meronym)
785 {
786 conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)");
787 }
788
789 if (!_member_meronym_of.empty())
790 {
791 std::stringstream cond;
792 if (_member_meronym_of.get_notlogic())
793 {
794 cond << "noun_id NOT IN";
795 } else {
796 cond << "noun_id IN";
797 }
798
799 cond << "(SELECT meronym_id FROM member_meronymy WHERE ";
800
801 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
802 switch (f.get_type())
803 {
804 case filter<noun>::type::singleton:
805 {
806 if (notlogic == f.get_notlogic())
807 {
808 return "holonym_id = @MHOLO";
809 } else {
810 return "holonym_id != @MHOLO";
811 }
812 }
813
814 case filter<noun>::type::group:
815 {
816 bool truelogic = notlogic != f.get_notlogic();
817
818 std::list<std::string> clauses;
819 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
820 return recur(f2, truelogic);
821 });
822
823 if (truelogic == f.get_orlogic())
824 {
825 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
826 } else {
827 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
828 }
829 }
830 }
831 };
832
833 cond << recur(_member_meronym_of, _member_meronym_of.get_notlogic());
834 cond << ")";
835 conditions.push_back(cond.str());
836 }
837
838 if (_is_member_holonym)
839 {
840 conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)");
841 }
842
843 if (!_member_holonym_of.empty())
844 {
845 std::stringstream cond;
846 if (_member_holonym_of.get_notlogic())
847 {
848 cond << "noun_id NOT IN";
849 } else {
850 cond << "noun_id IN";
851 }
852
853 cond << "(SELECT holonym_id FROM member_meronymy WHERE ";
854
855 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
856 switch (f.get_type())
857 {
858 case filter<noun>::type::singleton:
859 {
860 if (notlogic == f.get_notlogic())
861 {
862 return "meronym_id = @MMERO";
863 } else {
864 return "meronym_id != @MMERO";
865 }
866 }
867
868 case filter<noun>::type::group:
869 {
870 bool truelogic = notlogic != f.get_notlogic();
871
872 std::list<std::string> clauses;
873 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
874 return recur(f2, truelogic);
875 });
876
877 if (truelogic == f.get_orlogic())
878 {
879 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
880 } else {
881 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
882 }
883 }
884 }
885 };
886
887 cond << recur(_member_holonym_of, _member_holonym_of.get_notlogic());
888 cond << ")";
889 conditions.push_back(cond.str());
890 }
891
892 if (_is_proper)
893 {
894 conditions.push_back("proper = 1");
895 }
896
897 if (_is_not_proper)
898 {
899 conditions.push_back("proper = 0");
900 }
901
902 if (_is_instance)
903 {
904 conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)");
905 }
906
907 if (!_instance_of.empty())
908 {
909 std::stringstream cond;
910 if (_instance_of.get_notlogic())
911 {
912 cond << "noun_id NOT IN";
913 } else {
914 cond << "noun_id IN";
915 }
916
917 cond << "(SELECT instance_id FROM instantiation WHERE ";
918
919 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
920 switch (f.get_type())
921 {
922 case filter<noun>::type::singleton:
923 {
924 if (notlogic == f.get_notlogic())
925 {
926 return "class_id = @CLSID";
927 } else {
928 return "class_id != @CLSID";
929 }
930 }
931
932 case filter<noun>::type::group:
933 {
934 bool truelogic = notlogic != f.get_notlogic();
935
936 std::list<std::string> clauses;
937 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
938 return recur(f2, truelogic);
939 });
940
941 if (truelogic == f.get_orlogic())
942 {
943 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
944 } else {
945 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
946 }
947 }
948 }
949 };
950
951 cond << recur(_instance_of, _instance_of.get_notlogic());
952 cond << ")";
953 conditions.push_back(cond.str());
954 }
955
956 if (_is_class)
957 {
958 conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)");
959 }
960
961 if (!_class_of.empty())
962 {
963 std::stringstream cond;
964 if (_class_of.get_notlogic())
965 {
966 cond << "noun_id NOT IN";
967 } else {
968 cond << "noun_id IN";
969 }
970
971 cond << "(SELECT class_id FROM instantiation WHERE ";
972
973 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
974 switch (f.get_type())
975 {
976 case filter<noun>::type::singleton:
977 {
978 if (notlogic == f.get_notlogic())
979 {
980 return "instance_id = @INSID";
981 } else {
982 return "instance_id != @INSID";
983 }
984 }
985
986 case filter<noun>::type::group:
987 {
988 bool truelogic = notlogic != f.get_notlogic();
989
990 std::list<std::string> clauses;
991 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
992 return recur(f2, truelogic);
993 });
994
995 if (truelogic == f.get_orlogic())
996 {
997 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
998 } else {
999 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1000 }
1001 }
1002 }
1003 };
1004
1005 cond << recur(_class_of, _class_of.get_notlogic());
1006 cond << ")";
1007 conditions.push_back(cond.str());
1008 }
1009
1010 if (_has_synonyms)
1011 {
1012 conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_synonymy)");
1013 }
1014
1015 if (!_synonym_of.empty())
1016 {
1017 std::stringstream cond;
1018 if (_synonym_of.get_notlogic())
1019 {
1020 cond << "noun_id NOT IN";
1021 } else {
1022 cond << "noun_id IN";
1023 }
1024
1025 cond << "(SELECT noun_2_id FROM noun_synonymy WHERE ";
1026
1027 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1028 switch (f.get_type())
1029 {
1030 case filter<noun>::type::singleton:
1031 {
1032 if (notlogic == f.get_notlogic())
1033 {
1034 return "noun_1_id = @SYNID";
1035 } else {
1036 return "noun_1_id != @SYNID";
1037 }
1038 }
1039
1040 case filter<noun>::type::group:
1041 {
1042 bool truelogic = notlogic != f.get_notlogic();
1043
1044 std::list<std::string> clauses;
1045 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1046 return recur(f2, truelogic);
1047 });
1048
1049 if (truelogic == f.get_orlogic())
1050 {
1051 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1052 } else {
1053 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1054 }
1055 }
1056 }
1057 };
1058
1059 cond << recur(_synonym_of, _synonym_of.get_notlogic());
1060 cond << ")";
1061 conditions.push_back(cond.str());
1062 }
1063
1064 if (_has_antonyms)
1065 {
1066 conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_antonymy)");
1067 }
1068
1069 if (!_antonym_of.empty())
1070 {
1071 std::stringstream cond;
1072 if (_antonym_of.get_notlogic())
1073 {
1074 cond << "noun_id NOT IN";
1075 } else {
1076 cond << "noun_id IN";
1077 }
1078
1079 cond << "(SELECT noun_2_id FROM noun_antonymy WHERE ";
1080
1081 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
1082 switch (f.get_type())
1083 {
1084 case filter<noun>::type::singleton:
1085 {
1086 if (notlogic == f.get_notlogic())
1087 {
1088 return "noun_1_id = @ANTID";
1089 } else {
1090 return "noun_1_id != @ANTID";
1091 }
1092 }
1093
1094 case filter<noun>::type::group:
1095 {
1096 bool truelogic = notlogic != f.get_notlogic();
1097
1098 std::list<std::string> clauses;
1099 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
1100 return recur(f2, truelogic);
1101 });
1102
1103 if (truelogic == f.get_orlogic())
1104 {
1105 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1106 } else {
1107 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1108 }
1109 }
1110 }
1111 };
1112
1113 cond << recur(_antonym_of, _antonym_of.get_notlogic());
1114 cond << ")";
1115 conditions.push_back(cond.str());
1116 }
1117
1118 if (_has_pertainym)
1119 {
1120 conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)");
1121 }
1122
1123 if (!_anti_pertainym_of.empty())
1124 {
1125 std::stringstream cond;
1126 if (_anti_pertainym_of.get_notlogic())
1127 {
1128 cond << "noun_id NOT IN";
1129 } else {
1130 cond << "noun_id IN";
1131 }
1132
1133 cond << "(SELECT noun_id FROM pertainymy WHERE ";
1134
1135 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
1136 switch (f.get_type())
1137 {
1138 case filter<adjective>::type::singleton:
1139 {
1140 if (notlogic == f.get_notlogic())
1141 {
1142 return "pertainym_id = @PERID";
1143 } else {
1144 return "pertainym_id != @PERID";
1145 }
1146 }
1147
1148 case filter<adjective>::type::group:
1149 {
1150 bool truelogic = notlogic != f.get_notlogic();
1151
1152 std::list<std::string> clauses;
1153 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
1154 return recur(f2, truelogic);
1155 });
1156
1157 if (truelogic == f.get_orlogic())
1158 {
1159 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1160 } else {
1161 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1162 }
1163 }
1164 }
1165 };
1166
1167 cond << recur(_anti_pertainym_of, _anti_pertainym_of.get_notlogic());
1168 cond << ")";
1169 conditions.push_back(cond.str());
1170 }
1171
1172 if (_is_attribute)
1173 {
1174 conditions.push_back("noun_id IN (SELECT noun_id FROM variation)");
1175 }
1176
1177 if (!_attribute_of.empty())
1178 {
1179 std::stringstream cond;
1180 if (_attribute_of.get_notlogic())
1181 {
1182 cond << "noun_id NOT IN";
1183 } else {
1184 cond << "noun_id IN";
1185 }
1186
1187 cond << "(SELECT noun_id FROM variation WHERE ";
1188
1189 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
1190 switch (f.get_type())
1191 {
1192 case filter<adjective>::type::singleton:
1193 {
1194 if (notlogic == f.get_notlogic())
1195 {
1196 return "adjective_id = @VALID";
1197 } else {
1198 return "adjective_id != @VALID";
1199 }
1200 }
1201
1202 case filter<adjective>::type::group:
1203 {
1204 bool truelogic = notlogic != f.get_notlogic();
1205
1206 std::list<std::string> clauses;
1207 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
1208 return recur(f2, truelogic);
1209 });
1210
1211 if (truelogic == f.get_orlogic())
1212 {
1213 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
1214 } else {
1215 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1216 }
1217 }
1218 }
1219 };
1220
1221 cond << recur(_attribute_of, _attribute_of.get_notlogic());
1222 cond << ")";
1223 conditions.push_back(cond.str());
1224 }
1225 /*
1226 if (!_derived_from_adjective.empty())
1227 {
1228 std::list<std::string> clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ");
1229 std::string cond = "noun_id IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1230 conditions.push_back(cond);
1231 }
1232
1233 if (!_not_derived_from_adjective.empty())
1234 {
1235 std::list<std::string> clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ");
1236 std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1237 conditions.push_back(cond);
1238 }
1239
1240 if (!_derived_from_adverb.empty())
1241 {
1242 std::list<std::string> clauses(_derived_from_adverb.size(), "adverb_id = @DERADV");
1243 std::string cond = "noun_id IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1244 conditions.push_back(cond);
1245 }
1246
1247 if (!_not_derived_from_adverb.empty())
1248 {
1249 std::list<std::string> clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV");
1250 std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1251 conditions.push_back(cond);
1252 }
1253
1254 if (!_derived_from_noun.empty())
1255 {
1256 std::list<std::string> clauses(_derived_from_noun.size(), "noun_2_id = @DERN");
1257 std::string cond = "noun_id IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
1258 conditions.push_back(cond);
1259 }
1260
1261 if (!_not_derived_from_noun.empty())
1262 {
1263 std::list<std::string> clauses(_not_derived_from_noun.size(), "noun_2_id = @NDERN");
1264 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 ") + ")";
1265 conditions.push_back(cond);
1266 }
1267 */
1268 if (!conditions.empty())
1269 {
1270 construct << " WHERE ";
1271 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
1272 }
1273
1274 if (_random)
1275 {
1276 construct << " ORDER BY RANDOM()";
1277 }
1278
1279 if (_limit != unlimited)
1280 {
1281 construct << " LIMIT " << _limit;
1282 }
1283
1284 sqlite3_stmt* ppstmt;
1285 std::string query = construct.str();
1286 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1287 {
1288 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1289 }
1290
1291 if (!_rhymes.empty())
1292 {
1293 int i = 0;
1294 for (auto rhyme : _rhymes)
1295 {
1296 std::string rhymer = "%" + rhyme;
1297 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
1298
1299 i++;
1300 }
1301 }
1302
1303 for (auto except : _except)
1304 {
1305 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
1306 }
1307
1308 for (auto sform : _with_singular_form)
1309 {
1310 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SFORM"), sform.c_str(), sform.size(), SQLITE_STATIC);
1311 }
1312
1313 for (auto hyponym : _hypernym_of.inorder_flatten())
1314 {
1315 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id);
1316 }
1317
1318 for (auto hypernym : _hyponym_of.inorder_flatten())
1319 {
1320 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id);
1321 }
1322
1323 for (auto holonym : _part_meronym_of.inorder_flatten())
1324 {
1325 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id);
1326 }
1327
1328 for (auto meronym : _part_holonym_of.inorder_flatten())
1329 {
1330 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id);
1331 }
1332
1333 for (auto holonym : _substance_meronym_of.inorder_flatten())
1334 {
1335 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id);
1336 }
1337
1338 for (auto meronym : _substance_holonym_of.inorder_flatten())
1339 {
1340 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id);
1341 }
1342
1343 for (auto holonym : _member_meronym_of.inorder_flatten())
1344 {
1345 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id);
1346 }
1347
1348 for (auto meronym : _member_holonym_of.inorder_flatten())
1349 {
1350 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id);
1351 }
1352
1353 for (auto cls : _instance_of.inorder_flatten())
1354 {
1355 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id);
1356 }
1357
1358 for (auto inst : _class_of.inorder_flatten())
1359 {
1360 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id);
1361 }
1362
1363 for (auto synonym : _synonym_of.inorder_flatten())
1364 {
1365 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
1366 }
1367
1368 for (auto antonym : _antonym_of.inorder_flatten())
1369 {
1370 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
1371 }
1372
1373 for (auto pertainym : _anti_pertainym_of.inorder_flatten())
1374 {
1375 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id);
1376 }
1377
1378 for (auto value : _attribute_of.inorder_flatten())
1379 {
1380 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id);
1381 }
1382 /*
1383 for (auto adj : _derived_from_adjective)
1384 {
1385 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id);
1386 }
1387
1388 for (auto adj : _not_derived_from_adjective)
1389 {
1390 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id);
1391 }
1392
1393 for (auto adv : _derived_from_adverb)
1394 {
1395 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id);
1396 }
1397
1398 for (auto adv : _not_derived_from_adverb)
1399 {
1400 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id);
1401 }
1402
1403 for (auto n : _derived_from_noun)
1404 {
1405 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id);
1406 }
1407
1408 for (auto n : _not_derived_from_noun)
1409 {
1410 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id);
1411 }
1412*/
1413 std::list<noun> output;
1414 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1415 {
1416 noun tnc {_data, sqlite3_column_int(ppstmt, 0)};
1417 tnc._singular = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1418
1419 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
1420 {
1421 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1422 }
1423
1424 output.push_back(tnc);
1425 }
1426
1427 sqlite3_finalize(ppstmt);
1428
1429 for (auto& noun : output)
1430 {
1431 query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?";
1432 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1433 {
1434 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1435 }
1436
1437 sqlite3_bind_int(ppstmt, 1, noun._id);
1438
1439 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1440 {
1441 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
1442 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
1443
1444 noun.pronunciations.push_back(phonemes);
1445 }
1446
1447 sqlite3_finalize(ppstmt);
1448 }
1449
1450 return output;
1451 }
1452
1453};