summary refs log tree commit diff stats
path: root/lib
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
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')
-rw-r--r--lib/adjective.cpp113
-rw-r--r--lib/adjective.h51
-rw-r--r--lib/adjective_query.cpp1072
-rw-r--r--lib/adjective_query.h112
-rw-r--r--lib/adverb.cpp71
-rw-r--r--lib/adverb.h35
-rw-r--r--lib/adverb_query.cpp758
-rw-r--r--lib/adverb_query.h86
-rw-r--r--lib/binding.cpp180
-rw-r--r--lib/binding.h70
-rw-r--r--lib/data.cpp177
-rw-r--r--lib/data.h380
-rw-r--r--lib/database.cpp79
-rw-r--r--lib/database.h73
-rw-r--r--lib/enums.h45
-rw-r--r--lib/field.cpp91
-rw-r--r--lib/field.h306
-rw-r--r--lib/filter.cpp1365
-rw-r--r--lib/filter.h143
-rw-r--r--lib/form.cpp53
-rw-r--r--lib/form.h149
-rw-r--r--lib/frame.cpp317
-rw-r--r--lib/frame.h178
-rw-r--r--lib/group.cpp43
-rw-r--r--lib/group.h87
-rw-r--r--lib/lemma.cpp69
-rw-r--r--lib/lemma.h120
-rw-r--r--lib/notion.cpp94
-rw-r--r--lib/notion.h200
-rw-r--r--lib/noun.cpp221
-rw-r--r--lib/noun.h55
-rw-r--r--lib/noun_query.cpp2013
-rw-r--r--lib/noun_query.h180
-rw-r--r--lib/preposition.cpp107
-rw-r--r--lib/preposition.h38
-rw-r--r--lib/pronunciation.cpp69
-rw-r--r--lib/pronunciation.h163
-rw-r--r--lib/query.h123
-rw-r--r--lib/statement.cpp806
-rw-r--r--lib/statement.h272
-rw-r--r--lib/util.h24
-rw-r--r--lib/verb.cpp64
-rw-r--r--lib/verb.h34
-rw-r--r--lib/verb_query.cpp315
-rw-r--r--lib/verb_query.h45
-rw-r--r--lib/verbly.h36
-rw-r--r--lib/word.cpp120
-rw-r--r--lib/word.h193
48 files changed, 4950 insertions, 6445 deletions
diff --git a/lib/adjective.cpp b/lib/adjective.cpp deleted file mode 100644 index ba8254a..0000000 --- a/lib/adjective.cpp +++ /dev/null
@@ -1,113 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adjective::adjective()
6 {
7
8 }
9
10 adjective::adjective(const data& _data, int _id) : word(_data, _id)
11 {
12
13 }
14
15 std::string adjective::base_form() const
16 {
17 assert(_valid == true);
18
19 return _base_form;
20 }
21
22 std::string adjective::comparative_form() const
23 {
24 assert(_valid == true);
25
26 return _comparative_form;
27 }
28
29 std::string adjective::superlative_form() const
30 {
31 assert(_valid == true);
32
33 return _superlative_form;
34 }
35
36 adjective::positioning adjective::position() const
37 {
38 assert(_valid == true);
39
40 return _position;
41 }
42
43 bool adjective::has_comparative_form() const
44 {
45 assert(_valid == true);
46
47 return !_comparative_form.empty();
48 }
49
50 bool adjective::has_superlative_form() const
51 {
52 assert(_valid == true);
53
54 return !_superlative_form.empty();
55 }
56
57 bool adjective::has_position() const
58 {
59 assert(_valid == true);
60
61 return _position != adjective::positioning::undefined;
62 }
63
64 adjective_query adjective::antonyms() const
65 {
66 assert(_valid == true);
67
68 return _data->adjectives().antonym_of(*this);
69 }
70
71 adjective_query adjective::synonyms() const
72 {
73 assert(_valid == true);
74
75 return _data->adjectives().synonym_of(*this);
76 }
77
78 adjective_query adjective::generalizations() const
79 {
80 assert(_valid == true);
81
82 return _data->adjectives().generalization_of(*this);
83 }
84
85 adjective_query adjective::specifications() const
86 {
87 assert(_valid == true);
88
89 return _data->adjectives().specification_of(*this);
90 }
91
92 noun_query adjective::anti_pertainyms() const
93 {
94 assert(_valid == true);
95
96 return _data->nouns().anti_pertainym_of(*this);
97 }
98
99 adverb_query adjective::mannernyms() const
100 {
101 assert(_valid == true);
102
103 return _data->adverbs().mannernym_of(*this);
104 }
105
106 noun_query adjective::attributes() const
107 {
108 assert(_valid == true);
109
110 return _data->nouns().attribute_of(*this);
111 }
112
113};
diff --git a/lib/adjective.h b/lib/adjective.h deleted file mode 100644 index a6eb293..0000000 --- a/lib/adjective.h +++ /dev/null
@@ -1,51 +0,0 @@
1#ifndef ADJECTIVE_H_87B3FB75
2#define ADJECTIVE_H_87B3FB75
3
4namespace verbly {
5
6 class adjective_query;
7 class adverb_query;
8 class noun_query;
9
10 class adjective : public word {
11 public:
12 enum class positioning {
13 undefined,
14 predicate,
15 attributive,
16 postnominal
17 };
18
19 private:
20 std::string _base_form;
21 std::string _comparative_form;
22 std::string _superlative_form;
23 positioning _position = positioning::undefined;
24
25 friend class adjective_query;
26
27 public:
28 adjective();
29 adjective(const data& _data, int _id);
30
31 std::string base_form() const;
32 std::string comparative_form() const;
33 std::string superlative_form() const;
34 positioning position() const;
35
36 bool has_comparative_form() const;
37 bool has_superlative_form() const;
38 bool has_position() const;
39
40 adjective_query antonyms() const;
41 adjective_query synonyms() const;
42 adjective_query generalizations() const;
43 adjective_query specifications() const;
44 noun_query anti_pertainyms() const;
45 adverb_query mannernyms() const;
46 noun_query attributes() const;
47 };
48
49};
50
51#endif /* end of include guard: ADJECTIVE_H_87B3FB75 */
diff --git a/lib/adjective_query.cpp b/lib/adjective_query.cpp deleted file mode 100644 index 90ccef4..0000000 --- a/lib/adjective_query.cpp +++ /dev/null
@@ -1,1072 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adjective_query::adjective_query(const data& _data) : _data(_data)
6 {
7
8 }
9
10 adjective_query& adjective_query::limit(int _limit)
11 {
12 if ((_limit > 0) || (_limit == unlimited))
13 {
14 this->_limit = _limit;
15 }
16
17 return *this;
18 }
19
20 adjective_query& adjective_query::random()
21 {
22 this->_random = true;
23
24 return *this;
25 }
26
27 adjective_query& adjective_query::except(const adjective& _word)
28 {
29 _except.push_back(_word);
30
31 return *this;
32 }
33
34 adjective_query& adjective_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 adjective*>(&_word) != nullptr)
42 {
43 _except.push_back(dynamic_cast<const adjective&>(_word));
44 }
45
46 return *this;
47 }
48
49 adjective_query& adjective_query::rhymes_with(rhyme _r)
50 {
51 _rhymes.push_back(_r);
52
53 return *this;
54 }
55
56 adjective_query& adjective_query::has_pronunciation()
57 {
58 this->_has_prn = true;
59
60 return *this;
61 }
62
63 adjective_query& adjective_query::has_rhyming_noun()
64 {
65 _has_rhyming_noun = true;
66
67 return *this;
68 }
69
70 adjective_query& adjective_query::has_rhyming_adjective()
71 {
72 _has_rhyming_adjective = true;
73
74 return *this;
75 }
76
77 adjective_query& adjective_query::has_rhyming_adverb()
78 {
79 _has_rhyming_adverb = true;
80
81 return *this;
82 }
83
84 adjective_query& adjective_query::has_rhyming_verb()
85 {
86 _has_rhyming_verb = true;
87
88 return *this;
89 }
90
91 adjective_query& adjective_query::with_stress(filter<std::vector<bool>> _arg)
92 {
93 _stress = _arg;
94
95 return *this;
96 }
97
98 adjective_query& adjective_query::with_prefix(filter<std::string> _f)
99 {
100 _f.clean();
101 _with_prefix = _f;
102
103 return *this;
104 }
105
106 adjective_query& adjective_query::with_suffix(filter<std::string> _f)
107 {
108 _f.clean();
109 _with_suffix = _f;
110
111 return *this;
112 }
113
114 adjective_query& adjective_query::with_complexity(int _arg)
115 {
116 _with_complexity = _arg;
117
118 return *this;
119 }
120
121 adjective_query& adjective_query::requires_comparative_form()
122 {
123 _requires_comparative_form = true;
124
125 return *this;
126 }
127
128 adjective_query& adjective_query::requires_superlative_form()
129 {
130 _requires_superlative_form = true;
131
132 return *this;
133 }
134
135 adjective_query& adjective_query::position(adjective::positioning pos)
136 {
137 _position = pos;
138
139 return *this;
140 }
141
142 adjective_query& adjective_query::is_variant()
143 {
144 this->_is_variant = true;
145
146 return *this;
147 }
148
149 adjective_query& adjective_query::variant_of(filter<noun> _f)
150 {
151 _f.clean();
152 _variant_of = _f;
153
154 return *this;
155 }
156
157 adjective_query& adjective_query::has_antonyms()
158 {
159 this->_is_antonymic = true;
160
161 return *this;
162 }
163
164 adjective_query& adjective_query::antonym_of(filter<adjective> _f)
165 {
166 _f.clean();
167 _antonym_of = _f;
168
169 return *this;
170 }
171
172 adjective_query& adjective_query::has_synonyms()
173 {
174 this->_is_synonymic = true;
175
176 return *this;
177 }
178
179 adjective_query& adjective_query::synonym_of(filter<adjective> _f)
180 {
181 _f.clean();
182 _synonym_of = _f;
183
184 return *this;
185 }
186
187 adjective_query& adjective_query::is_generalization()
188 {
189 this->_is_generalization = true;
190
191 return *this;
192 }
193
194 adjective_query& adjective_query::generalization_of(filter<adjective> _f)
195 {
196 _f.clean();
197 _generalization_of = _f;
198
199 return *this;
200 }
201
202 adjective_query& adjective_query::is_specification()
203 {
204 this->_is_specification = true;
205
206 return *this;
207 }
208
209 adjective_query& adjective_query::specification_of(filter<adjective> _f)
210 {
211 _f.clean();
212 _specification_of = _f;
213
214 return *this;
215 }
216
217 adjective_query& adjective_query::is_pertainymic()
218 {
219 this->_is_pertainymic = true;
220
221 return *this;
222 }
223
224 adjective_query& adjective_query::pertainym_of(filter<noun> _f)
225 {
226 _f.clean();
227 _pertainym_of = _f;
228
229 return *this;
230 }
231
232 adjective_query& adjective_query::is_mannernymic()
233 {
234 this->_is_mannernymic = true;
235
236 return *this;
237 }
238
239 adjective_query& adjective_query::anti_mannernym_of(filter<adverb> _f)
240 {
241 _f.clean();
242 _anti_mannernym_of = _f;
243
244 return *this;
245 }
246 /*
247 adjective_query& adjective_query::derived_from(const word& _w)
248 {
249 if (dynamic_cast<const adjective*>(&_w) != nullptr)
250 {
251 _derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
252 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
253 {
254 _derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
255 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
256 {
257 _derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
258 }
259
260 return *this;
261 }
262
263 adjective_query& adjective_query::not_derived_from(const word& _w)
264 {
265 if (dynamic_cast<const adjective*>(&_w) != nullptr)
266 {
267 _not_derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
268 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
269 {
270 _not_derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
271 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
272 {
273 _not_derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
274 }
275
276 return *this;
277 }
278 */
279 std::list<adjective> adjective_query::run() const
280 {
281 std::stringstream construct;
282 construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives";
283 std::list<std::string> conditions;
284 std::list<binding> bindings;
285
286 if (_has_prn)
287 {
288 conditions.push_back("adjective_id IN (SELECT adjective_id FROM adjective_pronunciations)");
289 }
290
291 if (!_rhymes.empty())
292 {
293 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
294 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
295 conditions.push_back(cond);
296
297 for (auto rhy : _rhymes)
298 {
299 bindings.emplace_back(rhy.get_prerhyme());
300 bindings.emplace_back(rhy.get_rhyme());
301 }
302 }
303
304 if (_has_rhyming_noun)
305 {
306 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
307 }
308
309 if (_has_rhyming_adjective)
310 {
311 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adjective_id != curp.adjective_id)");
312 }
313
314 if (_has_rhyming_adverb)
315 {
316 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
317 }
318
319 if (_has_rhyming_verb)
320 {
321 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
322 }
323
324 for (auto except : _except)
325 {
326 conditions.push_back("adjective_id != ?");
327 bindings.emplace_back(except._id);
328 }
329
330 if (_requires_comparative_form)
331 {
332 conditions.push_back("comparative IS NOT NULL");
333 }
334
335 if (_requires_superlative_form)
336 {
337 conditions.push_back("superlative IS NOT NULL");
338 }
339
340 switch (_position)
341 {
342 case adjective::positioning::predicate: conditions.push_back("position = 'p'"); break;
343 case adjective::positioning::attributive: conditions.push_back("position = 'a'"); break;
344 case adjective::positioning::postnominal: conditions.push_back("position = 'i'"); break;
345 case adjective::positioning::undefined: break;
346 }
347
348 if (!_stress.empty())
349 {
350 std::stringstream cond;
351 if (_stress.get_notlogic())
352 {
353 cond << "adjective_id NOT IN";
354 } else {
355 cond << "adjective_id IN";
356 }
357
358 cond << "(SELECT adjective_id FROM adjective_pronunciations WHERE ";
359
360 std::function<std::string (filter<std::vector<bool>>, bool)> recur = [&] (filter<std::vector<bool>> f, bool notlogic) -> std::string {
361 switch (f.get_type())
362 {
363 case filter<std::vector<bool>>::type::singleton:
364 {
365 std::ostringstream _val;
366 for (auto syl : f.get_elem())
367 {
368 if (syl)
369 {
370 _val << "1";
371 } else {
372 _val << "0";
373 }
374 }
375
376 bindings.emplace_back(_val.str());
377
378 if (notlogic == f.get_notlogic())
379 {
380 return "stress = ?";
381 } else {
382 return "stress != ?";
383 }
384 }
385
386 case filter<std::vector<bool>>::type::group:
387 {
388 bool truelogic = notlogic != f.get_notlogic();
389
390 std::list<std::string> clauses;
391 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::vector<bool>> f2) {
392 return recur(f2, truelogic);
393 });
394
395 if (truelogic == f.get_orlogic())
396 {
397 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
398 } else {
399 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
400 }
401 }
402 }
403 };
404
405 cond << recur(_stress, _stress.get_notlogic());
406 cond << ")";
407 conditions.push_back(cond.str());
408 }
409
410 if (!_with_prefix.empty())
411 {
412 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
413 switch (f.get_type())
414 {
415 case filter<std::string>::type::singleton:
416 {
417 bindings.emplace_back(f.get_elem() + "%");
418
419 if (notlogic == f.get_notlogic())
420 {
421 return "base_form LIKE ?";
422 } else {
423 return "base_form NOT LIKE ?";
424 }
425 }
426
427 case filter<std::string>::type::group:
428 {
429 bool truelogic = notlogic != f.get_notlogic();
430
431 std::list<std::string> clauses;
432 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
433 return recur(f2, truelogic);
434 });
435
436 if (truelogic == f.get_orlogic())
437 {
438 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
439 } else {
440 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
441 }
442 }
443 }
444 };
445
446 conditions.push_back(recur(_with_prefix, false));
447 }
448
449 if (!_with_suffix.empty())
450 {
451 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
452 switch (f.get_type())
453 {
454 case filter<std::string>::type::singleton:
455 {
456 bindings.emplace_back("%" + f.get_elem());
457
458 if (notlogic == f.get_notlogic())
459 {
460 return "base_form LIKE ?";
461 } else {
462 return "base_form NOT LIKE ?";
463 }
464 }
465
466 case filter<std::string>::type::group:
467 {
468 bool truelogic = notlogic != f.get_notlogic();
469
470 std::list<std::string> clauses;
471 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
472 return recur(f2, truelogic);
473 });
474
475 if (truelogic == f.get_orlogic())
476 {
477 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
478 } else {
479 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
480 }
481 }
482 }
483 };
484
485 conditions.push_back(recur(_with_suffix, false));
486 }
487
488 if (_with_complexity != unlimited)
489 {
490 conditions.push_back("complexity = ?");
491 bindings.emplace_back(_with_complexity);
492 }
493
494 if (_is_variant)
495 {
496 conditions.push_back("adjective_id IN (SELECT adjective_id FROM variation)");
497 }
498
499 if (!_variant_of.empty())
500 {
501 std::stringstream cond;
502 if (_variant_of.get_notlogic())
503 {
504 cond << "adjective_id NOT IN";
505 } else {
506 cond << "adjective_id IN";
507 }
508
509 cond << "(SELECT adjective_id FROM variation WHERE ";
510
511 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
512 switch (f.get_type())
513 {
514 case filter<noun>::type::singleton:
515 {
516 bindings.emplace_back(f.get_elem()._id);
517
518 if (notlogic == f.get_notlogic())
519 {
520 return "noun_id = ?";
521 } else {
522 return "noun_id != ?";
523 }
524 }
525
526 case filter<noun>::type::group:
527 {
528 bool truelogic = notlogic != f.get_notlogic();
529
530 std::list<std::string> clauses;
531 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<noun> f2) {
532 return recur(f2, truelogic);
533 });
534
535 if (truelogic == f.get_orlogic())
536 {
537 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
538 } else {
539 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
540 }
541 }
542 }
543 };
544
545 cond << recur(_variant_of, _variant_of.get_notlogic());
546 cond << ")";
547 conditions.push_back(cond.str());
548 }
549
550 if (_is_antonymic)
551 {
552 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy)");
553 }
554
555 if (!_antonym_of.empty())
556 {
557 std::stringstream cond;
558 if (_antonym_of.get_notlogic())
559 {
560 cond << "adjective_id NOT IN";
561 } else {
562 cond << "adjective_id IN";
563 }
564
565 cond << "(SELECT adjective_2_id FROM adjective_antonymy WHERE ";
566
567 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
568 switch (f.get_type())
569 {
570 case filter<adjective>::type::singleton:
571 {
572 bindings.emplace_back(f.get_elem()._id);
573
574 if (notlogic == f.get_notlogic())
575 {
576 return "adjective_1_id = ?";
577 } else {
578 return "adjective_1_id != ?";
579 }
580 }
581
582 case filter<adjective>::type::group:
583 {
584 bool truelogic = notlogic != f.get_notlogic();
585
586 std::list<std::string> clauses;
587 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
588 return recur(f2, truelogic);
589 });
590
591 if (truelogic == f.get_orlogic())
592 {
593 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
594 } else {
595 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
596 }
597 }
598 }
599 };
600
601 cond << recur(_antonym_of, _antonym_of.get_notlogic());
602 cond << ")";
603 conditions.push_back(cond.str());
604 }
605
606 if (_is_synonymic)
607 {
608 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy)");
609 }
610
611 if (!_synonym_of.empty())
612 {
613 std::stringstream cond;
614 if (_synonym_of.get_notlogic())
615 {
616 cond << "adjective_id NOT IN";
617 } else {
618 cond << "adjective_id IN";
619 }
620
621 cond << "(SELECT adjective_2_id FROM adjective_synonymy WHERE ";
622
623 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
624 switch (f.get_type())
625 {
626 case filter<adjective>::type::singleton:
627 {
628 bindings.emplace_back(f.get_elem()._id);
629
630 if (notlogic == f.get_notlogic())
631 {
632 return "adjective_1_id = ?";
633 } else {
634 return "adjective_1_id != ?";
635 }
636 }
637
638 case filter<adjective>::type::group:
639 {
640 bool truelogic = notlogic != f.get_notlogic();
641
642 std::list<std::string> clauses;
643 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
644 return recur(f2, truelogic);
645 });
646
647 if (truelogic == f.get_orlogic())
648 {
649 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
650 } else {
651 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
652 }
653 }
654 }
655 };
656
657 cond << recur(_synonym_of, _synonym_of.get_notlogic());
658 cond << ")";
659 conditions.push_back(cond.str());
660 }
661
662 if (_is_generalization)
663 {
664 conditions.push_back("adjective_id IN (SELECT general_id FROM specification)");
665 }
666
667 if (!_generalization_of.empty())
668 {
669 std::stringstream cond;
670 if (_generalization_of.get_notlogic())
671 {
672 cond << "adjective_id NOT IN";
673 } else {
674 cond << "adjective_id IN";
675 }
676
677 cond << "(SELECT general_id FROM specification WHERE ";
678
679 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
680 switch (f.get_type())
681 {
682 case filter<adjective>::type::singleton:
683 {
684 bindings.emplace_back(f.get_elem()._id);
685
686 if (notlogic == f.get_notlogic())
687 {
688 return "specific_id = ?";
689 } else {
690 return "specific_id != ?";
691 }
692 }
693
694 case filter<adjective>::type::group:
695 {
696 bool truelogic = notlogic != f.get_notlogic();
697
698 std::list<std::string> clauses;
699 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
700 return recur(f2, truelogic);
701 });
702
703 if (truelogic == f.get_orlogic())
704 {
705 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
706 } else {
707 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
708 }
709 }
710 }
711 };
712
713 cond << recur(_generalization_of, _generalization_of.get_notlogic());
714 cond << ")";
715 conditions.push_back(cond.str());
716 }
717
718 if (_is_specification)
719 {
720 conditions.push_back("adjective_id IN (SELECT specific_id FROM specification)");
721 }
722
723 if (!_specification_of.empty())
724 {
725 std::stringstream cond;
726 if (_specification_of.get_notlogic())
727 {
728 cond << "adjective_id NOT IN";
729 } else {
730 cond << "adjective_id IN";
731 }
732
733 cond << "(SELECT specific_id FROM specification WHERE ";
734
735 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
736 switch (f.get_type())
737 {
738 case filter<adjective>::type::singleton:
739 {
740 bindings.emplace_back(f.get_elem()._id);
741
742 if (notlogic == f.get_notlogic())
743 {
744 return "general_id = ?";
745 } else {
746 return "general_id != ?";
747 }
748 }
749
750 case filter<adjective>::type::group:
751 {
752 bool truelogic = notlogic != f.get_notlogic();
753
754 std::list<std::string> clauses;
755 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
756 return recur(f2, truelogic);
757 });
758
759 if (truelogic == f.get_orlogic())
760 {
761 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
762 } else {
763 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
764 }
765 }
766 }
767 };
768
769 cond << recur(_specification_of, _specification_of.get_notlogic());
770 cond << ")";
771 conditions.push_back(cond.str());
772 }
773
774 if (_is_pertainymic)
775 {
776 conditions.push_back("adjective_id IN (SELECT pertainym_id FROM pertainymy)");
777 }
778
779 if (!_pertainym_of.empty())
780 {
781 std::stringstream cond;
782 if (_pertainym_of.get_notlogic())
783 {
784 cond << "adjective_id NOT IN";
785 } else {
786 cond << "adjective_id IN";
787 }
788
789 cond << "(SELECT pertainym_id FROM pertainymy WHERE ";
790
791 std::function<std::string (filter<noun>, bool)> recur = [&] (filter<noun> f, bool notlogic) -> std::string {
792 switch (f.get_type())
793 {
794 case filter<noun>::type::singleton:
795 {
796 bindings.emplace_back(f.get_elem()._id);
797
798 if (notlogic == f.get_notlogic())
799 {
800 return "noun_id = ?";
801 } else {
802 return "noun_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 cond << recur(_pertainym_of, _pertainym_of.get_notlogic());
826 cond << ")";
827 conditions.push_back(cond.str());
828 }
829
830 if (_is_mannernymic)
831 {
832 conditions.push_back("adjective_id IN (SELECT adjective_id FROM mannernymy)");
833 }
834
835 if (!_anti_mannernym_of.empty())
836 {
837 std::stringstream cond;
838 if (_anti_mannernym_of.get_notlogic())
839 {
840 cond << "adjective_id NOT IN";
841 } else {
842 cond << "adjective_id IN";
843 }
844
845 cond << "(SELECT adjective_id FROM mannernymy WHERE ";
846
847 std::function<std::string (filter<adverb>, bool)> recur = [&] (filter<adverb> f, bool notlogic) -> std::string {
848 switch (f.get_type())
849 {
850 case filter<adverb>::type::singleton:
851 {
852 bindings.emplace_back(f.get_elem()._id);
853
854 if (notlogic == f.get_notlogic())
855 {
856 return "mannernym_id = ?";
857 } else {
858 return "mannernym_id != ?";
859 }
860 }
861
862 case filter<adverb>::type::group:
863 {
864 bool truelogic = notlogic != f.get_notlogic();
865
866 std::list<std::string> clauses;
867 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adverb> f2) {
868 return recur(f2, truelogic);
869 });
870
871 if (truelogic == f.get_orlogic())
872 {
873 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
874 } else {
875 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
876 }
877 }
878 }
879 };
880
881 cond << recur(_anti_mannernym_of, _anti_mannernym_of.get_notlogic());
882 cond << ")";
883 conditions.push_back(cond.str());
884 }
885/*
886 if (!_derived_from_adjective.empty())
887 {
888 std::list<std::string> clauses(_derived_from_adjective.size(), "adjective_2_id = @DERADJ");
889 std::string cond = "adjective_id IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
890 conditions.push_back(cond);
891 }
892
893 if (!_not_derived_from_adjective.empty())
894 {
895 std::list<std::string> clauses(_not_derived_from_adjective.size(), "adjective_2_id = @NDERADJ");
896 std::string cond = "adjective_id NOT IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
897 conditions.push_back(cond);
898 }
899
900 if (!_derived_from_adverb.empty())
901 {
902 std::list<std::string> clauses(_derived_from_adverb.size(), "adverb_id = @DERADV");
903 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
904 conditions.push_back(cond);
905 }
906
907 if (!_not_derived_from_adverb.empty())
908 {
909 std::list<std::string> clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV");
910 std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
911 conditions.push_back(cond);
912 }
913
914 if (!_derived_from_noun.empty())
915 {
916 std::list<std::string> clauses(_derived_from_noun.size(), "noun_id = @DERN");
917 std::string cond = "adjective_id IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
918 conditions.push_back(cond);
919 }
920
921 if (!_not_derived_from_noun.empty())
922 {
923 std::list<std::string> clauses(_not_derived_from_noun.size(), "noun_id = @NDERN");
924 std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
925 conditions.push_back(cond);
926 }*/
927
928 if (!conditions.empty())
929 {
930 construct << " WHERE ";
931 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
932 }
933
934 if (_random)
935 {
936 construct << " ORDER BY RANDOM()";
937 }
938
939 if (_limit != unlimited)
940 {
941 construct << " LIMIT " << _limit;
942 }
943
944 sqlite3_stmt* ppstmt;
945 std::string query = construct.str();
946 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
947 {
948 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
949 }
950
951 int i = 1;
952 for (auto& binding : bindings)
953 {
954 switch (binding.get_type())
955 {
956 case binding::type::integer:
957 {
958 sqlite3_bind_int(ppstmt, i, binding.get_integer());
959
960 break;
961 }
962
963 case binding::type::string:
964 {
965 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
966
967 break;
968 }
969 }
970
971 i++;
972 }
973
974 /*
975 for (auto adj : _derived_from_adjective)
976 {
977 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id);
978 }
979
980 for (auto adj : _not_derived_from_adjective)
981 {
982 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id);
983 }
984
985 for (auto adv : _derived_from_adverb)
986 {
987 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id);
988 }
989
990 for (auto adv : _not_derived_from_adverb)
991 {
992 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id);
993 }
994
995 for (auto n : _derived_from_noun)
996 {
997 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id);
998 }
999
1000 for (auto n : _not_derived_from_noun)
1001 {
1002 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id);
1003 }
1004*/
1005 std::list<adjective> output;
1006 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1007 {
1008 adjective tnc {_data, sqlite3_column_int(ppstmt, 0)};
1009 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1010
1011 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
1012 {
1013 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1014 }
1015
1016 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
1017 {
1018 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
1019 }
1020
1021 if (sqlite3_column_type(ppstmt, 4) != SQLITE_NULL)
1022 {
1023 std::string adjpos(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
1024 if (adjpos == "p")
1025 {
1026 tnc._position = adjective::positioning::predicate;
1027 } else if (adjpos == "a")
1028 {
1029 tnc._position = adjective::positioning::attributive;
1030 } else if (adjpos == "i")
1031 {
1032 tnc._position = adjective::positioning::postnominal;
1033 }
1034 }
1035
1036 output.push_back(tnc);
1037 }
1038
1039 sqlite3_finalize(ppstmt);
1040
1041 for (auto& adjective : output)
1042 {
1043 query = "SELECT pronunciation, prerhyme, rhyme FROM adjective_pronunciations WHERE adjective_id = ?";
1044 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1045 {
1046 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1047 }
1048
1049 sqlite3_bind_int(ppstmt, 1, adjective._id);
1050
1051 while (sqlite3_step(ppstmt) == SQLITE_ROW)
1052 {
1053 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
1054 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
1055
1056 adjective.pronunciations.push_back(phonemes);
1057
1058 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
1059 {
1060 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1061 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1062 adjective.rhymes.emplace_back(prerhyme, rhyming);
1063 }
1064 }
1065
1066 sqlite3_finalize(ppstmt);
1067 }
1068
1069 return output;
1070 }
1071
1072};
diff --git a/lib/adjective_query.h b/lib/adjective_query.h deleted file mode 100644 index e6a6609..0000000 --- a/lib/adjective_query.h +++ /dev/null
@@ -1,112 +0,0 @@
1#ifndef ADJECTIVE_QUERY_H_05E590FD
2#define ADJECTIVE_QUERY_H_05E590FD
3
4namespace verbly {
5
6 class adjective_query {
7 public:
8 adjective_query(const data& _data);
9
10 adjective_query& limit(int _limit);
11 adjective_query& random();
12 adjective_query& except(const adjective& _word);
13 adjective_query& rhymes_with(const word& _word);
14 adjective_query& rhymes_with(rhyme _r);
15 adjective_query& has_pronunciation();
16 adjective_query& has_rhyming_noun();
17 adjective_query& has_rhyming_adjective();
18 adjective_query& has_rhyming_adverb();
19 adjective_query& has_rhyming_verb();
20 adjective_query& with_stress(filter<std::vector<bool>> _arg);
21
22 adjective_query& requires_comparative_form();
23 adjective_query& requires_superlative_form();
24 adjective_query& position(adjective::positioning pos);
25
26 adjective_query& with_prefix(filter<std::string> _f);
27 adjective_query& with_suffix(filter<std::string> _f);
28
29 adjective_query& with_complexity(int _arg);
30
31 adjective_query& is_variant();
32 adjective_query& variant_of(filter<noun> _f);
33
34 adjective_query& has_antonyms();
35 adjective_query& antonym_of(filter<adjective> _f);
36
37 adjective_query& has_synonyms();
38 adjective_query& synonym_of(filter<adjective> _f);
39
40 adjective_query& is_generalization();
41 adjective_query& generalization_of(filter<adjective> _f);
42
43 adjective_query& is_specification();
44 adjective_query& specification_of(filter<adjective> _f);
45
46 adjective_query& is_pertainymic();
47 adjective_query& pertainym_of(filter<noun> _f);
48
49 adjective_query& is_mannernymic();
50 adjective_query& anti_mannernym_of(filter<adverb> _f);
51
52/* adjective_query& derived_from(const word& _w);
53 adjective_query& not_derived_from(const word& _w);*/
54
55 std::list<adjective> run() const;
56
57 const static int unlimited = -1;
58
59 protected:
60 const data& _data;
61 int _limit = unlimited;
62 bool _random = false;
63 std::list<rhyme> _rhymes;
64 std::list<adjective> _except;
65 bool _has_prn = false;
66 bool _has_rhyming_noun = false;
67 bool _has_rhyming_adjective = false;
68 bool _has_rhyming_adverb = false;
69 bool _has_rhyming_verb = false;
70 filter<std::vector<bool>> _stress;
71
72 bool _requires_comparative_form = false;
73 bool _requires_superlative_form = false;
74 adjective::positioning _position = adjective::positioning::undefined;
75
76 filter<std::string> _with_prefix;
77 filter<std::string> _with_suffix;
78
79 int _with_complexity = unlimited;
80
81 bool _is_variant = false;
82 filter<noun> _variant_of;
83
84 bool _is_antonymic = false;
85 filter<adjective> _antonym_of;
86
87 bool _is_synonymic = false;
88 filter<adjective> _synonym_of;
89
90 bool _is_generalization = false;
91 filter<adjective> _generalization_of;
92
93 bool _is_specification = false;
94 filter<adjective> _specification_of;
95
96 bool _is_pertainymic = false;
97 filter<noun> _pertainym_of;
98
99 bool _is_mannernymic = false;
100 filter<adverb> _anti_mannernym_of;
101
102/* std::list<adjective> _derived_from_adjective;
103 std::list<adjective> _not_derived_from_adjective;
104 std::list<adverb> _derived_from_adverb;
105 std::list<adverb> _not_derived_from_adverb;
106 std::list<noun> _derived_from_noun;
107 std::list<noun> _not_derived_from_noun;*/
108 };
109
110};
111
112#endif /* end of include guard: ADJECTIVE_QUERY_H_05E590FD */
diff --git a/lib/adverb.cpp b/lib/adverb.cpp deleted file mode 100644 index 442574e..0000000 --- a/lib/adverb.cpp +++ /dev/null
@@ -1,71 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adverb::adverb()
6 {
7
8 }
9
10 adverb::adverb(const data& _data, int _id) : word(_data, _id)
11 {
12
13 }
14
15 std::string adverb::base_form() const
16 {
17 assert(_valid == true);
18
19 return _base_form;
20 }
21
22 std::string adverb::comparative_form() const
23 {
24 assert(_valid == true);
25
26 return _comparative_form;
27 }
28
29 std::string adverb::superlative_form() const
30 {
31 assert(_valid == true);
32
33 return _superlative_form;
34 }
35
36 bool adverb::has_comparative_form() const
37 {
38 assert(_valid == true);
39
40 return !_comparative_form.empty();
41 }
42
43 bool adverb::has_superlative_form() const
44 {
45 assert(_valid == true);
46
47 return !_superlative_form.empty();
48 }
49
50 adverb_query adverb::antonyms() const
51 {
52 assert(_valid == true);
53
54 return _data->adverbs().antonym_of(*this);
55 }
56
57 adverb_query adverb::synonyms() const
58 {
59 assert(_valid == true);
60
61 return _data->adverbs().synonym_of(*this);
62 }
63
64 adjective_query adverb::anti_mannernyms() const
65 {
66 assert(_valid == true);
67
68 return _data->adjectives().anti_mannernym_of(*this);
69 }
70
71};
diff --git a/lib/adverb.h b/lib/adverb.h deleted file mode 100644 index 56d4e28..0000000 --- a/lib/adverb.h +++ /dev/null
@@ -1,35 +0,0 @@
1#ifndef ADVERB_H_86F8302F
2#define ADVERB_H_86F8302F
3
4namespace verbly {
5
6 class adverb : public word {
7 private:
8 std::string _base_form;
9 std::string _comparative_form;
10 std::string _superlative_form;
11
12 friend class adverb_query;
13
14 public:
15 adverb();
16 adverb(const data& _data, int _id);
17
18 std::string base_form() const;
19 std::string comparative_form() const;
20 std::string superlative_form() const;
21
22 bool has_comparative_form() const;
23 bool has_superlative_form() const;
24
25 adverb_query antonyms() const;
26 adverb_query synonyms() const;
27 adjective_query anti_mannernyms() const;
28
29 adverb_query& derived_from(const word& _w);
30 adverb_query& not_derived_from(const word& _w);
31 };
32
33};
34
35#endif /* end of include guard: ADVERB_H_86F8302F */
diff --git a/lib/adverb_query.cpp b/lib/adverb_query.cpp deleted file mode 100644 index 3e62bb7..0000000 --- a/lib/adverb_query.cpp +++ /dev/null
@@ -1,758 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adverb_query::adverb_query(const data& _data) : _data(_data)
6 {
7
8 }
9
10 adverb_query& adverb_query::limit(int _limit)
11 {
12 if ((_limit > 0) || (_limit == unlimited))
13 {
14 this->_limit = _limit;
15 }
16
17 return *this;
18 }
19
20 adverb_query& adverb_query::random()
21 {
22 this->_random = true;
23
24 return *this;
25 }
26
27 adverb_query& adverb_query::except(const adverb& _word)
28 {
29 _except.push_back(_word);
30
31 return *this;
32 }
33
34 adverb_query& adverb_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 adverb*>(&_word) != nullptr)
42 {
43 _except.push_back(dynamic_cast<const adverb&>(_word));
44 }
45
46 return *this;
47 }
48
49 adverb_query& adverb_query::rhymes_with(rhyme _r)
50 {
51 _rhymes.push_back(_r);
52
53 return *this;
54 }
55
56 adverb_query& adverb_query::has_pronunciation()
57 {
58 this->_has_prn = true;
59
60 return *this;
61 }
62
63 adverb_query& adverb_query::has_rhyming_noun()
64 {
65 _has_rhyming_noun = true;
66
67 return *this;
68 }
69
70 adverb_query& adverb_query::has_rhyming_adjective()
71 {
72 _has_rhyming_adjective = true;
73
74 return *this;
75 }
76
77 adverb_query& adverb_query::has_rhyming_adverb()
78 {
79 _has_rhyming_adverb = true;
80
81 return *this;
82 }
83
84 adverb_query& adverb_query::has_rhyming_verb()
85 {
86 _has_rhyming_verb = true;
87
88 return *this;
89 }
90
91 adverb_query& adverb_query::requires_comparative_form()
92 {
93 _requires_comparative_form = true;
94
95 return *this;
96 }
97
98 adverb_query& adverb_query::requires_superlative_form()
99 {
100 _requires_superlative_form = true;
101
102 return *this;
103 }
104
105 adverb_query& adverb_query::with_stress(filter<std::vector<bool>> _arg)
106 {
107 _stress = _arg;
108
109 return *this;
110 }
111
112 adverb_query& adverb_query::with_prefix(filter<std::string> _f)
113 {
114 _f.clean();
115 _with_prefix = _f;
116
117 return *this;
118 }
119
120 adverb_query& adverb_query::with_suffix(filter<std::string> _f)
121 {
122 _f.clean();
123 _with_suffix = _f;
124
125 return *this;
126 }
127
128 adverb_query& adverb_query::with_complexity(int _arg)
129 {
130 _with_complexity = _arg;
131
132 return *this;
133 }
134
135 adverb_query& adverb_query::has_antonyms()
136 {
137 _has_antonyms = true;
138
139 return *this;
140 }
141
142 adverb_query& adverb_query::antonym_of(filter<adverb> _f)
143 {
144 _f.clean();
145 _antonym_of = _f;
146
147 return *this;
148 }
149
150 adverb_query& adverb_query::has_synonyms()
151 {
152 _has_synonyms = true;
153
154 return *this;
155 }
156
157 adverb_query& adverb_query::synonym_of(filter<adverb> _f)
158 {
159 _f.clean();
160 _synonym_of = _f;
161
162 return *this;
163 }
164
165 adverb_query& adverb_query::is_mannernymic()
166 {
167 _is_mannernymic = true;
168
169 return *this;
170 }
171
172 adverb_query& adverb_query::mannernym_of(filter<adjective> _f)
173 {
174 _f.clean();
175 _mannernym_of = _f;
176
177 return *this;
178 }
179 /*
180 adverb_query& adverb_query::derived_from(const word& _w)
181 {
182 if (dynamic_cast<const adjective*>(&_w) != nullptr)
183 {
184 _derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
185 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
186 {
187 _derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
188 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
189 {
190 _derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
191 }
192
193 return *this;
194 }
195
196 adverb_query& adverb_query::not_derived_from(const word& _w)
197 {
198 if (dynamic_cast<const adjective*>(&_w) != nullptr)
199 {
200 _not_derived_from_adjective.push_back(dynamic_cast<const adjective&>(_w));
201 } else if (dynamic_cast<const adverb*>(&_w) != nullptr)
202 {
203 _not_derived_from_adverb.push_back(dynamic_cast<const adverb&>(_w));
204 } else if (dynamic_cast<const noun*>(&_w) != nullptr)
205 {
206 _not_derived_from_noun.push_back(dynamic_cast<const noun&>(_w));
207 }
208
209 return *this;
210 }
211 */
212 std::list<adverb> adverb_query::run() const
213 {
214 std::stringstream construct;
215 construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs";
216 std::list<std::string> conditions;
217 std::list<binding> bindings;
218
219 if (_has_prn)
220 {
221 conditions.push_back("adverb_id IN (SELECT adverb_id FROM adverb_pronunciations)");
222 }
223
224 if (!_rhymes.empty())
225 {
226 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
227 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
228 conditions.push_back(cond);
229
230 for (auto rhy : _rhymes)
231 {
232 bindings.emplace_back(rhy.get_prerhyme());
233 bindings.emplace_back(rhy.get_rhyme());
234 }
235 }
236
237 if (_has_rhyming_noun)
238 {
239 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
240 }
241
242 if (_has_rhyming_adjective)
243 {
244 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
245 }
246
247 if (_has_rhyming_adverb)
248 {
249 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adverb_id != curp.adverb_id)");
250 }
251
252 if (_has_rhyming_verb)
253 {
254 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
255 }
256
257 for (auto except : _except)
258 {
259 conditions.push_back("adverb_id != ?");
260 bindings.emplace_back(except._id);
261 }
262
263 if (_requires_comparative_form)
264 {
265 conditions.push_back("comparative IS NOT NULL");
266 }
267
268 if (_requires_superlative_form)
269 {
270 conditions.push_back("superlative IS NOT NULL");
271 }
272
273 if (!_stress.empty())
274 {
275 std::stringstream cond;
276 if (_stress.get_notlogic())
277 {
278 cond << "adverb_id NOT IN";
279 } else {
280 cond << "adverb_id IN";
281 }
282
283 cond << "(SELECT adverb_id FROM adverb_pronunciations WHERE ";
284
285 std::function<std::string (filter<std::vector<bool>>, bool)> recur = [&] (filter<std::vector<bool>> f, bool notlogic) -> std::string {
286 switch (f.get_type())
287 {
288 case filter<std::vector<bool>>::type::singleton:
289 {
290 std::ostringstream _val;
291 for (auto syl : f.get_elem())
292 {
293 if (syl)
294 {
295 _val << "1";
296 } else {
297 _val << "0";
298 }
299 }
300
301 bindings.emplace_back(_val.str());
302
303 if (notlogic == f.get_notlogic())
304 {
305 return "stress = ?";
306 } else {
307 return "stress != ?";
308 }
309 }
310
311 case filter<std::vector<bool>>::type::group:
312 {
313 bool truelogic = notlogic != f.get_notlogic();
314
315 std::list<std::string> clauses;
316 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::vector<bool>> f2) {
317 return recur(f2, truelogic);
318 });
319
320 if (truelogic == f.get_orlogic())
321 {
322 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
323 } else {
324 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
325 }
326 }
327 }
328 };
329
330 cond << recur(_stress, _stress.get_notlogic());
331 cond << ")";
332 conditions.push_back(cond.str());
333 }
334
335 if (!_with_prefix.empty())
336 {
337 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
338 switch (f.get_type())
339 {
340 case filter<std::string>::type::singleton:
341 {
342 bindings.emplace_back(f.get_elem() + "%");
343
344 if (notlogic == f.get_notlogic())
345 {
346 return "base_form LIKE ?";
347 } else {
348 return "base_form NOT LIKE ?";
349 }
350 }
351
352 case filter<std::string>::type::group:
353 {
354 bool truelogic = notlogic != f.get_notlogic();
355
356 std::list<std::string> clauses;
357 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
358 return recur(f2, truelogic);
359 });
360
361 if (truelogic == f.get_orlogic())
362 {
363 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
364 } else {
365 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
366 }
367 }
368 }
369 };
370
371 conditions.push_back(recur(_with_prefix, false));
372 }
373
374 if (!_with_suffix.empty())
375 {
376 std::function<std::string (filter<std::string>, bool)> recur = [&] (filter<std::string> f, bool notlogic) -> std::string {
377 switch (f.get_type())
378 {
379 case filter<std::string>::type::singleton:
380 {
381 bindings.emplace_back("%" + f.get_elem());
382
383 if (notlogic == f.get_notlogic())
384 {
385 return "base_form LIKE ?";
386 } else {
387 return "base_form NOT LIKE ?";
388 }
389 }
390
391 case filter<std::string>::type::group:
392 {
393 bool truelogic = notlogic != f.get_notlogic();
394
395 std::list<std::string> clauses;
396 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::string> f2) {
397 return recur(f2, truelogic);
398 });
399
400 if (truelogic == f.get_orlogic())
401 {
402 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
403 } else {
404 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
405 }
406 }
407 }
408 };
409
410 conditions.push_back(recur(_with_suffix, false));
411 }
412
413 if (_with_complexity != unlimited)
414 {
415 conditions.push_back("complexity = ?");
416 bindings.emplace_back(_with_complexity);
417 }
418
419 if (_has_antonyms)
420 {
421 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy)");
422 }
423
424 if (!_antonym_of.empty())
425 {
426 std::stringstream cond;
427 if (_antonym_of.get_notlogic())
428 {
429 cond << "adverb_id NOT IN";
430 } else {
431 cond << "adverb_id IN";
432 }
433
434 cond << "(SELECT adverb_2_id FROM adverb_antonymy WHERE ";
435
436 std::function<std::string (filter<adverb>, bool)> recur = [&] (filter<adverb> f, bool notlogic) -> std::string {
437 switch (f.get_type())
438 {
439 case filter<adverb>::type::singleton:
440 {
441 bindings.emplace_back(f.get_elem()._id);
442
443 if (notlogic == f.get_notlogic())
444 {
445 return "adverb_1_id = ?";
446 } else {
447 return "adverb_1_id != ?";
448 }
449 }
450
451 case filter<adverb>::type::group:
452 {
453 bool truelogic = notlogic != f.get_notlogic();
454
455 std::list<std::string> clauses;
456 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adverb> f2) {
457 return recur(f2, truelogic);
458 });
459
460 if (truelogic == f.get_orlogic())
461 {
462 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
463 } else {
464 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
465 }
466 }
467 }
468 };
469
470 cond << recur(_antonym_of, _antonym_of.get_notlogic());
471 cond << ")";
472 conditions.push_back(cond.str());
473 }
474
475 if (_has_synonyms)
476 {
477 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy)");
478 }
479
480 if (!_synonym_of.empty())
481 {
482 std::stringstream cond;
483 if (_antonym_of.get_notlogic())
484 {
485 cond << "adverb_id NOT IN";
486 } else {
487 cond << "adverb_id IN";
488 }
489
490 cond << "(SELECT adverb_2_id FROM adverb_synonymy WHERE ";
491
492 std::function<std::string (filter<adverb>, bool)> recur = [&] (filter<adverb> f, bool notlogic) -> std::string {
493 switch (f.get_type())
494 {
495 case filter<adverb>::type::singleton:
496 {
497 bindings.emplace_back(f.get_elem()._id);
498
499 if (notlogic == f.get_notlogic())
500 {
501 return "adverb_1_id = ?";
502 } else {
503 return "adverb_1_id != ?";
504 }
505 }
506
507 case filter<adverb>::type::group:
508 {
509 bool truelogic = notlogic != f.get_notlogic();
510
511 std::list<std::string> clauses;
512 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adverb> f2) {
513 return recur(f2, truelogic);
514 });
515
516 if (truelogic == f.get_orlogic())
517 {
518 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
519 } else {
520 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
521 }
522 }
523 }
524 };
525
526 cond << recur(_synonym_of, _synonym_of.get_notlogic());
527 cond << ")";
528 conditions.push_back(cond.str());
529 }
530
531 if (_is_mannernymic)
532 {
533 conditions.push_back("adverb_id IN (SELECT mannernym_id FROM mannernymy)");
534 }
535
536 if (!_mannernym_of.empty())
537 {
538 std::stringstream cond;
539 if (_antonym_of.get_notlogic())
540 {
541 cond << "adverb_id NOT IN";
542 } else {
543 cond << "adverb_id IN";
544 }
545
546 cond << "(SELECT mannernym_id FROM mannernymy WHERE ";
547
548 std::function<std::string (filter<adjective>, bool)> recur = [&] (filter<adjective> f, bool notlogic) -> std::string {
549 switch (f.get_type())
550 {
551 case filter<adjective>::type::singleton:
552 {
553 bindings.emplace_back(f.get_elem()._id);
554
555 if (notlogic == f.get_notlogic())
556 {
557 return "adjective_id = ?";
558 } else {
559 return "adjective_id != ?";
560 }
561 }
562
563 case filter<adjective>::type::group:
564 {
565 bool truelogic = notlogic != f.get_notlogic();
566
567 std::list<std::string> clauses;
568 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<adjective> f2) {
569 return recur(f2, truelogic);
570 });
571
572 if (truelogic == f.get_orlogic())
573 {
574 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
575 } else {
576 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
577 }
578 }
579 }
580 };
581
582 cond << recur(_mannernym_of, _mannernym_of.get_notlogic());
583 cond << ")";
584 conditions.push_back(cond.str());
585 }
586
587/* if (!_derived_from_adjective.empty())
588 {
589 std::list<std::string> clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ");
590 std::string cond = "adverb_id IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
591 conditions.push_back(cond);
592 }
593
594 if (!_not_derived_from_adjective.empty())
595 {
596 std::list<std::string> clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ");
597 std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
598 conditions.push_back(cond);
599 }
600
601 if (!_derived_from_adverb.empty())
602 {
603 std::list<std::string> clauses(_derived_from_adverb.size(), "adverb_2_id = @DERADV");
604 std::string cond = "adverb_id IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
605 conditions.push_back(cond);
606 }
607
608 if (!_not_derived_from_adverb.empty())
609 {
610 std::list<std::string> clauses(_not_derived_from_adverb.size(), "adverb_2_id = @NDERADV");
611 std::string cond = "adverb_id NOT IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
612 conditions.push_back(cond);
613 }
614
615 if (!_derived_from_noun.empty())
616 {
617 std::list<std::string> clauses(_derived_from_noun.size(), "noun_id = @DERN");
618 std::string cond = "adverb_id IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
619 conditions.push_back(cond);
620 }
621
622 if (!_not_derived_from_noun.empty())
623 {
624 std::list<std::string> clauses(_not_derived_from_noun.size(), "noun_id = @NDERN");
625 std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
626 conditions.push_back(cond);
627 }*/
628
629 if (!conditions.empty())
630 {
631 construct << " WHERE ";
632 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
633 }
634
635 if (_random)
636 {
637 construct << " ORDER BY RANDOM()";
638 }
639
640 if (_limit != unlimited)
641 {
642 construct << " LIMIT " << _limit;
643 }
644
645 sqlite3_stmt* ppstmt;
646 std::string query = construct.str();
647 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
648 {
649 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
650 }
651
652 int i = 1;
653 for (auto& binding : bindings)
654 {
655 switch (binding.get_type())
656 {
657 case binding::type::integer:
658 {
659 sqlite3_bind_int(ppstmt, i, binding.get_integer());
660
661 break;
662 }
663
664 case binding::type::string:
665 {
666 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
667
668 break;
669 }
670 }
671
672 i++;
673 }
674
675 /*
676 for (auto adj : _derived_from_adjective)
677 {
678 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id);
679 }
680
681 for (auto adj : _not_derived_from_adjective)
682 {
683 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id);
684 }
685
686 for (auto adv : _derived_from_adverb)
687 {
688 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id);
689 }
690
691 for (auto adv : _not_derived_from_adverb)
692 {
693 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id);
694 }
695
696 for (auto n : _derived_from_noun)
697 {
698 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id);
699 }
700
701 for (auto n : _not_derived_from_noun)
702 {
703 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id);
704 }*/
705
706 std::list<adverb> output;
707 while (sqlite3_step(ppstmt) == SQLITE_ROW)
708 {
709 adverb tnc {_data, sqlite3_column_int(ppstmt, 0)};
710 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
711
712 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
713 {
714 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
715 }
716
717 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
718 {
719 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
720 }
721
722 output.push_back(tnc);
723 }
724
725 sqlite3_finalize(ppstmt);
726
727 for (auto& adverb : output)
728 {
729 query = "SELECT pronunciation, prerhyme, rhyme FROM adverb_pronunciations WHERE adverb_id = ?";
730 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
731 {
732 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
733 }
734
735 sqlite3_bind_int(ppstmt, 1, adverb._id);
736
737 while (sqlite3_step(ppstmt) == SQLITE_ROW)
738 {
739 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
740 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
741
742 adverb.pronunciations.push_back(phonemes);
743
744 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
745 {
746 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
747 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
748 adverb.rhymes.emplace_back(prerhyme, rhyming);
749 }
750 }
751
752 sqlite3_finalize(ppstmt);
753 }
754
755 return output;
756 }
757
758};
diff --git a/lib/adverb_query.h b/lib/adverb_query.h deleted file mode 100644 index 30e7400..0000000 --- a/lib/adverb_query.h +++ /dev/null
@@ -1,86 +0,0 @@
1#ifndef ADVERB_QUERY_H_CA13CCDD
2#define ADVERB_QUERY_H_CA13CCDD
3
4namespace verbly {
5
6 class adverb_query {
7 public:
8 adverb_query(const data& _data);
9
10 adverb_query& limit(int _limit);
11 adverb_query& random();
12 adverb_query& except(const adverb& _word);
13 adverb_query& rhymes_with(const word& _word);
14 adverb_query& rhymes_with(rhyme _r);
15 adverb_query& has_pronunciation();
16 adverb_query& has_rhyming_noun();
17 adverb_query& has_rhyming_adjective();
18 adverb_query& has_rhyming_adverb();
19 adverb_query& has_rhyming_verb();
20 adverb_query& with_stress(filter<std::vector<bool>> _arg);
21
22 adverb_query& requires_comparative_form();
23 adverb_query& requires_superlative_form();
24
25 adverb_query& with_prefix(filter<std::string> _f);
26 adverb_query& with_suffix(filter<std::string> _f);
27
28 adverb_query& with_complexity(int _arg);
29
30 adverb_query& has_antonyms();
31 adverb_query& antonym_of(filter<adverb> _f);
32
33 adverb_query& has_synonyms();
34 adverb_query& synonym_of(filter<adverb> _f);
35
36 adverb_query& is_mannernymic();
37 adverb_query& mannernym_of(filter<adjective> _f);
38
39/* adverb_query& derived_from(const word& _w);
40 adverb_query& not_derived_from(const word& _w);*/
41
42 std::list<adverb> run() const;
43
44 const static int unlimited = -1;
45
46 private:
47 const data& _data;
48 int _limit = unlimited;
49 bool _random = false;
50 std::list<rhyme> _rhymes;
51 std::list<adverb> _except;
52 bool _has_prn = false;
53 bool _has_rhyming_noun = false;
54 bool _has_rhyming_adjective = false;
55 bool _has_rhyming_adverb = false;
56 bool _has_rhyming_verb = false;
57 filter<std::vector<bool>> _stress;
58
59 bool _requires_comparative_form = false;
60 bool _requires_superlative_form = false;
61
62 filter<std::string> _with_prefix;
63 filter<std::string> _with_suffix;
64
65 int _with_complexity = unlimited;
66
67 bool _has_antonyms = false;
68 filter<adverb> _antonym_of;
69
70 bool _has_synonyms = false;
71 filter<adverb> _synonym_of;
72
73 bool _is_mannernymic = false;
74 filter<adjective> _mannernym_of;
75
76/* std::list<adjective> _derived_from_adjective;
77 std::list<adjective> _not_derived_from_adjective;
78 std::list<adverb> _derived_from_adverb;
79 std::list<adverb> _not_derived_from_adverb;
80 std::list<noun> _derived_from_noun;
81 std::list<noun> _not_derived_from_noun;*/
82 };
83
84};
85
86#endif /* end of include guard: ADVERB_QUERY_H_CA13CCDD */
diff --git a/lib/binding.cpp b/lib/binding.cpp new file mode 100644 index 0000000..349cd6f --- /dev/null +++ b/lib/binding.cpp
@@ -0,0 +1,180 @@
1#include "binding.h"
2#include <stdexcept>
3#include <utility>
4
5namespace verbly {
6
7 binding::binding(const binding& other)
8 {
9 type_ = other.type_;
10
11 switch (type_)
12 {
13 case type::integer:
14 {
15 integer_ = other.integer_;
16
17 break;
18 }
19
20 case type::string:
21 {
22 new(&string_) std::string(other.string_);
23
24 break;
25 }
26
27 case type::invalid:
28 {
29 break;
30 }
31 }
32 }
33
34 binding::binding(binding&& other) : binding()
35 {
36 swap(*this, other);
37 }
38
39 binding& binding::operator=(binding other)
40 {
41 swap(*this, other);
42
43 return *this;
44 }
45
46 void swap(binding& first, binding& second)
47 {
48 using type = binding::type;
49
50 type tempType = first.type_;
51 int tempInteger;
52 std::string tempString;
53
54 switch (first.type_)
55 {
56 case type::integer:
57 {
58 tempInteger = first.integer_;
59
60 break;
61 }
62
63 case type::string:
64 {
65 tempString = std::move(tempString);
66
67 break;
68 }
69
70 case type::invalid:
71 {
72 break;
73 }
74 }
75
76 first.~binding();
77
78 first.type_ = second.type_;
79
80 switch (second.type_)
81 {
82 case type::integer:
83 {
84 first.integer_ = second.integer_;
85
86 break;
87 }
88
89 case type::string:
90 {
91 new(&first.string_) std::string(std::move(second.string_));
92
93 break;
94 }
95
96 case type::invalid:
97 {
98 break;
99 }
100 }
101
102 second.~binding();
103
104 second.type_ = tempType;
105
106 switch (tempType)
107 {
108 case type::integer:
109 {
110 second.integer_ = tempInteger;
111
112 break;
113 }
114
115 case type::string:
116 {
117 new(&second.string_) std::string(std::move(tempString));
118
119 break;
120 }
121
122 case type::invalid:
123 {
124 break;
125 }
126 }
127 }
128
129 binding::~binding()
130 {
131 switch (type_)
132 {
133 case type::string:
134 {
135 using string_type = std::string;
136 string_.~string_type();
137
138 break;
139 }
140
141 case type::integer:
142 case type::invalid:
143 {
144 break;
145 }
146 }
147 }
148
149 binding::binding(int arg) :
150 type_(type::integer),
151 integer_(arg)
152 {
153 }
154
155 int binding::getInteger() const
156 {
157 if (type_ != type::integer)
158 {
159 throw std::domain_error("binding::getInteger called on non-integer binding");
160 }
161
162 return integer_;
163 }
164
165 binding::binding(std::string arg) : type_(type::string)
166 {
167 new(&string_) std::string(arg);
168 }
169
170 std::string binding::getString() const
171 {
172 if (type_ != type::string)
173 {
174 throw std::domain_error("binding::getString called on non-string binding");
175 }
176
177 return string_;
178 }
179
180};
diff --git a/lib/binding.h b/lib/binding.h new file mode 100644 index 0000000..7fbe20e --- /dev/null +++ b/lib/binding.h
@@ -0,0 +1,70 @@
1#ifndef BINDING_H_CAE0B18E
2#define BINDING_H_CAE0B18E
3
4#include <string>
5
6namespace verbly {
7
8 class binding {
9 public:
10 enum class type {
11 invalid,
12 integer,
13 string
14 };
15
16 // Default constructor
17
18 binding()
19 {
20 }
21
22 // Copy and move constructors
23
24 binding(const binding& other);
25 binding(binding&& other);
26
27 // Assignment
28
29 binding& operator=(binding other);
30
31 // Swap
32
33 friend void swap(binding& first, binding& second);
34
35 // Destructor
36
37 ~binding();
38
39 // Generic accessors
40
41 type getType() const
42 {
43 return type_;
44 }
45
46 // Integer
47
48 binding(int arg);
49
50 int getInteger() const;
51
52 // String
53
54 binding(std::string arg);
55
56 std::string getString() const;
57
58 private:
59
60 union {
61 int integer_;
62 std::string string_;
63 };
64
65 type type_ = type::invalid;
66 };
67
68};
69
70#endif /* end of include guard: BINDING_H_CAE0B18E */
diff --git a/lib/data.cpp b/lib/data.cpp deleted file mode 100644 index db42487..0000000 --- a/lib/data.cpp +++ /dev/null
@@ -1,177 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 data::data(std::string datafile)
6 {
7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
8 {
9 throw std::invalid_argument(sqlite3_errmsg(ppdb));
10 }
11 }
12
13 data::data(data&& other)
14 {
15 ppdb = other.ppdb;
16 }
17
18 data& data::operator=(data&& other)
19 {
20 ppdb = other.ppdb;
21
22 return *this;
23 }
24
25 data::~data()
26 {
27 sqlite3_close_v2(ppdb);
28 }
29
30 verb_query data::verbs() const
31 {
32 return verb_query(*this);
33 }
34
35 adjective_query data::adjectives() const
36 {
37 return adjective_query(*this);
38 }
39
40 adverb_query data::adverbs() const
41 {
42 return adverb_query(*this);
43 }
44
45 noun_query data::nouns() const
46 {
47 return noun_query(*this);
48 }
49
50 frame_query data::frames() const
51 {
52 return frame_query(*this);
53 }
54
55 preposition_query data::prepositions() const
56 {
57 return preposition_query(*this);
58 }
59
60 binding::type binding::get_type() const
61 {
62 return _type;
63 }
64
65 binding::binding(const binding& other)
66 {
67 _type = other._type;
68
69 switch (_type)
70 {
71 case type::integer:
72 {
73 _integer = other._integer;
74
75 break;
76 }
77
78 case type::string:
79 {
80 new(&_string) std::string(other._string);
81
82 break;
83 }
84 }
85 }
86
87 binding::~binding()
88 {
89 switch (_type)
90 {
91 case type::string:
92 {
93 using string_type = std::string;
94 _string.~string_type();
95
96 break;
97 }
98 }
99 }
100
101 binding& binding::operator=(const binding& other)
102 {
103 this->~binding();
104
105 _type = other._type;
106
107 switch (_type)
108 {
109 case type::integer:
110 {
111 _integer = other._integer;
112
113 break;
114 }
115
116 case type::string:
117 {
118 new(&_string) std::string(other._string);
119
120 break;
121 }
122 }
123
124 return *this;
125 }
126
127 binding::binding(int _arg)
128 {
129 _type = type::integer;
130 _integer = _arg;
131 }
132
133 int binding::get_integer() const
134 {
135 assert(_type == type::integer);
136
137 return _integer;
138 }
139
140 void binding::set_integer(int _arg)
141 {
142 *this = binding(_arg);
143 }
144
145 binding& binding::operator=(int _arg)
146 {
147 *this = binding(_arg);
148
149 return *this;
150 }
151
152 binding::binding(std::string _arg)
153 {
154 _type = type::string;
155 new(&_string) std::string(_arg);
156 }
157
158 std::string binding::get_string() const
159 {
160 assert(_type == type::string);
161
162 return _string;
163 }
164
165 void binding::set_string(std::string _arg)
166 {
167 *this = binding(_arg);
168 }
169
170 binding& binding::operator=(std::string _arg)
171 {
172 *this = binding(_arg);
173
174 return *this;
175 }
176
177};
diff --git a/lib/data.h b/lib/data.h deleted file mode 100644 index b8b12b9..0000000 --- a/lib/data.h +++ /dev/null
@@ -1,380 +0,0 @@
1#ifndef DATA_H_C4AEC3DD
2#define DATA_H_C4AEC3DD
3
4#include <sqlite3.h>
5
6namespace verbly {
7
8 class data;
9 class word;
10 class adjective;
11 class noun;
12 class verb;
13 class adverb;
14 class frame;
15 class adjective_query;
16 class adverb_query;
17 class noun_query;
18 class verb_query;
19 class frame_query;
20 class preposition_query;
21
22 class data {
23 private:
24 sqlite3* ppdb;
25
26 friend class adjective_query;
27 friend class noun_query;
28 friend class verb_query;
29 friend class adverb_query;
30 friend class frame_query;
31 friend class preposition_query;
32
33 public:
34 data(std::string datafile);
35
36 data(const data& other) = delete;
37 data& operator=(const data& other) = delete;
38
39 data(data&& other);
40 data& operator=(data&& other);
41
42 ~data();
43
44 verb_query verbs() const;
45 adjective_query adjectives() const;
46 adverb_query adverbs() const;
47 noun_query nouns() const;
48 frame_query frames() const;
49 preposition_query prepositions() const;
50
51 };
52
53 template <class T>
54 class filter {
55 public:
56 enum class type {
57 singleton,
58 group
59 };
60
61 typedef filter<T> value_type;
62
63 type get_type() const
64 {
65 return _type;
66 }
67
68 filter(const filter<T>& other)
69 {
70 _type = other._type;
71 _notlogic = other._notlogic;
72
73 switch (_type)
74 {
75 case type::singleton:
76 {
77 new(&_singleton.elem) T(other._singleton.elem);
78
79 break;
80 }
81
82 case type::group:
83 {
84 new(&_group.elems) std::list<filter<T>>(other._group.elems);
85 _group.orlogic = other._group.orlogic;
86
87 break;
88 }
89 }
90 }
91
92 filter<T>& operator=(const filter<T>& other)
93 {
94 this->~filter();
95
96 _type = other._type;
97 _notlogic = other._notlogic;
98
99 switch (_type)
100 {
101 case type::singleton:
102 {
103 new(&_singleton.elem) T(other._singleton.elem);
104
105 break;
106 }
107
108 case type::group:
109 {
110 new(&_group.elems) std::list<filter<T>>(other._group.elems);
111 _group.orlogic = other._group.orlogic;
112
113 break;
114 }
115 }
116
117 return *this;
118 }
119
120 ~filter()
121 {
122 switch (_type)
123 {
124 case type::singleton:
125 {
126 _singleton.elem.~T();
127
128 break;
129 }
130
131 case type::group:
132 {
133 using list_type = std::list<filter<T>>;
134 _group.elems.~list_type();
135
136 break;
137 }
138 }
139 }
140
141 bool get_notlogic() const
142 {
143 return _notlogic;
144 }
145
146 void set_notlogic(bool _nl)
147 {
148 _notlogic = _nl;
149 }
150
151 std::list<T> inorder_flatten() const
152 {
153 std::list<T> result;
154
155 if (_type == type::singleton)
156 {
157 result.push_back(_singleton.elem);
158 } else if (_type == type::group)
159 {
160 for (auto elem : _group.elems)
161 {
162 auto l = elem.inorder_flatten();
163 result.insert(std::end(result), std::begin(l), std::end(l));
164 }
165 }
166
167 return result;
168 }
169
170 std::set<T> uniq_flatten() const
171 {
172 std::set<T> result;
173
174 if (_type == type::singleton)
175 {
176 result.insert(_singleton.elem);
177 } else if (_type == type::group)
178 {
179 for (auto elem : _group.elems)
180 {
181 auto l = elem.uniq_flatten();
182 result.insert(std::begin(l), std::end(l));
183 }
184 }
185
186 return result;
187 }
188
189 void clean()
190 {
191 if (_type == type::group)
192 {
193 std::list<typename std::list<filter<T>>::iterator> toremove;
194 for (auto it = _group.elems.begin(); it != _group.elems.end(); it++)
195 {
196 it->clean();
197
198 if (it->get_type() == type::group)
199 {
200 if (it->_group.elems.size() == 0)
201 {
202 toremove.push_back(it);
203 } else if (it->_group.elems.size() == 1)
204 {
205 bool truelogic = it->_notlogic != it->_group.elems.front()._notlogic;
206 filter<T> e = it->_group.elems.front();
207 *it = e;
208 it->_notlogic = truelogic;
209 }
210 }
211 }
212
213 for (auto rem : toremove)
214 {
215 _group.elems.erase(rem);
216 }
217
218 if (_group.elems.size() == 1)
219 {
220 bool truelogic = _notlogic != _group.elems.front()._notlogic;
221 filter<T> e = _group.elems.front();
222 *this = e;
223 _notlogic = truelogic;
224 }
225 }
226 }
227
228 // Singleton
229 filter(T _elem, bool _notlogic = false) : _type(type::singleton)
230 {
231 new(&_singleton.elem) T(_elem);
232 this->_notlogic = _notlogic;
233 }
234
235 filter<T>& operator=(T _elem)
236 {
237 *this = filter<T>{_elem};
238
239 return *this;
240 }
241
242 T get_elem() const
243 {
244 assert(_type == type::singleton);
245
246 return _singleton.elem;
247 }
248
249 void set_elem(T _elem)
250 {
251 assert(_type == type::singleton);
252
253 _singleton.elem = _elem;
254 }
255
256 // Group
257 typedef typename std::list<filter<T>>::iterator iterator;
258
259 filter() : _type(type::group)
260 {
261 new(&_group.elems) std::list<filter<T>>();
262 _group.orlogic = false;
263 }
264
265 filter(std::initializer_list<filter<T>> _init) : _type(type::group)
266 {
267 new(&_group.elems) std::list<filter<T>>(_init);
268 _group.orlogic = false;
269 }
270
271 iterator begin()
272 {
273 assert(_type == type::group);
274
275 return _group.elems.begin();
276 }
277
278 iterator end()
279 {
280 assert(_type == type::group);
281
282 return _group.elems.end();
283 }
284
285 filter<T>& operator<<(filter<T> _elem)
286 {
287 assert(_type == type::group);
288
289 _group.elems.push_back(_elem);
290
291 return *this;
292 }
293
294 void push_back(filter<T> _elem)
295 {
296 assert(_type == type::group);
297
298 _group.elems.push_back(_elem);
299 }
300
301 bool get_orlogic() const
302 {
303 assert(_type == type::group);
304
305 return _group.orlogic;
306 }
307
308 void set_orlogic(bool _ol)
309 {
310 assert(_type == type::group);
311
312 _group.orlogic = _ol;
313 }
314
315 bool empty() const
316 {
317 if (_type == type::group)
318 {
319 return _group.elems.empty();
320 } else {
321 return false;
322 }
323 }
324
325 int size() const
326 {
327 assert(_type == type::group);
328
329 return _group.elems.size();
330 }
331
332 private:
333 type _type;
334 bool _notlogic = false;
335 union {
336 struct {
337 T elem;
338 } _singleton;
339 struct {
340 std::list<filter<T>> elems;
341 bool orlogic;
342 } _group;
343 };
344 };
345
346 class binding {
347 public:
348 enum class type {
349 integer,
350 string
351 };
352
353 type get_type() const;
354 binding(const binding& other);
355 ~binding();
356 binding& operator=(const binding& other);
357
358 // Integer
359 binding(int _arg);
360 int get_integer() const;
361 void set_integer(int _arg);
362 binding& operator=(int _arg);
363
364 // String
365 binding(std::string _arg);
366 std::string get_string() const;
367 void set_string(std::string _arg);
368 binding& operator=(std::string _arg);
369
370 private:
371 union {
372 int _integer;
373 std::string _string;
374 };
375 type _type;
376 };
377
378};
379
380#endif /* end of include guard: DATA_H_C4AEC3DD */
diff --git a/lib/database.cpp b/lib/database.cpp new file mode 100644 index 0000000..351b93d --- /dev/null +++ b/lib/database.cpp
@@ -0,0 +1,79 @@
1#include "database.h"
2#include <sqlite3.h>
3#include <stdexcept>
4#include "query.h"
5
6namespace verbly {
7
8 database::database(std::string path)
9 {
10 if (sqlite3_open_v2(path.c_str(), &ppdb_, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
11 {
12 // We still have to free the resources allocated. In the event that
13 // allocation failed, ppdb will be null and sqlite3_close_v2 will just
14 // ignore it.
15 std::string errmsg(sqlite3_errmsg(ppdb_));
16 sqlite3_close_v2(ppdb_);
17
18 throw database_error("Could not open verbly datafile", errmsg);
19 }
20 }
21
22 database::database(database&& other) : database()
23 {
24 swap(*this, other);
25 }
26
27 database& database::operator=(database&& other)
28 {
29 swap(*this, other);
30
31 return *this;
32 }
33
34 void swap(database& first, database& second)
35 {
36 std::swap(first.ppdb_, second.ppdb_);
37 }
38
39 database::~database()
40 {
41 sqlite3_close_v2(ppdb_);
42 }
43
44 query<notion> database::notions(filter where, bool random, int limit) const
45 {
46 return query<notion>(*this, ppdb_, std::move(where), random, limit);
47 }
48
49 query<word> database::words(filter where, bool random, int limit) const
50 {
51 return query<word>(*this, ppdb_, std::move(where), random, limit);
52 }
53
54 query<group> database::groups(filter where, bool random, int limit) const
55 {
56 return query<group>(*this, ppdb_, std::move(where), random, limit);
57 }
58
59 query<frame> database::frames(filter where, bool random, int limit) const
60 {
61 return query<frame>(*this, ppdb_, std::move(where), random, limit);
62 }
63
64 query<lemma> database::lemmas(filter where, bool random, int limit) const
65 {
66 return query<lemma>(*this, ppdb_, std::move(where), random, limit);
67 }
68
69 query<form> database::forms(filter where, bool random, int limit) const
70 {
71 return query<form>(*this, ppdb_, std::move(where), random, limit);
72 }
73
74 query<pronunciation> database::pronunciations(filter where, bool random, int limit) const
75 {
76 return query<pronunciation>(*this, ppdb_, std::move(where), random, limit);
77 }
78
79};
diff --git a/lib/database.h b/lib/database.h new file mode 100644 index 0000000..d68c40b --- /dev/null +++ b/lib/database.h
@@ -0,0 +1,73 @@
1#ifndef DATABASE_H_0B0A47D2
2#define DATABASE_H_0B0A47D2
3
4#include <string>
5#include <exception>
6#include <list>
7#include "notion.h"
8#include "word.h"
9#include "group.h"
10#include "frame.h"
11#include "lemma.h"
12#include "form.h"
13#include "pronunciation.h"
14
15struct sqlite3;
16
17namespace verbly {
18
19 template <typename Object>
20 class query;
21
22 class database {
23 public:
24
25 // Constructor
26
27 explicit database(std::string path);
28
29 // Disable copying
30
31 database(const database& other) = delete;
32 database& operator=(const database& other) = delete;
33
34 // Move constructor and move assignment
35
36 database(database&& other);
37 database& operator=(database&& other);
38
39 // Swap
40
41 friend void swap(database& first, database& second);
42
43 // Destructor
44
45 ~database();
46
47 // Queries
48
49 query<notion> notions(filter where, bool random = true, int limit = 1) const;
50
51 query<word> words(filter where, bool random = true, int limit = 1) const;
52
53 query<group> groups(filter where, bool random = true, int limit = 1) const;
54
55 query<frame> frames(filter where, bool random = true, int limit = 1) const;
56
57 query<lemma> lemmas(filter where, bool random = true, int limit = 1) const;
58
59 query<form> forms(filter where, bool random = true, int limit = 1) const;
60
61 query<pronunciation> pronunciations(filter where, bool random = true, int limit = 1) const;
62
63 private:
64
65 database() = default;
66
67 sqlite3* ppdb_ = nullptr;
68
69 };
70
71};
72
73#endif /* end of include guard: DATABASE_H_0B0A47D2 */
diff --git a/lib/enums.h b/lib/enums.h new file mode 100644 index 0000000..b37be7b --- /dev/null +++ b/lib/enums.h
@@ -0,0 +1,45 @@
1#ifndef ENUMS_H_260BA847
2#define ENUMS_H_260BA847
3
4namespace verbly {
5
6 enum class part_of_speech {
7 noun = 0,
8 adjective = 1,
9 adverb = 2,
10 verb = 3,
11 preposition = 4
12 };
13
14 enum class positioning {
15 undefined = -1,
16 predicate = 0,
17 attributive = 1,
18 postnominal = 2
19 };
20
21 enum class inflection {
22 base = 0,
23 plural = 1,
24 comparative = 2,
25 superlative = 3,
26 past_tense = 4,
27 past_participle = 5,
28 ing_form = 6,
29 s_form = 7
30 };
31
32 enum class object {
33 undefined = -1,
34 notion = 0,
35 word = 1,
36 group = 2,
37 frame = 3,
38 lemma = 4,
39 form = 5,
40 pronunciation = 6
41 };
42
43};
44
45#endif /* end of include guard: ENUMS_H_260BA847 */
diff --git a/lib/field.cpp b/lib/field.cpp new file mode 100644 index 0000000..d7adbb3 --- /dev/null +++ b/lib/field.cpp
@@ -0,0 +1,91 @@
1#include "field.h"
2#include "filter.h"
3
4namespace verbly {
5
6 filter field::operator==(int value) const
7 {
8 return filter(*this, filter::comparison::int_equals, value);
9 }
10
11 filter field::operator!=(int value) const
12 {
13 return filter(*this, filter::comparison::int_does_not_equal, value);
14 }
15
16 filter field::operator<(int value) const
17 {
18 return filter(*this, filter::comparison::int_is_less_than, value);
19 }
20
21 filter field::operator<=(int value) const
22 {
23 return filter(*this, filter::comparison::int_is_at_most, value);
24 }
25
26 filter field::operator>(int value) const
27 {
28 return filter(*this, filter::comparison::int_is_greater_than, value);
29 }
30
31 filter field::operator>=(int value) const
32 {
33 return filter(*this, filter::comparison::int_is_at_least, value);
34 }
35
36 filter field::operator==(part_of_speech value) const
37 {
38 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
39 }
40
41 filter field::operator==(positioning value) const
42 {
43 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
44 }
45
46 filter field::operator==(inflection value) const
47 {
48 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
49 }
50
51 filter field::operator==(bool value) const
52 {
53 return filter(*this, filter::comparison::boolean_equals, value);
54 }
55
56 filter field::operator==(std::string value) const
57 {
58 return filter(*this, filter::comparison::string_equals, std::move(value));
59 }
60
61 filter field::operator!=(std::string value) const
62 {
63 return filter(*this, filter::comparison::string_does_not_equal, std::move(value));
64 }
65
66 filter field::operator%=(std::string value) const
67 {
68 return filter(*this, filter::comparison::string_is_like, std::move(value));
69 }
70
71 field::operator filter() const
72 {
73 return filter(*this, filter::comparison::is_not_null);
74 }
75
76 filter field::operator!() const
77 {
78 return filter(*this, filter::comparison::is_null);
79 }
80
81 filter field::operator%=(filter joinCondition) const
82 {
83 if (type_ == type::hierarchal_join)
84 {
85 return filter(*this, filter::comparison::hierarchally_matches, std::move(joinCondition));
86 } else {
87 return filter(*this, filter::comparison::matches, std::move(joinCondition));
88 }
89 }
90
91};
diff --git a/lib/field.h b/lib/field.h new file mode 100644 index 0000000..30c62be --- /dev/null +++ b/lib/field.h
@@ -0,0 +1,306 @@
1#ifndef FIELD_H_43258321
2#define FIELD_H_43258321
3
4#include "enums.h"
5#include <stdexcept>
6#include <tuple>
7
8namespace verbly {
9
10 class filter;
11
12 class field {
13 public:
14 enum class type {
15 undefined,
16 string,
17 integer,
18 boolean,
19 join,
20 join_through,
21 hierarchal_join
22 };
23
24 // Default constructor
25
26 field()
27 {
28 }
29
30 // Static factories
31
32 static field stringField(
33 object obj,
34 const char* name,
35 bool nullable = false)
36 {
37 return field(obj, type::string, name, nullable);
38 }
39
40 static field stringField(
41 const char* table,
42 const char* name,
43 bool nullable = false)
44 {
45 return field(object::undefined, type::string, name, nullable, table);
46 }
47
48 static field integerField(
49 object obj,
50 const char* name,
51 bool nullable = false)
52 {
53 return field(obj, type::integer, name, nullable);
54 }
55
56 static field integerField(
57 const char* table,
58 const char* name,
59 bool nullable = false)
60 {
61 return field(object::undefined, type::integer, name, nullable, table);
62 }
63
64 static field booleanField(
65 object obj,
66 const char* name,
67 bool nullable = false)
68 {
69 return field(obj, type::boolean, name, nullable);
70 }
71
72 static field booleanField(
73 const char* table,
74 const char* name,
75 bool nullable = false)
76 {
77 return field(object::undefined, type::boolean, name, nullable, table);
78 }
79
80 static field joinField(
81 object obj,
82 const char* name,
83 object joinWith,
84 bool nullable = false)
85 {
86 return field(obj, type::join, name, nullable, 0, joinWith);
87 }
88
89 static field joinField(
90 object obj,
91 const char* name,
92 const char* table,
93 bool nullable = false)
94 {
95 return field(obj, type::join, name, nullable, table);
96 }
97
98 static field joinThrough(
99 object obj,
100 const char* name,
101 object joinWith,
102 const char* joinTable,
103 const char* foreignColumn)
104 {
105 return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, name, foreignColumn);
106 }
107
108 static field joinThrough(
109 object obj,
110 const char* name,
111 object joinWith,
112 const char* joinTable,
113 const char* foreignColumn,
114 const char* joinColumn,
115 const char* foreignJoinColumn)
116 {
117 return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, joinColumn, foreignJoinColumn);
118 }
119
120 static field selfJoin(
121 object obj,
122 const char* name,
123 const char* joinTable,
124 const char* joinColumn,
125 const char* foreignJoinColumn)
126 {
127 return field(obj, type::join_through, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn);
128 }
129
130 static field hierarchalSelfJoin(
131 object obj,
132 const char* name,
133 const char* joinTable,
134 const char* joinColumn,
135 const char* foreignJoinColumn)
136 {
137 return field(obj, type::hierarchal_join, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn);
138 }
139
140 // Accessors
141
142 object getObject() const
143 {
144 return object_;
145 }
146
147 type getType() const
148 {
149 return type_;
150 }
151
152 bool isJoin() const
153 {
154 return ((type_ == type::join) || (type_ == type::join_through) || (type_ == type::hierarchal_join));
155 }
156
157 const char* getColumn() const
158 {
159 return column_;
160 }
161
162 bool isNullable() const
163 {
164 return nullable_;
165 }
166
167 bool hasTable() const
168 {
169 return (table_ != 0);
170 }
171
172 const char* getTable() const
173 {
174 return table_;
175 }
176
177 // Joins
178
179 object getJoinObject() const
180 {
181 // We ignore hierarchal joins because they are always self joins.
182 return ((type_ == type::join) || (type_ == type::join_through))
183 ? joinObject_
184 : throw std::domain_error("Non-join fields don't have join objects");
185 }
186
187 // Many-to-many joins
188
189 const char* getForeignColumn() const
190 {
191 // We ignore hierarchal joins because they are always self joins.
192 return (type_ == type::join_through)
193 ? foreignColumn_
194 : throw std::domain_error("Only many-to-many join fields have a foreign column");
195 }
196
197 const char* getJoinColumn() const
198 {
199 return ((type_ == type::join_through) || (type_ == type::hierarchal_join))
200 ? joinColumn_
201 : throw std::domain_error("Only many-to-many join fields have a join column");
202 }
203
204 const char* getForeignJoinColumn() const
205 {
206 return ((type_ == type::join_through) || (type_ == type::hierarchal_join))
207 ? foreignJoinColumn_
208 : throw std::domain_error("Only many-to-many join fields have a foreign join column");
209 }
210
211 // Ordering
212
213 bool operator<(const field& other) const
214 {
215 // For the most part, (object, column) uniquely identifies fields.
216 // However, there do exist a number of relationships from an object to
217 // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have
218 // the same object (notion), the same column (notion_id), and the same
219 // table (hypernymy); however, they have different join columns.
220 return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
221 }
222
223 // Equality
224
225 bool operator==(const field& other) const
226 {
227 // For the most part, (object, column) uniquely identifies fields.
228 // However, there do exist a number of relationships from an object to
229 // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have
230 // the same object (notion), the same column (notion_id), and the same
231 // table (hypernymy); however, they have different join columns.
232 return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
233 }
234
235 // Filter construction
236
237 filter operator==(int value) const; // Integer equality
238 filter operator!=(int value) const; // Integer inequality
239 filter operator<(int value) const; // Integer is less than
240 filter operator<=(int value) const; // Integer is at most
241 filter operator>(int value) const; // Integer is greater than
242 filter operator>=(int value) const; // Integer is at least
243
244 filter operator==(part_of_speech value) const; // Part of speech equality
245 filter operator==(positioning value) const; // Adjective positioning equality
246 filter operator==(inflection value) const; // Inflection category equality
247
248 filter operator==(bool value) const; // Boolean equality
249
250 filter operator==(std::string value) const; // String equality
251 filter operator!=(std::string value) const; // String inequality
252 filter operator%=(std::string value) const; // String matching
253
254 operator filter() const; // Non-nullity
255 filter operator!() const; // Nullity
256
257 filter operator%=(filter joinCondition) const; // Join
258
259 private:
260
261 // Constructor
262
263 field(
264 object obj,
265 type datatype,
266 const char* column,
267 bool nullable = false,
268 const char* table = 0,
269 object joinObject = object::undefined,
270 const char* foreignColumn = 0,
271 const char* joinColumn = 0,
272 const char* foreignJoinColumn = 0) :
273 object_(obj),
274 type_(datatype),
275 column_(column),
276 nullable_(nullable),
277 table_(table),
278 joinObject_(joinObject),
279 foreignColumn_(foreignColumn),
280 joinColumn_(joinColumn),
281 foreignJoinColumn_(foreignJoinColumn)
282 {
283 }
284
285 // General
286 object object_ = object::undefined;
287 type type_ = type::undefined;
288 const char* column_ = 0;
289 const char* table_ = 0;
290
291 // Non-joins and belongs-to joins
292 bool nullable_ = false;
293
294 // Joins
295 object joinObject_ = object::undefined;
296
297 // Many-to-many joins
298 const char* foreignColumn_ = 0;
299 const char* joinColumn_ = 0;
300 const char* foreignJoinColumn_ = 0;
301
302 };
303
304};
305
306#endif /* end of include guard: FIELD_H_43258321 */
diff --git a/lib/filter.cpp b/lib/filter.cpp new file mode 100644 index 0000000..959fa05 --- /dev/null +++ b/lib/filter.cpp
@@ -0,0 +1,1365 @@
1#include "filter.h"
2#include <stdexcept>
3#include <map>
4#include "notion.h"
5#include "word.h"
6#include "group.h"
7#include "frame.h"
8#include "lemma.h"
9#include "form.h"
10#include "pronunciation.h"
11
12namespace verbly {
13
14 filter::filter(const filter& other)
15 {
16 type_ = other.type_;
17
18 switch (type_)
19 {
20 case type::empty:
21 {
22 break;
23 }
24
25 case type::singleton:
26 {
27 new(&singleton_.filterField) field(other.singleton_.filterField);
28 singleton_.filterType = other.singleton_.filterType;
29
30 switch (singleton_.filterType)
31 {
32 case comparison::int_equals:
33 case comparison::int_does_not_equal:
34 case comparison::int_is_at_least:
35 case comparison::int_is_greater_than:
36 case comparison::int_is_at_most:
37 case comparison::int_is_less_than:
38 {
39 singleton_.intValue = other.singleton_.intValue;
40
41 break;
42 }
43
44 case comparison::boolean_equals:
45 {
46 singleton_.boolValue = other.singleton_.boolValue;
47
48 break;
49 }
50
51 case comparison::string_equals:
52 case comparison::string_does_not_equal:
53 case comparison::string_is_like:
54 case comparison::string_is_not_like:
55 {
56 new(&singleton_.stringValue) std::string(other.singleton_.stringValue);
57
58 break;
59 }
60
61 case comparison::is_null:
62 case comparison::is_not_null:
63 {
64 break;
65 }
66
67 case comparison::matches:
68 case comparison::does_not_match:
69 case comparison::hierarchally_matches:
70 case comparison::does_not_hierarchally_match:
71 {
72 new(&singleton_.join) std::unique_ptr<filter>(new filter(*other.singleton_.join));
73
74 break;
75 }
76 }
77
78 break;
79 }
80
81 case type::group:
82 {
83 new(&group_.children) std::list<filter>(other.group_.children);
84 group_.orlogic = other.group_.orlogic;
85
86 break;
87 }
88 }
89 }
90
91 filter::filter(filter&& other) : filter()
92 {
93 swap(*this, other);
94 }
95
96 filter& filter::operator=(filter other)
97 {
98 swap(*this, other);
99
100 return *this;
101 }
102
103 void swap(filter& first, filter& second)
104 {
105 using type = filter::type;
106 using comparison = filter::comparison;
107
108 type tempType = first.type_;
109 field tempField;
110 comparison tempComparison;
111 std::unique_ptr<filter> tempJoin;
112 std::string tempStringValue;
113 int tempIntValue;
114 bool tempBoolValue;
115 std::list<filter> tempChildren;
116 bool tempOrlogic;
117
118 switch (tempType)
119 {
120 case type::empty:
121 {
122 break;
123 }
124
125 case type::singleton:
126 {
127 tempField = std::move(first.singleton_.filterField);
128 tempComparison = first.singleton_.filterType;
129
130 switch (tempComparison)
131 {
132 case comparison::int_equals:
133 case comparison::int_does_not_equal:
134 case comparison::int_is_at_least:
135 case comparison::int_is_greater_than:
136 case comparison::int_is_at_most:
137 case comparison::int_is_less_than:
138 {
139 tempIntValue = first.singleton_.intValue;
140
141 break;
142 }
143
144 case comparison::boolean_equals:
145 {
146 tempBoolValue = first.singleton_.boolValue;
147
148 break;
149 }
150
151 case comparison::string_equals:
152 case comparison::string_does_not_equal:
153 case comparison::string_is_like:
154 case comparison::string_is_not_like:
155 {
156 tempStringValue = std::move(first.singleton_.stringValue);
157
158 break;
159 }
160
161 case comparison::is_null:
162 case comparison::is_not_null:
163 {
164 break;
165 }
166
167 case comparison::matches:
168 case comparison::does_not_match:
169 case comparison::hierarchally_matches:
170 case comparison::does_not_hierarchally_match:
171 {
172 tempJoin = std::move(first.singleton_.join);
173
174 break;
175 }
176 }
177
178 break;
179 }
180
181 case type::group:
182 {
183 tempChildren = std::move(first.group_.children);
184 tempOrlogic = first.group_.orlogic;
185
186 break;
187 }
188 }
189
190 first.~filter();
191
192 first.type_ = second.type_;
193
194 switch (first.type_)
195 {
196 case type::empty:
197 {
198 break;
199 }
200
201 case type::singleton:
202 {
203 new(&first.singleton_.filterField) field(std::move(second.singleton_.filterField));
204 first.singleton_.filterType = second.singleton_.filterType;
205
206 switch (first.singleton_.filterType)
207 {
208 case comparison::int_equals:
209 case comparison::int_does_not_equal:
210 case comparison::int_is_at_least:
211 case comparison::int_is_greater_than:
212 case comparison::int_is_at_most:
213 case comparison::int_is_less_than:
214 {
215 first.singleton_.intValue = second.singleton_.intValue;
216
217 break;
218 }
219
220 case comparison::boolean_equals:
221 {
222 first.singleton_.boolValue = second.singleton_.boolValue;
223
224 break;
225 }
226
227 case comparison::string_equals:
228 case comparison::string_does_not_equal:
229 case comparison::string_is_like:
230 case comparison::string_is_not_like:
231 {
232 new(&first.singleton_.stringValue) std::string(std::move(second.singleton_.stringValue));
233
234 break;
235 }
236
237 case comparison::is_null:
238 case comparison::is_not_null:
239 {
240 break;
241 }
242
243 case comparison::matches:
244 case comparison::does_not_match:
245 case comparison::hierarchally_matches:
246 case comparison::does_not_hierarchally_match:
247 {
248 new(&first.singleton_.join) std::unique_ptr<filter>(std::move(second.singleton_.join));
249
250 break;
251 }
252 }
253
254 break;
255 }
256
257 case type::group:
258 {
259 new(&first.group_.children) std::list<filter>(std::move(second.group_.children));
260 first.group_.orlogic = second.group_.orlogic;
261
262 break;
263 }
264 }
265
266 second.~filter();
267
268 second.type_ = tempType;
269
270 switch (second.type_)
271 {
272 case type::empty:
273 {
274 break;
275 }
276
277 case type::singleton:
278 {
279 new(&second.singleton_.filterField) field(std::move(tempField));
280 second.singleton_.filterType = tempComparison;
281
282 switch (second.singleton_.filterType)
283 {
284 case comparison::int_equals:
285 case comparison::int_does_not_equal:
286 case comparison::int_is_at_least:
287 case comparison::int_is_greater_than:
288 case comparison::int_is_at_most:
289 case comparison::int_is_less_than:
290 {
291 second.singleton_.intValue = tempIntValue;
292
293 break;
294 }
295
296 case comparison::boolean_equals:
297 {
298 second.singleton_.boolValue = tempBoolValue;
299
300 break;
301 }
302
303 case comparison::string_equals:
304 case comparison::string_does_not_equal:
305 case comparison::string_is_like:
306 case comparison::string_is_not_like:
307 {
308 new(&second.singleton_.stringValue) std::string(std::move(tempStringValue));
309
310 break;
311 }
312
313 case comparison::is_null:
314 case comparison::is_not_null:
315 {
316 break;
317 }
318
319 case comparison::matches:
320 case comparison::does_not_match:
321 case comparison::hierarchally_matches:
322 case comparison::does_not_hierarchally_match:
323 {
324 new(&second.singleton_.join) std::unique_ptr<filter>(std::move(tempJoin));
325
326 break;
327 }
328 }
329
330 break;
331 }
332
333 case type::group:
334 {
335 new(&second.group_.children) std::list<filter>(std::move(tempChildren));
336 second.group_.orlogic = tempOrlogic;
337
338 break;
339 }
340 }
341 }
342
343 filter::~filter()
344 {
345 switch (type_)
346 {
347 case type::empty:
348 {
349 break;
350 }
351
352 case type::singleton:
353 {
354 singleton_.filterField.~field();
355
356 switch (singleton_.filterType)
357 {
358 case comparison::int_equals:
359 case comparison::int_does_not_equal:
360 case comparison::int_is_at_least:
361 case comparison::int_is_greater_than:
362 case comparison::int_is_at_most:
363 case comparison::int_is_less_than:
364 case comparison::boolean_equals:
365 case comparison::is_null:
366 case comparison::is_not_null:
367 {
368 break;
369 }
370
371 case comparison::string_equals:
372 case comparison::string_does_not_equal:
373 case comparison::string_is_like:
374 case comparison::string_is_not_like:
375 {
376 using string_type = std::string;
377
378 singleton_.stringValue.~string_type();
379
380 break;
381 }
382
383 case comparison::matches:
384 case comparison::does_not_match:
385 case comparison::hierarchally_matches:
386 case comparison::does_not_hierarchally_match:
387 {
388 using ptr_type = std::unique_ptr<filter>;
389
390 singleton_.join.~ptr_type();
391
392 break;
393 }
394 }
395
396 break;
397 }
398
399 case type::group:
400 {
401 using list_type = std::list<filter>;
402
403 group_.children.~list_type();
404
405 break;
406 }
407 }
408 }
409
410 filter::filter()
411 {
412 }
413
414 filter::filter(
415 field filterField,
416 comparison filterType,
417 int filterValue) :
418 type_(type::singleton)
419 {
420 if (filterField.getType() == field::type::integer)
421 {
422 switch (filterType)
423 {
424 case comparison::int_equals:
425 case comparison::int_does_not_equal:
426 case comparison::int_is_at_least:
427 case comparison::int_is_greater_than:
428 case comparison::int_is_at_most:
429 case comparison::int_is_less_than:
430 {
431 new(&singleton_.filterField) field(std::move(filterField));
432 singleton_.filterType = filterType;
433 singleton_.intValue = filterValue;
434
435 break;
436 }
437
438 case comparison::boolean_equals:
439 case comparison::string_equals:
440 case comparison::string_does_not_equal:
441 case comparison::string_is_like:
442 case comparison::string_is_not_like:
443 case comparison::is_null:
444 case comparison::is_not_null:
445 case comparison::matches:
446 case comparison::does_not_match:
447 case comparison::hierarchally_matches:
448 case comparison::does_not_hierarchally_match:
449 {
450 throw std::invalid_argument("Invalid comparison for integer field");
451 }
452 }
453 } else {
454 throw std::domain_error("Cannot match a non-integer field against an integer value");
455 }
456 }
457
458 filter::filter(
459 field filterField,
460 comparison filterType,
461 std::string filterValue) :
462 type_(type::singleton)
463 {
464 if (filterField.getType() == field::type::string)
465 {
466 switch (filterType)
467 {
468 case comparison::string_equals:
469 case comparison::string_does_not_equal:
470 case comparison::string_is_like:
471 case comparison::string_is_not_like:
472 {
473 new(&singleton_.filterField) field(std::move(filterField));
474 singleton_.filterType = filterType;
475 new(&singleton_.stringValue) std::string(std::move(filterValue));
476
477 break;
478 }
479
480 case comparison::int_equals:
481 case comparison::int_does_not_equal:
482 case comparison::int_is_at_least:
483 case comparison::int_is_greater_than:
484 case comparison::int_is_at_most:
485 case comparison::int_is_less_than:
486 case comparison::boolean_equals:
487 case comparison::is_null:
488 case comparison::is_not_null:
489 case comparison::matches:
490 case comparison::does_not_match:
491 case comparison::hierarchally_matches:
492 case comparison::does_not_hierarchally_match:
493 {
494 throw std::invalid_argument("Invalid comparison for string field");
495 }
496 }
497 } else {
498 throw std::domain_error("Cannot match a non-string field against an string value");
499 }
500 }
501
502 filter::filter(
503 field filterField,
504 comparison filterType,
505 bool filterValue) :
506 type_(type::singleton)
507 {
508 if (filterField.getType() == field::type::boolean)
509 {
510 switch (filterType)
511 {
512 case comparison::boolean_equals:
513 {
514 new(&singleton_.filterField) field(std::move(filterField));
515 singleton_.filterType = filterType;
516 singleton_.boolValue = filterValue;
517
518 break;
519 }
520
521 case comparison::string_equals:
522 case comparison::string_does_not_equal:
523 case comparison::string_is_like:
524 case comparison::string_is_not_like:
525 case comparison::int_equals:
526 case comparison::int_does_not_equal:
527 case comparison::int_is_at_least:
528 case comparison::int_is_greater_than:
529 case comparison::int_is_at_most:
530 case comparison::int_is_less_than:
531 case comparison::is_null:
532 case comparison::is_not_null:
533 case comparison::matches:
534 case comparison::does_not_match:
535 case comparison::hierarchally_matches:
536 case comparison::does_not_hierarchally_match:
537 {
538 throw std::invalid_argument("Invalid comparison for boolean field");
539 }
540 }
541 } else {
542 throw std::domain_error("Cannot match a non-boolean field against a boolean value");
543 }
544 }
545
546 filter::filter(
547 field filterField,
548 comparison filterType) :
549 type_(type::singleton)
550 {
551 if (filterField.isNullable())
552 {
553 switch (filterType)
554 {
555 case comparison::is_null:
556 case comparison::is_not_null:
557 {
558 new(&singleton_.filterField) field(std::move(filterField));
559 singleton_.filterType = filterType;
560
561 break;
562 }
563
564 case comparison::string_equals:
565 case comparison::string_does_not_equal:
566 case comparison::string_is_like:
567 case comparison::string_is_not_like:
568 case comparison::int_equals:
569 case comparison::int_does_not_equal:
570 case comparison::int_is_at_least:
571 case comparison::int_is_greater_than:
572 case comparison::int_is_at_most:
573 case comparison::int_is_less_than:
574 case comparison::boolean_equals:
575 case comparison::matches:
576 case comparison::does_not_match:
577 case comparison::hierarchally_matches:
578 case comparison::does_not_hierarchally_match:
579 {
580 throw std::invalid_argument("Incorrect constructor for given comparison");
581 }
582 }
583 } else {
584 throw std::domain_error("Cannot check nullity/non-nullity of non-nullable field");
585 }
586 }
587
588 filter::filter(
589 field joinOn,
590 comparison filterType,
591 filter joinCondition) :
592 type_(type::singleton)
593 {
594 switch (joinOn.getType())
595 {
596 case field::type::join:
597 case field::type::join_through:
598 {
599 switch (filterType)
600 {
601 case comparison::matches:
602 case comparison::does_not_match:
603 {
604 new(&singleton_.filterField) field(std::move(joinOn));
605 singleton_.filterType = filterType;
606 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getJoinObject())));
607
608 break;
609 }
610
611 case comparison::int_equals:
612 case comparison::int_does_not_equal:
613 case comparison::int_is_at_least:
614 case comparison::int_is_greater_than:
615 case comparison::int_is_at_most:
616 case comparison::int_is_less_than:
617 case comparison::boolean_equals:
618 case comparison::string_equals:
619 case comparison::string_does_not_equal:
620 case comparison::string_is_like:
621 case comparison::string_is_not_like:
622 case comparison::is_null:
623 case comparison::is_not_null:
624 case comparison::hierarchally_matches:
625 case comparison::does_not_hierarchally_match:
626 {
627 throw std::invalid_argument("Incorrect constructor for given comparison");
628 }
629 }
630
631 break;
632 }
633
634 case field::type::hierarchal_join:
635 {
636 switch (filterType)
637 {
638 case comparison::hierarchally_matches:
639 case comparison::does_not_hierarchally_match:
640 {
641 new(&singleton_.filterField) field(std::move(joinOn));
642 singleton_.filterType = filterType;
643 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getObject())));
644
645 break;
646 }
647
648 case comparison::int_equals:
649 case comparison::int_does_not_equal:
650 case comparison::int_is_at_least:
651 case comparison::int_is_greater_than:
652 case comparison::int_is_at_most:
653 case comparison::int_is_less_than:
654 case comparison::boolean_equals:
655 case comparison::string_equals:
656 case comparison::string_does_not_equal:
657 case comparison::string_is_like:
658 case comparison::string_is_not_like:
659 case comparison::is_null:
660 case comparison::is_not_null:
661 case comparison::matches:
662 case comparison::does_not_match:
663 {
664 throw std::invalid_argument("Incorrect constructor for given comparison");
665 }
666 }
667
668 break;
669 }
670
671 case field::type::undefined:
672 case field::type::string:
673 case field::type::integer:
674 case field::type::boolean:
675 {
676 throw std::domain_error("Matching field must be a join field");
677 }
678 }
679 }
680
681 field filter::getField() const
682 {
683 if (type_ == type::singleton)
684 {
685 return singleton_.filterField;
686 } else {
687 throw std::domain_error("This filter does not have a field");
688 }
689 }
690
691 filter::comparison filter::getComparison() const
692 {
693 if (type_ == type::singleton)
694 {
695 return singleton_.filterType;
696 } else {
697 throw std::domain_error("This filter does not have a comparison");
698 }
699 }
700
701 filter filter::getJoinCondition() const
702 {
703 if (type_ == type::singleton)
704 {
705 switch (singleton_.filterType)
706 {
707 case comparison::matches:
708 case comparison::does_not_match:
709 case comparison::hierarchally_matches:
710 case comparison::does_not_hierarchally_match:
711 {
712 return *singleton_.join;
713 }
714
715 case comparison::string_equals:
716 case comparison::string_does_not_equal:
717 case comparison::string_is_like:
718 case comparison::string_is_not_like:
719 case comparison::int_equals:
720 case comparison::int_does_not_equal:
721 case comparison::int_is_at_least:
722 case comparison::int_is_greater_than:
723 case comparison::int_is_at_most:
724 case comparison::int_is_less_than:
725 case comparison::boolean_equals:
726 case comparison::is_null:
727 case comparison::is_not_null:
728 {
729 throw std::domain_error("This filter does not have a join condition");
730 }
731 }
732 } else {
733 throw std::domain_error("This filter does not have a join condition");
734 }
735 }
736
737 std::string filter::getStringArgument() const
738 {
739 if (type_ == type::singleton)
740 {
741 switch (singleton_.filterType)
742 {
743 case comparison::string_equals:
744 case comparison::string_does_not_equal:
745 case comparison::string_is_like:
746 case comparison::string_is_not_like:
747 {
748 return singleton_.stringValue;
749 }
750
751 case comparison::int_equals:
752 case comparison::int_does_not_equal:
753 case comparison::int_is_at_least:
754 case comparison::int_is_greater_than:
755 case comparison::int_is_at_most:
756 case comparison::int_is_less_than:
757 case comparison::boolean_equals:
758 case comparison::is_null:
759 case comparison::is_not_null:
760 case comparison::matches:
761 case comparison::does_not_match:
762 case comparison::hierarchally_matches:
763 case comparison::does_not_hierarchally_match:
764 {
765 throw std::domain_error("This filter does not have a string argument");
766 }
767 }
768 } else {
769 throw std::domain_error("This filter does not have a string argument");
770 }
771 }
772
773 int filter::getIntegerArgument() const
774 {
775 if (type_ == type::singleton)
776 {
777 switch (singleton_.filterType)
778 {
779 case comparison::int_equals:
780 case comparison::int_does_not_equal:
781 case comparison::int_is_at_least:
782 case comparison::int_is_greater_than:
783 case comparison::int_is_at_most:
784 case comparison::int_is_less_than:
785 {
786 return singleton_.intValue;
787 }
788
789 case comparison::string_equals:
790 case comparison::string_does_not_equal:
791 case comparison::string_is_like:
792 case comparison::string_is_not_like:
793 case comparison::boolean_equals:
794 case comparison::is_null:
795 case comparison::is_not_null:
796 case comparison::matches:
797 case comparison::does_not_match:
798 case comparison::hierarchally_matches:
799 case comparison::does_not_hierarchally_match:
800 {
801 throw std::domain_error("This filter does not have an integer argument");
802 }
803 }
804 } else {
805 throw std::domain_error("This filter does not have an integer argument");
806 }
807 }
808
809 bool filter::getBooleanArgument() const
810 {
811 if ((type_ == type::singleton) && (singleton_.filterType == comparison::boolean_equals))
812 {
813 return singleton_.boolValue;
814 } else {
815 throw std::domain_error("This filter does not have a boolean argument");
816 }
817 }
818
819 filter::filter(bool orlogic) : type_(type::group)
820 {
821 new(&group_.children) std::list<filter>();
822 group_.orlogic = orlogic;
823 }
824
825 bool filter::getOrlogic() const
826 {
827 if (type_ == type::group)
828 {
829 return group_.orlogic;
830 } else {
831 throw std::domain_error("This filter is not a group filter");
832 }
833 }
834
835 filter filter::operator+(filter condition) const
836 {
837 filter result(*this);
838 result += std::move(condition);
839
840 return result;
841 }
842
843 filter& filter::operator+=(filter condition)
844 {
845 if (type_ == type::group)
846 {
847 group_.children.push_back(std::move(condition));
848
849 return *this;
850 } else {
851 throw std::domain_error("Children can only be added to group filters");
852 }
853 }
854
855 filter::const_iterator filter::begin() const
856 {
857 if (type_ == type::group)
858 {
859 return std::begin(group_.children);
860 } else {
861 throw std::domain_error("This filter has no children");
862 }
863 }
864
865 filter::const_iterator filter::end() const
866 {
867 if (type_ == type::group)
868 {
869 return std::end(group_.children);
870 } else {
871 throw std::domain_error("This filter has no children");
872 }
873 }
874
875 filter filter::operator!() const
876 {
877 switch (type_)
878 {
879 case type::empty:
880 {
881 return {};
882 }
883
884 case type::singleton:
885 {
886 switch (singleton_.filterType)
887 {
888 case comparison::int_equals:
889 {
890 return filter(singleton_.filterField, comparison::int_does_not_equal, singleton_.intValue);
891 }
892
893 case comparison::int_does_not_equal:
894 {
895 return filter(singleton_.filterField, comparison::int_equals, singleton_.intValue);
896 }
897
898 case comparison::int_is_at_least:
899 {
900 return filter(singleton_.filterField, comparison::int_is_less_than, singleton_.intValue);
901 }
902
903 case comparison::int_is_greater_than:
904 {
905 return filter(singleton_.filterField, comparison::int_is_at_most, singleton_.intValue);
906 }
907
908 case comparison::int_is_at_most:
909 {
910 return filter(singleton_.filterField, comparison::int_is_greater_than, singleton_.intValue);
911 }
912
913 case comparison::int_is_less_than:
914 {
915 return filter(singleton_.filterField, comparison::int_is_at_least, singleton_.intValue);
916 }
917
918 case comparison::boolean_equals:
919 {
920 return filter(singleton_.filterField, comparison::boolean_equals, !singleton_.boolValue);
921 }
922
923 case comparison::string_equals:
924 {
925 return filter(singleton_.filterField, comparison::string_does_not_equal, singleton_.stringValue);
926 }
927
928 case comparison::string_does_not_equal:
929 {
930 return filter(singleton_.filterField, comparison::string_equals, singleton_.stringValue);
931 }
932
933 case comparison::string_is_like:
934 {
935 return filter(singleton_.filterField, comparison::string_is_not_like, singleton_.stringValue);
936 }
937
938 case comparison::string_is_not_like:
939 {
940 return filter(singleton_.filterField, comparison::string_is_like, singleton_.stringValue);
941 }
942
943 case comparison::is_null:
944 {
945 return filter(singleton_.filterField, comparison::is_not_null);
946 }
947
948 case comparison::is_not_null:
949 {
950 return filter(singleton_.filterField, comparison::is_null);
951 }
952
953 case comparison::matches:
954 {
955 return filter(singleton_.filterField, comparison::does_not_match, *singleton_.join);
956 }
957
958 case comparison::does_not_match:
959 {
960 return filter(singleton_.filterField, comparison::matches, *singleton_.join);
961 }
962
963 case comparison::hierarchally_matches:
964 {
965 return filter(singleton_.filterField, comparison::does_not_hierarchally_match, *singleton_.join);
966 }
967
968 case comparison::does_not_hierarchally_match:
969 {
970 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join);
971 }
972 }
973 }
974
975 case type::group:
976 {
977 filter result(!group_.orlogic);
978
979 for (const filter& child : group_.children)
980 {
981 result += !child;
982 }
983
984 return result;
985 }
986 }
987 }
988
989 filter& filter::operator&=(filter condition)
990 {
991 return (*this = (*this && std::move(condition)));
992 }
993
994 filter& filter::operator|=(filter condition)
995 {
996 return (*this = (*this || std::move(condition)));
997 }
998
999 filter filter::operator&&(filter condition) const
1000 {
1001 switch (type_)
1002 {
1003 case type::empty:
1004 {
1005 return condition;
1006 }
1007
1008 case type::singleton:
1009 {
1010 filter result(false);
1011 result.group_.children.push_back(*this);
1012 result.group_.children.push_back(std::move(condition));
1013
1014 return result;
1015 }
1016
1017 case type::group:
1018 {
1019 if (group_.orlogic)
1020 {
1021 filter result(false);
1022 result.group_.children.push_back(*this);
1023 result.group_.children.push_back(std::move(condition));
1024
1025 return result;
1026 } else {
1027 filter result(*this);
1028 result.group_.children.push_back(std::move(condition));
1029
1030 return result;
1031 }
1032 }
1033 }
1034 }
1035
1036 filter filter::operator||(filter condition) const
1037 {
1038 switch (type_)
1039 {
1040 case type::empty:
1041 {
1042 return condition;
1043 }
1044
1045 case type::singleton:
1046 {
1047 filter result(true);
1048 result.group_.children.push_back(*this);
1049 result.group_.children.push_back(std::move(condition));
1050
1051 return result;
1052 }
1053
1054 case type::group:
1055 {
1056 if (!group_.orlogic)
1057 {
1058 filter result(true);
1059 result.group_.children.push_back(*this);
1060 result.group_.children.push_back(std::move(condition));
1061
1062 return result;
1063 } else {
1064 filter result(*this);
1065 result.group_.children.push_back(std::move(condition));
1066
1067 return result;
1068 }
1069 }
1070 }
1071 }
1072
1073 filter filter::normalize(object context) const
1074 {
1075 {
1076 switch (type_)
1077 {
1078 case type::empty:
1079 {
1080 return *this;
1081 }
1082
1083 case type::singleton:
1084 {
1085 // First, switch on the normalized context, and then switch on the
1086 // current context. We recursively recontextualize by using the
1087 // current filter as a subquery for a join such that the context of
1088 // the subquery is one step closer to the context of the current
1089 // filter, and then letting the filter constructor normalize the
1090 // subquery.
1091 switch (context)
1092 {
1093 case object::undefined:
1094 {
1095 // An undefined object indicates no participation in
1096 // recontexualization.
1097 return *this;
1098 }
1099
1100 case object::notion:
1101 {
1102 switch (singleton_.filterField.getObject())
1103 {
1104 case object::undefined:
1105 case object::notion:
1106 {
1107 return *this;
1108 }
1109
1110 case object::word:
1111 case object::group:
1112 case object::frame:
1113 case object::lemma:
1114 case object::form:
1115 case object::pronunciation:
1116 {
1117 return (verbly::notion::word %= *this);
1118 }
1119 }
1120 }
1121
1122 case object::word:
1123 {
1124 switch (singleton_.filterField.getObject())
1125 {
1126 case object::notion:
1127 {
1128 return (verbly::word::notion %= *this);
1129 }
1130
1131 case object::undefined:
1132 case object::word:
1133 {
1134 return *this;
1135 }
1136
1137 case object::group:
1138 case object::frame:
1139 {
1140 return (verbly::word::group %= *this);
1141 }
1142
1143 case object::lemma:
1144 case object::form:
1145 case object::pronunciation:
1146 {
1147 return (verbly::word::lemma %= *this);
1148 }
1149 }
1150
1151 case object::group:
1152 {
1153 switch (singleton_.filterField.getObject())
1154 {
1155 case object::undefined:
1156 case object::group:
1157 {
1158 return *this;
1159 }
1160
1161 case object::notion:
1162 case object::word:
1163 case object::lemma:
1164 case object::form:
1165 case object::pronunciation:
1166 {
1167 return (verbly::group::word %= *this);
1168 }
1169
1170 case object::frame:
1171 {
1172 return (verbly::group::frame %= *this);
1173 }
1174 }
1175 }
1176
1177 case object::frame:
1178 {
1179 switch (singleton_.filterField.getObject())
1180 {
1181 case object::undefined:
1182 case object::frame:
1183 {
1184 return *this;
1185 }
1186
1187 case object::notion:
1188 case object::word:
1189 case object::group:
1190 case object::lemma:
1191 case object::form:
1192 case object::pronunciation:
1193 {
1194 return (verbly::frame::group %= *this);
1195 }
1196 }
1197 }
1198
1199 case object::lemma:
1200 {
1201 switch (singleton_.filterField.getObject())
1202 {
1203 case object::notion:
1204 case object::word:
1205 case object::group:
1206 case object::frame:
1207 {
1208 return verbly::lemma::word %= *this;
1209 }
1210
1211 case object::undefined:
1212 case object::lemma:
1213 {
1214 return *this;
1215 }
1216
1217 case object::form:
1218 case object::pronunciation:
1219 {
1220 return (verbly::lemma::form(inflection::base) %= *this);
1221 }
1222 }
1223 }
1224
1225 case object::form:
1226 {
1227 switch (singleton_.filterField.getObject())
1228 {
1229 case object::notion:
1230 case object::word:
1231 case object::group:
1232 case object::frame:
1233 case object::lemma:
1234 {
1235 return verbly::form::lemma(inflection::base) %= *this;
1236 }
1237
1238 case object::undefined:
1239 case object::form:
1240 {
1241 return *this;
1242 }
1243
1244 case object::pronunciation:
1245 {
1246 return (verbly::form::pronunciation %= *this);
1247 }
1248 }
1249 }
1250
1251 case object::pronunciation:
1252 {
1253 switch (singleton_.filterField.getObject())
1254 {
1255 case object::notion:
1256 case object::word:
1257 case object::group:
1258 case object::frame:
1259 case object::lemma:
1260 case object::form:
1261 {
1262 return verbly::pronunciation::form %= *this;
1263 }
1264
1265 case object::undefined:
1266 case object::pronunciation:
1267 {
1268 return *this;
1269 }
1270 }
1271 }
1272 }
1273 }
1274 }
1275
1276 case type::group:
1277 {
1278 filter result(group_.orlogic);
1279 std::map<field, filter> joins;
1280
1281 for (const filter& child : group_.children)
1282 {
1283 filter normalized = child.normalize(context);
1284
1285 // Notably, this does not attempt to merge hierarchal matches.
1286 switch (normalized.getType())
1287 {
1288 case type::singleton:
1289 {
1290 switch (normalized.getComparison())
1291 {
1292 case comparison::matches:
1293 {
1294 if (!joins.count(normalized.singleton_.filterField))
1295 {
1296 joins[normalized.getField()] = filter(group_.orlogic);
1297 }
1298
1299 joins.at(normalized.getField()) += std::move(*normalized.singleton_.join);
1300
1301 break;
1302 }
1303
1304 case comparison::does_not_match:
1305 {
1306 if (!joins.count(normalized.singleton_.filterField))
1307 {
1308 joins[normalized.getField()] = filter(group_.orlogic);
1309 }
1310
1311 joins.at(normalized.getField()) += !*normalized.singleton_.join;
1312
1313 break;
1314 }
1315
1316 case comparison::int_equals:
1317 case comparison::int_does_not_equal:
1318 case comparison::int_is_at_least:
1319 case comparison::int_is_greater_than:
1320 case comparison::int_is_at_most:
1321 case comparison::int_is_less_than:
1322 case comparison::boolean_equals:
1323 case comparison::string_equals:
1324 case comparison::string_does_not_equal:
1325 case comparison::string_is_like:
1326 case comparison::string_is_not_like:
1327 case comparison::is_null:
1328 case comparison::is_not_null:
1329 case comparison::hierarchally_matches:
1330 case comparison::does_not_hierarchally_match:
1331 {
1332 result += std::move(normalized);
1333
1334 break;
1335 }
1336 }
1337
1338 break;
1339 }
1340
1341 case type::group:
1342 case type::empty:
1343 {
1344 result += std::move(normalized);
1345
1346 break;
1347 }
1348 }
1349 }
1350
1351 for (auto& mapping : joins)
1352 {
1353 const field& joinOn = mapping.first;
1354 filter& joinCondition = mapping.second;
1355
1356 result += (joinOn %= joinCondition.normalize(joinOn.getJoinObject()));
1357 }
1358
1359 return result;
1360 }
1361 }
1362 }
1363 }
1364
1365};
diff --git a/lib/filter.h b/lib/filter.h new file mode 100644 index 0000000..d213d7a --- /dev/null +++ b/lib/filter.h
@@ -0,0 +1,143 @@
1#ifndef FILTER_H_932BA9C6
2#define FILTER_H_932BA9C6
3
4#include <list>
5#include <string>
6#include <memory>
7#include "field.h"
8#include "enums.h"
9
10namespace verbly {
11
12 class filter {
13 public:
14 enum class type {
15 empty,
16 singleton,
17 group
18 };
19
20 enum class comparison {
21 int_equals,
22 int_does_not_equal,
23 int_is_at_least,
24 int_is_greater_than,
25 int_is_at_most,
26 int_is_less_than,
27 boolean_equals,
28 string_equals,
29 string_does_not_equal,
30 string_is_like,
31 string_is_not_like,
32 is_null,
33 is_not_null,
34 matches,
35 does_not_match,
36 hierarchally_matches,
37 does_not_hierarchally_match
38 };
39
40 // Copy and move constructors
41
42 filter(const filter& other);
43 filter(filter&& other);
44
45 // Assignment
46
47 filter& operator=(filter other);
48
49 // Swap
50
51 friend void swap(filter& first, filter& second);
52
53 // Destructor
54
55 ~filter();
56
57 // Accessors
58
59 type getType() const
60 {
61 return type_;
62 }
63
64 // Empty
65
66 filter();
67
68 // Singleton
69
70 filter(field filterField, comparison filterType, int filterValue);
71 filter(field filterField, comparison filterType, std::string filterValue);
72 filter(field filterField, comparison filterType, bool filterValue);
73 filter(field filterField, comparison filterType);
74 filter(field joinOn, comparison filterType, filter joinCondition);
75
76 field getField() const;
77
78 comparison getComparison() const;
79
80 filter getJoinCondition() const;
81
82 std::string getStringArgument() const;
83
84 int getIntegerArgument() const;
85
86 bool getBooleanArgument() const;
87
88 // Group
89
90 explicit filter(bool orlogic);
91
92 bool getOrlogic() const;
93
94 filter operator+(filter condition) const;
95
96 filter& operator+=(filter condition);
97
98 using const_iterator = std::list<filter>::const_iterator;
99
100 const_iterator begin() const;
101
102 const_iterator end() const;
103
104 // Negation
105
106 filter operator!() const;
107
108 // Groupifying
109
110 filter operator&&(filter condition) const;
111 filter operator||(filter condition) const;
112
113 filter& operator&=(filter condition);
114 filter& operator|=(filter condition);
115
116 // Utility
117
118 filter normalize(object context) const;
119
120 private:
121 union {
122 struct {
123 field filterField;
124 comparison filterType;
125 union {
126 std::unique_ptr<filter> join;
127 std::string stringValue;
128 int intValue;
129 bool boolValue;
130 };
131 } singleton_;
132 struct {
133 std::list<filter> children;
134 bool orlogic;
135 } group_;
136 };
137 type type_ = type::empty;
138
139 };
140
141};
142
143#endif /* end of include guard: FILTER_H_932BA9C6 */
diff --git a/lib/form.cpp b/lib/form.cpp new file mode 100644 index 0000000..8ba3bd7 --- /dev/null +++ b/lib/form.cpp
@@ -0,0 +1,53 @@
1#include "form.h"
2#include <sqlite3.h>
3#include "filter.h"
4#include "pronunciation.h"
5#include "database.h"
6#include "query.h"
7
8namespace verbly {
9
10 const object form::objectType = object::form;
11
12 const std::list<std::string> form::select = {"form_id", "form", "complexity", "proper"};
13
14 const field form::id = field::integerField(object::form, "form_id");
15 const field form::text = field::stringField(object::form, "form");
16 const field form::complexity = field::integerField(object::form, "complexity");
17 const field form::proper = field::booleanField(object::form, "proper");
18
19 const field form::pronunciation = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id");
20
21 const field form::lemmaJoin = field::joinField(object::form, "form_id", object::lemma);
22 const field form::inflectionCategory = field::integerField("lemmas_forms", "category");
23
24 form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
25 {
26 id_ = sqlite3_column_int(row, 0);
27 text_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 1)));
28 complexity_ = sqlite3_column_int(row, 2);
29 proper_ = (sqlite3_column_int(row, 3) == 1);
30 }
31
32 filter operator%=(form::inflection_field check, filter joinCondition)
33 {
34 return (form::lemmaJoin %= (joinCondition && (form::inflectionCategory == check.getCategory())));
35 }
36
37 const std::vector<pronunciation>& form::getPronunciations() const
38 {
39 if (!valid_)
40 {
41 throw std::domain_error("Bad access to uninitialized form");
42 }
43
44 if (!initializedPronunciations_)
45 {
46 pronunciations_ = db_->pronunciations(pronunciation::form %= *this, false, -1).all();
47 initializedPronunciations_ = true;
48 }
49
50 return pronunciations_;
51 }
52
53};
diff --git a/lib/form.h b/lib/form.h new file mode 100644 index 0000000..c6a1353 --- /dev/null +++ b/lib/form.h
@@ -0,0 +1,149 @@
1#ifndef FORM_H_3A6C962C
2#define FORM_H_3A6C962C
3
4#include <list>
5#include <vector>
6#include <string>
7#include <stdexcept>
8#include "field.h"
9#include "filter.h"
10
11struct sqlite3_stmt;
12
13namespace verbly {
14
15 class pronunciation;
16 class database;
17
18 class form {
19 public:
20
21 // Default constructor
22
23 form() = default;
24
25 // Construct from database
26
27 form(const database& db, sqlite3_stmt* row);
28
29 // Accessors
30
31 operator bool() const
32 {
33 return valid_;
34 }
35
36 int getId() const
37 {
38 if (!valid_)
39 {
40 throw std::domain_error("Bad access to uninitialized form");
41 }
42
43 return id_;
44 }
45
46 std::string getText() const
47 {
48 if (!valid_)
49 {
50 throw std::domain_error("Bad access to uninitialized form");
51 }
52
53 return text_;
54 }
55
56 int getComplexity() const
57 {
58 if (!valid_)
59 {
60 throw std::domain_error("Bad access to uninitialized form");
61 }
62
63 return complexity_;
64 }
65
66 bool isProper() const
67 {
68 if (!valid_)
69 {
70 throw std::domain_error("Bad access to uninitialized form");
71 }
72
73 return proper_;
74 }
75
76 const std::vector<pronunciation>& getPronunciations() const;
77
78 // Type info
79
80 static const object objectType;
81
82 static const std::list<std::string> select;
83
84 // Query fields
85
86 static const field id;
87 static const field text;
88 static const field complexity;
89 static const field proper;
90
91 operator filter() const
92 {
93 if (!valid_)
94 {
95 throw std::domain_error("Bad access to uninitialized form");
96 }
97
98 return (id == id_);
99 }
100
101 // Relationships to other objects
102
103 static const field pronunciation;
104
105 class inflection_field {
106 public:
107
108 inflection_field(inflection category) : category_(category)
109 {
110 }
111
112 const inflection getCategory() const
113 {
114 return category_;
115 }
116
117 private:
118
119 const inflection category_;
120 };
121
122 static const inflection_field lemma(inflection category)
123 {
124 return inflection_field(category);
125 }
126
127 friend filter operator%=(form::inflection_field check, filter joinCondition);
128
129 private:
130 bool valid_ = false;
131
132 int id_;
133 std::string text_;
134 int complexity_ ;
135 bool proper_;
136
137 const database* db_;
138
139 mutable bool initializedPronunciations_ = false;
140 mutable std::vector<class pronunciation> pronunciations_;
141
142 static const field lemmaJoin;
143 static const field inflectionCategory;
144
145 };
146
147};
148
149#endif /* end of include guard: FORM_H_3A6C962C */
diff --git a/lib/frame.cpp b/lib/frame.cpp index ccec81b..bc3f842 100644 --- a/lib/frame.cpp +++ b/lib/frame.cpp
@@ -1,320 +1,21 @@
1#include "verbly.h" 1#include "frame.h"
2#include <sqlite3.h>
2 3
3namespace verbly { 4namespace verbly {
4 5
5 frame::selrestr::type frame::selrestr::get_type() const 6 const object frame::objectType = object::frame;
6 {
7 return _type;
8 }
9
10 frame::selrestr::selrestr(const selrestr& other)
11 {
12 _type = other._type;
13
14 switch (_type)
15 {
16 case frame::selrestr::type::singleton:
17 {
18 _singleton.pos = other._singleton.pos;
19 new(&_singleton.restriction) std::string(other._singleton.restriction);
20
21 break;
22 }
23
24 case frame::selrestr::type::group:
25 {
26 new(&_group.children) std::list<selrestr>(other._group.children);
27 _group.orlogic = other._group.orlogic;
28
29 break;
30 }
31
32 case frame::selrestr::type::empty:
33 {
34 // Nothing!
35
36 break;
37 }
38 }
39 }
40
41 frame::selrestr::~selrestr()
42 {
43 switch (_type)
44 {
45 case frame::selrestr::type::singleton:
46 {
47 using string_type = std::string;
48 _singleton.restriction.~string_type();
49
50 break;
51 }
52
53 case frame::selrestr::type::group:
54 {
55 using list_type = std::list<selrestr>;
56 _group.children.~list_type();
57
58 break;
59 }
60
61 case frame::selrestr::type::empty:
62 {
63 // Nothing!
64
65 break;
66 }
67 }
68 }
69
70 frame::selrestr& frame::selrestr::operator=(const selrestr& other)
71 {
72 this->~selrestr();
73
74 _type = other._type;
75
76 switch (_type)
77 {
78 case frame::selrestr::type::singleton:
79 {
80 _singleton.pos = other._singleton.pos;
81 new(&_singleton.restriction) std::string(other._singleton.restriction);
82
83 break;
84 }
85
86 case frame::selrestr::type::group:
87 {
88 new(&_group.children) std::list<selrestr>(other._group.children);
89 _group.orlogic = other._group.orlogic;
90
91 break;
92 }
93
94 case frame::selrestr::type::empty:
95 {
96 // Nothing!
97
98 break;
99 }
100 }
101
102 return *this;
103 }
104
105 frame::selrestr::selrestr() : _type(frame::selrestr::type::empty)
106 {
107
108 }
109
110 frame::selrestr::selrestr(std::string restriction, bool pos) : _type(frame::selrestr::type::singleton)
111 {
112 new(&_singleton.restriction) std::string(restriction);
113 _singleton.pos = pos;
114 }
115
116 std::string frame::selrestr::get_restriction() const
117 {
118 assert(_type == frame::selrestr::type::singleton);
119
120 return _singleton.restriction;
121 }
122
123 bool frame::selrestr::get_pos() const
124 {
125 assert(_type == frame::selrestr::type::singleton);
126
127 return _singleton.pos;
128 }
129
130 frame::selrestr::selrestr(std::list<selrestr> children, bool orlogic) : _type(frame::selrestr::type::group)
131 {
132 new(&_group.children) std::list<selrestr>(children);
133 _group.orlogic = orlogic;
134 }
135
136 std::list<frame::selrestr> frame::selrestr::get_children() const
137 {
138 assert(_type == frame::selrestr::type::group);
139
140 return _group.children;
141 }
142
143 std::list<frame::selrestr>::const_iterator frame::selrestr::begin() const
144 {
145 assert(_type == frame::selrestr::type::group);
146
147 return _group.children.begin();
148 }
149
150 std::list<frame::selrestr>::const_iterator frame::selrestr::end() const
151 {
152 assert(_type == frame::selrestr::type::group);
153
154 return _group.children.end();
155 }
156
157 bool frame::selrestr::get_orlogic() const
158 {
159 assert(_type == frame::selrestr::type::group);
160
161 return _group.orlogic;
162 }
163
164 frame::part::type frame::part::get_type() const
165 {
166 return _type;
167 }
168
169 frame::part::part()
170 {
171
172 }
173 7
174 frame::part::part(const part& other) 8 const std::list<std::string> frame::select = {"frame_id", "data"};
175 {
176 _type = other._type;
177
178 switch (_type)
179 {
180 case frame::part::type::noun_phrase:
181 {
182 new(&_noun_phrase.role) std::string(other._noun_phrase.role);
183 new(&_noun_phrase.selrestrs) selrestr(other._noun_phrase.selrestrs);
184 new(&_noun_phrase.synrestrs) std::set<std::string>(other._noun_phrase.synrestrs);
185
186 break;
187 }
188
189 case frame::part::type::literal_preposition:
190 {
191 new(&_literal_preposition.choices) std::vector<std::string>(other._literal_preposition.choices);
192
193 break;
194 }
195
196 case frame::part::type::selection_preposition:
197 {
198 new(&_selection_preposition.preprestrs) std::vector<std::string>(other._selection_preposition.preprestrs);
199
200 break;
201 }
202
203 case frame::part::type::literal:
204 {
205 new(&_literal.lexval) std::string(other._literal.lexval);
206
207 break;
208 }
209
210 default:
211 {
212 // Nothing!
213
214 break;
215 }
216 }
217 }
218 9
219 frame::part::~part() 10 const field frame::id = field::integerField(object::frame, "frame_id");
220 {
221 switch (_type)
222 {
223 case frame::part::type::noun_phrase:
224 {
225 using string_type = std::string;
226 using set_type = std::set<std::string>;
227
228 _noun_phrase.role.~string_type();
229 _noun_phrase.selrestrs.~selrestr();
230 _noun_phrase.synrestrs.~set_type();
231
232 break;
233 }
234
235 case frame::part::type::literal_preposition:
236 {
237 using vector_type = std::vector<std::string>;
238 _literal_preposition.choices.~vector_type();
239
240 break;
241 }
242
243 case frame::part::type::selection_preposition:
244 {
245 using vector_type = std::vector<std::string>;
246 _selection_preposition.preprestrs.~vector_type();
247
248 break;
249 }
250
251 case frame::part::type::literal:
252 {
253 using string_type = std::string;
254 _literal.lexval.~string_type();
255
256 break;
257 }
258
259 default:
260 {
261 // Nothing!
262
263 break;
264 }
265 }
266 }
267 11
268 std::string frame::part::get_role() const 12 const field frame::group = field::joinThrough(object::frame, "frame_id", object::group, "groups_frames", "group_id");
269 {
270 assert(_type == frame::part::type::noun_phrase);
271
272 return _noun_phrase.role;
273 }
274 13
275 frame::selrestr frame::part::get_selrestrs() const 14 frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
276 { 15 {
277 assert(_type == frame::part::type::noun_phrase); 16 id_ = sqlite3_column_int(row, 0);
278 17
279 return _noun_phrase.selrestrs; 18 // TODO: Initialize frame data from row.
280 }
281
282 std::set<std::string> frame::part::get_synrestrs() const
283 {
284 assert(_type == frame::part::type::noun_phrase);
285
286 return _noun_phrase.synrestrs;
287 }
288
289 std::vector<std::string> frame::part::get_choices() const
290 {
291 assert(_type == frame::part::type::literal_preposition);
292
293 return _literal_preposition.choices;
294 }
295
296 std::vector<std::string> frame::part::get_preprestrs() const
297 {
298 assert(_type == frame::part::type::selection_preposition);
299
300 return _selection_preposition.preprestrs;
301 }
302
303 std::string frame::part::get_literal() const
304 {
305 assert(_type == frame::part::type::literal);
306
307 return _literal.lexval;
308 }
309
310 std::vector<frame::part> frame::parts() const
311 {
312 return _parts;
313 }
314
315 std::map<std::string, frame::selrestr> frame::roles() const
316 {
317 return _roles;
318 } 19 }
319 20
320}; 21};
diff --git a/lib/frame.h b/lib/frame.h index fa57e1b..68a4346 100644 --- a/lib/frame.h +++ b/lib/frame.h
@@ -1,118 +1,78 @@
1#ifndef FRAME_H_9A5D90FE 1#ifndef FRAME_H_EA29065A
2#define FRAME_H_9A5D90FE 2#define FRAME_H_EA29065A
3
4#include <stdexcept>
5#include <list>
6#include "field.h"
7#include "filter.h"
8
9struct sqlite3_stmt;
3 10
4namespace verbly { 11namespace verbly {
5 12
6 class frame_query; 13 class database;
7 14
8 class frame { 15 class frame {
9 public: 16 public:
10 class selrestr { 17
11 public: 18 // Default constructor
12 enum class type { 19
13 empty, 20 frame() = default;
14 singleton, 21
15 group 22 // Construct from database
16 }; 23
17 24 frame(const database& db, sqlite3_stmt* row);
18 type get_type() const; 25
19 selrestr(const selrestr& other); 26 // Accessors
20 ~selrestr(); 27
21 selrestr& operator=(const selrestr& other); 28 operator bool() const
22 29 {
23 // Empty 30 return valid_;
24 selrestr(); 31 }
25 32
26 // Singleton 33 int getId() const
27 selrestr(std::string restriction, bool pos); 34 {
28 std::string get_restriction() const; 35 if (!valid_)
29 bool get_pos() const; 36 {
30 37 throw std::domain_error("Bad access to uninitialized frame");
31 // Group 38 }
32 selrestr(std::list<selrestr> children, bool orlogic);
33 std::list<selrestr> get_children() const;
34 std::list<selrestr>::const_iterator begin() const;
35 std::list<selrestr>::const_iterator end() const;
36 bool get_orlogic() const;
37
38 private:
39 union {
40 struct {
41 bool pos;
42 std::string restriction;
43 } _singleton;
44 struct {
45 std::list<selrestr> children;
46 bool orlogic;
47 } _group;
48 };
49 type _type;
50 };
51 39
52 class part { 40 return id_;
53 public: 41 }
54 enum class type { 42
55 noun_phrase, 43 // Type info
56 verb, 44
57 literal_preposition, 45 static const object objectType;
58 selection_preposition, 46
59 adjective, 47 static const std::list<std::string> select;
60 adverb, 48
61 literal 49 // Query fields
62 }; 50
63 51 static const field id;
64 type get_type() const; 52
65 part(const part& other); 53 operator filter() const
66 ~part(); 54 {
67 55 if (!valid_)
68 // Noun phrase 56 {
69 std::string get_role() const; 57 throw std::domain_error("Bad access to uninitialized frame");
70 selrestr get_selrestrs() const; 58 }
71 std::set<std::string> get_synrestrs() const;
72
73 // Literal preposition
74 std::vector<std::string> get_choices() const;
75
76 // Selection preposition
77 std::vector<std::string> get_preprestrs() const;
78
79 // Literal
80 std::string get_literal() const;
81
82 private:
83 friend class frame_query;
84
85 part();
86
87 union {
88 struct {
89 std::string role;
90 selrestr selrestrs;
91 std::set<std::string> synrestrs;
92 } _noun_phrase;
93 struct {
94 std::vector<std::string> choices;
95 } _literal_preposition;
96 struct {
97 std::vector<std::string> preprestrs;
98 } _selection_preposition;
99 struct {
100 std::string lexval;
101 } _literal;
102 };
103 type _type;
104 };
105 59
106 std::vector<part> parts() const; 60 return (id == id_);
107 std::map<std::string, selrestr> roles() const; 61 }
108 62
109 private: 63 // Relationships to other objects
110 friend class frame_query; 64
111 65 static const field group;
112 std::vector<part> _parts; 66
113 std::map<std::string, selrestr> _roles; 67 private:
68 bool valid_ = false;
69
70 int id_;
71
72 const database* db_;
73
114 }; 74 };
115 75
116}; 76};
117 77
118#endif /* end of include guard: FRAME_H_9A5D90FE */ 78#endif /* end of include guard: FRAME_H_EA29065A */
diff --git a/lib/group.cpp b/lib/group.cpp new file mode 100644 index 0000000..8b6d985 --- /dev/null +++ b/lib/group.cpp
@@ -0,0 +1,43 @@
1#include "group.h"
2#include <sqlite3.h>
3#include "frame.h"
4#include "database.h"
5#include "query.h"
6
7namespace verbly {
8
9 const object group::objectType = object::group;
10
11 const std::list<std::string> group::select = {"group_id", "data"};
12
13 const field group::id = field::integerField(object::group, "group_id");
14
15 const field group::frame = field::joinThrough(object::group, "group_id", object::frame, "groups_frames", "frame_id");
16 const field group::word = field::joinField(object::group, "group_id", object::word);
17
18 group::group(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
19 {
20 id_ = sqlite3_column_int(row, 0);
21
22 // TODO: Initialize role data from row.
23 }
24
25 const std::vector<frame>& group::getFrames() const
26 {
27 if (!valid_)
28 {
29 throw std::domain_error("Bad access to uninitialized group");
30 }
31
32 if (!initializedFrames_)
33 {
34 frames_ = db_->frames(frame::group %= *this, false, -1).all();
35
36 initializedFrames_ = true;
37 }
38
39 return frames_;
40 }
41
42};
43
diff --git a/lib/group.h b/lib/group.h new file mode 100644 index 0000000..dd53503 --- /dev/null +++ b/lib/group.h
@@ -0,0 +1,87 @@
1#ifndef GROUP_H_BD6933C0
2#define GROUP_H_BD6933C0
3
4#include <stdexcept>
5#include <list>
6#include <vector>
7#include "field.h"
8#include "filter.h"
9
10struct sqlite3_stmt;
11
12namespace verbly {
13
14 class database;
15 class frame;
16
17 class group {
18 public:
19
20 // Default constructor
21
22 group() = default;
23
24 // Construct from database
25
26 group(const database& db, sqlite3_stmt* row);
27
28 // Accessors
29
30 operator bool() const
31 {
32 return valid_;
33 }
34
35 int getId() const
36 {
37 if (!valid_)
38 {
39 throw std::domain_error("Bad access to uninitialized group");
40 }
41
42 return id_;
43 }
44
45 const std::vector<frame>& getFrames() const;
46
47 // Type info
48
49 static const object objectType;
50
51 static const std::list<std::string> select;
52
53 // Query fields
54
55 static const field id;
56
57 operator filter() const
58 {
59 if (!valid_)
60 {
61 throw std::domain_error("Bad access to uninitialized group");
62 }
63
64 return (id == id_);
65 }
66
67 // Relationships to other objects
68
69 static const field frame;
70
71 static const field word;
72
73 private:
74 bool valid_ = false;
75
76 int id_;
77
78 const database* db_;
79
80 mutable bool initializedFrames_ = false;
81 mutable std::vector<class frame> frames_;
82
83 };
84
85};
86
87#endif /* end of include guard: GROUP_H_BD6933C0 */
diff --git a/lib/lemma.cpp b/lib/lemma.cpp new file mode 100644 index 0000000..f9e9fcc --- /dev/null +++ b/lib/lemma.cpp
@@ -0,0 +1,69 @@
1#include "lemma.h"
2#include <sqlite3.h>
3#include "database.h"
4#include "query.h"
5
6namespace verbly {
7
8 const object lemma::objectType = object::lemma;
9
10 const std::list<std::string> lemma::select = {"lemma_id"};
11
12 const field lemma::id = field::integerField(object::lemma, "lemma_id");
13
14 const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word);
15
16 const field lemma::formJoin = field::joinField(object::lemma, "form_id", object::form);
17 const field lemma::inflectionCategory = field::integerField(object::lemma, "category");
18
19 filter operator%=(lemma::inflection_field check, filter joinCondition)
20 {
21 return (lemma::formJoin %= joinCondition) && (lemma::inflectionCategory == check.getCategory());
22 }
23
24 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
25 {
26 id_ = sqlite3_column_int(row, 0);
27 }
28
29 const form& lemma::getBaseForm() const
30 {
31 if (!valid_)
32 {
33 throw std::domain_error("Bad access to uninitialized lemma");
34 }
35
36 if (!forms_.count(inflection::base))
37 {
38 initializeForm(inflection::base);
39 }
40
41 return forms_.at(inflection::base).front();
42 }
43
44 bool lemma::hasInflection(inflection category) const
45 {
46 return !getInflections(category).empty();
47 }
48
49 const std::vector<form>& lemma::getInflections(inflection category) const
50 {
51 if (!valid_)
52 {
53 throw std::domain_error("Bad access to uninitialized lemma");
54 }
55
56 if (!forms_.count(category))
57 {
58 initializeForm(category);
59 }
60
61 return forms_.at(category);
62 }
63
64 void lemma::initializeForm(inflection infl) const
65 {
66 forms_[infl] = db_->forms(form::lemma(infl) %= *this, false, -1).all();
67 }
68
69};
diff --git a/lib/lemma.h b/lib/lemma.h new file mode 100644 index 0000000..9a07f16 --- /dev/null +++ b/lib/lemma.h
@@ -0,0 +1,120 @@
1#ifndef LEMMA_H_0A180D30
2#define LEMMA_H_0A180D30
3
4#include <stdexcept>
5#include <vector>
6#include <list>
7#include <map>
8#include "field.h"
9#include "enums.h"
10#include "filter.h"
11
12struct sqlite3_stmt;
13
14namespace verbly {
15
16 class form;
17 class database;
18
19 class lemma {
20 public:
21
22 // Default constructor
23
24 lemma() = default;
25
26 // Construct from database
27
28 lemma(const database& db, sqlite3_stmt* row);
29
30 // Accessors
31
32 operator bool() const
33 {
34 return valid_;
35 }
36
37 int getId() const
38 {
39 if (!valid_)
40 {
41 throw std::domain_error("Bad access to uninitialized lemma");
42 }
43
44 return id_;
45 }
46
47 const form& getBaseForm() const;
48
49 bool hasInflection(inflection category) const;
50
51 const std::vector<form>& getInflections(inflection category) const;
52
53 // Type info
54
55 static const object objectType;
56
57 static const std::list<std::string> select;
58
59 // Query fields
60
61 static const field id;
62
63 operator filter() const
64 {
65 if (!valid_)
66 {
67 throw std::domain_error("Bad access to uninitialized lemma");
68 }
69
70 return (id == id_);
71 }
72
73 // Relationships to other objects
74
75 static const field word;
76
77 class inflection_field {
78 public:
79
80 inflection_field(inflection category) : category_(category)
81 {
82 }
83
84 const inflection getCategory() const
85 {
86 return category_;
87 }
88
89 private:
90
91 const inflection category_;
92 };
93
94 static const inflection_field form(inflection category)
95 {
96 return inflection_field(category);
97 }
98
99 friend filter operator%=(lemma::inflection_field check, filter joinCondition);
100
101 private:
102
103 void initializeForm(inflection category) const;
104
105 bool valid_ = false;
106
107 int id_;
108
109 mutable std::map<inflection, std::vector<class form>> forms_;
110
111 const database* db_;
112
113 static const field formJoin;
114 static const field inflectionCategory;
115
116 };
117
118};
119
120#endif /* end of include guard: LEMMA_H_0A180D30 */
diff --git a/lib/notion.cpp b/lib/notion.cpp new file mode 100644 index 0000000..16794d3 --- /dev/null +++ b/lib/notion.cpp
@@ -0,0 +1,94 @@
1#include "notion.h"
2#include <sqlite3.h>
3#include <sstream>
4
5namespace verbly {
6
7 const object notion::objectType = object::notion;
8
9 const std::list<std::string> notion::select = {"notion_id", "part_of_speech", "wnid", "images"};
10
11 const field notion::id = field::integerField(object::notion, "notion_id");
12 const field notion::partOfSpeech = field::integerField(object::notion, "part_of_speech");
13 const field notion::wnid = field::integerField(object::notion, "wnid", true);
14 const field notion::numOfImages = field::integerField(object::notion, "images", true);
15
16 const field notion::word = field::joinField(object::notion, "word_id", object::word);
17
18 const field notion::hypernyms = field::selfJoin(object::notion, "notion_id", "hypernymy", "hyponym_id", "hypernym_id");
19 const field notion::hyponyms = field::selfJoin(object::notion, "notion_id", "hypernymy", "hypernym_id", "hyponym_id");
20
21 const field notion::fullHypernyms = field::hierarchalSelfJoin(object::notion, "notion_id", "hypernymy", "hyponym_id", "hypernym_id");
22 const field notion::fullHyponyms = field::hierarchalSelfJoin(object::notion, "notion_id", "hypernymy", "hypernym_id", "hyponym_id");
23
24 const field notion::instances = field::selfJoin(object::notion, "notion_id", "instantiation", "class_id", "instance_id");
25 const field notion::classes = field::selfJoin(object::notion, "notion_id", "instantiation", "instance_id", "class_id");
26
27 const field notion::memberMeronyms = field::selfJoin(object::notion, "notion_id", "member_meronymy", "holonym_id", "meronym_id");
28 const field notion::memberHolonyms = field::selfJoin(object::notion, "notion_id", "member_meronymy", "meronym_id", "holonym_id");
29
30 const field notion::fullMemberMeronyms = field::hierarchalSelfJoin(object::notion, "notion_id", "member_meronymy", "holonym_id", "meronym_id");
31 const field notion::fullMemberHolonyms = field::hierarchalSelfJoin(object::notion, "notion_id", "member_meronymy", "meronym_id", "holonym_id");
32
33 const field notion::partMeronyms = field::selfJoin(object::notion, "notion_id", "part_meronymy", "holonym_id", "meronym_id");
34 const field notion::partHolonyms = field::selfJoin(object::notion, "notion_id", "part_meronymy", "meronym_id", "holonym_id");
35
36 const field notion::fullPartMeronyms = field::hierarchalSelfJoin(object::notion, "notion_id", "part_meronymy", "holonym_id", "meronym_id");
37 const field notion::fullPartHolonyms = field::hierarchalSelfJoin(object::notion, "notion_id", "part_meronymy", "meronym_id", "holonym_id");
38
39 const field notion::substanceMeronyms = field::selfJoin(object::notion, "notion_id", "substance_meronymy", "holonym_id", "meronym_id");
40 const field notion::substanceHolonyms = field::selfJoin(object::notion, "notion_id", "substance_meronymy", "meronym_id", "holonym_id");
41
42 const field notion::fullSubstanceMeronyms = field::hierarchalSelfJoin(object::notion, "notion_id", "substance_meronymy", "holonym_id", "meronym_id");
43 const field notion::fullSubstanceHolonyms = field::hierarchalSelfJoin(object::notion, "notion_id", "substance_meronymy", "meronym_id", "holonym_id");
44
45 const field notion::variants = field::selfJoin(object::notion, "notion_id", "variation", "noun_id", "adjective_id");
46 const field notion::attributes = field::selfJoin(object::notion, "notion_id", "variation", "adjective_id", "noun_id");
47
48 const field notion::similarAdjectives = field::selfJoin(object::notion, "notion_id", "similarity", "adjective_2_id", "adjective_1_id");
49
50 const field notion::entails = field::selfJoin(object::notion, "notion_id", "entailment", "given_id", "entailment_id");
51 const field notion::entailedBy = field::selfJoin(object::notion, "notion_id", "entailment", "entailment_id", "given_id");
52
53 const field notion::causes = field::selfJoin(object::notion, "notion_id", "causality", "effect_id", "cause_id");
54 const field notion::effects = field::selfJoin(object::notion, "notion_id", "causality", "cause_id", "effect_id");
55
56 const notion::preposition_group_field prepositionGroup = {};
57
58 const field notion::preposition_group_field::isA = field::joinField(object::notion, "notion_id", "is_a");
59 const field notion::preposition_group_field::groupNameField = field::stringField("is_a", "groupname");
60
61 notion::notion(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
62 {
63 id_ = sqlite3_column_int(row, 0);
64 partOfSpeech_ = static_cast<part_of_speech>(sqlite3_column_int(row, 1));
65
66 if (sqlite3_column_type(row, 2) != SQLITE_NULL)
67 {
68 hasWnid_ = true;
69 wnid_ = sqlite3_column_int(row, 2);
70 }
71
72 if (sqlite3_column_type(row, 3) != SQLITE_NULL)
73 {
74 hasNumOfImages_ = true;
75 numOfImages_ = sqlite3_column_int(row, 3);
76 }
77 }
78
79 std::string notion::getImageNetUrl() const
80 {
81 std::stringstream url;
82 url << "http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n";
83 url.width(8);
84 url.fill('0');
85 url << (getWnid() % 100000000);
86 return url.str();
87 }
88
89 filter notion::preposition_group_field::operator==(std::string groupName) const
90 {
91 return (isA %= (groupNameField == groupName));
92 }
93
94};
diff --git a/lib/notion.h b/lib/notion.h new file mode 100644 index 0000000..a180d73 --- /dev/null +++ b/lib/notion.h
@@ -0,0 +1,200 @@
1#ifndef NOTION_H_FD1C7646
2#define NOTION_H_FD1C7646
3
4#include <stdexcept>
5#include <string>
6#include "field.h"
7#include "filter.h"
8
9struct sqlite3_stmt;
10
11namespace verbly {
12
13 class database;
14
15 class notion {
16 public:
17
18 // Default constructor
19
20 notion() = default;
21
22 // Construct from database
23
24 notion(const database& db, sqlite3_stmt* row);
25
26 // Accessors
27
28 operator bool() const
29 {
30 return valid_;
31 }
32
33 int getId() const
34 {
35 if (!valid_)
36 {
37 throw std::domain_error("Bad access to uninitialized notion");
38 }
39
40 return id_;
41 }
42
43 part_of_speech getPartOfSpeech() const
44 {
45 if (!valid_)
46 {
47 throw std::domain_error("Bad access to uninitialized notion");
48 }
49
50 return partOfSpeech_;
51 }
52
53 bool hasWnid() const
54 {
55 if (!valid_)
56 {
57 throw std::domain_error("Bad access to uninitialized notion");
58 }
59
60 return hasWnid_;
61 }
62
63 int getWnid() const
64 {
65 if (!valid_)
66 {
67 throw std::domain_error("Bad access to uninitialized notion");
68 }
69
70 if (!hasWnid_)
71 {
72 throw std::domain_error("Notion has no wnid");
73 }
74
75 return wnid_;
76 }
77
78 bool hasNumOfImages() const
79 {
80 if (!valid_)
81 {
82 throw std::domain_error("Bad access to uninitialized notion");
83 }
84
85 return hasNumOfImages_;
86 }
87
88 int getNumOfImages() const
89 {
90 if (!valid_)
91 {
92 throw std::domain_error("Bad access to uninitialized notion");
93 }
94
95 if (!hasNumOfImages_)
96 {
97 throw std::domain_error("Notion does not have a number of images");
98 }
99
100 return numOfImages_;
101 }
102
103 // Convenience
104
105 std::string getImageNetUrl() const;
106
107 // Type info
108
109 static const object objectType;
110
111 static const std::list<std::string> select;
112
113 // Query fields
114
115 static const field id;
116 static const field partOfSpeech;
117 static const field wnid;
118 static const field numOfImages;
119
120 operator filter() const
121 {
122 return (id == id_);
123 }
124
125 // Relationships with other objects
126
127 static const field word;
128
129 // Relationships with self
130
131 static const field hypernyms;
132 static const field hyponyms;
133
134 static const field fullHypernyms;
135 static const field fullHyponyms;
136
137 static const field instances;
138 static const field classes;
139
140 static const field memberMeronyms;
141 static const field memberHolonyms;
142
143 static const field fullMemberMeronyms;
144 static const field fullMemberHolonyms;
145
146 static const field partMeronyms;
147 static const field partHolonyms;
148
149 static const field fullPartMeronyms;
150 static const field fullPartHolonyms;
151
152 static const field substanceMeronyms;
153 static const field substanceHolonyms;
154
155 static const field fullSubstanceMeronyms;
156 static const field fullSubstanceHolonyms;
157
158 static const field variants;
159 static const field attributes;
160
161 static const field similarAdjectives;
162
163 static const field entails;
164 static const field entailedBy;
165
166 static const field causes;
167 static const field effects;
168
169 // Preposition group relationship
170
171 class preposition_group_field {
172 public:
173
174 filter operator==(std::string groupName) const;
175
176 private:
177
178 static const field isA;
179 static const field groupNameField;
180 };
181
182 static const preposition_group_field prepositionGroup;
183
184 private:
185 bool valid_ = false;
186
187 int id_;
188 part_of_speech partOfSpeech_;
189 bool hasWnid_ = false;
190 int wnid_;
191 bool hasNumOfImages_ = false;
192 int numOfImages_;
193
194 const database* db_;
195
196 };
197
198};
199
200#endif /* end of include guard: NOTION_H_FD1C7646 */
diff --git a/lib/noun.cpp b/lib/noun.cpp deleted file mode 100644 index d8b34c9..0000000 --- a/lib/noun.cpp +++ /dev/null
@@ -1,221 +0,0 @@
1#include "verbly.h"
2#include <set>
3#include <iostream>
4
5namespace verbly {
6
7 noun::noun()
8 {
9
10 }
11
12 noun::noun(const data& _data, int _id) : word(_data, _id)
13 {
14
15 }
16
17 std::string noun::base_form() const
18 {
19 assert(_valid == true);
20
21 return _singular;
22 }
23
24 std::string noun::singular_form() const
25 {
26 assert(_valid == true);
27
28 return _singular;
29 }
30
31 std::string noun::plural_form() const
32 {
33 assert(_valid == true);
34
35 return _plural;
36 }
37
38 int noun::wnid() const
39 {
40 assert(_valid == true);
41
42 return _wnid;
43 }
44
45 bool noun::has_plural_form() const
46 {
47 assert(_valid == true);
48
49 return !_plural.empty();
50 }
51
52 noun_query noun::hypernyms() const
53 {
54 assert(_valid == true);
55
56 return _data->nouns().hypernym_of(*this);
57 }
58
59 noun_query noun::full_hypernyms() const
60 {
61 assert(_valid == true);
62
63 return _data->nouns().full_hypernym_of(*this);
64 }
65
66 noun_query noun::hyponyms() const
67 {
68 assert(_valid == true);
69
70 return _data->nouns().hyponym_of(*this);
71 }
72
73 noun_query noun::full_hyponyms() const
74 {
75 assert(_valid == true);
76
77 return _data->nouns().full_hyponym_of(*this);
78 }
79
80 noun_query noun::part_meronyms() const
81 {
82 assert(_valid == true);
83
84 return _data->nouns().part_meronym_of(*this);
85 }
86
87 noun_query noun::full_part_meronyms() const
88 {
89 assert(_valid == true);
90
91 return _data->nouns().full_part_meronym_of(*this);
92 }
93
94 noun_query noun::part_holonyms() const
95 {
96 assert(_valid == true);
97
98 return _data->nouns().part_holonym_of(*this);
99 }
100
101 noun_query noun::full_part_holonyms() const
102 {
103 assert(_valid == true);
104
105 return _data->nouns().full_part_holonym_of(*this);
106 }
107
108 noun_query noun::substance_meronyms() const
109 {
110 assert(_valid == true);
111
112 return _data->nouns().substance_meronym_of(*this);
113 }
114
115 noun_query noun::full_substance_meronyms() const
116 {
117 assert(_valid == true);
118
119 return _data->nouns().full_substance_meronym_of(*this);
120 }
121
122 noun_query noun::substance_holonyms() const
123 {
124 assert(_valid == true);
125
126 return _data->nouns().substance_holonym_of(*this);
127 }
128
129 noun_query noun::full_substance_holonyms() const
130 {
131 assert(_valid == true);
132
133 return _data->nouns().full_substance_holonym_of(*this);
134 }
135
136 noun_query noun::member_meronyms() const
137 {
138 assert(_valid == true);
139
140 return _data->nouns().member_meronym_of(*this);
141 }
142
143 noun_query noun::full_member_meronyms() const
144 {
145 assert(_valid == true);
146
147 return _data->nouns().full_member_meronym_of(*this);
148 }
149
150 noun_query noun::member_holonyms() const
151 {
152 assert(_valid == true);
153
154 return _data->nouns().member_holonym_of(*this);
155 }
156
157 noun_query noun::full_member_holonyms() const
158 {
159 assert(_valid == true);
160
161 return _data->nouns().full_member_holonym_of(*this);
162 }
163
164 noun_query noun::classes() const
165 {
166 assert(_valid == true);
167
168 return _data->nouns().class_of(*this);
169 }
170
171 noun_query noun::instances() const
172 {
173 assert(_valid == true);
174
175 return _data->nouns().instance_of(*this);
176 }
177
178 noun_query noun::synonyms() const
179 {
180 assert(_valid == true);
181
182 return _data->nouns().synonym_of(*this);
183 }
184
185 noun_query noun::antonyms() const
186 {
187 assert(_valid == true);
188
189 return _data->nouns().antonym_of(*this);
190 }
191
192 adjective_query noun::pertainyms() const
193 {
194 assert(_valid == true);
195
196 return _data->adjectives().pertainym_of(*this);
197 }
198
199 adjective_query noun::variations() const
200 {
201 assert(_valid == true);
202
203 return _data->adjectives().variant_of(*this);
204 }
205
206 std::string noun::imagenet_url() const
207 {
208 std::stringstream url;
209 url << "http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n";
210 url.width(8);
211 url.fill('0');
212 url << (_wnid % 100000000);
213 return url.str();
214 }
215
216 bool noun::operator<(const noun& other) const
217 {
218 return _id < other._id;
219 }
220
221};
diff --git a/lib/noun.h b/lib/noun.h deleted file mode 100644 index bd71e57..0000000 --- a/lib/noun.h +++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef NOUN_H_24A03C83
2#define NOUN_H_24A03C83
3
4namespace verbly {
5
6 class noun : public word {
7 private:
8 std::string _singular;
9 std::string _plural;
10 int _wnid;
11
12 friend class noun_query;
13
14 public:
15 noun();
16 noun(const data& _data, int _id);
17
18 std::string base_form() const;
19 std::string singular_form() const;
20 std::string plural_form() const;
21 int wnid() const;
22
23 bool has_plural_form() const;
24
25 noun_query hypernyms() const;
26 noun_query full_hypernyms() const;
27 noun_query hyponyms() const;
28 noun_query full_hyponyms() const;
29 noun_query part_meronyms() const;
30 noun_query full_part_meronyms() const;
31 noun_query part_holonyms() const;
32 noun_query full_part_holonyms() const;
33 noun_query substance_meronyms() const;
34 noun_query full_substance_meronyms() const;
35 noun_query substance_holonyms() const;
36 noun_query full_substance_holonyms() const;
37 noun_query member_meronyms() const;
38 noun_query full_member_meronyms() const;
39 noun_query member_holonyms() const;
40 noun_query full_member_holonyms() const;
41 noun_query classes() const;
42 noun_query instances() const;
43 noun_query synonyms() const;
44 noun_query antonyms() const;
45 adjective_query pertainyms() const;
46 adjective_query variations() const;
47
48 std::string imagenet_url() const;
49
50 bool operator<(const noun& other) const;
51 };
52
53};
54
55#endif /* end of include guard: NOUN_H_24A03C83 */
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};
diff --git a/lib/noun_query.h b/lib/noun_query.h deleted file mode 100644 index 74df260..0000000 --- a/lib/noun_query.h +++ /dev/null
@@ -1,180 +0,0 @@
1#ifndef NOUN_QUERY_H_5DE51DD7
2#define NOUN_QUERY_H_5DE51DD7
3
4namespace verbly {
5
6 class noun_query {
7 public:
8 noun_query(const data& _data);
9
10 noun_query& limit(int _limit);
11 noun_query& random();
12 noun_query& except(const noun& _word);
13 noun_query& rhymes_with(const word& _word);
14 noun_query& rhymes_with(rhyme _r);
15 noun_query& has_pronunciation();
16 noun_query& has_rhyming_noun();
17 noun_query& has_rhyming_adjective();
18 noun_query& has_rhyming_adverb();
19 noun_query& has_rhyming_verb();
20 noun_query& with_stress(filter<std::vector<bool>> _arg);
21
22 noun_query& with_singular_form(std::string _arg);
23 noun_query& with_prefix(filter<std::string> _f);
24 noun_query& with_suffix(filter<std::string> _f);
25
26 noun_query& requires_plural_form();
27
28 noun_query& with_complexity(int _arg);
29
30 noun_query& is_hypernym();
31 noun_query& hypernym_of(filter<noun> _f);
32 noun_query& full_hypernym_of(filter<noun> _f);
33
34 noun_query& is_hyponym();
35 noun_query& hyponym_of(filter<noun> _f);
36 noun_query& full_hyponym_of(filter<noun> _f);
37
38 noun_query& is_part_meronym();
39 noun_query& part_meronym_of(filter<noun> _f);
40 noun_query& full_part_meronym_of(filter<noun> _f);
41
42 noun_query& is_part_holonym();
43 noun_query& part_holonym_of(filter<noun> _f);
44 noun_query& full_part_holonym_of(filter<noun> _f);
45
46 noun_query& is_substance_meronym();
47 noun_query& substance_meronym_of(filter<noun> _f);
48 noun_query& full_substance_meronym_of(filter<noun> _f);
49
50 noun_query& is_substance_holonym();
51 noun_query& substance_holonym_of(filter<noun> _f);
52 noun_query& full_substance_holonym_of(filter<noun> _f);
53
54 noun_query& is_member_meronym();
55 noun_query& member_meronym_of(filter<noun> _f);
56 noun_query& full_member_meronym_of(filter<noun> _f);
57
58 noun_query& is_member_holonym();
59 noun_query& member_holonym_of(filter<noun> _f);
60 noun_query& full_member_holonym_of(filter<noun> _f);
61
62 noun_query& is_proper();
63 noun_query& is_not_proper();
64
65 noun_query& is_instance();
66 noun_query& instance_of(filter<noun> _f);
67
68 noun_query& is_class();
69 noun_query& class_of(filter<noun> _f);
70
71 noun_query& has_synonyms();
72 noun_query& synonym_of(filter<noun> _f);
73
74 noun_query& has_antonyms();
75 noun_query& antonym_of(filter<noun> _f);
76
77 noun_query& has_pertainym();
78 noun_query& anti_pertainym_of(filter<adjective> _f);
79
80 noun_query& is_attribute();
81 noun_query& attribute_of(filter<adjective> _f);
82
83 noun_query& at_least_n_images(int _arg);
84 noun_query& with_wnid(int _arg);
85
86/* noun_query& derived_from(const word& _w);
87 noun_query& not_derived_from(const word& _w);*/
88
89 std::list<noun> run() const;
90
91 const static int unlimited = -1;
92
93 private:
94 const data& _data;
95 int _limit = unlimited;
96 bool _random = false;
97 std::list<rhyme> _rhymes;
98 std::list<noun> _except;
99 bool _has_prn = false;
100 bool _has_rhyming_noun = false;
101 bool _has_rhyming_adjective = false;
102 bool _has_rhyming_adverb = false;
103 bool _has_rhyming_verb = false;
104 filter<std::vector<bool>> _stress;
105
106 std::list<std::string> _with_singular_form;
107 filter<std::string> _with_prefix;
108 filter<std::string> _with_suffix;
109
110 int _with_complexity = unlimited;
111
112 bool _requires_plural_form = false;
113
114 bool _is_hypernym = false;
115 filter<noun> _hypernym_of;
116 filter<noun> _full_hypernym_of;
117
118 bool _is_hyponym = false;
119 filter<noun> _hyponym_of;
120 filter<noun> _full_hyponym_of;
121
122 bool _is_part_meronym = false;
123 filter<noun> _part_meronym_of;
124 filter<noun> _full_part_meronym_of;
125
126 bool _is_substance_meronym = false;
127 filter<noun> _substance_meronym_of;
128 filter<noun> _full_substance_meronym_of;
129
130 bool _is_member_meronym = false;
131 filter<noun> _member_meronym_of;
132 filter<noun> _full_member_meronym_of;
133
134 bool _is_part_holonym = false;
135 filter<noun> _part_holonym_of;
136 filter<noun> _full_part_holonym_of;
137
138 bool _is_substance_holonym = false;
139 filter<noun> _substance_holonym_of;
140 filter<noun> _full_substance_holonym_of;
141
142 bool _is_member_holonym = false;
143 filter<noun> _member_holonym_of;
144 filter<noun> _full_member_holonym_of;
145
146 bool _is_proper = false;
147 bool _is_not_proper = false;
148
149 bool _is_instance = false;
150 filter<noun> _instance_of;
151
152 bool _is_class = false;
153 filter<noun> _class_of;
154
155 bool _has_synonyms = false;
156 filter<noun> _synonym_of;
157
158 bool _has_antonyms = false;
159 filter<noun> _antonym_of;
160
161 bool _has_pertainym = false;
162 filter<adjective> _anti_pertainym_of;
163
164 bool _is_attribute = false;
165 filter<adjective> _attribute_of;
166
167 int _at_least_n_images = unlimited;
168 std::set<int> _with_wnid;
169
170/* std::list<adjective> _derived_from_adjective;
171 std::list<adjective> _not_derived_from_adjective;
172 std::list<adverb> _derived_from_adverb;
173 std::list<adverb> _not_derived_from_adverb;
174 std::list<noun> _derived_from_noun;
175 std::list<noun> _not_derived_from_noun;*/
176 };
177
178};
179
180#endif /* end of include guard: NOUN_QUERY_H_5DE51DD7 */
diff --git a/lib/preposition.cpp b/lib/preposition.cpp deleted file mode 100644 index cea9165..0000000 --- a/lib/preposition.cpp +++ /dev/null
@@ -1,107 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 std::string preposition::get_form() const
6 {
7 return form;
8 }
9
10 preposition_query::preposition_query(const data& _data) : _data(_data)
11 {
12
13 }
14
15 preposition_query& preposition_query::limit(int _limit)
16 {
17 this->_limit = _limit;
18
19 return *this;
20 }
21
22 preposition_query& preposition_query::random()
23 {
24 _random = true;
25
26 return *this;
27 }
28
29 preposition_query& preposition_query::in_group(std::string _arg)
30 {
31 _in_group.push_back(_arg);
32
33 return *this;
34 }
35
36 std::list<preposition> preposition_query::run() const
37 {
38 std::stringstream construct;
39 construct << "SELECT form FROM prepositions";
40 std::list<binding> bindings;
41
42 if (!_in_group.empty())
43 {
44 std::list<std::string> clauses(_in_group.size(), "groupname = ?");
45 construct << " WHERE preposition_id IN (SELECT preposition_id FROM preposition_groups WHERE ";
46 construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR ");
47 construct << ")";
48
49 for (auto g : _in_group)
50 {
51 bindings.emplace_back(g);
52 }
53 }
54
55 if (_random)
56 {
57 construct << " ORDER BY RANDOM()";
58 }
59
60 if (_limit != unlimited)
61 {
62 construct << " LIMIT " << _limit;
63 }
64
65 sqlite3_stmt* ppstmt;
66 std::string query = construct.str();
67 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
68 {
69 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
70 }
71
72 int i = 1;
73 for (auto& binding : bindings)
74 {
75 switch (binding.get_type())
76 {
77 case binding::type::integer:
78 {
79 sqlite3_bind_int(ppstmt, i, binding.get_integer());
80
81 break;
82 }
83
84 case binding::type::string:
85 {
86 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
87
88 break;
89 }
90 }
91
92 i++;
93 }
94
95 std::list<preposition> output;
96 while (sqlite3_step(ppstmt) == SQLITE_ROW)
97 {
98 preposition pp;
99 pp.form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
100
101 output.push_back(pp);
102 }
103
104 return output;
105 }
106
107};
diff --git a/lib/preposition.h b/lib/preposition.h deleted file mode 100644 index 89f24fa..0000000 --- a/lib/preposition.h +++ /dev/null
@@ -1,38 +0,0 @@
1#ifndef PREPOSITION_H_FF908021
2#define PREPOSITION_H_FF908021
3
4namespace verbly {
5
6 class preposition_query;
7
8 class preposition {
9 public:
10 std::string get_form() const;
11
12 private:
13 friend class preposition_query;
14
15 std::string form;
16 };
17
18 class preposition_query {
19 public:
20 preposition_query(const data& _data);
21
22 preposition_query& limit(int _limit);
23 preposition_query& random();
24 preposition_query& in_group(std::string _arg);
25
26 std::list<preposition> run() const;
27
28 const static int unlimited = -1;
29 private:
30 const data& _data;
31 int _limit = unlimited;
32 bool _random = false;
33 std::list<std::string> _in_group;
34 };
35
36};
37
38#endif /* end of include guard: PREPOSITION_H_FF908021 */
diff --git a/lib/pronunciation.cpp b/lib/pronunciation.cpp new file mode 100644 index 0000000..f5b742f --- /dev/null +++ b/lib/pronunciation.cpp
@@ -0,0 +1,69 @@
1#include "pronunciation.h"
2#include <sqlite3.h>
3#include "form.h"
4#include "lemma.h"
5#include "word.h"
6#include "util.h"
7
8namespace verbly {
9
10 const object pronunciation::objectType = object::pronunciation;
11
12 const std::list<std::string> pronunciation::select = {"pronunciation_id", "phonemes", "syllables", "stress", "prerhyme", "rhyme"};
13
14 const field pronunciation::id = field::integerField(object::pronunciation, "pronunciation_id");
15 const field pronunciation::numOfSyllables = field::integerField(object::pronunciation, "syllables");
16 const field pronunciation::stress = field::stringField(object::pronunciation, "stress");
17
18 const field pronunciation::form = field::joinThrough(object::pronunciation, "pronunciation_id", object::form, "forms_pronunciations", "form_id");
19
20 const field pronunciation::prerhyme = field::stringField(object::pronunciation, "prerhyme", true);
21 const field pronunciation::rhyme = field::stringField(object::pronunciation, "rhyme", true);
22
23 pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
24 {
25 id_ = sqlite3_column_int(row, 0);
26
27 std::string phonemesStr(reinterpret_cast<const char*>(sqlite3_column_text(row, 1)));
28 phonemes_ = split<std::vector<std::string>>(phonemesStr, " ");
29
30 syllables_ = sqlite3_column_int(row, 2);
31 stress_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 3)));
32
33 if (sqlite3_column_type(row, 5) != SQLITE_NULL)
34 {
35 hasRhyme_ = true;
36
37 prerhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 4)));
38 rhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 5)));
39 }
40 }
41
42 filter pronunciation::rhymesWith(const pronunciation& arg)
43 {
44 return (prerhyme != arg.getPrerhyme()) && (rhyme == arg.getRhyme());
45 }
46
47 /*filter pronunciation::rhymesWith(const class form& arg)
48 {
49 filter result;
50
51 for (const pronunciation& p : arg.getPronunciations())
52 {
53 result |= rhymesWith(p);
54 }
55
56 return result;
57 }
58
59 filter pronunciation::rhymesWith(const lemma& arg)
60 {
61 return rhymesWith(arg.getBaseForm());
62 }
63
64 filter pronunciation::rhymesWith(const word& arg)
65 {
66 return rhymesWith(arg.getLemma());
67 }*/
68
69};
diff --git a/lib/pronunciation.h b/lib/pronunciation.h new file mode 100644 index 0000000..c7a1d4d --- /dev/null +++ b/lib/pronunciation.h
@@ -0,0 +1,163 @@
1#ifndef PRONUNCIATION_H_C68F86B0
2#define PRONUNCIATION_H_C68F86B0
3
4#include <stdexcept>
5#include <vector>
6#include <string>
7#include "field.h"
8#include "filter.h"
9
10struct sqlite3_stmt;
11
12namespace verbly {
13
14 class form;
15 class lemma;
16 class word;
17 class database;
18
19 class pronunciation {
20 public:
21
22 // Default constructor
23
24 pronunciation() = default;
25
26 // Construct from database
27
28 pronunciation(const database& db, sqlite3_stmt* row);
29
30 // Accessors
31
32 operator bool() const
33 {
34 return valid_;
35 }
36
37 int getId() const
38 {
39 if (!valid_)
40 {
41 throw std::domain_error("Bad access to uninitialized pronunciation");
42 }
43
44 return id_;
45 }
46
47 const std::vector<std::string>& getPhonemes() const
48 {
49 if (!valid_)
50 {
51 throw std::domain_error("Bad access to uninitialized pronunciation");
52 }
53
54 return phonemes_;
55 }
56
57 int getSyllables() const
58 {
59 if (!valid_)
60 {
61 throw std::domain_error("Bad access to uninitialized pronunciation");
62 }
63
64 return syllables_;
65 }
66
67 std::string getStress() const
68 {
69 if (!valid_)
70 {
71 throw std::domain_error("Bad access to uninitialized pronunciation");
72 }
73
74 return stress_;
75 }
76
77 bool hasRhyme() const
78 {
79 if (!valid_)
80 {
81 throw std::domain_error("Bad access to uninitialized pronunciation");
82 }
83
84 return hasRhyme_;
85 }
86
87 std::string getPrerhyme() const
88 {
89 if (!valid_)
90 {
91 throw std::domain_error("Bad access to uninitialized pronunciation");
92 }
93
94 if (!hasRhyme_)
95 {
96 throw std::domain_error("This pronunciation has no rhyme");
97 }
98
99 return prerhyme_;
100 }
101
102 std::string getRhyme() const
103 {
104 if (!valid_)
105 {
106 throw std::domain_error("Bad access to uninitialized pronunciation");
107 }
108
109 if (!hasRhyme_)
110 {
111 throw std::domain_error("This pronunciation has no rhyme");
112 }
113
114 return rhyme_;
115 }
116
117 // Type info
118
119 static const object objectType;
120
121 static const std::list<std::string> select;
122
123 // Query fields
124
125 static const field id;
126 static const field numOfSyllables;
127 static const field stress;
128
129 operator filter() const
130 {
131 return (id == id_);
132 }
133
134 static filter rhymesWith(const pronunciation& arg);
135 static filter rhymesWith(const class form& arg);
136 static filter rhymesWith(const lemma& arg);
137 static filter rhymesWith(const word& arg);
138
139 // Relationships to other objects
140
141 static const field form;
142
143 private:
144 bool valid_ = false;
145
146 int id_;
147 std::vector<std::string> phonemes_;
148 int syllables_;
149 std::string stress_;
150 bool hasRhyme_ = false;
151 std::string prerhyme_;
152 std::string rhyme_;
153
154 const database* db_;
155
156 static const field prerhyme;
157 static const field rhyme;
158
159 };
160
161};
162
163#endif /* end of include guard: PRONUNCIATION_H_C68F86B0 */
diff --git a/lib/query.h b/lib/query.h new file mode 100644 index 0000000..e31be3d --- /dev/null +++ b/lib/query.h
@@ -0,0 +1,123 @@
1#ifndef QUERY_H_7CC5284C
2#define QUERY_H_7CC5284C
3
4#include <vector>
5#include <stdexcept>
6#include <string>
7#include <list>
8#include <sqlite3.h>
9#include <iostream>
10#include "statement.h"
11#include "binding.h"
12
13namespace verbly {
14
15 class database_error : public std::logic_error {
16 public:
17
18 database_error(std::string msg, std::string sqlMsg) : std::logic_error(msg + " (" + sqlMsg + ")")
19 {
20 }
21 };
22
23 template <typename Object>
24 class query {
25 public:
26
27 query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db)
28 {
29 statement stmt(Object::objectType, std::move(queryFilter));
30
31 std::string queryString = stmt.getQueryString(Object::select, random, limit);
32 std::list<binding> bindings = stmt.getBindings();
33
34 std::cout << queryString << std::endl;
35
36 if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK)
37 {
38 std::string errorMsg = sqlite3_errmsg(ppdb);
39 sqlite3_finalize(ppstmt_);
40
41 throw database_error("Error preparing query", errorMsg);
42 }
43
44 int i = 1;
45 for (const binding& value : bindings)
46 {
47 switch (value.getType())
48 {
49 case binding::type::integer:
50 {
51 if (sqlite3_bind_int(ppstmt_, i, value.getInteger()) != SQLITE_OK)
52 {
53 std::string errorMsg = sqlite3_errmsg(ppdb);
54 sqlite3_finalize(ppstmt_);
55
56 throw database_error("Error binding value to query", errorMsg);
57 }
58
59 break;
60 }
61
62 case binding::type::string:
63 {
64 if (sqlite3_bind_text(ppstmt_, i, value.getString().c_str(), value.getString().length(), SQLITE_TRANSIENT) != SQLITE_OK)
65 {
66 std::string errorMsg = sqlite3_errmsg(ppdb);
67 sqlite3_finalize(ppstmt_);
68
69 throw database_error("Error binding value to query", errorMsg);
70 }
71
72 break;
73 }
74
75 case binding::type::invalid:
76 {
77 throw std::logic_error("Cannot use invalid bindings");
78 }
79 }
80
81 i++;
82 }
83 }
84
85 ~query()
86 {
87 sqlite3_finalize(ppstmt_);
88 }
89
90 std::vector<Object> all() const
91 {
92 std::vector<Object> result;
93
94 while (sqlite3_step(ppstmt_) == SQLITE_ROW)
95 {
96 result.emplace_back(*db_, ppstmt_);
97 }
98
99 sqlite3_reset(ppstmt_);
100
101 return result;
102 }
103
104 Object first() const
105 {
106 std::vector<Object> results = all();
107 if (!results.empty())
108 {
109 return results.front();
110 } else {
111 throw std::logic_error("query returned empty dataset");
112 }
113 }
114
115 private:
116 const database* db_;
117 sqlite3_stmt* ppstmt_;
118
119 };
120
121};
122
123#endif /* end of include guard: QUERY_H_7CC5284C */
diff --git a/lib/statement.cpp b/lib/statement.cpp new file mode 100644 index 0000000..52fa00d --- /dev/null +++ b/lib/statement.cpp
@@ -0,0 +1,806 @@
1#include "statement.h"
2#include <sstream>
3#include <utility>
4#include "filter.h"
5#include "util.h"
6#include "notion.h"
7#include "word.h"
8#include "group.h"
9#include "frame.h"
10#include "lemma.h"
11#include "form.h"
12#include "pronunciation.h"
13
14namespace verbly {
15
16 statement::statement(
17 object context,
18 filter queryFilter) :
19 statement(getTableForContext(context), queryFilter.normalize(context))
20 {
21 }
22
23 std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const
24 {
25 std::stringstream queryStream;
26
27 if (!withs_.empty())
28 {
29 queryStream << "WITH RECURSIVE ";
30
31 std::list<std::string> ctes;
32 for (const with& cte : withs_)
33 {
34 std::stringstream cteStream;
35 cteStream << cte.getIdentifier();
36 cteStream << " AS (SELECT ";
37 cteStream << cte.getTopTable();
38 cteStream << ".* FROM ";
39 cteStream << cte.getTableForId(cte.getTopTable());
40 cteStream << " AS ";
41 cteStream << cte.getTopTable();
42
43 for (const join& j : cte.getJoins())
44 {
45 cteStream << " ";
46 cteStream << j;
47 }
48
49 if (cte.getCondition().getType() != condition::type::empty)
50 {
51 cteStream << " WHERE ";
52 cteStream << cte.getCondition().toSql();
53 }
54
55 cteStream << " UNION SELECT l.* FROM ";
56 cteStream << cte.getIdentifier();
57 cteStream << " AS t INNER JOIN ";
58 cteStream << cte.getField().getTable();
59 cteStream << " AS j ON t.";
60 cteStream << cte.getField().getColumn();
61 cteStream << " = j.";
62 cteStream << cte.getField().getForeignJoinColumn();
63 cteStream << " INNER JOIN ";
64 cteStream << cte.getTableForId(cte.getTopTable());
65 cteStream << " AS l ON j.";
66 cteStream << cte.getField().getJoinColumn();
67 cteStream << " = l.";
68 cteStream << cte.getField().getColumn();
69 cteStream << ")";
70
71 ctes.push_back(cteStream.str());
72 }
73
74 queryStream << implode(std::begin(ctes), std::end(ctes), ", ");
75 queryStream << " ";
76 }
77
78 std::list<std::string> realSelect;
79 for (std::string& s : select)
80 {
81 realSelect.push_back(topTable_ + "." + s);
82 }
83
84 queryStream << "SELECT ";
85 queryStream << implode(std::begin(realSelect), std::end(realSelect), ", ");
86 queryStream << " FROM ";
87 queryStream << tables_.at(topTable_);
88 queryStream << " AS ";
89 queryStream << topTable_;
90
91 for (const join& j : joins_)
92 {
93 queryStream << " ";
94 queryStream << j;
95 }
96
97 if (topCondition_.getType() != condition::type::empty)
98 {
99 queryStream << " WHERE ";
100 queryStream << topCondition_.toSql();
101 }
102
103 if (random)
104 {
105 queryStream << " ORDER BY RANDOM()";
106 }
107
108 if (limit > 0)
109 {
110 queryStream << " LIMIT ";
111 queryStream << limit;
112 }
113
114 return queryStream.str();
115 }
116
117 std::list<binding> statement::getBindings() const
118 {
119 std::list<binding> result;
120
121 for (const with& w : withs_)
122 {
123 for (binding value : w.getCondition().flattenBindings())
124 {
125 result.push_back(std::move(value));
126 }
127 }
128
129 for (binding value : topCondition_.flattenBindings())
130 {
131 result.push_back(std::move(value));
132 }
133
134 return result;
135 }
136
137 statement::statement(
138 std::string tableName,
139 filter clause,
140 int nextTableId,
141 int nextWithId) :
142 nextTableId_(nextTableId),
143 nextWithId_(nextWithId),
144 topTable_(instantiateTable(std::move(tableName))),
145 topCondition_(parseFilter(std::move(clause)))
146 {
147 }
148
149 statement::condition statement::parseFilter(filter clause)
150 {
151 switch (clause.getType())
152 {
153 case filter::type::empty:
154 {
155 return {};
156 }
157
158 case filter::type::singleton:
159 {
160 switch (clause.getField().getType())
161 {
162 case field::type::undefined:
163 {
164 return {};
165 }
166
167 case field::type::string:
168 case field::type::integer:
169 case field::type::boolean:
170 {
171 switch (clause.getComparison())
172 {
173 case filter::comparison::is_null:
174 {
175 return condition(topTable_, clause.getField().getColumn(), true);
176 }
177
178 case filter::comparison::is_not_null:
179 {
180 return condition(topTable_, clause.getField().getColumn(), false);
181 }
182
183 case filter::comparison::int_equals:
184 {
185 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getIntegerArgument());
186 }
187
188 case filter::comparison::int_does_not_equal:
189 {
190 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getIntegerArgument());
191 }
192
193 case filter::comparison::int_is_at_least:
194 {
195 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_least, clause.getIntegerArgument());
196 }
197
198 case filter::comparison::int_is_greater_than:
199 {
200 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_greater_than, clause.getIntegerArgument());
201 }
202
203 case filter::comparison::int_is_at_most:
204 {
205 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_most, clause.getIntegerArgument());
206 }
207
208 case filter::comparison::int_is_less_than:
209 {
210 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_less_than, clause.getIntegerArgument());
211 }
212
213 case filter::comparison::boolean_equals:
214 {
215 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getBooleanArgument() ? 1 : 0);
216 }
217
218 case filter::comparison::string_equals:
219 {
220 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getStringArgument());
221 }
222
223 case filter::comparison::string_does_not_equal:
224 {
225 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getStringArgument());
226 }
227
228 case filter::comparison::string_is_like:
229 {
230 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_like, clause.getStringArgument());
231 }
232
233 case filter::comparison::string_is_not_like:
234 {
235 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument());
236 }
237
238 case filter::comparison::matches:
239 case filter::comparison::does_not_match:
240 case filter::comparison::hierarchally_matches:
241 case filter::comparison::does_not_hierarchally_match:
242 {
243 throw std::logic_error("Invalid comparison type for field");
244 }
245 }
246 }
247
248 case field::type::join:
249 {
250 std::string joinTableName;
251 if (clause.getField().hasTable())
252 {
253 joinTableName = clause.getField().getTable();
254 } else {
255 joinTableName = getTableForContext(clause.getField().getJoinObject());
256 }
257
258 statement joinStmt(
259 joinTableName,
260 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
261 nextTableId_,
262 nextWithId_);
263
264 std::string joinTable = joinStmt.topTable_;
265 condition curCond = integrate(std::move(joinStmt));
266
267 bool outer = false;
268 if (clause.getComparison() == filter::comparison::does_not_match)
269 {
270 outer = true;
271
272 curCond &= condition(joinTable, clause.getField().getColumn(), true);
273 }
274
275 joins_.emplace_back(outer, joinTableName, topTable_, clause.getField().getColumn(), joinTable, clause.getField().getColumn());
276
277 return curCond;
278 }
279
280 case field::type::join_through:
281 {
282 statement joinStmt(
283 getTableForContext(clause.getField().getJoinObject()),
284 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
285 nextTableId_,
286 nextWithId_);
287
288 std::string joinTable = joinStmt.topTable_;
289 std::string throughTable = instantiateTable(clause.getField().getTable());
290 condition curCond = integrate(std::move(joinStmt));
291
292 bool outer = false;
293 if (clause.getComparison() == filter::comparison::does_not_match)
294 {
295 outer = true;
296
297 curCond &= condition(throughTable, clause.getField().getJoinColumn(), true);
298 }
299
300 joins_.emplace_back(outer, clause.getField().getTable(), topTable_, clause.getField().getColumn(), throughTable, clause.getField().getJoinColumn());
301 joins_.emplace_back(false, getTableForContext(clause.getField().getJoinObject()), throughTable, clause.getField().getForeignJoinColumn(), joinTable, clause.getField().getForeignColumn());
302
303 return curCond;
304 }
305
306 case field::type::hierarchal_join:
307 {
308 std::string withName = std::string(clause.getField().getTable()) + "_tree_" + std::to_string(nextWithId_++);
309 std::string withInstName = instantiateTable(withName);
310
311 bool outer = false;
312 if (clause.getComparison() == filter::comparison::does_not_hierarchally_match)
313 {
314 outer = true;
315 }
316
317 joins_.emplace_back(outer, withName, topTable_, clause.getField().getColumn(), withInstName, clause.getField().getColumn());
318
319 statement withStmt(
320 getTableForContext(clause.getField().getObject()),
321 clause.getJoinCondition().normalize(clause.getField().getObject()),
322 nextTableId_,
323 nextWithId_);
324
325 for (auto& w : withStmt.withs_)
326 {
327 withs_.push_back(std::move(w));
328 }
329
330 nextTableId_ = withStmt.nextTableId_;
331 nextWithId_ = withStmt.nextWithId_;
332
333 withs_.emplace_back(
334 withName,
335 clause.getField(),
336 std::move(withStmt.tables_),
337 std::move(withStmt.topTable_),
338 std::move(withStmt.topCondition_),
339 std::move(withStmt.joins_));
340
341 if (clause.getComparison() == filter::comparison::does_not_hierarchally_match)
342 {
343 return condition(withInstName, clause.getField().getColumn(), true);
344 } else {
345 return {};
346 }
347 }
348 }
349 }
350
351 case filter::type::group:
352 {
353 condition grp(clause.getOrlogic());
354
355 for (const filter& child : clause)
356 {
357 condition newChild = parseFilter(child);
358 if (newChild.getType() != condition::type::empty)
359 {
360 grp += std::move(newChild);
361 }
362 }
363
364 if (grp.getChildren().empty())
365 {
366 grp = {};
367 }
368
369 return grp;
370 }
371 }
372 }
373
374 std::string statement::instantiateTable(std::string name)
375 {
376 std::string identifier = name + "_" + std::to_string(nextTableId_++);
377 tables_[identifier] = name;
378
379 return identifier;
380 }
381
382 statement::condition statement::integrate(statement subStmt)
383 {
384 for (auto& mapping : subStmt.tables_)
385 {
386 tables_[mapping.first] = mapping.second;
387 }
388
389 for (auto& j : subStmt.joins_)
390 {
391 joins_.push_back(j);
392 }
393
394 for (auto& w : subStmt.withs_)
395 {
396 withs_.push_back(w);
397 }
398
399 nextTableId_ = subStmt.nextTableId_;
400 nextWithId_ = subStmt.nextWithId_;
401
402 return subStmt.topCondition_;
403 }
404
405 std::ostream& operator<<(std::ostream& oss, const statement::join& j)
406 {
407 if (j.isOuterJoin())
408 {
409 oss << "LEFT";
410 } else {
411 oss << "INNER";
412 }
413
414 return oss
415 << " JOIN "
416 << j.getForeignTableName()
417 << " AS "
418 << j.getForeignTable()
419 << " ON "
420 << j.getForeignTable()
421 << "."
422 << j.getForeignColumn()
423 << " = "
424 << j.getJoinTable()
425 << "."
426 << j.getJoinColumn();
427 }
428
429 statement::condition::condition(const condition& other)
430 {
431 type_ = other.type_;
432
433 switch (type_)
434 {
435 case type::empty:
436 {
437 break;
438 }
439
440 case type::singleton:
441 {
442 new(&singleton_.table_) std::string(other.singleton_.table_);
443 new(&singleton_.column_) std::string(other.singleton_.column_);
444 singleton_.comparison_ = other.singleton_.comparison_;
445 new(&singleton_.value_) binding(other.singleton_.value_);
446
447 break;
448 }
449
450 case type::group:
451 {
452 new(&group_.children_) std::list<condition>(other.group_.children_);
453 group_.orlogic_ = other.group_.orlogic_;
454
455 break;
456 }
457 }
458 }
459
460 statement::condition::condition(condition&& other) : condition()
461 {
462 swap(*this, other);
463 }
464
465 statement::condition& statement::condition::operator=(condition other)
466 {
467 swap(*this, other);
468
469 return *this;
470 }
471
472 void swap(statement::condition& first, statement::condition& second)
473 {
474 using type = statement::condition::type;
475 using condition = statement::condition;
476
477 type tempType = first.type_;
478 std::string tempTable;
479 std::string tempColumn;
480 condition::comparison tempComparison;
481 binding tempBinding;
482 std::list<condition> tempChildren;
483 bool tempOrlogic;
484
485 switch (tempType)
486 {
487 case type::empty:
488 {
489 break;
490 }
491
492 case type::singleton:
493 {
494 tempTable = std::move(first.singleton_.table_);
495 tempColumn = std::move(first.singleton_.column_);
496 tempComparison = first.singleton_.comparison_;
497 tempBinding = std::move(first.singleton_.value_);
498
499 break;
500 }
501
502 case type::group:
503 {
504 tempChildren = std::move(first.group_.children_);
505 tempOrlogic = first.group_.orlogic_;
506
507 break;
508 }
509 }
510
511 first.~condition();
512
513 first.type_ = second.type_;
514
515 switch (first.type_)
516 {
517 case type::empty:
518 {
519 break;
520 }
521
522 case type::singleton:
523 {
524 new(&first.singleton_.table_) std::string(std::move(second.singleton_.table_));
525 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_));
526 first.singleton_.comparison_ = second.singleton_.comparison_;
527 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_));
528
529 break;
530 }
531
532 case type::group:
533 {
534 new(&first.group_.children_) std::list<condition>(std::move(second.group_.children_));
535 first.group_.orlogic_ = second.group_.orlogic_;
536
537 break;
538 }
539 }
540
541 second.~condition();
542
543 second.type_ = tempType;
544
545 switch (second.type_)
546 {
547 case type::empty:
548 {
549 break;
550 }
551
552 case type::singleton:
553 {
554 new(&second.singleton_.table_) std::string(std::move(tempTable));
555 new(&second.singleton_.column_) std::string(std::move(tempColumn));
556 second.singleton_.comparison_ = tempComparison;
557 new(&second.singleton_.value_) binding(std::move(tempBinding));
558
559 break;
560 }
561
562 case type::group:
563 {
564 new(&second.group_.children_) std::list<condition>(std::move(tempChildren));
565 second.group_.orlogic_ = tempOrlogic;
566
567 break;
568 }
569 }
570 }
571
572 statement::condition::~condition()
573 {
574 switch (type_)
575 {
576 case type::empty:
577 {
578 break;
579 }
580
581 case type::singleton:
582 {
583 using string_type = std::string;
584
585 singleton_.table_.~string_type();
586 singleton_.column_.~string_type();
587 singleton_.value_.~binding();
588
589 break;
590 }
591
592 case type::group:
593 {
594 using list_type = std::list<condition>;
595
596 group_.children_.~list_type();
597
598 break;
599 }
600 }
601 }
602
603 statement::condition::condition() : type_(type::empty)
604 {
605 }
606
607 statement::condition::condition(
608 std::string table,
609 std::string column,
610 bool isNull) :
611 type_(type::singleton)
612 {
613 new(&singleton_.table_) std::string(std::move(table));
614 new(&singleton_.column_) std::string(std::move(column));
615
616 if (isNull)
617 {
618 singleton_.comparison_ = comparison::is_null;
619 } else {
620 singleton_.comparison_ = comparison::is_not_null;
621 }
622 }
623
624 statement::condition::condition(
625 std::string table,
626 std::string column,
627 comparison comp,
628 binding value) :
629 type_(type::singleton)
630 {
631 new(&singleton_.table_) std::string(std::move(table));
632 new(&singleton_.column_) std::string(std::move(column));
633 singleton_.comparison_ = comp;
634 new(&singleton_.value_) binding(std::move(value));
635 }
636
637 std::string statement::condition::toSql() const
638 {
639 switch (type_)
640 {
641 case type::empty:
642 {
643 return "";
644 }
645
646 case type::singleton:
647 {
648 switch (singleton_.comparison_)
649 {
650 case comparison::equals:
651 {
652 return singleton_.table_ + "." + singleton_.column_ + " = ?";
653 }
654
655 case comparison::does_not_equal:
656 {
657 return singleton_.table_ + "." + singleton_.column_ + " != ?";
658 }
659
660 case comparison::is_greater_than:
661 {
662 return singleton_.table_ + "." + singleton_.column_ + " > ?";
663 }
664
665 case comparison::is_at_most:
666 {
667 return singleton_.table_ + "." + singleton_.column_ + " <= ?";
668 }
669
670 case comparison::is_less_than:
671 {
672 return singleton_.table_ + "." + singleton_.column_ + " < ?";
673 }
674
675 case comparison::is_at_least:
676 {
677 return singleton_.table_ + "." + singleton_.column_ + " >= ?";
678 }
679
680 case comparison::is_like:
681 {
682 return singleton_.table_ + "." + singleton_.column_ + " LIKE ?";
683 }
684
685 case comparison::is_not_like:
686 {
687 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?";
688 }
689
690 case comparison::is_not_null:
691 {
692 return singleton_.table_ + "." + singleton_.column_ + " IS NOT NULL";
693 }
694
695 case comparison::is_null:
696 {
697 return singleton_.table_ + "." + singleton_.column_ + " IS NULL";
698 }
699 }
700 }
701
702 case type::group:
703 {
704 std::list<std::string> clauses;
705 for (const condition& cond : group_.children_)
706 {
707 clauses.push_back(cond.toSql());
708 }
709
710 return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND ");
711 }
712 }
713 }
714
715 std::list<binding> statement::condition::flattenBindings() const
716 {
717 switch (type_)
718 {
719 case type::empty:
720 {
721 return {};
722 }
723
724 case type::singleton:
725 {
726 return {singleton_.value_};
727 }
728
729 case type::group:
730 {
731 std::list<binding> bindings;
732 for (const condition& cond : group_.children_)
733 {
734 for (binding value : cond.flattenBindings())
735 {
736 bindings.push_back(std::move(value));
737 }
738 }
739
740 return bindings;
741 }
742 }
743 }
744
745 statement::condition::condition(bool orlogic) : type_(type::group)
746 {
747 new(&group_.children_) std::list<condition>();
748 group_.orlogic_ = orlogic;
749 }
750
751 statement::condition& statement::condition::operator+=(condition n)
752 {
753 if (type_ == type::group)
754 {
755 group_.children_.push_back(std::move(n));
756
757 return *this;
758 } else {
759 throw std::domain_error("Cannot add condition to non-group condition");
760 }
761 }
762
763 statement::condition& statement::condition::operator&=(condition n)
764 {
765 switch (type_)
766 {
767 case type::empty:
768 {
769 *this = std::move(n);
770
771 break;
772 }
773
774 case type::singleton:
775 {
776 condition grp(false);
777 grp += *this;
778 grp += std::move(n);
779
780 *this = grp;
781
782 break;
783 }
784
785 case type::group:
786 {
787 *this += std::move(n);
788
789 break;
790 }
791 }
792
793 return *this;
794 }
795
796 const std::list<statement::condition>& statement::condition::getChildren() const
797 {
798 if (type_ == type::group)
799 {
800 return group_.children_;
801 } else {
802 throw std::domain_error("Cannot get children of non-group condition");
803 }
804 }
805
806};
diff --git a/lib/statement.h b/lib/statement.h new file mode 100644 index 0000000..a528d60 --- /dev/null +++ b/lib/statement.h
@@ -0,0 +1,272 @@
1#ifndef STATEMENT_H_29F51659
2#define STATEMENT_H_29F51659
3
4#include <string>
5#include <list>
6#include <map>
7#include <set>
8#include "binding.h"
9#include "enums.h"
10#include "field.h"
11#include "filter.h"
12
13namespace verbly {
14
15 class filter;
16
17 class statement {
18 public:
19
20 statement(object context, filter queryFilter);
21
22 std::string getQueryString(std::list<std::string> select, bool random, int limit) const;
23
24 std::list<binding> getBindings() const;
25
26 private:
27
28 class join {
29 public:
30
31 join(
32 bool outer,
33 std::string foreignTableName,
34 std::string joinTable,
35 std::string joinColumn,
36 std::string foreignTable,
37 std::string foreignColumn) :
38 outer_(outer),
39 foreignTableName_(std::move(foreignTableName)),
40 joinTable_(std::move(joinTable)),
41 joinColumn_(std::move(joinColumn)),
42 foreignTable_(std::move(foreignTable)),
43 foreignColumn_(std::move(foreignColumn))
44 {
45 }
46
47 bool isOuterJoin() const
48 {
49 return outer_;
50 }
51
52 const std::string& getForeignTableName() const
53 {
54 return foreignTableName_;
55 }
56
57 const std::string& getJoinTable() const
58 {
59 return joinTable_;
60 }
61
62 const std::string& getJoinColumn() const
63 {
64 return joinColumn_;
65 }
66
67 const std::string& getForeignTable() const
68 {
69 return foreignTable_;
70 }
71
72 const std::string& getForeignColumn() const
73 {
74 return foreignColumn_;
75 }
76
77 private:
78 bool outer_ = false;
79 std::string foreignTableName_;
80 std::string joinTable_;
81 std::string joinColumn_;
82 std::string foreignTable_;
83 std::string foreignColumn_;
84
85 };
86
87 friend std::ostream& operator<<(std::ostream& oss, const join& j);
88
89 class condition {
90 public:
91 enum class type {
92 empty,
93 singleton,
94 group
95 };
96
97 enum class comparison {
98 equals,
99 does_not_equal,
100 is_greater_than,
101 is_at_most,
102 is_less_than,
103 is_at_least,
104 is_like,
105 is_not_like,
106 is_not_null,
107 is_null
108 };
109
110 // Copy and move constructors
111
112 condition(const condition& other);
113 condition(condition&& other);
114
115 // Assignment
116
117 condition& operator=(condition other);
118
119 // Swap
120
121 friend void swap(condition& first, condition& second);
122
123 // Destructor
124
125 ~condition();
126
127 // Accessors
128
129 type getType() const
130 {
131 return type_;
132 }
133
134 // Empty
135
136 condition();
137
138 // Singleton
139
140 condition(std::string table, std::string column, bool isNull);
141
142 condition(std::string table, std::string column, comparison comp, binding value);
143
144 // Group
145
146 explicit condition(bool orlogic);
147
148 condition& operator+=(condition n);
149
150 condition& operator&=(condition n);
151
152 const std::list<condition>& getChildren() const;
153
154 // Utility
155
156 std::string toSql() const;
157
158 std::list<binding> flattenBindings() const;
159
160 private:
161 union {
162 struct {
163 std::string table_;
164 std::string column_;
165 comparison comparison_;
166 binding value_;
167 } singleton_;
168 struct {
169 std::list<condition> children_;
170 bool orlogic_;
171 } group_;
172 };
173 type type_;
174 };
175
176 friend void swap(condition& first, condition& second);
177
178 class with {
179 public:
180
181 with(
182 std::string identifier,
183 field f,
184 std::map<std::string, std::string> tables,
185 std::string topTable,
186 condition where,
187 std::list<join> joins) :
188 identifier_(std::move(identifier)),
189 field_(f),
190 tables_(std::move(tables)),
191 topTable_(std::move(topTable)),
192 topCondition_(std::move(where)),
193 joins_(std::move(joins))
194 {
195 }
196
197 const std::string& getIdentifier() const
198 {
199 return identifier_;
200 }
201
202 field getField() const
203 {
204 return field_;
205 }
206
207 std::string getTableForId(std::string identifier) const
208 {
209 return tables_.at(identifier);
210 }
211
212 const std::string& getTopTable() const
213 {
214 return topTable_;
215 }
216
217 const condition& getCondition() const
218 {
219 return topCondition_;
220 }
221
222 const std::list<join>& getJoins() const
223 {
224 return joins_;
225 }
226
227 private:
228 std::string identifier_;
229 field field_;
230 std::map<std::string, std::string> tables_;
231 std::string topTable_;
232 condition topCondition_;
233 std::list<join> joins_;
234
235 };
236
237 static constexpr const char* getTableForContext(object context)
238 {
239 return (context == object::notion) ? "notions"
240 : (context == object::word) ? "words"
241 : (context == object::group) ? "groups"
242 : (context == object::frame) ? "frames"
243 : (context == object::lemma) ? "lemmas_forms"
244 : (context == object::form) ? "forms"
245 : (context == object::pronunciation) ? "pronunciations"
246 : throw std::domain_error("Provided context has no associated table");
247 }
248
249 static const std::list<field> getSelectForContext(object context);
250
251 statement(std::string tableName, filter clause, int nextTableId = 0, int nextWithId = 0);
252
253 condition parseFilter(filter queryFilter);
254
255 std::string instantiateTable(std::string name);
256
257 condition integrate(statement subStmt);
258
259 int nextTableId_;
260 int nextWithId_;
261
262 std::map<std::string, std::string> tables_;
263 std::string topTable_;
264 std::list<join> joins_;
265 std::list<with> withs_;
266 condition topCondition_;
267
268 };
269
270};
271
272#endif /* end of include guard: STATEMENT_H_29F51659 */
diff --git a/lib/util.h b/lib/util.h index fb5fe67..b74b050 100644 --- a/lib/util.h +++ b/lib/util.h
@@ -1,6 +1,10 @@
1#ifndef UTIL_H_15DDCA2D 1#ifndef UTIL_H_15DDCA2D
2#define UTIL_H_15DDCA2D 2#define UTIL_H_15DDCA2D
3 3
4#include <string>
5#include <sstream>
6#include <iterator>
7
4namespace verbly { 8namespace verbly {
5 9
6 template <class InputIterator> 10 template <class InputIterator>
@@ -21,25 +25,33 @@ namespace verbly {
21 return result.str(); 25 return result.str();
22 } 26 }
23 27
24 template <class Container> 28 template <class OutputIterator>
25 Container split(std::string input, std::string delimiter) 29 void split(std::string input, std::string delimiter, OutputIterator out)
26 { 30 {
27 Container result;
28
29 while (!input.empty()) 31 while (!input.empty())
30 { 32 {
31 int divider = input.find(delimiter); 33 int divider = input.find(delimiter);
32 if (divider == std::string::npos) 34 if (divider == std::string::npos)
33 { 35 {
34 result.push_back(input); 36 *out = input;
37 out++;
35 38
36 input = ""; 39 input = "";
37 } else { 40 } else {
38 result.push_back(input.substr(0, divider)); 41 *out = input.substr(0, divider);
42 out++;
39 43
40 input = input.substr(divider+delimiter.length()); 44 input = input.substr(divider+delimiter.length());
41 } 45 }
42 } 46 }
47 }
48
49 template <class Container>
50 Container split(std::string input, std::string delimiter)
51 {
52 Container result;
53
54 split(input, delimiter, std::back_inserter(result));
43 55
44 return result; 56 return result;
45 } 57 }
diff --git a/lib/verb.cpp b/lib/verb.cpp deleted file mode 100644 index 1f45d53..0000000 --- a/lib/verb.cpp +++ /dev/null
@@ -1,64 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 verb::verb()
6 {
7
8 }
9
10 verb::verb(const data& _data, int _id) : word(_data, _id)
11 {
12
13 }
14
15 std::string verb::base_form() const
16 {
17 assert(_valid == true);
18
19 return _infinitive;
20 }
21
22 std::string verb::infinitive_form() const
23 {
24 assert(_valid == true);
25
26 return _infinitive;
27 }
28
29 std::string verb::past_tense_form() const
30 {
31 assert(_valid == true);
32
33 return _past_tense;
34 }
35
36 std::string verb::past_participle_form() const
37 {
38 assert(_valid == true);
39
40 return _past_participle;
41 }
42
43 std::string verb::ing_form() const
44 {
45 assert(_valid == true);
46
47 return _ing_form;
48 }
49
50 std::string verb::s_form() const
51 {
52 assert(_valid == true);
53
54 return _s_form;
55 }
56
57 frame_query verb::frames() const
58 {
59 assert(_valid == true);
60
61 return _data->frames().for_verb(*this);
62 }
63
64};
diff --git a/lib/verb.h b/lib/verb.h deleted file mode 100644 index 7a2486e..0000000 --- a/lib/verb.h +++ /dev/null
@@ -1,34 +0,0 @@
1#ifndef VERB_H_BCC929AD
2#define VERB_H_BCC929AD
3
4namespace verbly {
5
6 class frame_query;
7
8 class verb : public word {
9 private:
10 std::string _infinitive;
11 std::string _past_tense;
12 std::string _past_participle;
13 std::string _ing_form;
14 std::string _s_form;
15
16 friend class verb_query;
17
18 public:
19 verb();
20 verb(const data& _data, int _id);
21
22 std::string base_form() const;
23 std::string infinitive_form() const;
24 std::string past_tense_form() const;
25 std::string past_participle_form() const;
26 std::string ing_form() const;
27 std::string s_form() const;
28
29 frame_query frames() const;
30 };
31
32};
33
34#endif /* end of include guard: VERB_H_BCC929AD */
diff --git a/lib/verb_query.cpp b/lib/verb_query.cpp deleted file mode 100644 index 4e6c253..0000000 --- a/lib/verb_query.cpp +++ /dev/null
@@ -1,315 +0,0 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 verb_query::verb_query(const data& _data) : _data(_data)
6 {
7
8 }
9
10 verb_query& verb_query::limit(int _limit)
11 {
12 if ((_limit > 0) || (_limit == unlimited))
13 {
14 this->_limit = _limit;
15 }
16
17 return *this;
18 }
19
20 verb_query& verb_query::random()
21 {
22 this->_random = true;
23
24 return *this;
25 }
26
27 verb_query& verb_query::except(const verb& _word)
28 {
29 _except.push_back(_word);
30
31 return *this;
32 }
33
34 verb_query& verb_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 verb*>(&_word) != nullptr)
42 {
43 _except.push_back(dynamic_cast<const verb&>(_word));
44 }
45
46 return *this;
47 }
48
49 verb_query& verb_query::rhymes_with(rhyme _r)
50 {
51 _rhymes.push_back(_r);
52
53 return *this;
54 }
55
56 verb_query& verb_query::has_pronunciation()
57 {
58 this->_has_prn = true;
59
60 return *this;
61 }
62
63 verb_query& verb_query::has_rhyming_noun()
64 {
65 _has_rhyming_noun = true;
66
67 return *this;
68 }
69
70 verb_query& verb_query::has_rhyming_adjective()
71 {
72 _has_rhyming_adjective = true;
73
74 return *this;
75 }
76
77 verb_query& verb_query::has_rhyming_adverb()
78 {
79 _has_rhyming_adverb = true;
80
81 return *this;
82 }
83
84 verb_query& verb_query::has_rhyming_verb()
85 {
86 _has_rhyming_verb = true;
87
88 return *this;
89 }
90
91 verb_query& verb_query::with_stress(filter<std::vector<bool>> _arg)
92 {
93 _stress = _arg;
94
95 return *this;
96 }
97
98 verb_query& verb_query::has_frames()
99 {
100 this->_has_frames = true;
101
102 return *this;
103 }
104
105 std::list<verb> verb_query::run() const
106 {
107 std::stringstream construct;
108 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
109 std::list<std::string> conditions;
110 std::list<binding> bindings;
111
112 if (_has_prn)
113 {
114 conditions.push_back("verb_id IN (SELECT verb_id FROM verb_pronunciations)");
115 }
116
117 if (!_rhymes.empty())
118 {
119 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
120 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
121 conditions.push_back(cond);
122
123 for (auto rhy : _rhymes)
124 {
125 bindings.emplace_back(rhy.get_prerhyme());
126 bindings.emplace_back(rhy.get_rhyme());
127 }
128 }
129
130 if (_has_rhyming_noun)
131 {
132 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
133 }
134
135 if (_has_rhyming_adjective)
136 {
137 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
138 }
139
140 if (_has_rhyming_adverb)
141 {
142 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
143 }
144
145 if (_has_rhyming_verb)
146 {
147 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.verb_id != curp.verb_id)");
148 }
149
150 if (!_stress.empty())
151 {
152 std::stringstream cond;
153 if (_stress.get_notlogic())
154 {
155 cond << "verb_id NOT IN";
156 } else {
157 cond << "verb_id IN";
158 }
159
160 cond << "(SELECT verb_id FROM verb_pronunciations WHERE ";
161
162 std::function<std::string (filter<std::vector<bool>>, bool)> recur = [&] (filter<std::vector<bool>> f, bool notlogic) -> std::string {
163 switch (f.get_type())
164 {
165 case filter<std::vector<bool>>::type::singleton:
166 {
167 std::ostringstream _val;
168 for (auto syl : f.get_elem())
169 {
170 if (syl)
171 {
172 _val << "1";
173 } else {
174 _val << "0";
175 }
176 }
177
178 bindings.emplace_back(_val.str());
179
180 if (notlogic == f.get_notlogic())
181 {
182 return "stress = ?";
183 } else {
184 return "stress != ?";
185 }
186 }
187
188 case filter<std::vector<bool>>::type::group:
189 {
190 bool truelogic = notlogic != f.get_notlogic();
191
192 std::list<std::string> clauses;
193 std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter<std::vector<bool>> f2) {
194 return recur(f2, truelogic);
195 });
196
197 if (truelogic == f.get_orlogic())
198 {
199 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")";
200 } else {
201 return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
202 }
203 }
204 }
205 };
206
207 cond << recur(_stress, _stress.get_notlogic());
208 cond << ")";
209 conditions.push_back(cond.str());
210 }
211
212 for (auto except : _except)
213 {
214 conditions.push_back("verb_id != ?");
215 bindings.emplace_back(except._id);
216 }
217
218 if (!_has_frames)
219 {
220 conditions.push_back("verb_id IN (SELECT verb_id FROM verb_groups)");
221 }
222
223 if (!conditions.empty())
224 {
225 construct << " WHERE ";
226 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
227 }
228
229 if (_random)
230 {
231 construct << " ORDER BY RANDOM()";
232 }
233
234 if (_limit != unlimited)
235 {
236 construct << " LIMIT " << _limit;
237 }
238
239 sqlite3_stmt* ppstmt;
240 std::string query = construct.str();
241 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
242 {
243 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
244 }
245
246 int i = 1;
247 for (auto& binding : bindings)
248 {
249 switch (binding.get_type())
250 {
251 case binding::type::integer:
252 {
253 sqlite3_bind_int(ppstmt, i, binding.get_integer());
254
255 break;
256 }
257
258 case binding::type::string:
259 {
260 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
261
262 break;
263 }
264 }
265
266 i++;
267 }
268
269 std::list<verb> output;
270 while (sqlite3_step(ppstmt) == SQLITE_ROW)
271 {
272 verb tnc {_data, sqlite3_column_int(ppstmt, 0)};
273 tnc._infinitive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
274 tnc._past_tense = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
275 tnc._past_participle = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
276 tnc._ing_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
277 tnc._s_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 5)));
278
279 output.push_back(tnc);
280 }
281
282 sqlite3_finalize(ppstmt);
283
284 for (auto& verb : output)
285 {
286 query = "SELECT pronunciation, prerhyme, rhyme FROM verb_pronunciations WHERE verb_id = ?";
287 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
288 {
289 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
290 }
291
292 sqlite3_bind_int(ppstmt, 1, verb._id);
293
294 while (sqlite3_step(ppstmt) == SQLITE_ROW)
295 {
296 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
297 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
298
299 verb.pronunciations.push_back(phonemes);
300
301 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
302 {
303 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
304 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
305 verb.rhymes.emplace_back(prerhyme, rhyming);
306 }
307 }
308
309 sqlite3_finalize(ppstmt);
310 }
311
312 return output;
313 }
314
315};
diff --git a/lib/verb_query.h b/lib/verb_query.h deleted file mode 100644 index 566ae37..0000000 --- a/lib/verb_query.h +++ /dev/null
@@ -1,45 +0,0 @@
1#ifndef VERB_QUERY_H_34E5A679
2#define VERB_QUERY_H_34E5A679
3
4namespace verbly {
5
6 class verb_query {
7 public:
8 verb_query(const data& _data);
9
10 verb_query& limit(int _limit);
11 verb_query& random();
12 verb_query& except(const verb& _word);
13 verb_query& rhymes_with(const word& _word);
14 verb_query& rhymes_with(rhyme _r);
15 verb_query& has_pronunciation();
16 verb_query& has_rhyming_noun();
17 verb_query& has_rhyming_adjective();
18 verb_query& has_rhyming_adverb();
19 verb_query& has_rhyming_verb();
20 verb_query& with_stress(filter<std::vector<bool>> _arg);
21
22 verb_query& has_frames();
23
24 std::list<verb> run() const;
25
26 const static int unlimited = -1;
27
28 private:
29 const data& _data;
30 int _limit = unlimited;
31 bool _random = false;
32 std::list<rhyme> _rhymes;
33 std::list<verb> _except;
34 bool _has_prn = false;
35 bool _has_frames = false;
36 bool _has_rhyming_noun = false;
37 bool _has_rhyming_adjective = false;
38 bool _has_rhyming_adverb = false;
39 bool _has_rhyming_verb = false;
40 filter<std::vector<bool>> _stress;
41 };
42
43};
44
45#endif /* end of include guard: VERB_QUERY_H_34E5A679 */
diff --git a/lib/verbly.h b/lib/verbly.h index cfaf5bc..6dfc01a 100644 --- a/lib/verbly.h +++ b/lib/verbly.h
@@ -1,35 +1,17 @@
1#ifndef VERBLY_H_5B39CE50 1#ifndef VERBLY_H_5B39CE50
2#define VERBLY_H_5B39CE50 2#define VERBLY_H_5B39CE50
3 3
4#include <string>
5#include <list>
6#include <sstream>
7#include <algorithm>
8#include <cassert>
9#include <set>
10#include <stdexcept>
11#include <vector>
12#include <map>
13#include <iterator>
14#include <sstream>
15#include <functional>
16#include <iostream>
17#include <new>
18
19#include "util.h" 4#include "util.h"
20#include "data.h" 5#include "database.h"
6#include "filter.h"
7#include "field.h"
8#include "query.h"
9#include "notion.h"
21#include "word.h" 10#include "word.h"
22#include "verb.h" 11#include "group.h"
23#include "adverb.h"
24#include "adjective.h"
25#include "noun.h"
26#include "frame.h" 12#include "frame.h"
27#include "preposition.h" 13#include "lemma.h"
28#include "token.h" 14#include "form.h"
29#include "noun_query.h" 15#include "pronunciation.h"
30#include "adverb_query.h"
31#include "adjective_query.h"
32#include "verb_query.h"
33#include "frame_query.h"
34 16
35#endif /* end of include guard: VERBLY_H_5B39CE50 */ 17#endif /* end of include guard: VERBLY_H_5B39CE50 */
diff --git a/lib/word.cpp b/lib/word.cpp index 49e34a1..3edf2d2 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -1,60 +1,112 @@
1#include "verbly.h" 1#include "word.h"
2#include <algorithm> 2#include <sqlite3.h>
3#include "form.h"
4#include "util.h"
5#include "database.h"
6#include "query.h"
3 7
4namespace verbly { 8namespace verbly {
5 9
6 rhyme::rhyme(std::string prerhyme, std::string phonemes) : _prerhyme(prerhyme), _rhyme(phonemes) 10 const object word::objectType = object::word;
7 {
8
9 }
10 11
11 std::string rhyme::get_prerhyme() const 12 const std::list<std::string> word::select = {"word_id", "notion_id", "lemma_id", "tag_count", "position", "group_id"};
12 {
13 return _prerhyme;
14 }
15 13
16 std::string rhyme::get_rhyme() const 14 const field word::id = field::integerField(object::word, "word_id");
17 { 15 const field word::tagCount = field::integerField(object::word, "tag_count", true);
18 return _rhyme; 16 const field word::adjectivePosition = field::integerField(object::word, "position", true);
19 } 17
18 const field word::notion = field::joinField(object::word, "notion_id", object::notion);
19 const field word::lemma = field::joinField(object::word, "lemma_id", object::lemma);
20 const field word::group = field::joinField(object::word, "group_id", object::group, true);
21
22 const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id");
23
24 const field word::specifications = field::selfJoin(object::word, "word_id", "specification", "general_id", "specific_id");
25 const field word::generalizations = field::selfJoin(object::word, "word_id", "specification", "specific_id", "general_id");
20 26
21 bool rhyme::operator==(const rhyme& other) const 27 const field word::pertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "noun_id", "pertainym_id");
28 const field word::antiPertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "pertainym_id", "noun_id");
29
30 const field word::mannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "adjective_id", "mannernym_id");
31 const field word::antiMannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "mannernym_id", "adjective_id");
32
33 const field word::usageTerms = field::selfJoin(object::word, "word_id", "usage", "domain_id", "term_id");
34 const field word::usageDomains = field::selfJoin(object::word, "word_id", "usage", "term_id", "domain_id");
35
36 const field word::topicalTerms = field::selfJoin(object::word, "word_id", "topicality", "domain_id", "term_id");
37 const field word::topicalDomains = field::selfJoin(object::word, "word_id", "topicality", "term_id", "domain_id");
38
39 const field word::regionalTerms = field::selfJoin(object::word, "word_id", "regionality", "domain_id", "term_id");
40 const field word::regionalDomains = field::selfJoin(object::word, "word_id", "regionality", "term_id", "domain_id");
41
42 word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
22 { 43 {
23 return std::tie(_prerhyme, _rhyme) == std::tie(other._prerhyme, other._rhyme); 44 id_ = sqlite3_column_int(row, 0);
45 notionId_ = sqlite3_column_int(row, 1);
46 lemmaId_ = sqlite3_column_int(row, 2);
47
48 if (sqlite3_column_type(row, 3) != SQLITE_NULL)
49 {
50 hasTagCount_ = true;
51 tagCount_ = sqlite3_column_int(row, 3);
52 }
53
54 if (sqlite3_column_type(row, 4) != SQLITE_NULL)
55 {
56 adjectivePosition_ = static_cast<positioning>(sqlite3_column_int(row, 4));
57 }
58
59 if (sqlite3_column_type(row, 5) != SQLITE_NULL)
60 {
61 hasGroup_ = true;
62 groupId_ = sqlite3_column_int(row, 5);
63 }
24 } 64 }
25 65
26 word::word() 66 const notion& word::getNotion() const
27 { 67 {
68 if (!valid_)
69 {
70 throw std::domain_error("Bad access to uninitialized word");
71 }
72
73 if (!notion_)
74 {
75 notion_ = db_->notions(notion::id == notionId_).first();
76 }
28 77
78 return notion_;
29 } 79 }
30 80
31 word::word(const data& _data, int _id) : _data(&_data), _id(_id), _valid(true) 81 const lemma& word::getLemma() const
32 { 82 {
83 if (!valid_)
84 {
85 throw std::domain_error("Bad access to uninitialized word");
86 }
33 87
88 if (!lemma_)
89 {
90 lemma_ = db_->lemmas(lemma::id == lemmaId_).first();
91 }
92
93 return lemma_;
34 } 94 }
35 95
36 std::list<rhyme> word::get_rhymes() const 96 std::string word::getBaseForm() const
37 { 97 {
38 assert(_valid == true); 98 return getLemma().getBaseForm().getText();
39
40 return rhymes;
41 } 99 }
42 100
43 bool word::starts_with_vowel_sound() const 101 std::list<std::string> word::getInflections(inflection category) const
44 { 102 {
45 assert(_valid == true); 103 std::list<std::string> result;
46 104 for (const form& infl : getLemma().getInflections(category))
47 if (pronunciations.size() > 0)
48 { 105 {
49 return std::any_of(std::begin(pronunciations), std::end(pronunciations), [] (std::list<std::string> phonemes) { 106 result.push_back(infl.getText());
50 return (phonemes.front().find_first_of("012") != std::string::npos);
51 });
52 } else {
53 // If the word is not in CMUDICT, fall back to checking whether the first letter is a vowel
54 // Not perfect but will work in most cases
55 char ch = tolower(base_form().front());
56 return (ch == 'a') || (ch == 'e') || (ch == 'i') || (ch == 'o') || (ch == 'u');
57 } 107 }
108
109 return result;
58 } 110 }
59 111
60}; 112};
diff --git a/lib/word.h b/lib/word.h index 08797a3..f71dad9 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -1,48 +1,173 @@
1#ifndef WORD_H_8FC89498 1#ifndef WORD_H_DF91B1B4
2#define WORD_H_8FC89498 2#define WORD_H_DF91B1B4
3
4#include <stdexcept>
5#include <map>
6#include "field.h"
7#include "filter.h"
8#include "notion.h"
9#include "lemma.h"
10#include "group.h"
11
12struct sqlite3_stmt;
3 13
4namespace verbly { 14namespace verbly {
5 15
6 class rhyme { 16 class database;
7 public: 17
8 rhyme(std::string prerhyme, std::string phonemes); 18 class word {
19 public:
20
21 // Default constructor
22
23 word() = default;
24
25 // Construct from database
26
27 word(const database& db, sqlite3_stmt* row);
28
29 // Accessors
30
31 operator bool() const
32 {
33 return valid_;
34 }
35
36 int getId() const
37 {
38 if (!valid_)
39 {
40 throw std::domain_error("Bad access to uninitialized word");
41 }
9 42
10 std::string get_prerhyme() const; 43 return id_;
11 std::string get_rhyme() const; 44 }
45
46 bool hasTagCount() const
47 {
48 if (!valid_)
49 {
50 throw std::domain_error("Bad access to uninitialized word");
51 }
12 52
13 bool operator==(const rhyme& other) const; 53 return hasTagCount_;
54 }
55
56 int getTagCount() const
57 {
58 if (!valid_)
59 {
60 throw std::domain_error("Bad access to uninitialized word");
61 }
14 62
15 private: 63 if (!hasTagCount_)
16 std::string _prerhyme; 64 {
17 std::string _rhyme; 65 throw std::domain_error("Word has no tag count");
18 }; 66 }
19
20 class word {
21 protected:
22 const data* _data;
23 int _id;
24 bool _valid = false;
25 67
26 std::list<std::list<std::string>> pronunciations; 68 return tagCount_;
27 std::list<rhyme> rhymes; 69 }
70
71 bool hasAdjectivePositioning() const
72 {
73 if (!valid_)
74 {
75 throw std::domain_error("Bad access to uninitialized word");
76 }
28 77
29 word(); 78 return (adjectivePosition_ != positioning::undefined);
30 word(const data& _data, int _id); 79 }
80
81 positioning getAdjectivePosition() const
82 {
83 if (!valid_)
84 {
85 throw std::domain_error("Bad access to uninitialized word");
86 }
31 87
32 friend class adjective_query; 88 if (adjectivePosition_ == positioning::undefined)
33 friend class verb_query; 89 {
34 friend class noun_query; 90 throw std::domain_error("Word has no adjective position");
35 friend class adverb_query; 91 }
36 friend class frame_query;
37 friend class preposition_query;
38
39 public:
40 virtual std::string base_form() const = 0;
41 92
42 std::list<rhyme> get_rhymes() const; 93 return adjectivePosition_;
43 bool starts_with_vowel_sound() const; 94 }
95
96 const notion& getNotion() const;
97
98 const lemma& getLemma() const;
99
100 // Convenience accessors
101
102 std::string getBaseForm() const;
103
104 std::list<std::string> getInflections(inflection infl) const;
105
106 // Type info
107
108 static const object objectType;
109
110 static const std::list<std::string> select;
111
112 // Query fields
113
114 static const field id;
115 static const field tagCount;
116 static const field adjectivePosition;
117
118 operator filter() const
119 {
120 return (id == id_);
121 }
122
123 // Relationships with other objects
124
125 static const field notion;
126 static const field lemma;
127 static const field group;
128
129 // Relationships with self
130
131 static const field antonyms;
132
133 static const field specifications;
134 static const field generalizations;
135
136 static const field pertainyms;
137 static const field antiPertainyms;
138
139 static const field mannernyms;
140 static const field antiMannernyms;
141
142 static const field usageTerms;
143 static const field usageDomains;
144
145 static const field topicalTerms;
146 static const field topicalDomains;
147
148 static const field regionalTerms;
149 static const field regionalDomains;
150
151 private:
152 bool valid_ = false;
153
154 int id_;
155 bool hasTagCount_ = false;
156 int tagCount_;
157 positioning adjectivePosition_ = positioning::undefined;
158 int notionId_;
159 int lemmaId_;
160 bool hasGroup_ = false;
161 int groupId_;
162
163 const database* db_;
164
165 mutable class notion notion_;
166 mutable class lemma lemma_;
167 mutable class group group_;
168
44 }; 169 };
45 170
46}; 171};
47 172
48#endif /* end of include guard: WORD_H_8FC89498 */ 173#endif /* end of include guard: WORD_H_DF91B1B4 */