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 | ||
