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