diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/database.cpp | 60 | ||||
-rw-r--r-- | lib/database.h | 20 | ||||
-rw-r--r-- | lib/enums.h | 14 | ||||
-rw-r--r-- | lib/field.cpp | 20 | ||||
-rw-r--r-- | lib/field.h | 78 | ||||
-rw-r--r-- | lib/filter.cpp | 35 | ||||
-rw-r--r-- | lib/form.cpp | 16 | ||||
-rw-r--r-- | lib/form.h | 31 | ||||
-rw-r--r-- | lib/frame.cpp | 95 | ||||
-rw-r--r-- | lib/frame.h | 21 | ||||
-rw-r--r-- | lib/group.cpp | 61 | ||||
-rw-r--r-- | lib/group.h | 91 | ||||
-rw-r--r-- | lib/lemma.cpp | 15 | ||||
-rw-r--r-- | lib/lemma.h | 27 | ||||
-rw-r--r-- | lib/order.h | 69 | ||||
-rw-r--r-- | lib/part.cpp | 128 | ||||
-rw-r--r-- | lib/part.h | 64 | ||||
-rw-r--r-- | lib/query.h | 11 | ||||
-rw-r--r-- | lib/role.h | 60 | ||||
-rw-r--r-- | lib/statement.cpp | 164 | ||||
-rw-r--r-- | lib/statement.h | 9 | ||||
-rw-r--r-- | lib/verbly.h | 5 | ||||
-rw-r--r-- | lib/word.cpp | 36 | ||||
-rw-r--r-- | lib/word.h | 23 |
24 files changed, 644 insertions, 509 deletions
diff --git a/lib/database.cpp b/lib/database.cpp index fb00ef3..563ec31 100644 --- a/lib/database.cpp +++ b/lib/database.cpp | |||
@@ -41,39 +41,71 @@ namespace verbly { | |||
41 | sqlite3_close_v2(ppdb_); | 41 | sqlite3_close_v2(ppdb_); |
42 | } | 42 | } |
43 | 43 | ||
44 | query<notion> database::notions(filter where, bool random, int limit) const | 44 | query<notion> database::notions(filter where, order sortOrder, int limit) const |
45 | { | 45 | { |
46 | return query<notion>(*this, ppdb_, std::move(where), random, limit); | 46 | return query<notion>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
47 | } | 47 | } |
48 | 48 | ||
49 | query<word> database::words(filter where, bool random, int limit) const | 49 | query<word> database::words(filter where, order sortOrder, int limit) const |
50 | { | 50 | { |
51 | return query<word>(*this, ppdb_, std::move(where), random, limit); | 51 | return query<word>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
52 | } | 52 | } |
53 | 53 | ||
54 | query<group> database::groups(filter where, bool random, int limit) const | 54 | query<frame> database::frames(filter where, order sortOrder, int limit) const |
55 | { | 55 | { |
56 | return query<group>(*this, ppdb_, std::move(where), random, limit); | 56 | return query<frame>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
57 | } | 57 | } |
58 | 58 | ||
59 | query<frame> database::frames(filter where, bool random, int limit) const | 59 | query<part> database::parts(filter where, order sortOrder, int limit) const |
60 | { | 60 | { |
61 | return query<frame>(*this, ppdb_, std::move(where), random, 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, bool random, int limit) const | 64 | query<lemma> database::lemmas(filter where, order sortOrder, int limit) const |
65 | { | 65 | { |
66 | return query<lemma>(*this, ppdb_, std::move(where), random, limit); | 66 | return query<lemma>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
67 | } | 67 | } |
68 | 68 | ||
69 | query<form> database::forms(filter where, bool random, int limit) const | 69 | query<form> database::forms(filter where, order sortOrder, int limit) const |
70 | { | 70 | { |
71 | return query<form>(*this, ppdb_, std::move(where), random, limit); | 71 | return query<form>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
72 | } | 72 | } |
73 | 73 | ||
74 | query<pronunciation> database::pronunciations(filter where, bool random, int limit) const | 74 | query<pronunciation> database::pronunciations(filter where, order sortOrder, int limit) const |
75 | { | 75 | { |
76 | return query<pronunciation>(*this, ppdb_, std::move(where), random, limit); | 76 | return query<pronunciation>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
77 | } | ||
78 | |||
79 | std::set<std::string> database::synrestrs(int partId) const | ||
80 | { | ||
81 | std::string queryString = "SELECT synrestr FROM synrestrs WHERE part_id = ?"; | ||
82 | |||
83 | sqlite3_stmt* ppstmt; | ||
84 | if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK) | ||
85 | { | ||
86 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
87 | sqlite3_finalize(ppstmt); | ||
88 | |||
89 | throw database_error("Error preparing query", errorMsg); | ||
90 | } | ||
91 | |||
92 | if (sqlite3_bind_int(ppstmt, 1, partId) != SQLITE_OK) | ||
93 | { | ||
94 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
95 | sqlite3_finalize(ppstmt); | ||
96 | |||
97 | throw database_error("Error binding value to query", errorMsg); | ||
98 | } | ||
99 | |||
100 | std::set<std::string> result; | ||
101 | while (sqlite3_step(ppstmt) == SQLITE_ROW) | ||
102 | { | ||
103 | result.insert(reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0))); | ||
104 | } | ||
105 | |||
106 | sqlite3_finalize(ppstmt); | ||
107 | |||
108 | return result; | ||
77 | } | 109 | } |
78 | 110 | ||
79 | }; | 111 | }; |
diff --git a/lib/database.h b/lib/database.h index ef50739..0b10eba 100644 --- a/lib/database.h +++ b/lib/database.h | |||
@@ -4,13 +4,15 @@ | |||
4 | #include <string> | 4 | #include <string> |
5 | #include <exception> | 5 | #include <exception> |
6 | #include <list> | 6 | #include <list> |
7 | #include <set> | ||
7 | #include "notion.h" | 8 | #include "notion.h" |
8 | #include "word.h" | 9 | #include "word.h" |
9 | #include "group.h" | ||
10 | #include "frame.h" | 10 | #include "frame.h" |
11 | #include "part.h" | ||
11 | #include "lemma.h" | 12 | #include "lemma.h" |
12 | #include "form.h" | 13 | #include "form.h" |
13 | #include "pronunciation.h" | 14 | #include "pronunciation.h" |
15 | #include "order.h" | ||
14 | 16 | ||
15 | struct sqlite3; | 17 | struct sqlite3; |
16 | 18 | ||
@@ -46,19 +48,21 @@ namespace verbly { | |||
46 | 48 | ||
47 | // Queries | 49 | // Queries |
48 | 50 | ||
49 | query<notion> notions(filter where, bool random = true, int limit = 1) const; | 51 | query<notion> notions(filter where, order sortOrder = {}, int limit = 1) const; |
50 | 52 | ||
51 | query<word> words(filter where, bool random = true, int limit = 1) const; | 53 | query<word> words(filter where, order sortOrder = {}, int limit = 1) const; |
52 | 54 | ||
53 | query<group> groups(filter where, bool random = true, int limit = 1) const; | 55 | query<frame> frames(filter where, order sortOrder = {}, int limit = 1) const; |
54 | 56 | ||
55 | query<frame> frames(filter where, bool random = true, int limit = 1) const; | 57 | query<part> parts(filter where, order sortOrder = {}, int limit = 1) const; |
56 | 58 | ||
57 | query<lemma> lemmas(filter where, bool random = true, int limit = 1) const; | 59 | query<lemma> lemmas(filter where, order sortOrder = {}, int limit = 1) const; |
58 | 60 | ||
59 | query<form> forms(filter where, bool random = true, int limit = 1) const; | 61 | query<form> forms(filter where, order sortOrder = {}, int limit = 1) const; |
60 | 62 | ||
61 | query<pronunciation> pronunciations(filter where, bool random = true, int limit = 1) const; | 63 | query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const; |
64 | |||
65 | std::set<std::string> synrestrs(int partId) const; | ||
62 | 66 | ||
63 | private: | 67 | private: |
64 | 68 | ||
diff --git a/lib/enums.h b/lib/enums.h index e634959..2646fa4 100644 --- a/lib/enums.h +++ b/lib/enums.h | |||
@@ -33,13 +33,23 @@ namespace verbly { | |||
33 | undefined = -1, | 33 | undefined = -1, |
34 | notion = 0, | 34 | notion = 0, |
35 | word = 1, | 35 | word = 1, |
36 | group = 2, | 36 | frame = 2, |
37 | frame = 3, | 37 | part = 3, |
38 | lemma = 4, | 38 | lemma = 4, |
39 | form = 5, | 39 | form = 5, |
40 | pronunciation = 6 | 40 | pronunciation = 6 |
41 | }; | 41 | }; |
42 | 42 | ||
43 | enum class part_type { | ||
44 | invalid = -1, | ||
45 | noun_phrase = 0, | ||
46 | verb = 1, | ||
47 | preposition = 2, | ||
48 | adjective = 3, | ||
49 | adverb = 4, | ||
50 | literal = 5 | ||
51 | }; | ||
52 | |||
43 | }; | 53 | }; |
44 | 54 | ||
45 | #endif /* end of include guard: ENUMS_H_260BA847 */ | 55 | #endif /* end of include guard: ENUMS_H_260BA847 */ |
diff --git a/lib/field.cpp b/lib/field.cpp index deecb06..5b51ef4 100644 --- a/lib/field.cpp +++ b/lib/field.cpp | |||
@@ -48,6 +48,11 @@ namespace verbly { | |||
48 | return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); | 48 | return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); |
49 | } | 49 | } |
50 | 50 | ||
51 | filter field::operator==(part_type value) const | ||
52 | { | ||
53 | return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); | ||
54 | } | ||
55 | |||
51 | filter field::operator==(bool value) const | 56 | filter field::operator==(bool value) const |
52 | { | 57 | { |
53 | return filter(*this, filter::comparison::boolean_equals, value); | 58 | return filter(*this, filter::comparison::boolean_equals, value); |
@@ -68,6 +73,21 @@ namespace verbly { | |||
68 | return filter(*this, filter::comparison::string_is_like, std::move(value)); | 73 | return filter(*this, filter::comparison::string_is_like, std::move(value)); |
69 | } | 74 | } |
70 | 75 | ||
76 | filter field::operator==(const char* value) const | ||
77 | { | ||
78 | return filter(*this, filter::comparison::string_equals, std::string(value)); | ||
79 | } | ||
80 | |||
81 | filter field::operator!=(const char* value) const | ||
82 | { | ||
83 | return filter(*this, filter::comparison::string_does_not_equal, std::string(value)); | ||
84 | } | ||
85 | |||
86 | filter field::operator%=(const char* value) const | ||
87 | { | ||
88 | return filter(*this, filter::comparison::string_is_like, std::string(value)); | ||
89 | } | ||
90 | |||
71 | field::operator filter() const | 91 | field::operator filter() const |
72 | { | 92 | { |
73 | if (isJoin()) | 93 | if (isJoin()) |
diff --git a/lib/field.h b/lib/field.h index f61e038..b4bf02d 100644 --- a/lib/field.h +++ b/lib/field.h | |||
@@ -17,6 +17,7 @@ namespace verbly { | |||
17 | integer, | 17 | integer, |
18 | boolean, | 18 | boolean, |
19 | join, | 19 | join, |
20 | join_where, | ||
20 | join_through, | 21 | join_through, |
21 | hierarchal_join | 22 | hierarchal_join |
22 | }; | 23 | }; |
@@ -95,6 +96,17 @@ namespace verbly { | |||
95 | return field(obj, type::join, name, nullable, table); | 96 | return field(obj, type::join, name, nullable, table); |
96 | } | 97 | } |
97 | 98 | ||
99 | static field joinWhere( | ||
100 | object obj, | ||
101 | const char* name, | ||
102 | object joinWith, | ||
103 | const field& conditionField, | ||
104 | int conditionValue, | ||
105 | bool nullable = false) | ||
106 | { | ||
107 | return field(obj, type::join_where, name, nullable, 0, joinWith, 0, 0, 0, &conditionField, conditionValue); | ||
108 | } | ||
109 | |||
98 | static field joinThrough( | 110 | static field joinThrough( |
99 | object obj, | 111 | object obj, |
100 | const char* name, | 112 | const char* name, |
@@ -151,7 +163,10 @@ namespace verbly { | |||
151 | 163 | ||
152 | bool isJoin() const | 164 | bool isJoin() const |
153 | { | 165 | { |
154 | return ((type_ == type::join) || (type_ == type::join_through) || (type_ == type::hierarchal_join)); | 166 | return ((type_ == type::join) |
167 | || (type_ == type::join_where) | ||
168 | || (type_ == type::join_through) | ||
169 | || (type_ == type::hierarchal_join)); | ||
155 | } | 170 | } |
156 | 171 | ||
157 | const char* getColumn() const | 172 | const char* getColumn() const |
@@ -180,7 +195,7 @@ namespace verbly { | |||
180 | { | 195 | { |
181 | return (type_ == type::hierarchal_join) | 196 | return (type_ == type::hierarchal_join) |
182 | ? object_ | 197 | ? object_ |
183 | : ((type_ == type::join) || (type_ == type::join_through)) | 198 | : ((type_ == type::join) || (type_ == type::join_where) || (type_ == type::join_through)) |
184 | ? joinObject_ | 199 | ? joinObject_ |
185 | : throw std::domain_error("Non-join fields don't have join objects"); | 200 | : throw std::domain_error("Non-join fields don't have join objects"); |
186 | } | 201 | } |
@@ -209,6 +224,22 @@ namespace verbly { | |||
209 | : throw std::domain_error("Only many-to-many join fields have a foreign join column"); | 224 | : throw std::domain_error("Only many-to-many join fields have a foreign join column"); |
210 | } | 225 | } |
211 | 226 | ||
227 | // Condition joins | ||
228 | |||
229 | const field& getConditionField() const | ||
230 | { | ||
231 | return (type_ == type::join_where) | ||
232 | ? *conditionField_ | ||
233 | : throw std::domain_error("Only condition join fields have a condition field"); | ||
234 | } | ||
235 | |||
236 | int getConditionValue() const | ||
237 | { | ||
238 | return (type_ == type::join_where) | ||
239 | ? conditionValue_ | ||
240 | : throw std::domain_error("Only condition join fields have a condition value"); | ||
241 | } | ||
242 | |||
212 | // Ordering | 243 | // Ordering |
213 | 244 | ||
214 | bool operator<(const field& other) const | 245 | bool operator<(const field& other) const |
@@ -217,20 +248,30 @@ namespace verbly { | |||
217 | // However, there do exist a number of relationships from an object to | 248 | // However, there do exist a number of relationships from an object to |
218 | // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have | 249 | // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have |
219 | // the same object (notion), the same column (notion_id), and the same | 250 | // the same object (notion), the same column (notion_id), and the same |
220 | // table (hypernymy); however, they have different join columns. | 251 | // table (hypernymy); however, they have different join columns. For |
221 | return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | 252 | // condition joins, the condition field and condition value are also |
253 | // significant. | ||
254 | if (conditionField_) | ||
255 | { | ||
256 | return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_) | ||
257 | < std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_); | ||
258 | } else { | ||
259 | return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | ||
260 | } | ||
222 | } | 261 | } |
223 | 262 | ||
224 | // Equality | 263 | // Equality |
225 | 264 | ||
226 | bool operator==(const field& other) const | 265 | bool operator==(const field& other) const |
227 | { | 266 | { |
228 | // For the most part, (object, column) uniquely identifies fields. | 267 | // See operator<() for documentation. |
229 | // However, there do exist a number of relationships from an object to | 268 | if (conditionField_) |
230 | // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have | 269 | { |
231 | // the same object (notion), the same column (notion_id), and the same | 270 | return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_) |
232 | // table (hypernymy); however, they have different join columns. | 271 | == std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_); |
233 | return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | 272 | } else { |
273 | return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | ||
274 | } | ||
234 | } | 275 | } |
235 | 276 | ||
236 | // Filter construction | 277 | // Filter construction |
@@ -245,6 +286,7 @@ namespace verbly { | |||
245 | filter operator==(part_of_speech value) const; // Part of speech equality | 286 | filter operator==(part_of_speech value) const; // Part of speech equality |
246 | filter operator==(positioning value) const; // Adjective positioning equality | 287 | filter operator==(positioning value) const; // Adjective positioning equality |
247 | filter operator==(inflection value) const; // Inflection category equality | 288 | filter operator==(inflection value) const; // Inflection category equality |
289 | filter operator==(part_type value) const; // Verb frame part type equality | ||
248 | 290 | ||
249 | filter operator==(bool value) const; // Boolean equality | 291 | filter operator==(bool value) const; // Boolean equality |
250 | 292 | ||
@@ -252,6 +294,10 @@ namespace verbly { | |||
252 | filter operator!=(std::string value) const; // String inequality | 294 | filter operator!=(std::string value) const; // String inequality |
253 | filter operator%=(std::string value) const; // String matching | 295 | filter operator%=(std::string value) const; // String matching |
254 | 296 | ||
297 | filter operator==(const char* value) const; // String equality | ||
298 | filter operator!=(const char* value) const; // String inequality | ||
299 | filter operator%=(const char* value) const; // String matching | ||
300 | |||
255 | operator filter() const; // Non-nullity | 301 | operator filter() const; // Non-nullity |
256 | filter operator!() const; // Nullity | 302 | filter operator!() const; // Nullity |
257 | 303 | ||
@@ -270,7 +316,9 @@ namespace verbly { | |||
270 | object joinObject = object::undefined, | 316 | object joinObject = object::undefined, |
271 | const char* foreignColumn = 0, | 317 | const char* foreignColumn = 0, |
272 | const char* joinColumn = 0, | 318 | const char* joinColumn = 0, |
273 | const char* foreignJoinColumn = 0) : | 319 | const char* foreignJoinColumn = 0, |
320 | const field* conditionField = 0, | ||
321 | int conditionValue = 0) : | ||
274 | object_(obj), | 322 | object_(obj), |
275 | type_(datatype), | 323 | type_(datatype), |
276 | column_(column), | 324 | column_(column), |
@@ -279,7 +327,9 @@ namespace verbly { | |||
279 | joinObject_(joinObject), | 327 | joinObject_(joinObject), |
280 | foreignColumn_(foreignColumn), | 328 | foreignColumn_(foreignColumn), |
281 | joinColumn_(joinColumn), | 329 | joinColumn_(joinColumn), |
282 | foreignJoinColumn_(foreignJoinColumn) | 330 | foreignJoinColumn_(foreignJoinColumn), |
331 | conditionField_(conditionField), | ||
332 | conditionValue_(conditionValue) | ||
283 | { | 333 | { |
284 | } | 334 | } |
285 | 335 | ||
@@ -300,6 +350,10 @@ namespace verbly { | |||
300 | const char* joinColumn_ = 0; | 350 | const char* joinColumn_ = 0; |
301 | const char* foreignJoinColumn_ = 0; | 351 | const char* foreignJoinColumn_ = 0; |
302 | 352 | ||
353 | // Condition joins | ||
354 | const field* conditionField_ = 0; | ||
355 | int conditionValue_ = 0; | ||
356 | |||
303 | }; | 357 | }; |
304 | 358 | ||
305 | }; | 359 | }; |
diff --git a/lib/filter.cpp b/lib/filter.cpp index ceb9327..ab46df2 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp | |||
@@ -3,8 +3,8 @@ | |||
3 | #include <map> | 3 | #include <map> |
4 | #include "notion.h" | 4 | #include "notion.h" |
5 | #include "word.h" | 5 | #include "word.h" |
6 | #include "group.h" | ||
7 | #include "frame.h" | 6 | #include "frame.h" |
7 | #include "part.h" | ||
8 | #include "lemma.h" | 8 | #include "lemma.h" |
9 | #include "form.h" | 9 | #include "form.h" |
10 | #include "pronunciation.h" | 10 | #include "pronunciation.h" |
@@ -594,6 +594,7 @@ namespace verbly { | |||
594 | switch (joinOn.getType()) | 594 | switch (joinOn.getType()) |
595 | { | 595 | { |
596 | case field::type::join: | 596 | case field::type::join: |
597 | case field::type::join_where: | ||
597 | case field::type::join_through: | 598 | case field::type::join_through: |
598 | { | 599 | { |
599 | switch (filterType) | 600 | switch (filterType) |
@@ -1108,8 +1109,8 @@ namespace verbly { | |||
1108 | } | 1109 | } |
1109 | 1110 | ||
1110 | case object::word: | 1111 | case object::word: |
1111 | case object::group: | ||
1112 | case object::frame: | 1112 | case object::frame: |
1113 | case object::part: | ||
1113 | case object::lemma: | 1114 | case object::lemma: |
1114 | case object::form: | 1115 | case object::form: |
1115 | case object::pronunciation: | 1116 | case object::pronunciation: |
@@ -1134,10 +1135,10 @@ namespace verbly { | |||
1134 | return *this; | 1135 | return *this; |
1135 | } | 1136 | } |
1136 | 1137 | ||
1137 | case object::group: | ||
1138 | case object::frame: | 1138 | case object::frame: |
1139 | case object::part: | ||
1139 | { | 1140 | { |
1140 | return (verbly::word::group %= *this); | 1141 | return (verbly::word::frame %= *this); |
1141 | } | 1142 | } |
1142 | 1143 | ||
1143 | case object::lemma: | 1144 | case object::lemma: |
@@ -1148,12 +1149,12 @@ namespace verbly { | |||
1148 | } | 1149 | } |
1149 | } | 1150 | } |
1150 | 1151 | ||
1151 | case object::group: | 1152 | case object::frame: |
1152 | { | 1153 | { |
1153 | switch (singleton_.filterField.getObject()) | 1154 | switch (singleton_.filterField.getObject()) |
1154 | { | 1155 | { |
1155 | case object::undefined: | 1156 | case object::undefined: |
1156 | case object::group: | 1157 | case object::frame: |
1157 | { | 1158 | { |
1158 | return *this; | 1159 | return *this; |
1159 | } | 1160 | } |
@@ -1164,34 +1165,34 @@ namespace verbly { | |||
1164 | case object::form: | 1165 | case object::form: |
1165 | case object::pronunciation: | 1166 | case object::pronunciation: |
1166 | { | 1167 | { |
1167 | return (verbly::group::word %= *this); | 1168 | return (verbly::frame::word %= *this); |
1168 | } | 1169 | } |
1169 | 1170 | ||
1170 | case object::frame: | 1171 | case object::part: |
1171 | { | 1172 | { |
1172 | return (verbly::group::frame %= *this); | 1173 | return (verbly::frame::part() %= *this); |
1173 | } | 1174 | } |
1174 | } | 1175 | } |
1175 | } | 1176 | } |
1176 | 1177 | ||
1177 | case object::frame: | 1178 | case object::part: |
1178 | { | 1179 | { |
1179 | switch (singleton_.filterField.getObject()) | 1180 | switch (singleton_.filterField.getObject()) |
1180 | { | 1181 | { |
1181 | case object::undefined: | 1182 | case object::undefined: |
1182 | case object::frame: | 1183 | case object::part: |
1183 | { | 1184 | { |
1184 | return *this; | 1185 | return *this; |
1185 | } | 1186 | } |
1186 | 1187 | ||
1187 | case object::notion: | 1188 | case object::notion: |
1188 | case object::word: | 1189 | case object::word: |
1189 | case object::group: | 1190 | case object::frame: |
1190 | case object::lemma: | 1191 | case object::lemma: |
1191 | case object::form: | 1192 | case object::form: |
1192 | case object::pronunciation: | 1193 | case object::pronunciation: |
1193 | { | 1194 | { |
1194 | return (verbly::frame::group %= *this); | 1195 | return (verbly::part::frame %= *this); |
1195 | } | 1196 | } |
1196 | } | 1197 | } |
1197 | } | 1198 | } |
@@ -1202,8 +1203,8 @@ namespace verbly { | |||
1202 | { | 1203 | { |
1203 | case object::notion: | 1204 | case object::notion: |
1204 | case object::word: | 1205 | case object::word: |
1205 | case object::group: | ||
1206 | case object::frame: | 1206 | case object::frame: |
1207 | case object::part: | ||
1207 | { | 1208 | { |
1208 | return verbly::lemma::word %= *this; | 1209 | return verbly::lemma::word %= *this; |
1209 | } | 1210 | } |
@@ -1228,11 +1229,11 @@ namespace verbly { | |||
1228 | { | 1229 | { |
1229 | case object::notion: | 1230 | case object::notion: |
1230 | case object::word: | 1231 | case object::word: |
1231 | case object::group: | ||
1232 | case object::frame: | 1232 | case object::frame: |
1233 | case object::part: | ||
1233 | case object::lemma: | 1234 | case object::lemma: |
1234 | { | 1235 | { |
1235 | return verbly::form::lemma(inflection::base) %= *this; | 1236 | return verbly::form::lemma %= *this; |
1236 | } | 1237 | } |
1237 | 1238 | ||
1238 | case object::undefined: | 1239 | case object::undefined: |
@@ -1254,8 +1255,8 @@ namespace verbly { | |||
1254 | { | 1255 | { |
1255 | case object::notion: | 1256 | case object::notion: |
1256 | case object::word: | 1257 | case object::word: |
1257 | case object::group: | ||
1258 | case object::frame: | 1258 | case object::frame: |
1259 | case object::part: | ||
1259 | case object::lemma: | 1260 | case object::lemma: |
1260 | case object::form: | 1261 | case object::form: |
1261 | { | 1262 | { |
diff --git a/lib/form.cpp b/lib/form.cpp index 5d4c343..4811f14 100644 --- a/lib/form.cpp +++ b/lib/form.cpp | |||
@@ -16,11 +16,9 @@ namespace verbly { | |||
16 | const field form::complexity = field::integerField(object::form, "complexity"); | 16 | const field form::complexity = field::integerField(object::form, "complexity"); |
17 | const field form::proper = field::booleanField(object::form, "proper"); | 17 | const field form::proper = field::booleanField(object::form, "proper"); |
18 | 18 | ||
19 | const field form::lemma = field::joinField(object::form, "form_id", object::lemma); | ||
19 | const field form::pronunciation = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id"); | 20 | const field form::pronunciation = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id"); |
20 | 21 | ||
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) | 22 | form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) |
25 | { | 23 | { |
26 | id_ = sqlite3_column_int(row, 0); | 24 | id_ = sqlite3_column_int(row, 0); |
@@ -29,16 +27,6 @@ namespace verbly { | |||
29 | proper_ = (sqlite3_column_int(row, 3) == 1); | 27 | proper_ = (sqlite3_column_int(row, 3) == 1); |
30 | } | 28 | } |
31 | 29 | ||
32 | filter operator%=(form::inflection_field check, filter joinCondition) | ||
33 | { | ||
34 | return (form::lemmaJoin %= (joinCondition && (form::inflectionCategory == check.getCategory()))); | ||
35 | } | ||
36 | |||
37 | form::inflection_field::operator filter() const | ||
38 | { | ||
39 | return (form::lemmaJoin %= (form::inflectionCategory == category_)); | ||
40 | } | ||
41 | |||
42 | const std::vector<pronunciation>& form::getPronunciations() const | 30 | const std::vector<pronunciation>& form::getPronunciations() const |
43 | { | 31 | { |
44 | if (!valid_) | 32 | if (!valid_) |
@@ -48,7 +36,7 @@ namespace verbly { | |||
48 | 36 | ||
49 | if (!initializedPronunciations_) | 37 | if (!initializedPronunciations_) |
50 | { | 38 | { |
51 | pronunciations_ = db_->pronunciations(pronunciation::form %= *this, false, -1).all(); | 39 | pronunciations_ = db_->pronunciations(pronunciation::form %= *this, verbly::pronunciation::id, -1).all(); |
52 | initializedPronunciations_ = true; | 40 | initializedPronunciations_ = true; |
53 | } | 41 | } |
54 | 42 | ||
diff --git a/lib/form.h b/lib/form.h index aca5b2f..cf64117 100644 --- a/lib/form.h +++ b/lib/form.h | |||
@@ -104,33 +104,9 @@ namespace verbly { | |||
104 | 104 | ||
105 | // Relationships to other objects | 105 | // Relationships to other objects |
106 | 106 | ||
107 | static const field pronunciation; | 107 | static const field lemma; |
108 | |||
109 | class inflection_field { | ||
110 | public: | ||
111 | |||
112 | inflection_field(inflection category) : category_(category) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | const inflection getCategory() const | ||
117 | { | ||
118 | return category_; | ||
119 | } | ||
120 | 108 | ||
121 | operator filter() const; | 109 | static const field pronunciation; |
122 | |||
123 | private: | ||
124 | |||
125 | const inflection category_; | ||
126 | }; | ||
127 | |||
128 | static const inflection_field lemma(inflection category) | ||
129 | { | ||
130 | return inflection_field(category); | ||
131 | } | ||
132 | |||
133 | friend filter operator%=(form::inflection_field check, filter joinCondition); | ||
134 | 110 | ||
135 | private: | 111 | private: |
136 | bool valid_ = false; | 112 | bool valid_ = false; |
@@ -145,9 +121,6 @@ namespace verbly { | |||
145 | mutable bool initializedPronunciations_ = false; | 121 | mutable bool initializedPronunciations_ = false; |
146 | mutable std::vector<class pronunciation> pronunciations_; | 122 | mutable std::vector<class pronunciation> pronunciations_; |
147 | 123 | ||
148 | static const field lemmaJoin; | ||
149 | static const field inflectionCategory; | ||
150 | |||
151 | }; | 124 | }; |
152 | 125 | ||
153 | }; | 126 | }; |
diff --git a/lib/frame.cpp b/lib/frame.cpp index 8cab56b..a73fbda 100644 --- a/lib/frame.cpp +++ b/lib/frame.cpp | |||
@@ -1,95 +1,36 @@ | |||
1 | #include "frame.h" | 1 | #include "frame.h" |
2 | #include <sqlite3.h> | 2 | #include <sqlite3.h> |
3 | #include <json.hpp> | 3 | #include "database.h" |
4 | #include "query.h" | ||
4 | 5 | ||
5 | namespace verbly { | 6 | namespace verbly { |
6 | 7 | ||
7 | const object frame::objectType = object::frame; | 8 | const object frame::objectType = object::frame; |
8 | 9 | ||
9 | const std::list<std::string> frame::select = {"frame_id", "data"}; | 10 | const std::list<std::string> frame::select = {"frame_id", "group_id", "length"}; |
10 | 11 | ||
11 | const field frame::id = field::integerField(object::frame, "frame_id"); | 12 | const field frame::id = field::integerField(object::frame, "frame_id"); |
13 | const field frame::length = field::integerField(object::frame, "length"); | ||
12 | 14 | ||
13 | const field frame::group = field::joinThrough(object::frame, "frame_id", object::group, "groups_frames", "group_id"); | 15 | const field frame::word = field::joinField(object::frame, "group_id", object::word); |
14 | 16 | ||
15 | frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 17 | field frame::part() |
16 | { | 18 | { |
17 | id_ = sqlite3_column_int(row, 0); | 19 | return field::joinField(object::frame, "frame_id", object::part); |
18 | 20 | } | |
19 | std::string partsJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 1))); | ||
20 | nlohmann::json partsJson = nlohmann::json::parse(std::move(partsJsonStr)); | ||
21 | |||
22 | for (const nlohmann::json& partJson : partsJson) | ||
23 | { | ||
24 | part::type partType = static_cast<part::type>(partJson["type"].get<int>()); | ||
25 | |||
26 | switch (partType) | ||
27 | { | ||
28 | case part::type::noun_phrase: | ||
29 | { | ||
30 | std::set<std::string> synrestrs; | ||
31 | for (const nlohmann::json& synrestrJson : partJson["synrestrs"]) | ||
32 | { | ||
33 | synrestrs.insert(synrestrJson.get<std::string>()); | ||
34 | } | ||
35 | |||
36 | parts_.push_back(part::createNounPhrase( | ||
37 | partJson["role"].get<std::string>(), | ||
38 | selrestr(partJson["selrestrs"]), | ||
39 | std::move(synrestrs))); | ||
40 | |||
41 | break; | ||
42 | } | ||
43 | |||
44 | case part::type::preposition: | ||
45 | { | ||
46 | std::vector<std::string> choices; | ||
47 | for (const nlohmann::json& choiceJson : partJson["choices"]) | ||
48 | { | ||
49 | choices.push_back(choiceJson.get<std::string>()); | ||
50 | } | ||
51 | |||
52 | parts_.push_back(part::createPreposition( | ||
53 | std::move(choices), | ||
54 | partJson["literal"].get<bool>())); | ||
55 | |||
56 | break; | ||
57 | } | ||
58 | |||
59 | case part::type::verb: | ||
60 | { | ||
61 | parts_.push_back(part::createVerb()); | ||
62 | |||
63 | break; | ||
64 | } | ||
65 | |||
66 | case part::type::adjective: | ||
67 | { | ||
68 | parts_.push_back(part::createAdjective()); | ||
69 | |||
70 | break; | ||
71 | } | ||
72 | |||
73 | case part::type::adverb: | ||
74 | { | ||
75 | parts_.push_back(part::createAdverb()); | ||
76 | |||
77 | break; | ||
78 | } | ||
79 | 21 | ||
80 | case part::type::literal: | 22 | field frame::part(int index) |
81 | { | 23 | { |
82 | parts_.push_back(part::createLiteral(partJson["value"].get<std::string>())); | 24 | return field::joinWhere(object::frame, "frame_id", object::part, part::index, index); |
25 | } | ||
83 | 26 | ||
84 | break; | 27 | frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) |
85 | } | 28 | { |
29 | id_ = sqlite3_column_int(row, 0); | ||
30 | groupId_ = sqlite3_column_int(row, 1); | ||
31 | length_ = sqlite3_column_int(row, 2); | ||
86 | 32 | ||
87 | case part::type::invalid: | 33 | parts_ = db.parts(*this, verbly::part::index, -1).all(); |
88 | { | ||
89 | throw std::domain_error("Invalid part data"); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | } | 34 | } |
94 | 35 | ||
95 | }; | 36 | }; |
diff --git a/lib/frame.h b/lib/frame.h index 97473a0..36e179e 100644 --- a/lib/frame.h +++ b/lib/frame.h | |||
@@ -41,6 +41,16 @@ namespace verbly { | |||
41 | return id_; | 41 | return id_; |
42 | } | 42 | } |
43 | 43 | ||
44 | int getLength() const | ||
45 | { | ||
46 | if (!valid_) | ||
47 | { | ||
48 | throw std::domain_error("Bad access to uninitialized frame"); | ||
49 | } | ||
50 | |||
51 | return length_; | ||
52 | } | ||
53 | |||
44 | const std::vector<part>& getParts() const | 54 | const std::vector<part>& getParts() const |
45 | { | 55 | { |
46 | if (!valid_) | 56 | if (!valid_) |
@@ -61,6 +71,8 @@ namespace verbly { | |||
61 | 71 | ||
62 | static const field id; | 72 | static const field id; |
63 | 73 | ||
74 | static const field length; | ||
75 | |||
64 | operator filter() const | 76 | operator filter() const |
65 | { | 77 | { |
66 | if (!valid_) | 78 | if (!valid_) |
@@ -73,13 +85,18 @@ namespace verbly { | |||
73 | 85 | ||
74 | // Relationships to other objects | 86 | // Relationships to other objects |
75 | 87 | ||
76 | static const field group; | 88 | static const field word; |
89 | |||
90 | static field part(); | ||
91 | static field part(int index); | ||
77 | 92 | ||
78 | private: | 93 | private: |
79 | bool valid_ = false; | 94 | bool valid_ = false; |
80 | 95 | ||
81 | int id_; | 96 | int id_; |
82 | std::vector<part> parts_; | 97 | int groupId_; |
98 | int length_; | ||
99 | std::vector<class part> parts_; | ||
83 | 100 | ||
84 | const database* db_; | 101 | const database* db_; |
85 | 102 | ||
diff --git a/lib/group.cpp b/lib/group.cpp deleted file mode 100644 index d5790e9..0000000 --- a/lib/group.cpp +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | #include "group.h" | ||
2 | #include <sqlite3.h> | ||
3 | #include <json.hpp> | ||
4 | #include "database.h" | ||
5 | #include "query.h" | ||
6 | |||
7 | namespace 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 | std::string rolesJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 1))); | ||
23 | nlohmann::json rolesJson = nlohmann::json::parse(std::move(rolesJsonStr)); | ||
24 | for (const nlohmann::json& roleJson : rolesJson) | ||
25 | { | ||
26 | std::string roleName = roleJson["type"]; | ||
27 | selrestr roleSelrestr; | ||
28 | |||
29 | if (roleJson.find("selrestrs") != roleJson.end()) | ||
30 | { | ||
31 | roleSelrestr = selrestr(roleJson["selrestrs"]); | ||
32 | } | ||
33 | |||
34 | roles_[roleName] = role(roleName, std::move(roleSelrestr)); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | const std::vector<frame>& group::getFrames() const | ||
39 | { | ||
40 | if (!valid_) | ||
41 | { | ||
42 | throw std::domain_error("Bad access to uninitialized group"); | ||
43 | } | ||
44 | |||
45 | if (!initializedFrames_) | ||
46 | { | ||
47 | frames_ = db_->frames(frame::group %= *this, false, -1).all(); | ||
48 | |||
49 | initializedFrames_ = true; | ||
50 | } | ||
51 | |||
52 | return frames_; | ||
53 | } | ||
54 | |||
55 | const role& group::getRole(std::string roleName) const | ||
56 | { | ||
57 | return roles_.at(roleName); | ||
58 | } | ||
59 | |||
60 | }; | ||
61 | |||
diff --git a/lib/group.h b/lib/group.h deleted file mode 100644 index fe62d39..0000000 --- a/lib/group.h +++ /dev/null | |||
@@ -1,91 +0,0 @@ | |||
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 | #include "frame.h" | ||
10 | #include "role.h" | ||
11 | |||
12 | struct sqlite3_stmt; | ||
13 | |||
14 | namespace verbly { | ||
15 | |||
16 | class database; | ||
17 | |||
18 | class group { | ||
19 | public: | ||
20 | |||
21 | // Default constructor | ||
22 | |||
23 | group() = default; | ||
24 | |||
25 | // Construct from database | ||
26 | |||
27 | group(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 group"); | ||
41 | } | ||
42 | |||
43 | return id_; | ||
44 | } | ||
45 | |||
46 | const std::vector<frame>& getFrames() const; | ||
47 | |||
48 | const role& getRole(std::string roleName) const; | ||
49 | |||
50 | // Type info | ||
51 | |||
52 | static const object objectType; | ||
53 | |||
54 | static const std::list<std::string> select; | ||
55 | |||
56 | // Query fields | ||
57 | |||
58 | static const field id; | ||
59 | |||
60 | operator filter() const | ||
61 | { | ||
62 | if (!valid_) | ||
63 | { | ||
64 | throw std::domain_error("Bad access to uninitialized group"); | ||
65 | } | ||
66 | |||
67 | return (id == id_); | ||
68 | } | ||
69 | |||
70 | // Relationships to other objects | ||
71 | |||
72 | static const field frame; | ||
73 | |||
74 | static const field word; | ||
75 | |||
76 | private: | ||
77 | bool valid_ = false; | ||
78 | |||
79 | int id_; | ||
80 | std::map<std::string, role> roles_; | ||
81 | |||
82 | const database* db_; | ||
83 | |||
84 | mutable bool initializedFrames_ = false; | ||
85 | mutable std::vector<class frame> frames_; | ||
86 | |||
87 | }; | ||
88 | |||
89 | }; | ||
90 | |||
91 | #endif /* end of include guard: GROUP_H_BD6933C0 */ | ||
diff --git a/lib/lemma.cpp b/lib/lemma.cpp index 1601460..0c6e99e 100644 --- a/lib/lemma.cpp +++ b/lib/lemma.cpp | |||
@@ -10,20 +10,13 @@ namespace verbly { | |||
10 | const std::list<std::string> lemma::select = {"lemma_id"}; | 10 | const std::list<std::string> lemma::select = {"lemma_id"}; |
11 | 11 | ||
12 | const field lemma::id = field::integerField(object::lemma, "lemma_id"); | 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"); | 13 | const field lemma::inflectionCategory = field::integerField(object::lemma, "category"); |
18 | 14 | ||
19 | filter operator%=(lemma::inflection_field check, filter joinCondition) | 15 | const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word); |
20 | { | ||
21 | return (lemma::formJoin %= joinCondition) && (lemma::inflectionCategory == check.getCategory()); | ||
22 | } | ||
23 | 16 | ||
24 | lemma::inflection_field::operator filter() const | 17 | field lemma::form(inflection category) |
25 | { | 18 | { |
26 | return (lemma::inflectionCategory == category_); | 19 | return field::joinWhere(object::lemma, "form_id", object::form, inflectionCategory, static_cast<int>(category)); |
27 | } | 20 | } |
28 | 21 | ||
29 | lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 22 | lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) |
@@ -68,7 +61,7 @@ namespace verbly { | |||
68 | 61 | ||
69 | void lemma::initializeForm(inflection infl) const | 62 | void lemma::initializeForm(inflection infl) const |
70 | { | 63 | { |
71 | forms_[infl] = db_->forms(form::lemma(infl) %= *this, false, -1).all(); | 64 | forms_[infl] = db_->forms(form::lemma %= ((inflectionCategory == infl) && *this), verbly::form::id, -1).all(); |
72 | } | 65 | } |
73 | 66 | ||
74 | }; | 67 | }; |
diff --git a/lib/lemma.h b/lib/lemma.h index 407fa3c..56cfc56 100644 --- a/lib/lemma.h +++ b/lib/lemma.h | |||
@@ -74,31 +74,7 @@ namespace verbly { | |||
74 | 74 | ||
75 | static const field word; | 75 | static const field word; |
76 | 76 | ||
77 | class inflection_field { | 77 | static field form(inflection category); |
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 | operator filter() const; | ||
90 | |||
91 | private: | ||
92 | |||
93 | const inflection category_; | ||
94 | }; | ||
95 | |||
96 | static const inflection_field form(inflection category) | ||
97 | { | ||
98 | return inflection_field(category); | ||
99 | } | ||
100 | |||
101 | friend filter operator%=(lemma::inflection_field check, filter joinCondition); | ||
102 | 78 | ||
103 | private: | 79 | private: |
104 | 80 | ||
@@ -112,7 +88,6 @@ namespace verbly { | |||
112 | 88 | ||
113 | const database* db_; | 89 | const database* db_; |
114 | 90 | ||
115 | static const field formJoin; | ||
116 | static const field inflectionCategory; | 91 | static const field inflectionCategory; |
117 | 92 | ||
118 | }; | 93 | }; |
diff --git a/lib/order.h b/lib/order.h new file mode 100644 index 0000000..d2f0f92 --- /dev/null +++ b/lib/order.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef ORDER_H_0EC669D5 | ||
2 | #define ORDER_H_0EC669D5 | ||
3 | |||
4 | #include <stdexcept> | ||
5 | #include "field.h" | ||
6 | |||
7 | namespace verbly { | ||
8 | |||
9 | class order { | ||
10 | public: | ||
11 | enum class type { | ||
12 | random, | ||
13 | field | ||
14 | }; | ||
15 | |||
16 | // Type | ||
17 | |||
18 | type getType() const | ||
19 | { | ||
20 | return type_; | ||
21 | } | ||
22 | |||
23 | // Random | ||
24 | |||
25 | order() : type_(type::random) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | // Field | ||
30 | |||
31 | order( | ||
32 | field arg, | ||
33 | bool asc = true) : | ||
34 | type_(type::field), | ||
35 | sortField_(std::move(arg)), | ||
36 | ascending_(asc) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | field getSortField() const | ||
41 | { | ||
42 | if (type_ != type::field) | ||
43 | { | ||
44 | throw std::domain_error("Invalid access to non-field order"); | ||
45 | } | ||
46 | |||
47 | return sortField_; | ||
48 | } | ||
49 | |||
50 | bool isAscending() const | ||
51 | { | ||
52 | if (type_ != type::field) | ||
53 | { | ||
54 | throw std::domain_error("Invalid access to non-field order"); | ||
55 | } | ||
56 | |||
57 | return ascending_; | ||
58 | } | ||
59 | |||
60 | private: | ||
61 | type type_; | ||
62 | field sortField_; | ||
63 | bool ascending_; | ||
64 | |||
65 | }; | ||
66 | |||
67 | }; | ||
68 | |||
69 | #endif /* end of include guard: ORDER_H_0EC669D5 */ | ||
diff --git a/lib/part.cpp b/lib/part.cpp index e66d151..1fbb24d 100644 --- a/lib/part.cpp +++ b/lib/part.cpp | |||
@@ -1,12 +1,30 @@ | |||
1 | #include "part.h" | 1 | #include "part.h" |
2 | #include <stdexcept> | 2 | #include <stdexcept> |
3 | #include <sqlite3.h> | ||
3 | #include "selrestr.h" | 4 | #include "selrestr.h" |
5 | #include "database.h" | ||
4 | 6 | ||
5 | namespace verbly { | 7 | namespace verbly { |
6 | 8 | ||
9 | const object part::objectType = object::part; | ||
10 | |||
11 | const std::list<std::string> part::select = {"part_id", "frame_id", "part_index", "type", "role", "selrestrs", "prepositions", "preposition_literality", "literal_value"}; | ||
12 | |||
13 | const field part::index = field::integerField(object::part, "part_index"); | ||
14 | const field part::type = field::integerField(object::part, "type"); | ||
15 | |||
16 | const field part::role = field::stringField(object::part, "role", true); | ||
17 | |||
18 | const field part::frame = field::joinField(object::part, "frame_id", object::frame); | ||
19 | |||
20 | const field part::synrestr_field::synrestrJoin = field::joinField(object::part, "part_id", "synrestrs"); | ||
21 | const field part::synrestr_field::synrestrField = field::stringField("synrestrs", "synrestr"); | ||
22 | |||
23 | const part::synrestr_field part::synrestr = {}; | ||
24 | |||
7 | part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) | 25 | part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) |
8 | { | 26 | { |
9 | part p(type::noun_phrase); | 27 | part p(part_type::noun_phrase); |
10 | 28 | ||
11 | new(&p.noun_phrase_.role) std::string(std::move(role)); | 29 | new(&p.noun_phrase_.role) std::string(std::move(role)); |
12 | new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs)); | 30 | new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs)); |
@@ -17,12 +35,12 @@ namespace verbly { | |||
17 | 35 | ||
18 | part part::createVerb() | 36 | part part::createVerb() |
19 | { | 37 | { |
20 | return part(type::verb); | 38 | return part(part_type::verb); |
21 | } | 39 | } |
22 | 40 | ||
23 | part part::createPreposition(std::vector<std::string> choices, bool literal) | 41 | part part::createPreposition(std::vector<std::string> choices, bool literal) |
24 | { | 42 | { |
25 | part p(type::preposition); | 43 | part p(part_type::preposition); |
26 | 44 | ||
27 | new(&p.preposition_.choices) std::vector<std::string>(std::move(choices)); | 45 | new(&p.preposition_.choices) std::vector<std::string>(std::move(choices)); |
28 | p.preposition_.literal = literal; | 46 | p.preposition_.literal = literal; |
@@ -32,30 +50,79 @@ namespace verbly { | |||
32 | 50 | ||
33 | part part::createAdjective() | 51 | part part::createAdjective() |
34 | { | 52 | { |
35 | return part(type::adjective); | 53 | return part(part_type::adjective); |
36 | } | 54 | } |
37 | 55 | ||
38 | part part::createAdverb() | 56 | part part::createAdverb() |
39 | { | 57 | { |
40 | return part(type::adverb); | 58 | return part(part_type::adverb); |
41 | } | 59 | } |
42 | 60 | ||
43 | part part::createLiteral(std::string value) | 61 | part part::createLiteral(std::string value) |
44 | { | 62 | { |
45 | part p(type::literal); | 63 | part p(part_type::literal); |
46 | 64 | ||
47 | new(&p.literal_) std::string(std::move(value)); | 65 | new(&p.literal_) std::string(std::move(value)); |
48 | 66 | ||
49 | return p; | 67 | return p; |
50 | } | 68 | } |
51 | 69 | ||
70 | part::part(const database& db, sqlite3_stmt* row) | ||
71 | { | ||
72 | int id = sqlite3_column_int(row, 0); | ||
73 | |||
74 | type_ = static_cast<part_type>(sqlite3_column_int(row, 3)); | ||
75 | |||
76 | switch (type_) | ||
77 | { | ||
78 | case part_type::noun_phrase: | ||
79 | { | ||
80 | new(&noun_phrase_.role) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 4))); | ||
81 | new(&noun_phrase_.selrestrs) selrestr(nlohmann::json::parse(reinterpret_cast<const char*>(sqlite3_column_blob(row, 5)))); | ||
82 | new(&noun_phrase_.synrestrs) std::set<std::string>(db.synrestrs(id)); | ||
83 | |||
84 | break; | ||
85 | } | ||
86 | |||
87 | case part_type::preposition: | ||
88 | { | ||
89 | new(&preposition_.choices) std::vector<std::string>(); | ||
90 | preposition_.literal = (sqlite3_column_int(row, 7) == 1); | ||
91 | |||
92 | std::string choicesJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 6))); | ||
93 | nlohmann::json choicesJson = nlohmann::json::parse(std::move(choicesJsonStr)); | ||
94 | for (const nlohmann::json& choiceJson : choicesJson) | ||
95 | { | ||
96 | preposition_.choices.push_back(choiceJson.get<std::string>()); | ||
97 | } | ||
98 | |||
99 | break; | ||
100 | } | ||
101 | |||
102 | case part_type::literal: | ||
103 | { | ||
104 | new(&literal_) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 8))); | ||
105 | |||
106 | break; | ||
107 | } | ||
108 | |||
109 | case part_type::verb: | ||
110 | case part_type::adjective: | ||
111 | case part_type::adverb: | ||
112 | case part_type::invalid: | ||
113 | { | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
52 | part::part(const part& other) | 119 | part::part(const part& other) |
53 | { | 120 | { |
54 | type_ = other.type_; | 121 | type_ = other.type_; |
55 | 122 | ||
56 | switch (type_) | 123 | switch (type_) |
57 | { | 124 | { |
58 | case type::noun_phrase: | 125 | case part_type::noun_phrase: |
59 | { | 126 | { |
60 | new(&noun_phrase_.role) std::string(other.noun_phrase_.role); | 127 | new(&noun_phrase_.role) std::string(other.noun_phrase_.role); |
61 | new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); | 128 | new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); |
@@ -64,7 +131,7 @@ namespace verbly { | |||
64 | break; | 131 | break; |
65 | } | 132 | } |
66 | 133 | ||
67 | case type::preposition: | 134 | case part_type::preposition: |
68 | { | 135 | { |
69 | new(&preposition_.choices) std::vector<std::string>(other.preposition_.choices); | 136 | new(&preposition_.choices) std::vector<std::string>(other.preposition_.choices); |
70 | preposition_.literal = other.preposition_.literal; | 137 | preposition_.literal = other.preposition_.literal; |
@@ -72,17 +139,17 @@ namespace verbly { | |||
72 | break; | 139 | break; |
73 | } | 140 | } |
74 | 141 | ||
75 | case type::literal: | 142 | case part_type::literal: |
76 | { | 143 | { |
77 | new(&literal_) std::string(other.literal_); | 144 | new(&literal_) std::string(other.literal_); |
78 | 145 | ||
79 | break; | 146 | break; |
80 | } | 147 | } |
81 | 148 | ||
82 | case type::verb: | 149 | case part_type::verb: |
83 | case type::adjective: | 150 | case part_type::adjective: |
84 | case type::adverb: | 151 | case part_type::adverb: |
85 | case type::invalid: | 152 | case part_type::invalid: |
86 | { | 153 | { |
87 | break; | 154 | break; |
88 | } | 155 | } |
@@ -103,7 +170,7 @@ namespace verbly { | |||
103 | 170 | ||
104 | void swap(part& first, part& second) | 171 | void swap(part& first, part& second) |
105 | { | 172 | { |
106 | using type = part::type; | 173 | using type = part_type; |
107 | 174 | ||
108 | type tempType = first.type_; | 175 | type tempType = first.type_; |
109 | std::string tempRole; | 176 | std::string tempRole; |
@@ -231,7 +298,7 @@ namespace verbly { | |||
231 | { | 298 | { |
232 | switch (type_) | 299 | switch (type_) |
233 | { | 300 | { |
234 | case type::noun_phrase: | 301 | case part_type::noun_phrase: |
235 | { | 302 | { |
236 | using string_type = std::string; | 303 | using string_type = std::string; |
237 | using set_type = std::set<std::string>; | 304 | using set_type = std::set<std::string>; |
@@ -243,7 +310,7 @@ namespace verbly { | |||
243 | break; | 310 | break; |
244 | } | 311 | } |
245 | 312 | ||
246 | case type::preposition: | 313 | case part_type::preposition: |
247 | { | 314 | { |
248 | using vector_type = std::vector<std::string>; | 315 | using vector_type = std::vector<std::string>; |
249 | 316 | ||
@@ -252,7 +319,7 @@ namespace verbly { | |||
252 | break; | 319 | break; |
253 | } | 320 | } |
254 | 321 | ||
255 | case type::literal: | 322 | case part_type::literal: |
256 | { | 323 | { |
257 | using string_type = std::string; | 324 | using string_type = std::string; |
258 | 325 | ||
@@ -261,10 +328,10 @@ namespace verbly { | |||
261 | break; | 328 | break; |
262 | } | 329 | } |
263 | 330 | ||
264 | case type::verb: | 331 | case part_type::verb: |
265 | case type::adjective: | 332 | case part_type::adjective: |
266 | case type::adverb: | 333 | case part_type::adverb: |
267 | case type::invalid: | 334 | case part_type::invalid: |
268 | { | 335 | { |
269 | break; | 336 | break; |
270 | } | 337 | } |
@@ -273,7 +340,7 @@ namespace verbly { | |||
273 | 340 | ||
274 | std::string part::getNounRole() const | 341 | std::string part::getNounRole() const |
275 | { | 342 | { |
276 | if (type_ == type::noun_phrase) | 343 | if (type_ == part_type::noun_phrase) |
277 | { | 344 | { |
278 | return noun_phrase_.role; | 345 | return noun_phrase_.role; |
279 | } else { | 346 | } else { |
@@ -283,7 +350,7 @@ namespace verbly { | |||
283 | 350 | ||
284 | selrestr part::getNounSelrestrs() const | 351 | selrestr part::getNounSelrestrs() const |
285 | { | 352 | { |
286 | if (type_ == type::noun_phrase) | 353 | if (type_ == part_type::noun_phrase) |
287 | { | 354 | { |
288 | return noun_phrase_.selrestrs; | 355 | return noun_phrase_.selrestrs; |
289 | } else { | 356 | } else { |
@@ -293,7 +360,7 @@ namespace verbly { | |||
293 | 360 | ||
294 | std::set<std::string> part::getNounSynrestrs() const | 361 | std::set<std::string> part::getNounSynrestrs() const |
295 | { | 362 | { |
296 | if (type_ == type::noun_phrase) | 363 | if (type_ == part_type::noun_phrase) |
297 | { | 364 | { |
298 | return noun_phrase_.synrestrs; | 365 | return noun_phrase_.synrestrs; |
299 | } else { | 366 | } else { |
@@ -303,7 +370,7 @@ namespace verbly { | |||
303 | 370 | ||
304 | bool part::nounHasSynrestr(std::string synrestr) const | 371 | bool part::nounHasSynrestr(std::string synrestr) const |
305 | { | 372 | { |
306 | if (type_ != type::noun_phrase) | 373 | if (type_ != part_type::noun_phrase) |
307 | { | 374 | { |
308 | throw std::domain_error("part::nounHasSynrestr is only valid for noun phrase parts"); | 375 | throw std::domain_error("part::nounHasSynrestr is only valid for noun phrase parts"); |
309 | } | 376 | } |
@@ -313,7 +380,7 @@ namespace verbly { | |||
313 | 380 | ||
314 | std::vector<std::string> part::getPrepositionChoices() const | 381 | std::vector<std::string> part::getPrepositionChoices() const |
315 | { | 382 | { |
316 | if (type_ == type::preposition) | 383 | if (type_ == part_type::preposition) |
317 | { | 384 | { |
318 | return preposition_.choices; | 385 | return preposition_.choices; |
319 | } else { | 386 | } else { |
@@ -323,7 +390,7 @@ namespace verbly { | |||
323 | 390 | ||
324 | bool part::isPrepositionLiteral() const | 391 | bool part::isPrepositionLiteral() const |
325 | { | 392 | { |
326 | if (type_ == type::preposition) | 393 | if (type_ == part_type::preposition) |
327 | { | 394 | { |
328 | return preposition_.literal; | 395 | return preposition_.literal; |
329 | } else { | 396 | } else { |
@@ -333,7 +400,7 @@ namespace verbly { | |||
333 | 400 | ||
334 | std::string part::getLiteralValue() const | 401 | std::string part::getLiteralValue() const |
335 | { | 402 | { |
336 | if (type_ == type::literal) | 403 | if (type_ == part_type::literal) |
337 | { | 404 | { |
338 | return literal_; | 405 | return literal_; |
339 | } else { | 406 | } else { |
@@ -341,4 +408,9 @@ namespace verbly { | |||
341 | } | 408 | } |
342 | } | 409 | } |
343 | 410 | ||
411 | filter part::synrestr_field::operator%=(std::string synrestr) const | ||
412 | { | ||
413 | return (synrestrJoin %= (synrestrField == synrestr)); | ||
414 | } | ||
415 | |||
344 | }; | 416 | }; |
diff --git a/lib/part.h b/lib/part.h index 3a15638..9a01312 100644 --- a/lib/part.h +++ b/lib/part.h | |||
@@ -4,21 +4,20 @@ | |||
4 | #include <string> | 4 | #include <string> |
5 | #include <vector> | 5 | #include <vector> |
6 | #include <set> | 6 | #include <set> |
7 | #include <list> | ||
7 | #include "selrestr.h" | 8 | #include "selrestr.h" |
9 | #include "field.h" | ||
10 | #include "filter.h" | ||
11 | #include "enums.h" | ||
12 | |||
13 | struct sqlite3_stmt; | ||
8 | 14 | ||
9 | namespace verbly { | 15 | namespace verbly { |
10 | 16 | ||
17 | class database; | ||
18 | |||
11 | class part { | 19 | class part { |
12 | public: | 20 | public: |
13 | enum class type { | ||
14 | invalid = -1, | ||
15 | noun_phrase = 0, | ||
16 | verb = 1, | ||
17 | preposition = 2, | ||
18 | adjective = 3, | ||
19 | adverb = 4, | ||
20 | literal = 5 | ||
21 | }; | ||
22 | 21 | ||
23 | // Static factories | 22 | // Static factories |
24 | 23 | ||
@@ -40,6 +39,10 @@ namespace verbly { | |||
40 | { | 39 | { |
41 | } | 40 | } |
42 | 41 | ||
42 | // Construct from database | ||
43 | |||
44 | part(const database& db, sqlite3_stmt* row); | ||
45 | |||
43 | // Copy and move constructors | 46 | // Copy and move constructors |
44 | 47 | ||
45 | part(const part& other); | 48 | part(const part& other); |
@@ -60,7 +63,12 @@ namespace verbly { | |||
60 | 63 | ||
61 | // General accessors | 64 | // General accessors |
62 | 65 | ||
63 | type getType() const | 66 | operator bool() const |
67 | { | ||
68 | return (type_ != part_type::invalid); | ||
69 | } | ||
70 | |||
71 | part_type getType() const | ||
64 | { | 72 | { |
65 | return type_; | 73 | return type_; |
66 | } | 74 | } |
@@ -85,11 +93,43 @@ namespace verbly { | |||
85 | 93 | ||
86 | std::string getLiteralValue() const; | 94 | std::string getLiteralValue() const; |
87 | 95 | ||
96 | // Type info | ||
97 | |||
98 | static const object objectType; | ||
99 | |||
100 | static const std::list<std::string> select; | ||
101 | |||
102 | // Query fields | ||
103 | |||
104 | static const field index; | ||
105 | static const field type; | ||
106 | |||
107 | static const field role; | ||
108 | |||
109 | // Relationships to other objects | ||
110 | |||
111 | static const field frame; | ||
112 | |||
113 | // Noun synrestr relationship | ||
114 | |||
115 | class synrestr_field { | ||
116 | public: | ||
117 | |||
118 | filter operator%=(std::string synrestr) const; | ||
119 | |||
120 | private: | ||
121 | |||
122 | static const field synrestrJoin; | ||
123 | static const field synrestrField; | ||
124 | }; | ||
125 | |||
126 | static const synrestr_field synrestr; | ||
127 | |||
88 | private: | 128 | private: |
89 | 129 | ||
90 | // Private constructors | 130 | // Private constructors |
91 | 131 | ||
92 | part(type t) : type_(t) | 132 | part(part_type t) : type_(t) |
93 | { | 133 | { |
94 | } | 134 | } |
95 | 135 | ||
@@ -108,7 +148,7 @@ namespace verbly { | |||
108 | std::string literal_; | 148 | std::string literal_; |
109 | }; | 149 | }; |
110 | 150 | ||
111 | type type_ = type::invalid; | 151 | part_type type_ = part_type::invalid; |
112 | 152 | ||
113 | }; | 153 | }; |
114 | 154 | ||
diff --git a/lib/query.h b/lib/query.h index 214bf99..75651f6 100644 --- a/lib/query.h +++ b/lib/query.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <iostream> | 9 | #include <iostream> |
10 | #include "statement.h" | 10 | #include "statement.h" |
11 | #include "binding.h" | 11 | #include "binding.h" |
12 | #include "order.h" | ||
12 | 13 | ||
13 | namespace verbly { | 14 | namespace verbly { |
14 | 15 | ||
@@ -24,11 +25,17 @@ namespace verbly { | |||
24 | class query { | 25 | class query { |
25 | public: | 26 | public: |
26 | 27 | ||
27 | query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db) | 28 | query(const database& db, sqlite3* ppdb, filter queryFilter, order sortOrder, int limit) : db_(&db) |
28 | { | 29 | { |
30 | if ((sortOrder.getType() == order::type::field) | ||
31 | && (sortOrder.getSortField().getObject() != Object::objectType)) | ||
32 | { | ||
33 | throw std::invalid_argument("Can only sort query by a field in the result table"); | ||
34 | } | ||
35 | |||
29 | statement stmt(Object::objectType, std::move(queryFilter)); | 36 | statement stmt(Object::objectType, std::move(queryFilter)); |
30 | 37 | ||
31 | std::string queryString = stmt.getQueryString(Object::select, random, limit); | 38 | std::string queryString = stmt.getQueryString(Object::select, std::move(sortOrder), limit); |
32 | std::list<binding> bindings = stmt.getBindings(); | 39 | std::list<binding> bindings = stmt.getBindings(); |
33 | 40 | ||
34 | if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) | 41 | if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) |
diff --git a/lib/role.h b/lib/role.h deleted file mode 100644 index 4884ef3..0000000 --- a/lib/role.h +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | #ifndef ROLE_H_249F9A9C | ||
2 | #define ROLE_H_249F9A9C | ||
3 | |||
4 | #include <stdexcept> | ||
5 | #include <string> | ||
6 | #include "../lib/selrestr.h" | ||
7 | |||
8 | namespace verbly { | ||
9 | |||
10 | class role { | ||
11 | public: | ||
12 | |||
13 | // Default constructor | ||
14 | |||
15 | role() = default; | ||
16 | |||
17 | // Constructor | ||
18 | |||
19 | role( | ||
20 | std::string name, | ||
21 | selrestr selrestrs = {}) : | ||
22 | valid_(true), | ||
23 | name_(name), | ||
24 | selrestrs_(selrestrs) | ||
25 | { | ||
26 | } | ||
27 | |||
28 | // Accessors | ||
29 | |||
30 | const std::string& getName() const | ||
31 | { | ||
32 | if (!valid_) | ||
33 | { | ||
34 | throw std::domain_error("Bad access to invalid role"); | ||
35 | } | ||
36 | |||
37 | return name_; | ||
38 | } | ||
39 | |||
40 | const selrestr& getSelrestrs() const | ||
41 | { | ||
42 | if (!valid_) | ||
43 | { | ||
44 | throw std::domain_error("Bad access to invalid role"); | ||
45 | } | ||
46 | |||
47 | return selrestrs_; | ||
48 | } | ||
49 | |||
50 | private: | ||
51 | |||
52 | bool valid_ = false; | ||
53 | std::string name_; | ||
54 | selrestr selrestrs_; | ||
55 | |||
56 | }; | ||
57 | |||
58 | }; | ||
59 | |||
60 | #endif /* end of include guard: ROLE_H_249F9A9C */ | ||
diff --git a/lib/statement.cpp b/lib/statement.cpp index 846b9de..1512aa5 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp | |||
@@ -5,11 +5,12 @@ | |||
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "notion.h" | 6 | #include "notion.h" |
7 | #include "word.h" | 7 | #include "word.h" |
8 | #include "group.h" | ||
9 | #include "frame.h" | 8 | #include "frame.h" |
9 | #include "part.h" | ||
10 | #include "lemma.h" | 10 | #include "lemma.h" |
11 | #include "form.h" | 11 | #include "form.h" |
12 | #include "pronunciation.h" | 12 | #include "pronunciation.h" |
13 | #include "order.h" | ||
13 | 14 | ||
14 | namespace verbly { | 15 | namespace verbly { |
15 | 16 | ||
@@ -20,7 +21,7 @@ namespace verbly { | |||
20 | { | 21 | { |
21 | } | 22 | } |
22 | 23 | ||
23 | std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const | 24 | std::string statement::getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug) const |
24 | { | 25 | { |
25 | std::stringstream queryStream; | 26 | std::stringstream queryStream; |
26 | 27 | ||
@@ -49,7 +50,7 @@ namespace verbly { | |||
49 | if (cte.getCondition().getType() != condition::type::empty) | 50 | if (cte.getCondition().getType() != condition::type::empty) |
50 | { | 51 | { |
51 | cteStream << " WHERE "; | 52 | cteStream << " WHERE "; |
52 | cteStream << cte.getCondition().toSql(); | 53 | cteStream << cte.getCondition().flatten().toSql(true, debug); |
53 | } | 54 | } |
54 | 55 | ||
55 | if (cte.isRecursive()) | 56 | if (cte.isRecursive()) |
@@ -101,12 +102,28 @@ namespace verbly { | |||
101 | if (topCondition_.getType() != condition::type::empty) | 102 | if (topCondition_.getType() != condition::type::empty) |
102 | { | 103 | { |
103 | queryStream << " WHERE "; | 104 | queryStream << " WHERE "; |
104 | queryStream << topCondition_.toSql(); | 105 | queryStream << topCondition_.flatten().toSql(true, debug); |
105 | } | 106 | } |
106 | 107 | ||
107 | if (random) | 108 | queryStream << " ORDER BY "; |
109 | |||
110 | switch (sortOrder.getType()) | ||
108 | { | 111 | { |
109 | queryStream << " ORDER BY RANDOM()"; | 112 | case order::type::random: |
113 | { | ||
114 | queryStream << "RANDOM()"; | ||
115 | |||
116 | break; | ||
117 | } | ||
118 | |||
119 | case order::type::field: | ||
120 | { | ||
121 | queryStream << topTable_; | ||
122 | queryStream << "."; | ||
123 | queryStream << sortOrder.getSortField().getColumn(); | ||
124 | |||
125 | break; | ||
126 | } | ||
110 | } | 127 | } |
111 | 128 | ||
112 | if (limit > 0) | 129 | if (limit > 0) |
@@ -260,6 +277,7 @@ namespace verbly { | |||
260 | } | 277 | } |
261 | 278 | ||
262 | case field::type::join: | 279 | case field::type::join: |
280 | case field::type::join_where: | ||
263 | { | 281 | { |
264 | // First, figure out what table we need to join against. | 282 | // First, figure out what table we need to join against. |
265 | std::string joinTableName; | 283 | std::string joinTableName; |
@@ -269,13 +287,22 @@ namespace verbly { | |||
269 | } else { | 287 | } else { |
270 | joinTableName = getTableForContext(clause.getField().getJoinObject()); | 288 | joinTableName = getTableForContext(clause.getField().getJoinObject()); |
271 | } | 289 | } |
290 | |||
291 | filter joinCondition = clause.getJoinCondition(); | ||
292 | |||
293 | // If this is a condition join, we need to add the field join | ||
294 | // condition to the clause. | ||
295 | if (clause.getField().getType() == field::type::join_where) | ||
296 | { | ||
297 | joinCondition &= (clause.getField().getConditionField() == clause.getField().getConditionValue()); | ||
298 | } | ||
272 | 299 | ||
273 | // Recursively parse the subquery, and therefore obtain an | 300 | // Recursively parse the subquery, and therefore obtain an |
274 | // instantiated table to join against, as well as any joins or CTEs | 301 | // instantiated table to join against, as well as any joins or CTEs |
275 | // that the subquery may require to function. | 302 | // that the subquery may require to function. |
276 | statement joinStmt( | 303 | statement joinStmt( |
277 | joinTableName, | 304 | joinTableName, |
278 | clause.getJoinCondition().normalize(clause.getField().getJoinObject()), | 305 | std::move(joinCondition).normalize(clause.getField().getJoinObject()), |
279 | nextTableId_, | 306 | nextTableId_, |
280 | nextWithId_); | 307 | nextWithId_); |
281 | 308 | ||
@@ -801,7 +828,7 @@ namespace verbly { | |||
801 | new(&singleton_.value_) binding(std::move(value)); | 828 | new(&singleton_.value_) binding(std::move(value)); |
802 | } | 829 | } |
803 | 830 | ||
804 | std::string statement::condition::toSql() const | 831 | std::string statement::condition::toSql(bool toplevel, bool debug) const |
805 | { | 832 | { |
806 | switch (type_) | 833 | switch (type_) |
807 | { | 834 | { |
@@ -816,42 +843,92 @@ namespace verbly { | |||
816 | { | 843 | { |
817 | case comparison::equals: | 844 | case comparison::equals: |
818 | { | 845 | { |
819 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | 846 | if (debug) |
847 | { | ||
848 | if (singleton_.value_.getType() == binding::type::string) | ||
849 | { | ||
850 | return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; | ||
851 | } else { | ||
852 | return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); | ||
853 | } | ||
854 | } else { | ||
855 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | ||
856 | } | ||
820 | } | 857 | } |
821 | 858 | ||
822 | case comparison::does_not_equal: | 859 | case comparison::does_not_equal: |
823 | { | 860 | { |
824 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | 861 | if (debug) |
862 | { | ||
863 | if (singleton_.value_.getType() == binding::type::string) | ||
864 | { | ||
865 | return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; | ||
866 | } else { | ||
867 | return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); | ||
868 | } | ||
869 | } else { | ||
870 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | ||
871 | } | ||
825 | } | 872 | } |
826 | 873 | ||
827 | case comparison::is_greater_than: | 874 | case comparison::is_greater_than: |
828 | { | 875 | { |
829 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | 876 | if (debug) |
877 | { | ||
878 | return singleton_.table_ + "." + singleton_.column_ + " > " + std::to_string(singleton_.value_.getInteger()); | ||
879 | } else { | ||
880 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | ||
881 | } | ||
830 | } | 882 | } |
831 | 883 | ||
832 | case comparison::is_at_most: | 884 | case comparison::is_at_most: |
833 | { | 885 | { |
834 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | 886 | if (debug) |
887 | { | ||
888 | return singleton_.table_ + "." + singleton_.column_ + " <= " + std::to_string(singleton_.value_.getInteger()); | ||
889 | } else { | ||
890 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | ||
891 | } | ||
835 | } | 892 | } |
836 | 893 | ||
837 | case comparison::is_less_than: | 894 | case comparison::is_less_than: |
838 | { | 895 | { |
839 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | 896 | if (debug) |
897 | { | ||
898 | return singleton_.table_ + "." + singleton_.column_ + " < " + std::to_string(singleton_.value_.getInteger()); | ||
899 | } else { | ||
900 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | ||
901 | } | ||
840 | } | 902 | } |
841 | 903 | ||
842 | case comparison::is_at_least: | 904 | case comparison::is_at_least: |
843 | { | 905 | { |
844 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | 906 | if (debug) |
907 | { | ||
908 | return singleton_.table_ + "." + singleton_.column_ + " >= " + std::to_string(singleton_.value_.getInteger()); | ||
909 | } else { | ||
910 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | ||
911 | } | ||
845 | } | 912 | } |
846 | 913 | ||
847 | case comparison::is_like: | 914 | case comparison::is_like: |
848 | { | 915 | { |
849 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | 916 | if (debug) |
917 | { | ||
918 | return singleton_.table_ + "." + singleton_.column_ + " LIKE \"" + singleton_.value_.getString() + "\""; | ||
919 | } else { | ||
920 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | ||
921 | } | ||
850 | } | 922 | } |
851 | 923 | ||
852 | case comparison::is_not_like: | 924 | case comparison::is_not_like: |
853 | { | 925 | { |
854 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | 926 | if (debug) |
927 | { | ||
928 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE \"" + singleton_.value_.getString() + "\""; | ||
929 | } else { | ||
930 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | ||
931 | } | ||
855 | } | 932 | } |
856 | 933 | ||
857 | case comparison::is_not_null: | 934 | case comparison::is_not_null: |
@@ -871,10 +948,25 @@ namespace verbly { | |||
871 | std::list<std::string> clauses; | 948 | std::list<std::string> clauses; |
872 | for (const condition& cond : group_.children_) | 949 | for (const condition& cond : group_.children_) |
873 | { | 950 | { |
874 | clauses.push_back(cond.toSql()); | 951 | clauses.push_back(cond.toSql(false, debug)); |
875 | } | 952 | } |
876 | 953 | ||
877 | return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | 954 | if (clauses.empty()) |
955 | { | ||
956 | return ""; | ||
957 | } else if (clauses.size() == 1) | ||
958 | { | ||
959 | return clauses.front(); | ||
960 | } else { | ||
961 | std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | ||
962 | |||
963 | if (toplevel) | ||
964 | { | ||
965 | return result; | ||
966 | } else { | ||
967 | return "(" + result + ")"; | ||
968 | } | ||
969 | } | ||
878 | } | 970 | } |
879 | } | 971 | } |
880 | } | 972 | } |
@@ -988,5 +1080,39 @@ namespace verbly { | |||
988 | throw std::domain_error("Cannot get children of non-group condition"); | 1080 | throw std::domain_error("Cannot get children of non-group condition"); |
989 | } | 1081 | } |
990 | } | 1082 | } |
1083 | |||
1084 | statement::condition statement::condition::flatten() const | ||
1085 | { | ||
1086 | switch (type_) | ||
1087 | { | ||
1088 | case type::empty: | ||
1089 | case type::singleton: | ||
1090 | { | ||
1091 | return *this; | ||
1092 | } | ||
1093 | |||
1094 | case type::group: | ||
1095 | { | ||
1096 | condition result(group_.orlogic_); | ||
1097 | |||
1098 | for (const condition& child : group_.children_) | ||
1099 | { | ||
1100 | condition newChild = child.flatten(); | ||
1101 | |||
1102 | if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) | ||
1103 | { | ||
1104 | for (condition subChild : std::move(newChild.group_.children_)) | ||
1105 | { | ||
1106 | result += std::move(subChild); | ||
1107 | } | ||
1108 | } else { | ||
1109 | result += std::move(newChild); | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | return result; | ||
1114 | } | ||
1115 | } | ||
1116 | } | ||
991 | 1117 | ||
992 | }; | 1118 | }; |
diff --git a/lib/statement.h b/lib/statement.h index aa56568..15c4ac3 100644 --- a/lib/statement.h +++ b/lib/statement.h | |||
@@ -13,13 +13,14 @@ | |||
13 | namespace verbly { | 13 | namespace verbly { |
14 | 14 | ||
15 | class filter; | 15 | class filter; |
16 | class order; | ||
16 | 17 | ||
17 | class statement { | 18 | class statement { |
18 | public: | 19 | public: |
19 | 20 | ||
20 | statement(object context, filter queryFilter); | 21 | statement(object context, filter queryFilter); |
21 | 22 | ||
22 | std::string getQueryString(std::list<std::string> select, bool random, int limit) const; | 23 | std::string getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug = false) const; |
23 | 24 | ||
24 | std::list<binding> getBindings() const; | 25 | std::list<binding> getBindings() const; |
25 | 26 | ||
@@ -153,10 +154,12 @@ namespace verbly { | |||
153 | 154 | ||
154 | // Utility | 155 | // Utility |
155 | 156 | ||
156 | std::string toSql() const; | 157 | std::string toSql(bool toplevel, bool debug = false) const; |
157 | 158 | ||
158 | std::list<binding> flattenBindings() const; | 159 | std::list<binding> flattenBindings() const; |
159 | 160 | ||
161 | condition flatten() const; | ||
162 | |||
160 | private: | 163 | private: |
161 | union { | 164 | union { |
162 | struct { | 165 | struct { |
@@ -246,8 +249,8 @@ namespace verbly { | |||
246 | { | 249 | { |
247 | return (context == object::notion) ? "notions" | 250 | return (context == object::notion) ? "notions" |
248 | : (context == object::word) ? "words" | 251 | : (context == object::word) ? "words" |
249 | : (context == object::group) ? "groups" | ||
250 | : (context == object::frame) ? "frames" | 252 | : (context == object::frame) ? "frames" |
253 | : (context == object::part) ? "parts" | ||
251 | : (context == object::lemma) ? "lemmas_forms" | 254 | : (context == object::lemma) ? "lemmas_forms" |
252 | : (context == object::form) ? "forms" | 255 | : (context == object::form) ? "forms" |
253 | : (context == object::pronunciation) ? "pronunciations" | 256 | : (context == object::pronunciation) ? "pronunciations" |
diff --git a/lib/verbly.h b/lib/verbly.h index d8875b3..112907b 100644 --- a/lib/verbly.h +++ b/lib/verbly.h | |||
@@ -6,16 +6,15 @@ | |||
6 | #include "filter.h" | 6 | #include "filter.h" |
7 | #include "field.h" | 7 | #include "field.h" |
8 | #include "query.h" | 8 | #include "query.h" |
9 | #include "order.h" | ||
9 | #include "notion.h" | 10 | #include "notion.h" |
10 | #include "word.h" | 11 | #include "word.h" |
11 | #include "group.h" | ||
12 | #include "frame.h" | 12 | #include "frame.h" |
13 | #include "part.h" | ||
13 | #include "lemma.h" | 14 | #include "lemma.h" |
14 | #include "form.h" | 15 | #include "form.h" |
15 | #include "pronunciation.h" | 16 | #include "pronunciation.h" |
16 | #include "token.h" | 17 | #include "token.h" |
17 | #include "selrestr.h" | 18 | #include "selrestr.h" |
18 | #include "part.h" | ||
19 | #include "role.h" | ||
20 | 19 | ||
21 | #endif /* end of include guard: VERBLY_H_5B39CE50 */ | 20 | #endif /* end of include guard: VERBLY_H_5B39CE50 */ |
diff --git a/lib/word.cpp b/lib/word.cpp index a928659..90eab1d 100644 --- a/lib/word.cpp +++ b/lib/word.cpp | |||
@@ -17,7 +17,7 @@ namespace verbly { | |||
17 | 17 | ||
18 | const field word::notion = field::joinField(object::word, "notion_id", object::notion); | 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); | 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); | 20 | const field word::frame = field::joinField(object::word, "group_id", object::frame, true); |
21 | 21 | ||
22 | const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id"); | 22 | const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id"); |
23 | 23 | ||
@@ -93,7 +93,27 @@ namespace verbly { | |||
93 | return lemma_; | 93 | return lemma_; |
94 | } | 94 | } |
95 | 95 | ||
96 | const group& word::getGroup() const | 96 | bool word::hasFrames() const |
97 | { | ||
98 | if (!valid_) | ||
99 | { | ||
100 | throw std::domain_error("Bad access to uninitialized word"); | ||
101 | } | ||
102 | |||
103 | if (!hasGroup_) | ||
104 | { | ||
105 | return false; | ||
106 | } | ||
107 | |||
108 | if (!initializedFrames_) | ||
109 | { | ||
110 | initializeFrames(); | ||
111 | } | ||
112 | |||
113 | return !frames_.empty(); | ||
114 | } | ||
115 | |||
116 | const std::vector<frame>& word::getFrames() const | ||
97 | { | 117 | { |
98 | if (!valid_) | 118 | if (!valid_) |
99 | { | 119 | { |
@@ -105,12 +125,12 @@ namespace verbly { | |||
105 | throw std::domain_error("Word does not have a group"); | 125 | throw std::domain_error("Word does not have a group"); |
106 | } | 126 | } |
107 | 127 | ||
108 | if (!group_) | 128 | if (!initializedFrames_) |
109 | { | 129 | { |
110 | group_ = db_->groups(group::id == groupId_).first(); | 130 | initializeFrames(); |
111 | } | 131 | } |
112 | 132 | ||
113 | return group_; | 133 | return frames_; |
114 | } | 134 | } |
115 | 135 | ||
116 | std::string word::getBaseForm() const | 136 | std::string word::getBaseForm() const |
@@ -129,4 +149,10 @@ namespace verbly { | |||
129 | return result; | 149 | return result; |
130 | } | 150 | } |
131 | 151 | ||
152 | void word::initializeFrames() const | ||
153 | { | ||
154 | initializedFrames_ = true; | ||
155 | frames_ = db_->frames(*this, {}, -1).all(); | ||
156 | } | ||
157 | |||
132 | }; | 158 | }; |
diff --git a/lib/word.h b/lib/word.h index ddcabe4..8a333a4 100644 --- a/lib/word.h +++ b/lib/word.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include "filter.h" | 7 | #include "filter.h" |
8 | #include "notion.h" | 8 | #include "notion.h" |
9 | #include "lemma.h" | 9 | #include "lemma.h" |
10 | #include "group.h" | 10 | #include "frame.h" |
11 | 11 | ||
12 | struct sqlite3_stmt; | 12 | struct sqlite3_stmt; |
13 | 13 | ||
@@ -97,17 +97,9 @@ namespace verbly { | |||
97 | 97 | ||
98 | const lemma& getLemma() const; | 98 | const lemma& getLemma() const; |
99 | 99 | ||
100 | bool hasGroup() const | 100 | bool hasFrames() const; |
101 | { | ||
102 | if (!valid_) | ||
103 | { | ||
104 | throw std::domain_error("Bad access to uninitialized word"); | ||
105 | } | ||
106 | 101 | ||
107 | return hasGroup_; | 102 | const std::vector<frame>& getFrames() const; |
108 | } | ||
109 | |||
110 | const group& getGroup() const; | ||
111 | 103 | ||
112 | // Convenience accessors | 104 | // Convenience accessors |
113 | 105 | ||
@@ -136,7 +128,7 @@ namespace verbly { | |||
136 | 128 | ||
137 | static const field notion; | 129 | static const field notion; |
138 | static const field lemma; | 130 | static const field lemma; |
139 | static const field group; | 131 | static const field frame; |
140 | 132 | ||
141 | // Relationships with self | 133 | // Relationships with self |
142 | 134 | ||
@@ -161,6 +153,9 @@ namespace verbly { | |||
161 | static const field regionalDomains; | 153 | static const field regionalDomains; |
162 | 154 | ||
163 | private: | 155 | private: |
156 | |||
157 | void initializeFrames() const; | ||
158 | |||
164 | bool valid_ = false; | 159 | bool valid_ = false; |
165 | 160 | ||
166 | int id_; | 161 | int id_; |
@@ -176,7 +171,9 @@ namespace verbly { | |||
176 | 171 | ||
177 | mutable class notion notion_; | 172 | mutable class notion notion_; |
178 | mutable class lemma lemma_; | 173 | mutable class lemma lemma_; |
179 | mutable class group group_; | 174 | |
175 | mutable bool initializedFrames_ = false; | ||
176 | mutable std::vector<class frame> frames_; | ||
180 | 177 | ||
181 | }; | 178 | }; |
182 | 179 | ||