summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--generator/schema.sql2
-rw-r--r--lib/binding.cpp71
-rw-r--r--lib/binding.h14
-rw-r--r--lib/database.cpp5
-rw-r--r--lib/database.h3
-rw-r--r--lib/enums.h5
-rw-r--r--lib/field.h61
-rw-r--r--lib/filter.cpp201
-rw-r--r--lib/filter.h8
-rw-r--r--lib/form.cpp6
-rw-r--r--lib/form.h2
-rw-r--r--lib/frame.cpp2
-rw-r--r--lib/lemma.cpp67
-rw-r--r--lib/lemma.h97
-rw-r--r--lib/pronunciation.cpp37
-rw-r--r--lib/pronunciation.h23
-rw-r--r--lib/query.h5
-rw-r--r--lib/statement.cpp232
-rw-r--r--lib/statement.h9
-rw-r--r--lib/token.cpp2
-rw-r--r--lib/verbly.h1
-rw-r--r--lib/word.cpp65
-rw-r--r--lib/word.h19
24 files changed, 574 insertions, 365 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ea601e..5d4f476 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ pkg_check_modules(sqlite3 sqlite3>=3.8.3 REQUIRED)
6 6
7set(CMAKE_BUILD_TYPE Debug) 7set(CMAKE_BUILD_TYPE Debug)
8 8
9add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/lemma.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/part.cpp) 9add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/part.cpp)
10set_property(TARGET verbly PROPERTY CXX_STANDARD 11) 10set_property(TARGET verbly PROPERTY CXX_STANDARD 11)
11set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) 11set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON)
12target_link_libraries(verbly ${sqlite3_LIBRARIES}) 12target_link_libraries(verbly ${sqlite3_LIBRARIES})
diff --git a/generator/schema.sql b/generator/schema.sql index 2ac658c..c07bf57 100644 --- a/generator/schema.sql +++ b/generator/schema.sql
@@ -178,6 +178,8 @@ CREATE TABLE `pronunciations` (
178 `stress` VARCHAR(64) NOT NULL 178 `stress` VARCHAR(64) NOT NULL
179); 179);
180 180
181CREATE INDEX `rhymes_with` ON `pronunciations`(`rhyme`);
182
181CREATE TABLE `forms_pronunciations` ( 183CREATE TABLE `forms_pronunciations` (
182 `form_id` INTEGER NOT NULL, 184 `form_id` INTEGER NOT NULL,
183 `pronunciation_id` INTEGER NOT NULL 185 `pronunciation_id` INTEGER NOT NULL
diff --git a/lib/binding.cpp b/lib/binding.cpp index 349cd6f..0b58785 100644 --- a/lib/binding.cpp +++ b/lib/binding.cpp
@@ -24,6 +24,14 @@ namespace verbly {
24 break; 24 break;
25 } 25 }
26 26
27 case type::field:
28 {
29 new(&field_.table_) std::string(other.field_.table_);
30 new(&field_.column_) std::string(other.field_.column_);
31
32 break;
33 }
34
27 case type::invalid: 35 case type::invalid:
28 { 36 {
29 break; 37 break;
@@ -50,6 +58,8 @@ namespace verbly {
50 type tempType = first.type_; 58 type tempType = first.type_;
51 int tempInteger; 59 int tempInteger;
52 std::string tempString; 60 std::string tempString;
61 std::string tempTable;
62 std::string tempColumn;
53 63
54 switch (first.type_) 64 switch (first.type_)
55 { 65 {
@@ -67,6 +77,14 @@ namespace verbly {
67 break; 77 break;
68 } 78 }
69 79
80 case type::field:
81 {
82 tempTable = std::move(first.field_.table_);
83 tempColumn = std::move(first.field_.column_);
84
85 break;
86 }
87
70 case type::invalid: 88 case type::invalid:
71 { 89 {
72 break; 90 break;
@@ -93,6 +111,14 @@ namespace verbly {
93 break; 111 break;
94 } 112 }
95 113
114 case type::field:
115 {
116 new(&first.field_.table_) std::string(std::move(second.field_.table_));
117 new(&first.field_.column_) std::string(std::move(second.field_.column_));
118
119 break;
120 }
121
96 case type::invalid: 122 case type::invalid:
97 { 123 {
98 break; 124 break;
@@ -119,6 +145,14 @@ namespace verbly {
119 break; 145 break;
120 } 146 }
121 147
148 case type::field:
149 {
150 new(&first.field_.table_) std::string(std::move(tempTable));
151 new(&first.field_.column_) std::string(std::move(tempColumn));
152
153 break;
154 }
155
122 case type::invalid: 156 case type::invalid:
123 { 157 {
124 break; 158 break;
@@ -138,6 +172,15 @@ namespace verbly {
138 break; 172 break;
139 } 173 }
140 174
175 case type::field:
176 {
177 using string_type = std::string;
178 field_.table_.~string_type();
179 field_.column_.~string_type();
180
181 break;
182 }
183
141 case type::integer: 184 case type::integer:
142 case type::invalid: 185 case type::invalid:
143 { 186 {
@@ -164,7 +207,7 @@ namespace verbly {
164 207
165 binding::binding(std::string arg) : type_(type::string) 208 binding::binding(std::string arg) : type_(type::string)
166 { 209 {
167 new(&string_) std::string(arg); 210 new(&string_) std::string(std::move(arg));
168 } 211 }
169 212
170 std::string binding::getString() const 213 std::string binding::getString() const
@@ -177,4 +220,30 @@ namespace verbly {
177 return string_; 220 return string_;
178 } 221 }
179 222
223 binding::binding(std::string table, std::string column) : type_(type::field)
224 {
225 new(&field_.table_) std::string(std::move(table));
226 new(&field_.column_) std::string(std::move(column));
227 }
228
229 std::string binding::getTable() const
230 {
231 if (type_ != type::field)
232 {
233 throw std::domain_error("binding::getTable called on non-field binding");
234 }
235
236 return field_.table_;
237 }
238
239 std::string binding::getColumn() const
240 {
241 if (type_ != type::field)
242 {
243 throw std::domain_error("binding::getColumn called on non-field binding");
244 }
245
246 return field_.column_;
247 }
248
180}; 249};
diff --git a/lib/binding.h b/lib/binding.h index 5578a09..5da1e71 100644 --- a/lib/binding.h +++ b/lib/binding.h
@@ -10,7 +10,8 @@ namespace verbly {
10 enum class type { 10 enum class type {
11 invalid, 11 invalid,
12 integer, 12 integer,
13 string 13 string,
14 field
14 }; 15 };
15 16
16 // Default constructor 17 // Default constructor
@@ -55,11 +56,22 @@ namespace verbly {
55 56
56 std::string getString() const; 57 std::string getString() const;
57 58
59 // Field
60
61 binding(std::string table, std::string column);
62
63 std::string getTable() const;
64 std::string getColumn() const;
65
58 private: 66 private:
59 67
60 union { 68 union {
61 int integer_; 69 int integer_;
62 std::string string_; 70 std::string string_;
71 struct {
72 std::string table_;
73 std::string column_;
74 } field_;
63 }; 75 };
64 76
65 type type_ = type::invalid; 77 type type_ = type::invalid;
diff --git a/lib/database.cpp b/lib/database.cpp index c7b37ec..a4d056d 100644 --- a/lib/database.cpp +++ b/lib/database.cpp
@@ -61,11 +61,6 @@ namespace verbly {
61 return query<part>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); 61 return query<part>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
62 } 62 }
63 63
64 query<lemma> database::lemmas(filter where, order sortOrder, int limit) const
65 {
66 return query<lemma>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
67 }
68
69 query<form> database::forms(filter where, order sortOrder, int limit) const 64 query<form> database::forms(filter where, order sortOrder, int limit) const
70 { 65 {
71 return query<form>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); 66 return query<form>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
diff --git a/lib/database.h b/lib/database.h index 5567061..ef5ff87 100644 --- a/lib/database.h +++ b/lib/database.h
@@ -9,7 +9,6 @@
9#include "word.h" 9#include "word.h"
10#include "frame.h" 10#include "frame.h"
11#include "part.h" 11#include "part.h"
12#include "lemma.h"
13#include "form.h" 12#include "form.h"
14#include "pronunciation.h" 13#include "pronunciation.h"
15#include "order.h" 14#include "order.h"
@@ -56,8 +55,6 @@ namespace verbly {
56 55
57 query<part> parts(filter where, order sortOrder = {}, int limit = 1) const; 56 query<part> parts(filter where, order sortOrder = {}, int limit = 1) const;
58 57
59 query<lemma> lemmas(filter where, order sortOrder = {}, int limit = 1) const;
60
61 query<form> forms(filter where, order sortOrder = {}, int limit = 1) const; 58 query<form> forms(filter where, order sortOrder = {}, int limit = 1) const;
62 59
63 query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const; 60 query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const;
diff --git a/lib/enums.h b/lib/enums.h index 2646fa4..55a1bda 100644 --- a/lib/enums.h +++ b/lib/enums.h
@@ -35,9 +35,8 @@ namespace verbly {
35 word = 1, 35 word = 1,
36 frame = 2, 36 frame = 2,
37 part = 3, 37 part = 3,
38 lemma = 4, 38 form = 4,
39 form = 5, 39 pronunciation = 5
40 pronunciation = 6
41 }; 40 };
42 41
43 enum class part_type { 42 enum class part_type {
diff --git a/lib/field.h b/lib/field.h index bec0618..f799900 100644 --- a/lib/field.h +++ b/lib/field.h
@@ -19,6 +19,7 @@ namespace verbly {
19 join, 19 join,
20 join_where, 20 join_where,
21 join_through, 21 join_through,
22 join_through_where,
22 hierarchal_join 23 hierarchal_join
23 }; 24 };
24 25
@@ -100,11 +101,11 @@ namespace verbly {
100 object obj, 101 object obj,
101 const char* name, 102 const char* name,
102 object joinWith, 103 object joinWith,
103 const field& conditionField, 104 const char* conditionColumn,
104 int conditionValue, 105 int conditionValue,
105 bool nullable = false) 106 bool nullable = false)
106 { 107 {
107 return field(obj, type::join_where, name, nullable, 0, joinWith, 0, 0, 0, &conditionField, conditionValue); 108 return field(obj, type::join_where, name, nullable, 0, joinWith, 0, 0, 0, conditionColumn, conditionValue);
108 } 109 }
109 110
110 static field joinThrough( 111 static field joinThrough(
@@ -129,6 +130,19 @@ namespace verbly {
129 return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, joinColumn, foreignJoinColumn); 130 return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, joinColumn, foreignJoinColumn);
130 } 131 }
131 132
133 static field joinThroughWhere(
134 object obj,
135 const char* name,
136 object joinWith,
137 const char* joinTable,
138 const char* foreignColumn,
139 const char* conditionColumn,
140 int conditionValue,
141 bool nullable = false)
142 {
143 return field(obj, type::join_through_where, name, nullable, joinTable, joinWith, foreignColumn, name, foreignColumn, conditionColumn, conditionValue);
144 }
145
132 static field selfJoin( 146 static field selfJoin(
133 object obj, 147 object obj,
134 const char* name, 148 const char* name,
@@ -166,6 +180,7 @@ namespace verbly {
166 return ((type_ == type::join) 180 return ((type_ == type::join)
167 || (type_ == type::join_where) 181 || (type_ == type::join_where)
168 || (type_ == type::join_through) 182 || (type_ == type::join_through)
183 || (type_ == type::join_through_where)
169 || (type_ == type::hierarchal_join)); 184 || (type_ == type::hierarchal_join));
170 } 185 }
171 186
@@ -195,7 +210,7 @@ namespace verbly {
195 { 210 {
196 return (type_ == type::hierarchal_join) 211 return (type_ == type::hierarchal_join)
197 ? object_ 212 ? object_
198 : ((type_ == type::join) || (type_ == type::join_where) || (type_ == type::join_through)) 213 : ((type_ == type::join) || (type_ == type::join_where) || (type_ == type::join_through) || (type_ == type::join_through_where))
199 ? joinObject_ 214 ? joinObject_
200 : throw std::domain_error("Non-join fields don't have join objects"); 215 : throw std::domain_error("Non-join fields don't have join objects");
201 } 216 }
@@ -205,40 +220,40 @@ namespace verbly {
205 const char* getForeignColumn() const 220 const char* getForeignColumn() const
206 { 221 {
207 // We ignore hierarchal joins because they are always self joins. 222 // We ignore hierarchal joins because they are always self joins.
208 return (type_ == type::join_through) 223 return ((type_ == type::join_through) || (type_ == type::join_through_where))
209 ? foreignColumn_ 224 ? foreignColumn_
210 : throw std::domain_error("Only many-to-many join fields have a foreign column"); 225 : throw std::domain_error("Only many-to-many join fields have a foreign column");
211 } 226 }
212 227
213 const char* getJoinColumn() const 228 const char* getJoinColumn() const
214 { 229 {
215 return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) 230 return ((type_ == type::join_through) || (type_ == type::join_through_where) || (type_ == type::hierarchal_join))
216 ? joinColumn_ 231 ? joinColumn_
217 : throw std::domain_error("Only many-to-many join fields have a join column"); 232 : throw std::domain_error("Only many-to-many join fields have a join column");
218 } 233 }
219 234
220 const char* getForeignJoinColumn() const 235 const char* getForeignJoinColumn() const
221 { 236 {
222 return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) 237 return ((type_ == type::join_through) || (type_ == type::join_through_where) || (type_ == type::hierarchal_join))
223 ? foreignJoinColumn_ 238 ? foreignJoinColumn_
224 : throw std::domain_error("Only many-to-many join fields have a foreign join column"); 239 : throw std::domain_error("Only many-to-many join fields have a foreign join column");
225 } 240 }
226 241
227 // Condition joins 242 // Condition joins
228 243
229 const field& getConditionField() const 244 const char* getConditionColumn() const
230 { 245 {
231 if (type_ == type::join_where) 246 if ((type_ == type::join_where) || (type_ == type::join_through_where))
232 { 247 {
233 return *conditionField_; 248 return conditionColumn_;
234 } else { 249 } else {
235 throw std::domain_error("Only condition join fields have a condition field"); 250 throw std::domain_error("Only condition join fields have a condition column");
236 } 251 }
237 } 252 }
238 253
239 int getConditionValue() const 254 int getConditionValue() const
240 { 255 {
241 return (type_ == type::join_where) 256 return ((type_ == type::join_where) || (type_ == type::join_through_where))
242 ? conditionValue_ 257 ? conditionValue_
243 : throw std::domain_error("Only condition join fields have a condition value"); 258 : throw std::domain_error("Only condition join fields have a condition value");
244 } 259 }
@@ -254,13 +269,8 @@ namespace verbly {
254 // table (hypernymy); however, they have different join columns. For 269 // table (hypernymy); however, they have different join columns. For
255 // condition joins, the condition field and condition value are also 270 // condition joins, the condition field and condition value are also
256 // significant. 271 // significant.
257 if (conditionField_) 272 return std::tie(object_, column_, table_, joinColumn_, conditionColumn_, conditionValue_)
258 { 273 < std::tie(other.object_, other.column_, other.table_, other.joinColumn_, other.conditionColumn_, other.conditionValue_);
259 return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_)
260 < std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_);
261 } else {
262 return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
263 }
264 } 274 }
265 275
266 // Equality 276 // Equality
@@ -268,13 +278,8 @@ namespace verbly {
268 bool operator==(const field& other) const 278 bool operator==(const field& other) const
269 { 279 {
270 // See operator<() for documentation. 280 // See operator<() for documentation.
271 if (conditionField_) 281 return std::tie(object_, column_, table_, joinColumn_, conditionColumn_, conditionValue_)
272 { 282 == std::tie(other.object_, other.column_, other.table_, other.joinColumn_, other.conditionColumn_, other.conditionValue_);
273 return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_)
274 == std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_);
275 } else {
276 return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
277 }
278 } 283 }
279 284
280 // Filter construction 285 // Filter construction
@@ -325,7 +330,7 @@ namespace verbly {
325 const char* foreignColumn = 0, 330 const char* foreignColumn = 0,
326 const char* joinColumn = 0, 331 const char* joinColumn = 0,
327 const char* foreignJoinColumn = 0, 332 const char* foreignJoinColumn = 0,
328 const field* conditionField = 0, 333 const char* conditionColumn = 0,
329 int conditionValue = 0) : 334 int conditionValue = 0) :
330 object_(obj), 335 object_(obj),
331 type_(datatype), 336 type_(datatype),
@@ -336,7 +341,7 @@ namespace verbly {
336 foreignColumn_(foreignColumn), 341 foreignColumn_(foreignColumn),
337 joinColumn_(joinColumn), 342 joinColumn_(joinColumn),
338 foreignJoinColumn_(foreignJoinColumn), 343 foreignJoinColumn_(foreignJoinColumn),
339 conditionField_(conditionField), 344 conditionColumn_(conditionColumn),
340 conditionValue_(conditionValue) 345 conditionValue_(conditionValue)
341 { 346 {
342 } 347 }
@@ -359,7 +364,7 @@ namespace verbly {
359 const char* foreignJoinColumn_ = 0; 364 const char* foreignJoinColumn_ = 0;
360 365
361 // Condition joins 366 // Condition joins
362 const field* conditionField_ = 0; 367 const char* conditionColumn_ = 0;
363 int conditionValue_ = 0; 368 int conditionValue_ = 0;
364 369
365 }; 370 };
diff --git a/lib/filter.cpp b/lib/filter.cpp index ecff8ac..c201618 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp
@@ -5,7 +5,6 @@
5#include "word.h" 5#include "word.h"
6#include "frame.h" 6#include "frame.h"
7#include "part.h" 7#include "part.h"
8#include "lemma.h"
9#include "form.h" 8#include "form.h"
10#include "pronunciation.h" 9#include "pronunciation.h"
11 10
@@ -73,6 +72,14 @@ namespace verbly {
73 72
74 break; 73 break;
75 } 74 }
75
76 case comparison::field_equals:
77 case comparison::field_does_not_equal:
78 {
79 new(&singleton_.compareField) field(other.singleton_.compareField);
80
81 break;
82 }
76 } 83 }
77 84
78 break; 85 break;
@@ -112,6 +119,7 @@ namespace verbly {
112 std::string tempStringValue; 119 std::string tempStringValue;
113 int tempIntValue; 120 int tempIntValue;
114 bool tempBoolValue; 121 bool tempBoolValue;
122 field tempCompareField;
115 std::list<filter> tempChildren; 123 std::list<filter> tempChildren;
116 bool tempOrlogic; 124 bool tempOrlogic;
117 125
@@ -173,6 +181,14 @@ namespace verbly {
173 181
174 break; 182 break;
175 } 183 }
184
185 case comparison::field_equals:
186 case comparison::field_does_not_equal:
187 {
188 tempCompareField = std::move(first.singleton_.compareField);
189
190 break;
191 }
176 } 192 }
177 193
178 break; 194 break;
@@ -249,6 +265,14 @@ namespace verbly {
249 265
250 break; 266 break;
251 } 267 }
268
269 case comparison::field_equals:
270 case comparison::field_does_not_equal:
271 {
272 new(&first.singleton_.compareField) field(std::move(second.singleton_.compareField));
273
274 break;
275 }
252 } 276 }
253 277
254 break; 278 break;
@@ -325,6 +349,14 @@ namespace verbly {
325 349
326 break; 350 break;
327 } 351 }
352
353 case comparison::field_equals:
354 case comparison::field_does_not_equal:
355 {
356 new(&second.singleton_.compareField) field(std::move(tempCompareField));
357
358 break;
359 }
328 } 360 }
329 361
330 break; 362 break;
@@ -391,6 +423,14 @@ namespace verbly {
391 423
392 break; 424 break;
393 } 425 }
426
427 case comparison::field_equals:
428 case comparison::field_does_not_equal:
429 {
430 singleton_.compareField.~field();
431
432 break;
433 }
394 } 434 }
395 435
396 break; 436 break;
@@ -446,6 +486,8 @@ namespace verbly {
446 case comparison::does_not_match: 486 case comparison::does_not_match:
447 case comparison::hierarchally_matches: 487 case comparison::hierarchally_matches:
448 case comparison::does_not_hierarchally_match: 488 case comparison::does_not_hierarchally_match:
489 case comparison::field_equals:
490 case comparison::field_does_not_equal:
449 { 491 {
450 throw std::invalid_argument("Invalid comparison for integer field"); 492 throw std::invalid_argument("Invalid comparison for integer field");
451 } 493 }
@@ -490,6 +532,8 @@ namespace verbly {
490 case comparison::does_not_match: 532 case comparison::does_not_match:
491 case comparison::hierarchally_matches: 533 case comparison::hierarchally_matches:
492 case comparison::does_not_hierarchally_match: 534 case comparison::does_not_hierarchally_match:
535 case comparison::field_equals:
536 case comparison::field_does_not_equal:
493 { 537 {
494 throw std::invalid_argument("Invalid comparison for string field"); 538 throw std::invalid_argument("Invalid comparison for string field");
495 } 539 }
@@ -534,6 +578,8 @@ namespace verbly {
534 case comparison::does_not_match: 578 case comparison::does_not_match:
535 case comparison::hierarchally_matches: 579 case comparison::hierarchally_matches:
536 case comparison::does_not_hierarchally_match: 580 case comparison::does_not_hierarchally_match:
581 case comparison::field_equals:
582 case comparison::field_does_not_equal:
537 { 583 {
538 throw std::invalid_argument("Invalid comparison for boolean field"); 584 throw std::invalid_argument("Invalid comparison for boolean field");
539 } 585 }
@@ -576,6 +622,8 @@ namespace verbly {
576 case comparison::does_not_match: 622 case comparison::does_not_match:
577 case comparison::hierarchally_matches: 623 case comparison::hierarchally_matches:
578 case comparison::does_not_hierarchally_match: 624 case comparison::does_not_hierarchally_match:
625 case comparison::field_equals:
626 case comparison::field_does_not_equal:
579 { 627 {
580 throw std::invalid_argument("Incorrect constructor for given comparison"); 628 throw std::invalid_argument("Incorrect constructor for given comparison");
581 } 629 }
@@ -596,6 +644,7 @@ namespace verbly {
596 case field::type::join: 644 case field::type::join:
597 case field::type::join_where: 645 case field::type::join_where:
598 case field::type::join_through: 646 case field::type::join_through:
647 case field::type::join_through_where:
599 { 648 {
600 switch (filterType) 649 switch (filterType)
601 { 650 {
@@ -624,6 +673,8 @@ namespace verbly {
624 case comparison::is_not_null: 673 case comparison::is_not_null:
625 case comparison::hierarchally_matches: 674 case comparison::hierarchally_matches:
626 case comparison::does_not_hierarchally_match: 675 case comparison::does_not_hierarchally_match:
676 case comparison::field_equals:
677 case comparison::field_does_not_equal:
627 { 678 {
628 throw std::invalid_argument("Incorrect constructor for given comparison"); 679 throw std::invalid_argument("Incorrect constructor for given comparison");
629 } 680 }
@@ -661,6 +712,8 @@ namespace verbly {
661 case comparison::is_not_null: 712 case comparison::is_not_null:
662 case comparison::matches: 713 case comparison::matches:
663 case comparison::does_not_match: 714 case comparison::does_not_match:
715 case comparison::field_equals:
716 case comparison::field_does_not_equal:
664 { 717 {
665 throw std::invalid_argument("Incorrect constructor for given comparison"); 718 throw std::invalid_argument("Incorrect constructor for given comparison");
666 } 719 }
@@ -679,6 +732,57 @@ namespace verbly {
679 } 732 }
680 } 733 }
681 734
735 filter::filter(
736 field filterField,
737 comparison filterType,
738 field compareField) :
739 type_(type::singleton)
740 {
741 switch (filterType)
742 {
743 case comparison::field_equals:
744 case comparison::field_does_not_equal:
745 {
746 if (filterField.getType() != compareField.getType())
747 {
748 throw std::invalid_argument("Cannot compare two fields of different types");
749 }
750
751 if (filterField.isJoin())
752 {
753 throw std::domain_error("Cannot compare join fields");
754 }
755
756 new(&singleton_.filterField) field(std::move(filterField));
757 singleton_.filterType = filterType;
758 new(&singleton_.compareField) field(std::move(compareField));
759
760 break;
761 }
762
763 case comparison::int_equals:
764 case comparison::int_does_not_equal:
765 case comparison::int_is_at_least:
766 case comparison::int_is_greater_than:
767 case comparison::int_is_at_most:
768 case comparison::int_is_less_than:
769 case comparison::boolean_equals:
770 case comparison::string_equals:
771 case comparison::string_does_not_equal:
772 case comparison::string_is_like:
773 case comparison::string_is_not_like:
774 case comparison::is_null:
775 case comparison::is_not_null:
776 case comparison::matches:
777 case comparison::does_not_match:
778 case comparison::hierarchally_matches:
779 case comparison::does_not_hierarchally_match:
780 {
781 throw std::domain_error("Incorrect constructor for given comparison");
782 }
783 }
784 }
785
682 field filter::getField() const 786 field filter::getField() const
683 { 787 {
684 if (type_ == type::singleton) 788 if (type_ == type::singleton)
@@ -726,6 +830,8 @@ namespace verbly {
726 case comparison::boolean_equals: 830 case comparison::boolean_equals:
727 case comparison::is_null: 831 case comparison::is_null:
728 case comparison::is_not_null: 832 case comparison::is_not_null:
833 case comparison::field_equals:
834 case comparison::field_does_not_equal:
729 { 835 {
730 throw std::domain_error("This filter does not have a join condition"); 836 throw std::domain_error("This filter does not have a join condition");
731 } 837 }
@@ -762,6 +868,8 @@ namespace verbly {
762 case comparison::does_not_match: 868 case comparison::does_not_match:
763 case comparison::hierarchally_matches: 869 case comparison::hierarchally_matches:
764 case comparison::does_not_hierarchally_match: 870 case comparison::does_not_hierarchally_match:
871 case comparison::field_equals:
872 case comparison::field_does_not_equal:
765 { 873 {
766 throw std::domain_error("This filter does not have a string argument"); 874 throw std::domain_error("This filter does not have a string argument");
767 } 875 }
@@ -798,6 +906,8 @@ namespace verbly {
798 case comparison::does_not_match: 906 case comparison::does_not_match:
799 case comparison::hierarchally_matches: 907 case comparison::hierarchally_matches:
800 case comparison::does_not_hierarchally_match: 908 case comparison::does_not_hierarchally_match:
909 case comparison::field_equals:
910 case comparison::field_does_not_equal:
801 { 911 {
802 throw std::domain_error("This filter does not have an integer argument"); 912 throw std::domain_error("This filter does not have an integer argument");
803 } 913 }
@@ -817,6 +927,47 @@ namespace verbly {
817 } 927 }
818 } 928 }
819 929
930 field filter::getCompareField() const
931 {
932 if (type_ != type::singleton)
933 {
934 throw std::domain_error("This filter does not have a compare field");
935 }
936
937 switch (singleton_.filterType)
938 {
939 case comparison::field_equals:
940 case comparison::field_does_not_equal:
941 {
942 return singleton_.compareField;
943
944 break;
945 }
946
947 case comparison::int_equals:
948 case comparison::int_does_not_equal:
949 case comparison::int_is_at_least:
950 case comparison::int_is_greater_than:
951 case comparison::int_is_at_most:
952 case comparison::int_is_less_than:
953 case comparison::boolean_equals:
954 case comparison::string_equals:
955 case comparison::string_does_not_equal:
956 case comparison::string_is_like:
957 case comparison::string_is_not_like:
958 case comparison::is_null:
959 case comparison::is_not_null:
960 case comparison::matches:
961 case comparison::does_not_match:
962 case comparison::hierarchally_matches:
963 case comparison::does_not_hierarchally_match:
964 {
965 throw std::domain_error("This filter doesn't have a compare field");
966 }
967 }
968
969 }
970
820 filter::filter(bool orlogic) : type_(type::group) 971 filter::filter(bool orlogic) : type_(type::group)
821 { 972 {
822 new(&group_.children) std::list<filter>(); 973 new(&group_.children) std::list<filter>();
@@ -970,6 +1121,16 @@ namespace verbly {
970 { 1121 {
971 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join); 1122 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join);
972 } 1123 }
1124
1125 case comparison::field_equals:
1126 {
1127 return filter(singleton_.filterField, comparison::field_does_not_equal, singleton_.compareField);
1128 }
1129
1130 case comparison::field_does_not_equal:
1131 {
1132 return filter(singleton_.filterField, comparison::field_equals, singleton_.compareField);
1133 }
973 } 1134 }
974 } 1135 }
975 1136
@@ -1111,7 +1272,6 @@ namespace verbly {
1111 case object::word: 1272 case object::word:
1112 case object::frame: 1273 case object::frame:
1113 case object::part: 1274 case object::part:
1114 case object::lemma:
1115 case object::form: 1275 case object::form:
1116 case object::pronunciation: 1276 case object::pronunciation:
1117 { 1277 {
@@ -1141,11 +1301,10 @@ namespace verbly {
1141 return (verbly::word::frames %= *this); 1301 return (verbly::word::frames %= *this);
1142 } 1302 }
1143 1303
1144 case object::lemma:
1145 case object::form: 1304 case object::form:
1146 case object::pronunciation: 1305 case object::pronunciation:
1147 { 1306 {
1148 return (verbly::word::lemmas %= *this); 1307 return (verbly::word::forms(inflection::base) %= *this);
1149 } 1308 }
1150 } 1309 }
1151 1310
@@ -1161,7 +1320,6 @@ namespace verbly {
1161 1320
1162 case object::notion: 1321 case object::notion:
1163 case object::word: 1322 case object::word:
1164 case object::lemma:
1165 case object::form: 1323 case object::form:
1166 case object::pronunciation: 1324 case object::pronunciation:
1167 { 1325 {
@@ -1188,7 +1346,6 @@ namespace verbly {
1188 case object::notion: 1346 case object::notion:
1189 case object::word: 1347 case object::word:
1190 case object::frame: 1348 case object::frame:
1191 case object::lemma:
1192 case object::form: 1349 case object::form:
1193 case object::pronunciation: 1350 case object::pronunciation:
1194 { 1351 {
@@ -1197,32 +1354,6 @@ namespace verbly {
1197 } 1354 }
1198 } 1355 }
1199 1356
1200 case object::lemma:
1201 {
1202 switch (singleton_.filterField.getObject())
1203 {
1204 case object::notion:
1205 case object::word:
1206 case object::frame:
1207 case object::part:
1208 {
1209 return verbly::lemma::words %= *this;
1210 }
1211
1212 case object::undefined:
1213 case object::lemma:
1214 {
1215 return *this;
1216 }
1217
1218 case object::form:
1219 case object::pronunciation:
1220 {
1221 return (verbly::lemma::forms(inflection::base) %= *this);
1222 }
1223 }
1224 }
1225
1226 case object::form: 1357 case object::form:
1227 { 1358 {
1228 switch (singleton_.filterField.getObject()) 1359 switch (singleton_.filterField.getObject())
@@ -1231,9 +1362,8 @@ namespace verbly {
1231 case object::word: 1362 case object::word:
1232 case object::frame: 1363 case object::frame:
1233 case object::part: 1364 case object::part:
1234 case object::lemma:
1235 { 1365 {
1236 return verbly::form::lemmas %= *this; 1366 return verbly::form::words(inflection::base) %= *this;
1237 } 1367 }
1238 1368
1239 case object::undefined: 1369 case object::undefined:
@@ -1257,7 +1387,6 @@ namespace verbly {
1257 case object::word: 1387 case object::word:
1258 case object::frame: 1388 case object::frame:
1259 case object::part: 1389 case object::part:
1260 case object::lemma:
1261 case object::form: 1390 case object::form:
1262 { 1391 {
1263 return verbly::pronunciation::forms %= *this; 1392 return verbly::pronunciation::forms %= *this;
@@ -1354,6 +1483,8 @@ namespace verbly {
1354 case comparison::string_is_not_like: 1483 case comparison::string_is_not_like:
1355 case comparison::is_null: 1484 case comparison::is_null:
1356 case comparison::is_not_null: 1485 case comparison::is_not_null:
1486 case comparison::field_equals:
1487 case comparison::field_does_not_equal:
1357 { 1488 {
1358 result += std::move(normalized); 1489 result += std::move(normalized);
1359 1490
diff --git a/lib/filter.h b/lib/filter.h index dcadf95..a12a822 100644 --- a/lib/filter.h +++ b/lib/filter.h
@@ -34,7 +34,9 @@ namespace verbly {
34 matches, 34 matches,
35 does_not_match, 35 does_not_match,
36 hierarchally_matches, 36 hierarchally_matches,
37 does_not_hierarchally_match 37 does_not_hierarchally_match,
38 field_equals,
39 field_does_not_equal
38 }; 40 };
39 41
40 // Copy and move constructors 42 // Copy and move constructors
@@ -72,6 +74,7 @@ namespace verbly {
72 filter(field filterField, comparison filterType, bool filterValue); 74 filter(field filterField, comparison filterType, bool filterValue);
73 filter(field filterField, comparison filterType); 75 filter(field filterField, comparison filterType);
74 filter(field joinOn, comparison filterType, filter joinCondition); 76 filter(field joinOn, comparison filterType, filter joinCondition);
77 filter(field filterField, comparison filterType, field compareField);
75 78
76 field getField() const; 79 field getField() const;
77 80
@@ -85,6 +88,8 @@ namespace verbly {
85 88
86 bool getBooleanArgument() const; 89 bool getBooleanArgument() const;
87 90
91 field getCompareField() const;
92
88 // Group 93 // Group
89 94
90 explicit filter(bool orlogic); 95 explicit filter(bool orlogic);
@@ -129,6 +134,7 @@ namespace verbly {
129 std::string stringValue; 134 std::string stringValue;
130 int intValue; 135 int intValue;
131 bool boolValue; 136 bool boolValue;
137 field compareField;
132 }; 138 };
133 } singleton_; 139 } singleton_;
134 struct { 140 struct {
diff --git a/lib/form.cpp b/lib/form.cpp index 4548582..2f9509f 100644 --- a/lib/form.cpp +++ b/lib/form.cpp
@@ -17,9 +17,13 @@ namespace verbly {
17 const field form::complexity = field::integerField(object::form, "complexity"); 17 const field form::complexity = field::integerField(object::form, "complexity");
18 const field form::proper = field::booleanField(object::form, "proper"); 18 const field form::proper = field::booleanField(object::form, "proper");
19 19
20 const field form::lemmas = field::joinField(object::form, "form_id", object::lemma);
21 const field form::pronunciations = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id"); 20 const field form::pronunciations = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id");
22 21
22 field form::words(inflection category)
23 {
24 return field::joinThroughWhere(object::form, "form_id", object::word, "lemmas_forms", "lemma_id", "category", static_cast<int>(category));
25 }
26
23 form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 27 form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
24 { 28 {
25 id_ = sqlite3_column_int(row, 0); 29 id_ = sqlite3_column_int(row, 0);
diff --git a/lib/form.h b/lib/form.h index a05d015..fe0886c 100644 --- a/lib/form.h +++ b/lib/form.h
@@ -104,7 +104,7 @@ namespace verbly {
104 104
105 // Relationships to other objects 105 // Relationships to other objects
106 106
107 static const field lemmas; 107 static field words(inflection category);
108 108
109 static const field pronunciations; 109 static const field pronunciations;
110 110
diff --git a/lib/frame.cpp b/lib/frame.cpp index b5ba914..2351973 100644 --- a/lib/frame.cpp +++ b/lib/frame.cpp
@@ -21,7 +21,7 @@ namespace verbly {
21 21
22 field frame::parts(int index) 22 field frame::parts(int index)
23 { 23 {
24 return field::joinWhere(object::frame, "frame_id", object::part, part::index, index); 24 return field::joinWhere(object::frame, "frame_id", object::part, "part_index", index);
25 } 25 }
26 26
27 frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 27 frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
diff --git a/lib/lemma.cpp b/lib/lemma.cpp deleted file mode 100644 index ea7b0ea..0000000 --- a/lib/lemma.cpp +++ /dev/null
@@ -1,67 +0,0 @@
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 const field lemma::inflectionCategory = field::integerField(object::lemma, "category");
14
15 const field lemma::words = field::joinField(object::lemma, "lemma_id", object::word);
16
17 field lemma::forms(inflection category)
18 {
19 return field::joinWhere(object::lemma, "form_id", object::form, inflectionCategory, static_cast<int>(category));
20 }
21
22 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
23 {
24 id_ = sqlite3_column_int(row, 0);
25 }
26
27 const form& lemma::getBaseForm() const
28 {
29 if (!valid_)
30 {
31 throw std::domain_error("Bad access to uninitialized lemma");
32 }
33
34 if (!forms_.count(inflection::base))
35 {
36 initializeForm(inflection::base);
37 }
38
39 return forms_.at(inflection::base).front();
40 }
41
42 bool lemma::hasInflection(inflection category) const
43 {
44 return !getInflections(category).empty();
45 }
46
47 const std::vector<form>& lemma::getInflections(inflection category) const
48 {
49 if (!valid_)
50 {
51 throw std::domain_error("Bad access to uninitialized lemma");
52 }
53
54 if (!forms_.count(category))
55 {
56 initializeForm(category);
57 }
58
59 return forms_.at(category);
60 }
61
62 void lemma::initializeForm(inflection infl) const
63 {
64 forms_[infl] = db_->forms(form::lemmas %= ((inflectionCategory == infl) && *this), verbly::form::id, -1).all();
65 }
66
67};
diff --git a/lib/lemma.h b/lib/lemma.h deleted file mode 100644 index bba5572..0000000 --- a/lib/lemma.h +++ /dev/null
@@ -1,97 +0,0 @@
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 "form.h"
10#include "enums.h"
11#include "filter.h"
12
13struct sqlite3_stmt;
14
15namespace verbly {
16
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 words;
76
77 static field forms(inflection category);
78
79 private:
80
81 void initializeForm(inflection category) const;
82
83 bool valid_ = false;
84
85 int id_;
86
87 mutable std::map<inflection, std::vector<form>> forms_;
88
89 const database* db_;
90
91 static const field inflectionCategory;
92
93 };
94
95};
96
97#endif /* end of include guard: LEMMA_H_0A180D30 */
diff --git a/lib/pronunciation.cpp b/lib/pronunciation.cpp index 3ddb1c5..fa471ec 100644 --- a/lib/pronunciation.cpp +++ b/lib/pronunciation.cpp
@@ -1,7 +1,6 @@
1#include "pronunciation.h" 1#include "pronunciation.h"
2#include <sqlite3.h> 2#include <sqlite3.h>
3#include "form.h" 3#include "form.h"
4#include "lemma.h"
5#include "word.h" 4#include "word.h"
6#include "util.h" 5#include "util.h"
7 6
@@ -20,6 +19,9 @@ namespace verbly {
20 const field pronunciation::prerhyme = field::stringField(object::pronunciation, "prerhyme", true); 19 const field pronunciation::prerhyme = field::stringField(object::pronunciation, "prerhyme", true);
21 const field pronunciation::rhyme = field::stringField(object::pronunciation, "rhyme", true); 20 const field pronunciation::rhyme = field::stringField(object::pronunciation, "rhyme", true);
22 21
22 const field pronunciation::rhymes_field::rhymeJoin = field::joinField(object::pronunciation, "rhyme", object::pronunciation);
23 const pronunciation::rhymes_field pronunciation::rhymes = {};
24
23 pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 25 pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
24 { 26 {
25 id_ = sqlite3_column_int(row, 0); 27 id_ = sqlite3_column_int(row, 0);
@@ -39,31 +41,22 @@ namespace verbly {
39 } 41 }
40 } 42 }
41 43
42 filter pronunciation::rhymesWith(const pronunciation& arg) 44 filter pronunciation::rhymes_field::operator%=(filter joinCondition) const
43 { 45 {
44 return (prerhyme != arg.getPrerhyme()) && (rhyme == arg.getRhyme()); 46 return (rhymeJoin %= (
45 } 47 joinCondition
46 48 && filter(
47 /*filter pronunciation::rhymesWith(const class form& arg) 49 verbly::pronunciation::prerhyme,
48 { 50 filter::comparison::field_does_not_equal,
49 filter result; 51 verbly::pronunciation::prerhyme)));
50
51 for (const pronunciation& p : arg.getPronunciations())
52 {
53 result |= rhymesWith(p);
54 }
55
56 return result;
57 } 52 }
58 53
59 filter pronunciation::rhymesWith(const lemma& arg) 54 pronunciation::rhymes_field::operator filter() const
60 { 55 {
61 return rhymesWith(arg.getBaseForm()); 56 return (rhymeJoin %= filter(
57 verbly::pronunciation::prerhyme,
58 filter::comparison::field_does_not_equal,
59 verbly::pronunciation::prerhyme));
62 } 60 }
63 61
64 filter pronunciation::rhymesWith(const word& arg)
65 {
66 return rhymesWith(arg.getLemma());
67 }*/
68
69}; 62};
diff --git a/lib/pronunciation.h b/lib/pronunciation.h index e171fe8..1162360 100644 --- a/lib/pronunciation.h +++ b/lib/pronunciation.h
@@ -12,7 +12,6 @@ struct sqlite3_stmt;
12namespace verbly { 12namespace verbly {
13 13
14 class form; 14 class form;
15 class lemma;
16 class word; 15 class word;
17 class database; 16 class database;
18 17
@@ -131,14 +130,26 @@ namespace verbly {
131 return (id == id_); 130 return (id == id_);
132 } 131 }
133 132
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 133 // Relationships to other objects
140 134
141 static const field forms; 135 static const field forms;
136
137 // Rhyming relationship
138
139 class rhymes_field {
140 public:
141
142 filter operator%=(filter joinCondition) const;
143
144 operator filter() const;
145
146 private:
147
148 static const field rhymeJoin;
149
150 };
151
152 static const rhymes_field rhymes;
142 153
143 private: 154 private:
144 bool valid_ = false; 155 bool valid_ = false;
diff --git a/lib/query.h b/lib/query.h index 75651f6..0f490ed 100644 --- a/lib/query.h +++ b/lib/query.h
@@ -81,6 +81,11 @@ namespace verbly {
81 { 81 {
82 throw std::logic_error("Cannot use invalid bindings"); 82 throw std::logic_error("Cannot use invalid bindings");
83 } 83 }
84
85 case binding::type::field:
86 {
87 throw std::logic_error("Compare field binding made it past statement generation");
88 }
84 } 89 }
85 90
86 i++; 91 i++;
diff --git a/lib/statement.cpp b/lib/statement.cpp index 562eef2..b892cab 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp
@@ -3,13 +3,6 @@
3#include <utility> 3#include <utility>
4#include "filter.h" 4#include "filter.h"
5#include "util.h" 5#include "util.h"
6#include "notion.h"
7#include "word.h"
8#include "frame.h"
9#include "part.h"
10#include "lemma.h"
11#include "form.h"
12#include "pronunciation.h"
13#include "order.h" 6#include "order.h"
14 7
15namespace verbly { 8namespace verbly {
@@ -17,7 +10,7 @@ namespace verbly {
17 statement::statement( 10 statement::statement(
18 object context, 11 object context,
19 filter queryFilter) : 12 filter queryFilter) :
20 statement(getTableForContext(context), queryFilter.compact().normalize(context)) 13 statement(context, getTableForContext(context), queryFilter.compact().normalize(context))
21 { 14 {
22 } 15 }
23 16
@@ -104,24 +97,29 @@ namespace verbly {
104 queryStream << " WHERE "; 97 queryStream << " WHERE ";
105 queryStream << topCondition_.flatten().toSql(true, debug); 98 queryStream << topCondition_.flatten().toSql(true, debug);
106 } 99 }
107 100
101 queryStream << " GROUP BY ";
102 queryStream << topTable_;
103 queryStream << ".";
104 queryStream << select.front();
105
108 queryStream << " ORDER BY "; 106 queryStream << " ORDER BY ";
109 107
110 switch (sortOrder.getType()) 108 switch (sortOrder.getType())
111 { 109 {
112 case order::type::random: 110 case order::type::random:
113 { 111 {
114 queryStream << "RANDOM()"; 112 queryStream << "RANDOM()";
115 113
116 break; 114 break;
117 } 115 }
118 116
119 case order::type::field: 117 case order::type::field:
120 { 118 {
121 queryStream << topTable_; 119 queryStream << topTable_;
122 queryStream << "."; 120 queryStream << ".";
123 queryStream << sortOrder.getSortField().getColumn(); 121 queryStream << sortOrder.getSortField().getColumn();
124 122
125 break; 123 break;
126 } 124 }
127 } 125 }
@@ -156,10 +154,12 @@ namespace verbly {
156 } 154 }
157 155
158 statement::statement( 156 statement::statement(
157 object context,
159 std::string tableName, 158 std::string tableName,
160 filter clause, 159 filter clause,
161 int nextTableId, 160 int nextTableId,
162 int nextWithId) : 161 int nextWithId) :
162 context_(context),
163 nextTableId_(nextTableId), 163 nextTableId_(nextTableId),
164 nextWithId_(nextWithId), 164 nextWithId_(nextWithId),
165 topTable_(instantiateTable(std::move(tableName))), 165 topTable_(instantiateTable(std::move(tableName))),
@@ -266,6 +266,16 @@ namespace verbly {
266 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument()); 266 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument());
267 } 267 }
268 268
269 case filter::comparison::field_equals:
270 {
271 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject());
272 }
273
274 case filter::comparison::field_does_not_equal:
275 {
276 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject());
277 }
278
269 case filter::comparison::matches: 279 case filter::comparison::matches:
270 case filter::comparison::does_not_match: 280 case filter::comparison::does_not_match:
271 case filter::comparison::hierarchally_matches: 281 case filter::comparison::hierarchally_matches:
@@ -281,26 +291,29 @@ namespace verbly {
281 { 291 {
282 // First, figure out what table we need to join against. 292 // First, figure out what table we need to join against.
283 std::string joinTableName; 293 std::string joinTableName;
294 object joinContext = object::undefined;
284 if (clause.getField().hasTable()) 295 if (clause.getField().hasTable())
285 { 296 {
286 joinTableName = clause.getField().getTable(); 297 joinTableName = clause.getField().getTable();
287 } else { 298 } else {
288 joinTableName = getTableForContext(clause.getField().getJoinObject()); 299 joinContext = clause.getField().getJoinObject();
300 joinTableName = getTableForContext(joinContext);
289 } 301 }
290 302
291 filter joinCondition = clause.getJoinCondition(); 303 filter joinCondition = clause.getJoinCondition();
292 304
293 // If this is a condition join, we need to add the field join 305 // If this is a condition join, we need to add the field join
294 // condition to the clause. 306 // condition to the clause.
295 if (clause.getField().getType() == field::type::join_where) 307 if (clause.getField().getType() == field::type::join_where)
296 { 308 {
297 joinCondition &= (clause.getField().getConditionField() == clause.getField().getConditionValue()); 309 joinCondition &= (field::integerField(joinTableName.c_str(), clause.getField().getConditionColumn()) == clause.getField().getConditionValue());
298 } 310 }
299 311
300 // Recursively parse the subquery, and therefore obtain an 312 // Recursively parse the subquery, and therefore obtain an
301 // instantiated table to join against, as well as any joins or CTEs 313 // instantiated table to join against, as well as any joins or CTEs
302 // that the subquery may require to function. 314 // that the subquery may require to function.
303 statement joinStmt( 315 statement joinStmt(
316 joinContext,
304 joinTableName, 317 joinTableName,
305 std::move(joinCondition).normalize(clause.getField().getJoinObject()), 318 std::move(joinCondition).normalize(clause.getField().getJoinObject()),
306 nextTableId_, 319 nextTableId_,
@@ -368,11 +381,13 @@ namespace verbly {
368 } 381 }
369 382
370 case field::type::join_through: 383 case field::type::join_through:
384 case field::type::join_through_where:
371 { 385 {
372 // Recursively parse the subquery, and therefore obtain an 386 // Recursively parse the subquery, and therefore obtain an
373 // instantiated table to join against, as well as any joins or CTEs 387 // instantiated table to join against, as well as any joins or CTEs
374 // that the subquery may require to function. 388 // that the subquery may require to function.
375 statement joinStmt( 389 statement joinStmt(
390 clause.getField().getJoinObject(),
376 getTableForContext(clause.getField().getJoinObject()), 391 getTableForContext(clause.getField().getJoinObject()),
377 clause.getJoinCondition().normalize(clause.getField().getJoinObject()), 392 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
378 nextTableId_, 393 nextTableId_,
@@ -424,6 +439,17 @@ namespace verbly {
424 std::list<join> cteJoins = std::move(joinStmt.joins_); 439 std::list<join> cteJoins = std::move(joinStmt.joins_);
425 condition cteCondition = integrate(std::move(joinStmt), true); 440 condition cteCondition = integrate(std::move(joinStmt), true);
426 441
442 // If this is a condition join, add the condition.
443 if (clause.getField().getType() == field::type::join_through_where)
444 {
445 cteCondition &=
446 condition(
447 throughTable,
448 clause.getField().getConditionColumn(),
449 condition::comparison::equals,
450 clause.getField().getConditionValue());
451 }
452
427 withs_.emplace_back( 453 withs_.emplace_back(
428 std::move(withName), 454 std::move(withName),
429 clause.getField(), 455 clause.getField(),
@@ -453,7 +479,7 @@ namespace verbly {
453 joins_.emplace_back( 479 joins_.emplace_back(
454 false, 480 false,
455 getTableForContext(clause.getField().getJoinObject()), 481 getTableForContext(clause.getField().getJoinObject()),
456 std::move(throughTable), 482 throughTable,
457 clause.getField().getForeignJoinColumn(), 483 clause.getField().getForeignJoinColumn(),
458 std::move(joinTable), 484 std::move(joinTable),
459 clause.getField().getForeignColumn()); 485 clause.getField().getForeignColumn());
@@ -461,7 +487,20 @@ namespace verbly {
461 // Integrate the subquery's table mappings, joins, and CTEs into 487 // Integrate the subquery's table mappings, joins, and CTEs into
462 // this statement, and return the subquery condition as our 488 // this statement, and return the subquery condition as our
463 // condition. 489 // condition.
464 return integrate(std::move(joinStmt)); 490 condition resultCond = integrate(std::move(joinStmt));
491
492 // If this is a condition join, add the condition.
493 if (clause.getField().getType() == field::type::join_through_where)
494 {
495 resultCond &=
496 condition(
497 throughTable,
498 clause.getField().getConditionColumn(),
499 condition::comparison::equals,
500 clause.getField().getConditionValue());
501 }
502
503 return std::move(resultCond);
465 } 504 }
466 } 505 }
467 506
@@ -491,6 +530,7 @@ namespace verbly {
491 530
492 // Recursively parse the subquery in order to create the CTE. 531 // Recursively parse the subquery in order to create the CTE.
493 statement withStmt( 532 statement withStmt(
533 clause.getField().getObject(),
494 getTableForContext(clause.getField().getObject()), 534 getTableForContext(clause.getField().getObject()),
495 clause.getJoinCondition().normalize(clause.getField().getObject()), 535 clause.getJoinCondition().normalize(clause.getField().getObject()),
496 nextTableId_, 536 nextTableId_,
@@ -593,7 +633,7 @@ namespace verbly {
593 nextTableId_ = subStmt.nextTableId_; 633 nextTableId_ = subStmt.nextTableId_;
594 nextWithId_ = subStmt.nextWithId_; 634 nextWithId_ = subStmt.nextWithId_;
595 635
596 return subStmt.topCondition_; 636 return subStmt.topCondition_.resolveCompareFields(context_, topTable_);
597 } 637 }
598 638
599 std::ostream& operator<<(std::ostream& oss, const statement::join& j) 639 std::ostream& operator<<(std::ostream& oss, const statement::join& j)
@@ -637,6 +677,7 @@ namespace verbly {
637 new(&singleton_.column_) std::string(other.singleton_.column_); 677 new(&singleton_.column_) std::string(other.singleton_.column_);
638 singleton_.comparison_ = other.singleton_.comparison_; 678 singleton_.comparison_ = other.singleton_.comparison_;
639 new(&singleton_.value_) binding(other.singleton_.value_); 679 new(&singleton_.value_) binding(other.singleton_.value_);
680 singleton_.parentObject_ = other.singleton_.parentObject_;
640 681
641 break; 682 break;
642 } 683 }
@@ -673,6 +714,7 @@ namespace verbly {
673 std::string tempColumn; 714 std::string tempColumn;
674 condition::comparison tempComparison; 715 condition::comparison tempComparison;
675 binding tempBinding; 716 binding tempBinding;
717 object tempParentObject;
676 std::list<condition> tempChildren; 718 std::list<condition> tempChildren;
677 bool tempOrlogic; 719 bool tempOrlogic;
678 720
@@ -689,6 +731,7 @@ namespace verbly {
689 tempColumn = std::move(first.singleton_.column_); 731 tempColumn = std::move(first.singleton_.column_);
690 tempComparison = first.singleton_.comparison_; 732 tempComparison = first.singleton_.comparison_;
691 tempBinding = std::move(first.singleton_.value_); 733 tempBinding = std::move(first.singleton_.value_);
734 tempParentObject = first.singleton_.parentObject_;
692 735
693 break; 736 break;
694 } 737 }
@@ -719,6 +762,7 @@ namespace verbly {
719 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_)); 762 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_));
720 first.singleton_.comparison_ = second.singleton_.comparison_; 763 first.singleton_.comparison_ = second.singleton_.comparison_;
721 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_)); 764 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_));
765 first.singleton_.parentObject_ = second.singleton_.parentObject_;
722 766
723 break; 767 break;
724 } 768 }
@@ -749,6 +793,7 @@ namespace verbly {
749 new(&second.singleton_.column_) std::string(std::move(tempColumn)); 793 new(&second.singleton_.column_) std::string(std::move(tempColumn));
750 second.singleton_.comparison_ = tempComparison; 794 second.singleton_.comparison_ = tempComparison;
751 new(&second.singleton_.value_) binding(std::move(tempBinding)); 795 new(&second.singleton_.value_) binding(std::move(tempBinding));
796 second.singleton_.parentObject_ = tempParentObject;
752 797
753 break; 798 break;
754 } 799 }
@@ -813,19 +858,23 @@ namespace verbly {
813 } else { 858 } else {
814 singleton_.comparison_ = comparison::is_not_null; 859 singleton_.comparison_ = comparison::is_not_null;
815 } 860 }
861
862 singleton_.parentObject_ = object::undefined;
816 } 863 }
817 864
818 statement::condition::condition( 865 statement::condition::condition(
819 std::string table, 866 std::string table,
820 std::string column, 867 std::string column,
821 comparison comp, 868 comparison comp,
822 binding value) : 869 binding value,
870 object parentObject) :
823 type_(type::singleton) 871 type_(type::singleton)
824 { 872 {
825 new(&singleton_.table_) std::string(std::move(table)); 873 new(&singleton_.table_) std::string(std::move(table));
826 new(&singleton_.column_) std::string(std::move(column)); 874 new(&singleton_.column_) std::string(std::move(column));
827 singleton_.comparison_ = comp; 875 singleton_.comparison_ = comp;
828 new(&singleton_.value_) binding(std::move(value)); 876 new(&singleton_.value_) binding(std::move(value));
877 singleton_.parentObject_ = parentObject;
829 } 878 }
830 879
831 std::string statement::condition::toSql(bool toplevel, bool debug) const 880 std::string statement::condition::toSql(bool toplevel, bool debug) const
@@ -845,14 +894,35 @@ namespace verbly {
845 { 894 {
846 if (debug) 895 if (debug)
847 { 896 {
848 if (singleton_.value_.getType() == binding::type::string) 897 switch (singleton_.value_.getType())
849 { 898 {
850 return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; 899 case binding::type::string:
851 } else { 900 {
852 return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); 901 return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\"";
902 }
903
904 case binding::type::integer:
905 {
906 return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger());
907 }
908
909 case binding::type::field:
910 {
911 return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
912 }
913
914 case binding::type::invalid:
915 {
916 throw std::logic_error("Invalid binding in statement generation");
917 }
853 } 918 }
854 } else { 919 } else {
855 return singleton_.table_ + "." + singleton_.column_ + " = ?"; 920 if (singleton_.value_.getType() == binding::type::field)
921 {
922 return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
923 } else {
924 return singleton_.table_ + "." + singleton_.column_ + " = ?";
925 }
856 } 926 }
857 } 927 }
858 928
@@ -860,14 +930,35 @@ namespace verbly {
860 { 930 {
861 if (debug) 931 if (debug)
862 { 932 {
863 if (singleton_.value_.getType() == binding::type::string) 933 switch (singleton_.value_.getType())
864 { 934 {
865 return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; 935 case binding::type::string:
866 } else { 936 {
867 return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); 937 return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\"";
938 }
939
940 case binding::type::integer:
941 {
942 return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger());
943 }
944
945 case binding::type::field:
946 {
947 return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
948 }
949
950 case binding::type::invalid:
951 {
952 throw std::logic_error("Invalid binding in statement generation");
953 }
868 } 954 }
869 } else { 955 } else {
870 return singleton_.table_ + "." + singleton_.column_ + " != ?"; 956 if (singleton_.value_.getType() == binding::type::field)
957 {
958 return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn();
959 } else {
960 return singleton_.table_ + "." + singleton_.column_ + " != ?";
961 }
871 } 962 }
872 } 963 }
873 964
@@ -959,7 +1050,7 @@ namespace verbly {
959 return clauses.front(); 1050 return clauses.front();
960 } else { 1051 } else {
961 std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); 1052 std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND ");
962 1053
963 if (toplevel) 1054 if (toplevel)
964 { 1055 {
965 return result; 1056 return result;
@@ -982,24 +1073,29 @@ namespace verbly {
982 1073
983 case type::singleton: 1074 case type::singleton:
984 { 1075 {
985 switch (singleton_.comparison_) 1076 if (singleton_.value_.getType() == binding::type::field)
986 { 1077 {
987 case comparison::equals: 1078 return {};
988 case comparison::does_not_equal: 1079 } else {
989 case comparison::is_greater_than: 1080 switch (singleton_.comparison_)
990 case comparison::is_at_most:
991 case comparison::is_less_than:
992 case comparison::is_at_least:
993 case comparison::is_like:
994 case comparison::is_not_like:
995 { 1081 {
996 return {singleton_.value_}; 1082 case comparison::equals:
997 } 1083 case comparison::does_not_equal:
1084 case comparison::is_greater_than:
1085 case comparison::is_at_most:
1086 case comparison::is_less_than:
1087 case comparison::is_at_least:
1088 case comparison::is_like:
1089 case comparison::is_not_like:
1090 {
1091 return {singleton_.value_};
1092 }
998 1093
999 case comparison::is_not_null: 1094 case comparison::is_not_null:
1000 case comparison::is_null: 1095 case comparison::is_null:
1001 { 1096 {
1002 return {}; 1097 return {};
1098 }
1003 } 1099 }
1004 } 1100 }
1005 } 1101 }
@@ -1080,7 +1176,7 @@ namespace verbly {
1080 throw std::domain_error("Cannot get children of non-group condition"); 1176 throw std::domain_error("Cannot get children of non-group condition");
1081 } 1177 }
1082 } 1178 }
1083 1179
1084 statement::condition statement::condition::flatten() const 1180 statement::condition statement::condition::flatten() const
1085 { 1181 {
1086 switch (type_) 1182 switch (type_)
@@ -1090,15 +1186,15 @@ namespace verbly {
1090 { 1186 {
1091 return *this; 1187 return *this;
1092 } 1188 }
1093 1189
1094 case type::group: 1190 case type::group:
1095 { 1191 {
1096 condition result(group_.orlogic_); 1192 condition result(group_.orlogic_);
1097 1193
1098 for (const condition& child : group_.children_) 1194 for (const condition& child : group_.children_)
1099 { 1195 {
1100 condition newChild = child.flatten(); 1196 condition newChild = child.flatten();
1101 1197
1102 if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) 1198 if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_))
1103 { 1199 {
1104 for (condition subChild : std::move(newChild.group_.children_)) 1200 for (condition subChild : std::move(newChild.group_.children_))
@@ -1109,7 +1205,39 @@ namespace verbly {
1109 result += std::move(newChild); 1205 result += std::move(newChild);
1110 } 1206 }
1111 } 1207 }
1112 1208
1209 return result;
1210 }
1211 }
1212 }
1213
1214 statement::condition statement::condition::resolveCompareFields(object context, std::string tableName) const
1215 {
1216 switch (type_)
1217 {
1218 case type::empty:
1219 {
1220 return *this;
1221 }
1222
1223 case type::singleton:
1224 {
1225 if ((singleton_.parentObject_ != object::undefined) && (singleton_.parentObject_ == context))
1226 {
1227 return condition(singleton_.table_, singleton_.column_, singleton_.comparison_, {tableName, singleton_.value_.getColumn()});
1228 } else {
1229 return *this;
1230 }
1231 }
1232
1233 case type::group:
1234 {
1235 condition result(group_.orlogic_);
1236 for (const condition& cond : group_.children_)
1237 {
1238 result += cond.resolveCompareFields(context, tableName);
1239 }
1240
1113 return result; 1241 return result;
1114 } 1242 }
1115 } 1243 }
diff --git a/lib/statement.h b/lib/statement.h index 15c4ac3..2fadf05 100644 --- a/lib/statement.h +++ b/lib/statement.h
@@ -140,7 +140,7 @@ namespace verbly {
140 140
141 condition(std::string table, std::string column, bool isNull); 141 condition(std::string table, std::string column, bool isNull);
142 142
143 condition(std::string table, std::string column, comparison comp, binding value); 143 condition(std::string table, std::string column, comparison comp, binding value, object parentObject = object::undefined);
144 144
145 // Group 145 // Group
146 146
@@ -160,6 +160,8 @@ namespace verbly {
160 160
161 condition flatten() const; 161 condition flatten() const;
162 162
163 condition resolveCompareFields(object context, std::string tableName) const;
164
163 private: 165 private:
164 union { 166 union {
165 struct { 167 struct {
@@ -167,6 +169,7 @@ namespace verbly {
167 std::string column_; 169 std::string column_;
168 comparison comparison_; 170 comparison comparison_;
169 binding value_; 171 binding value_;
172 object parentObject_;
170 } singleton_; 173 } singleton_;
171 struct { 174 struct {
172 std::list<condition> children_; 175 std::list<condition> children_;
@@ -251,7 +254,6 @@ namespace verbly {
251 : (context == object::word) ? "words" 254 : (context == object::word) ? "words"
252 : (context == object::frame) ? "frames" 255 : (context == object::frame) ? "frames"
253 : (context == object::part) ? "parts" 256 : (context == object::part) ? "parts"
254 : (context == object::lemma) ? "lemmas_forms"
255 : (context == object::form) ? "forms" 257 : (context == object::form) ? "forms"
256 : (context == object::pronunciation) ? "pronunciations" 258 : (context == object::pronunciation) ? "pronunciations"
257 : throw std::domain_error("Provided context has no associated table"); 259 : throw std::domain_error("Provided context has no associated table");
@@ -259,7 +261,7 @@ namespace verbly {
259 261
260 static const std::list<field> getSelectForContext(object context); 262 static const std::list<field> getSelectForContext(object context);
261 263
262 statement(std::string tableName, filter clause, int nextTableId = 0, int nextWithId = 0); 264 statement(object context, std::string tableName, filter clause, int nextTableId = 0, int nextWithId = 0);
263 265
264 condition parseFilter(filter queryFilter); 266 condition parseFilter(filter queryFilter);
265 267
@@ -272,6 +274,7 @@ namespace verbly {
272 int nextTableId_; 274 int nextTableId_;
273 int nextWithId_; 275 int nextWithId_;
274 276
277 object context_;
275 std::map<std::string, std::string> tables_; 278 std::map<std::string, std::string> tables_;
276 std::string topTable_; 279 std::string topTable_;
277 std::list<join> joins_; 280 std::list<join> joins_;
diff --git a/lib/token.cpp b/lib/token.cpp index d2024b8..735aa7e 100644 --- a/lib/token.cpp +++ b/lib/token.cpp
@@ -261,7 +261,7 @@ namespace verbly {
261 { 261 {
262 switch (type_) 262 switch (type_)
263 { 263 {
264 case type::word: return word_.word_.getInflections(word_.category_).front(); 264 case type::word: return word_.word_.getInflections(word_.category_).front().getText();
265 case type::literal: return literal_; 265 case type::literal: return literal_;
266 case type::part: throw std::domain_error("Cannot compile incomplete token"); 266 case type::part: throw std::domain_error("Cannot compile incomplete token");
267 case type::fillin: throw std::domain_error("Cannot compile incomplete token"); 267 case type::fillin: throw std::domain_error("Cannot compile incomplete token");
diff --git a/lib/verbly.h b/lib/verbly.h index 0f48a8c..5bf204d 100644 --- a/lib/verbly.h +++ b/lib/verbly.h
@@ -11,7 +11,6 @@
11#include "word.h" 11#include "word.h"
12#include "frame.h" 12#include "frame.h"
13#include "part.h" 13#include "part.h"
14#include "lemma.h"
15#include "form.h" 14#include "form.h"
16#include "pronunciation.h" 15#include "pronunciation.h"
17#include "token.h" 16#include "token.h"
diff --git a/lib/word.cpp b/lib/word.cpp index d75159c..4dea569 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -16,7 +16,6 @@ namespace verbly {
16 const field word::adjectivePosition = field::integerField(object::word, "position", true); 16 const field word::adjectivePosition = field::integerField(object::word, "position", true);
17 17
18 const field word::notions = field::joinField(object::word, "notion_id", object::notion); 18 const field word::notions = field::joinField(object::word, "notion_id", object::notion);
19 const field word::lemmas = field::joinField(object::word, "lemma_id", object::lemma);
20 const field word::frames = field::joinField(object::word, "group_id", object::frame, true); 19 const field word::frames = field::joinField(object::word, "group_id", object::frame, true);
21 20
22 const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id"); 21 const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id");
@@ -39,6 +38,11 @@ namespace verbly {
39 const field word::regionalTerms = field::selfJoin(object::word, "word_id", "regionality", "domain_id", "term_id"); 38 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"); 39 const field word::regionalDomains = field::selfJoin(object::word, "word_id", "regionality", "term_id", "domain_id");
41 40
41 field word::forms(inflection category)
42 {
43 return field::joinThroughWhere(object::word, "lemma_id", object::form, "lemmas_forms", "form_id", "category", static_cast<int>(category));
44 }
45
42 word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 46 word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
43 { 47 {
44 id_ = sqlite3_column_int(row, 0); 48 id_ = sqlite3_column_int(row, 0);
@@ -78,21 +82,6 @@ namespace verbly {
78 return notion_; 82 return notion_;
79 } 83 }
80 84
81 const lemma& word::getLemma() const
82 {
83 if (!valid_)
84 {
85 throw std::domain_error("Bad access to uninitialized word");
86 }
87
88 if (!lemma_)
89 {
90 lemma_ = db_->lemmas(lemma::id == lemmaId_).first();
91 }
92
93 return lemma_;
94 }
95
96 bool word::hasFrames() const 85 bool word::hasFrames() const
97 { 86 {
98 if (!valid_) 87 if (!valid_)
@@ -133,26 +122,50 @@ namespace verbly {
133 return frames_; 122 return frames_;
134 } 123 }
135 124
136 std::string word::getBaseForm() const 125 void word::initializeFrames() const
137 { 126 {
138 return getLemma().getBaseForm().getText(); 127 initializedFrames_ = true;
128 frames_ = db_->frames(*this, {}, -1).all();
139 } 129 }
140 130
141 std::vector<std::string> word::getInflections(inflection category) const 131 const form& word::getBaseForm() const
142 { 132 {
143 std::vector<std::string> result; 133 if (!valid_)
144 for (const form& infl : getLemma().getInflections(category))
145 { 134 {
146 result.push_back(infl.getText()); 135 throw std::domain_error("Bad access to uninitialized word");
147 } 136 }
148 137
149 return result; 138 if (!forms_.count(inflection::base))
139 {
140 initializeForm(inflection::base);
141 }
142
143 return forms_.at(inflection::base).front();
150 } 144 }
151 145
152 void word::initializeFrames() const 146 bool word::hasInflection(inflection category) const
153 { 147 {
154 initializedFrames_ = true; 148 return !getInflections(category).empty();
155 frames_ = db_->frames(*this, {}, -1).all(); 149 }
150
151 const std::vector<form>& word::getInflections(inflection category) const
152 {
153 if (!valid_)
154 {
155 throw std::domain_error("Bad access to uninitialized word");
156 }
157
158 if (!forms_.count(category))
159 {
160 initializeForm(category);
161 }
162
163 return forms_.at(category);
164 }
165
166 void word::initializeForm(inflection infl) const
167 {
168 forms_[infl] = db_->forms(form::words(infl) %= *this, verbly::form::id, -1).all();
156 } 169 }
157 170
158}; 171};
diff --git a/lib/word.h b/lib/word.h index 864cee1..a16319d 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -6,8 +6,8 @@
6#include "field.h" 6#include "field.h"
7#include "filter.h" 7#include "filter.h"
8#include "notion.h" 8#include "notion.h"
9#include "lemma.h"
10#include "frame.h" 9#include "frame.h"
10#include "form.h"
11 11
12struct sqlite3_stmt; 12struct sqlite3_stmt;
13 13
@@ -95,17 +95,17 @@ namespace verbly {
95 95
96 const notion& getNotion() const; 96 const notion& getNotion() const;
97 97
98 const lemma& getLemma() const;
99
100 bool hasFrames() const; 98 bool hasFrames() const;
101 99
102 const std::vector<frame>& getFrames() const; 100 const std::vector<frame>& getFrames() const;
103 101
104 // Convenience accessors 102 const form& getBaseForm() const;
103
104 bool hasInflection(inflection category) const;
105
106 const std::vector<form>& getInflections(inflection category) const;
105 107
106 std::string getBaseForm() const;
107 108
108 std::vector<std::string> getInflections(inflection infl) const;
109 109
110 // Type info 110 // Type info
111 111
@@ -127,9 +127,10 @@ namespace verbly {
127 // Relationships with other objects 127 // Relationships with other objects
128 128
129 static const field notions; 129 static const field notions;
130 static const field lemmas;
131 static const field frames; 130 static const field frames;
132 131
132 static field forms(inflection category);
133
133 // Relationships with self 134 // Relationships with self
134 135
135 static const field antonyms; 136 static const field antonyms;
@@ -154,6 +155,7 @@ namespace verbly {
154 155
155 private: 156 private:
156 157
158 void initializeForm(inflection category) const;
157 void initializeFrames() const; 159 void initializeFrames() const;
158 160
159 bool valid_ = false; 161 bool valid_ = false;
@@ -170,10 +172,9 @@ namespace verbly {
170 const database* db_; 172 const database* db_;
171 173
172 mutable notion notion_; 174 mutable notion notion_;
173 mutable lemma lemma_;
174
175 mutable bool initializedFrames_ = false; 175 mutable bool initializedFrames_ = false;
176 mutable std::vector<frame> frames_; 176 mutable std::vector<frame> frames_;
177 mutable std::map<inflection, std::vector<form>> forms_;
177 178
178 }; 179 };
179 180