diff options
-rw-r--r-- | lib/field.h | 107 | ||||
-rw-r--r-- | lib/filter.cpp | 32 |
2 files changed, 82 insertions, 57 deletions
diff --git a/lib/field.h b/lib/field.h index 30c62be..f61e038 100644 --- a/lib/field.h +++ b/lib/field.h | |||
@@ -6,9 +6,9 @@ | |||
6 | #include <tuple> | 6 | #include <tuple> |
7 | 7 | ||
8 | namespace verbly { | 8 | namespace verbly { |
9 | 9 | ||
10 | class filter; | 10 | class filter; |
11 | 11 | ||
12 | class field { | 12 | class field { |
13 | public: | 13 | public: |
14 | enum class type { | 14 | enum class type { |
@@ -20,15 +20,15 @@ namespace verbly { | |||
20 | join_through, | 20 | join_through, |
21 | hierarchal_join | 21 | hierarchal_join |
22 | }; | 22 | }; |
23 | 23 | ||
24 | // Default constructor | 24 | // Default constructor |
25 | 25 | ||
26 | field() | 26 | field() |
27 | { | 27 | { |
28 | } | 28 | } |
29 | 29 | ||
30 | // Static factories | 30 | // Static factories |
31 | 31 | ||
32 | static field stringField( | 32 | static field stringField( |
33 | object obj, | 33 | object obj, |
34 | const char* name, | 34 | const char* name, |
@@ -36,7 +36,7 @@ namespace verbly { | |||
36 | { | 36 | { |
37 | return field(obj, type::string, name, nullable); | 37 | return field(obj, type::string, name, nullable); |
38 | } | 38 | } |
39 | 39 | ||
40 | static field stringField( | 40 | static field stringField( |
41 | const char* table, | 41 | const char* table, |
42 | const char* name, | 42 | const char* name, |
@@ -44,7 +44,7 @@ namespace verbly { | |||
44 | { | 44 | { |
45 | return field(object::undefined, type::string, name, nullable, table); | 45 | return field(object::undefined, type::string, name, nullable, table); |
46 | } | 46 | } |
47 | 47 | ||
48 | static field integerField( | 48 | static field integerField( |
49 | object obj, | 49 | object obj, |
50 | const char* name, | 50 | const char* name, |
@@ -52,7 +52,7 @@ namespace verbly { | |||
52 | { | 52 | { |
53 | return field(obj, type::integer, name, nullable); | 53 | return field(obj, type::integer, name, nullable); |
54 | } | 54 | } |
55 | 55 | ||
56 | static field integerField( | 56 | static field integerField( |
57 | const char* table, | 57 | const char* table, |
58 | const char* name, | 58 | const char* name, |
@@ -60,7 +60,7 @@ namespace verbly { | |||
60 | { | 60 | { |
61 | return field(object::undefined, type::integer, name, nullable, table); | 61 | return field(object::undefined, type::integer, name, nullable, table); |
62 | } | 62 | } |
63 | 63 | ||
64 | static field booleanField( | 64 | static field booleanField( |
65 | object obj, | 65 | object obj, |
66 | const char* name, | 66 | const char* name, |
@@ -68,7 +68,7 @@ namespace verbly { | |||
68 | { | 68 | { |
69 | return field(obj, type::boolean, name, nullable); | 69 | return field(obj, type::boolean, name, nullable); |
70 | } | 70 | } |
71 | 71 | ||
72 | static field booleanField( | 72 | static field booleanField( |
73 | const char* table, | 73 | const char* table, |
74 | const char* name, | 74 | const char* name, |
@@ -76,7 +76,7 @@ namespace verbly { | |||
76 | { | 76 | { |
77 | return field(object::undefined, type::boolean, name, nullable, table); | 77 | return field(object::undefined, type::boolean, name, nullable, table); |
78 | } | 78 | } |
79 | 79 | ||
80 | static field joinField( | 80 | static field joinField( |
81 | object obj, | 81 | object obj, |
82 | const char* name, | 82 | const char* name, |
@@ -85,7 +85,7 @@ namespace verbly { | |||
85 | { | 85 | { |
86 | return field(obj, type::join, name, nullable, 0, joinWith); | 86 | return field(obj, type::join, name, nullable, 0, joinWith); |
87 | } | 87 | } |
88 | 88 | ||
89 | static field joinField( | 89 | static field joinField( |
90 | object obj, | 90 | object obj, |
91 | const char* name, | 91 | const char* name, |
@@ -94,7 +94,7 @@ namespace verbly { | |||
94 | { | 94 | { |
95 | return field(obj, type::join, name, nullable, table); | 95 | return field(obj, type::join, name, nullable, table); |
96 | } | 96 | } |
97 | 97 | ||
98 | static field joinThrough( | 98 | static field joinThrough( |
99 | object obj, | 99 | object obj, |
100 | const char* name, | 100 | const char* name, |
@@ -104,7 +104,7 @@ namespace verbly { | |||
104 | { | 104 | { |
105 | return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, name, foreignColumn); | 105 | return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, name, foreignColumn); |
106 | } | 106 | } |
107 | 107 | ||
108 | static field joinThrough( | 108 | static field joinThrough( |
109 | object obj, | 109 | object obj, |
110 | const char* name, | 110 | const char* name, |
@@ -116,7 +116,7 @@ namespace verbly { | |||
116 | { | 116 | { |
117 | return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, joinColumn, foreignJoinColumn); | 117 | return field(obj, type::join_through, name, true, joinTable, joinWith, foreignColumn, joinColumn, foreignJoinColumn); |
118 | } | 118 | } |
119 | 119 | ||
120 | static field selfJoin( | 120 | static field selfJoin( |
121 | object obj, | 121 | object obj, |
122 | const char* name, | 122 | const char* name, |
@@ -126,7 +126,7 @@ namespace verbly { | |||
126 | { | 126 | { |
127 | return field(obj, type::join_through, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn); | 127 | return field(obj, type::join_through, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn); |
128 | } | 128 | } |
129 | 129 | ||
130 | static field hierarchalSelfJoin( | 130 | static field hierarchalSelfJoin( |
131 | object obj, | 131 | object obj, |
132 | const char* name, | 132 | const char* name, |
@@ -136,56 +136,57 @@ namespace verbly { | |||
136 | { | 136 | { |
137 | return field(obj, type::hierarchal_join, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn); | 137 | return field(obj, type::hierarchal_join, name, true, joinTable, obj, name, joinColumn, foreignJoinColumn); |
138 | } | 138 | } |
139 | 139 | ||
140 | // Accessors | 140 | // Accessors |
141 | 141 | ||
142 | object getObject() const | 142 | object getObject() const |
143 | { | 143 | { |
144 | return object_; | 144 | return object_; |
145 | } | 145 | } |
146 | 146 | ||
147 | type getType() const | 147 | type getType() const |
148 | { | 148 | { |
149 | return type_; | 149 | return type_; |
150 | } | 150 | } |
151 | 151 | ||
152 | bool isJoin() const | 152 | bool isJoin() const |
153 | { | 153 | { |
154 | return ((type_ == type::join) || (type_ == type::join_through) || (type_ == type::hierarchal_join)); | 154 | return ((type_ == type::join) || (type_ == type::join_through) || (type_ == type::hierarchal_join)); |
155 | } | 155 | } |
156 | 156 | ||
157 | const char* getColumn() const | 157 | const char* getColumn() const |
158 | { | 158 | { |
159 | return column_; | 159 | return column_; |
160 | } | 160 | } |
161 | 161 | ||
162 | bool isNullable() const | 162 | bool isNullable() const |
163 | { | 163 | { |
164 | return nullable_; | 164 | return nullable_; |
165 | } | 165 | } |
166 | 166 | ||
167 | bool hasTable() const | 167 | bool hasTable() const |
168 | { | 168 | { |
169 | return (table_ != 0); | 169 | return (table_ != 0); |
170 | } | 170 | } |
171 | 171 | ||
172 | const char* getTable() const | 172 | const char* getTable() const |
173 | { | 173 | { |
174 | return table_; | 174 | return table_; |
175 | } | 175 | } |
176 | 176 | ||
177 | // Joins | 177 | // Joins |
178 | 178 | ||
179 | object getJoinObject() const | 179 | object getJoinObject() const |
180 | { | 180 | { |
181 | // We ignore hierarchal joins because they are always self joins. | 181 | return (type_ == type::hierarchal_join) |
182 | return ((type_ == type::join) || (type_ == type::join_through)) | 182 | ? object_ |
183 | : ((type_ == type::join) || (type_ == type::join_through)) | ||
183 | ? joinObject_ | 184 | ? joinObject_ |
184 | : throw std::domain_error("Non-join fields don't have join objects"); | 185 | : throw std::domain_error("Non-join fields don't have join objects"); |
185 | } | 186 | } |
186 | 187 | ||
187 | // Many-to-many joins | 188 | // Many-to-many joins |
188 | 189 | ||
189 | const char* getForeignColumn() const | 190 | const char* getForeignColumn() const |
190 | { | 191 | { |
191 | // We ignore hierarchal joins because they are always self joins. | 192 | // We ignore hierarchal joins because they are always self joins. |
@@ -193,23 +194,23 @@ namespace verbly { | |||
193 | ? foreignColumn_ | 194 | ? foreignColumn_ |
194 | : throw std::domain_error("Only many-to-many join fields have a foreign column"); | 195 | : throw std::domain_error("Only many-to-many join fields have a foreign column"); |
195 | } | 196 | } |
196 | 197 | ||
197 | const char* getJoinColumn() const | 198 | const char* getJoinColumn() const |
198 | { | 199 | { |
199 | return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) | 200 | return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) |
200 | ? joinColumn_ | 201 | ? joinColumn_ |
201 | : throw std::domain_error("Only many-to-many join fields have a join column"); | 202 | : throw std::domain_error("Only many-to-many join fields have a join column"); |
202 | } | 203 | } |
203 | 204 | ||
204 | const char* getForeignJoinColumn() const | 205 | const char* getForeignJoinColumn() const |
205 | { | 206 | { |
206 | return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) | 207 | return ((type_ == type::join_through) || (type_ == type::hierarchal_join)) |
207 | ? foreignJoinColumn_ | 208 | ? foreignJoinColumn_ |
208 | : throw std::domain_error("Only many-to-many join fields have a foreign join column"); | 209 | : throw std::domain_error("Only many-to-many join fields have a foreign join column"); |
209 | } | 210 | } |
210 | 211 | ||
211 | // Ordering | 212 | // Ordering |
212 | 213 | ||
213 | bool operator<(const field& other) const | 214 | bool operator<(const field& other) const |
214 | { | 215 | { |
215 | // For the most part, (object, column) uniquely identifies fields. | 216 | // For the most part, (object, column) uniquely identifies fields. |
@@ -219,9 +220,9 @@ namespace verbly { | |||
219 | // table (hypernymy); however, they have different join columns. | 220 | // table (hypernymy); however, they have different join columns. |
220 | return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | 221 | return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_); |
221 | } | 222 | } |
222 | 223 | ||
223 | // Equality | 224 | // Equality |
224 | 225 | ||
225 | bool operator==(const field& other) const | 226 | bool operator==(const field& other) const |
226 | { | 227 | { |
227 | // For the most part, (object, column) uniquely identifies fields. | 228 | // For the most part, (object, column) uniquely identifies fields. |
@@ -231,35 +232,35 @@ namespace verbly { | |||
231 | // table (hypernymy); however, they have different join columns. | 232 | // table (hypernymy); however, they have different join columns. |
232 | return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_); | 233 | return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_); |
233 | } | 234 | } |
234 | 235 | ||
235 | // Filter construction | 236 | // Filter construction |
236 | 237 | ||
237 | filter operator==(int value) const; // Integer equality | 238 | filter operator==(int value) const; // Integer equality |
238 | filter operator!=(int value) const; // Integer inequality | 239 | filter operator!=(int value) const; // Integer inequality |
239 | filter operator<(int value) const; // Integer is less than | 240 | filter operator<(int value) const; // Integer is less than |
240 | filter operator<=(int value) const; // Integer is at most | 241 | filter operator<=(int value) const; // Integer is at most |
241 | filter operator>(int value) const; // Integer is greater than | 242 | filter operator>(int value) const; // Integer is greater than |
242 | filter operator>=(int value) const; // Integer is at least | 243 | filter operator>=(int value) const; // Integer is at least |
243 | 244 | ||
244 | filter operator==(part_of_speech value) const; // Part of speech equality | 245 | filter operator==(part_of_speech value) const; // Part of speech equality |
245 | filter operator==(positioning value) const; // Adjective positioning equality | 246 | filter operator==(positioning value) const; // Adjective positioning equality |
246 | filter operator==(inflection value) const; // Inflection category equality | 247 | filter operator==(inflection value) const; // Inflection category equality |
247 | 248 | ||
248 | filter operator==(bool value) const; // Boolean equality | 249 | filter operator==(bool value) const; // Boolean equality |
249 | 250 | ||
250 | filter operator==(std::string value) const; // String equality | 251 | filter operator==(std::string value) const; // String equality |
251 | filter operator!=(std::string value) const; // String inequality | 252 | filter operator!=(std::string value) const; // String inequality |
252 | filter operator%=(std::string value) const; // String matching | 253 | filter operator%=(std::string value) const; // String matching |
253 | 254 | ||
254 | operator filter() const; // Non-nullity | 255 | operator filter() const; // Non-nullity |
255 | filter operator!() const; // Nullity | 256 | filter operator!() const; // Nullity |
256 | 257 | ||
257 | filter operator%=(filter joinCondition) const; // Join | 258 | filter operator%=(filter joinCondition) const; // Join |
258 | 259 | ||
259 | private: | 260 | private: |
260 | 261 | ||
261 | // Constructor | 262 | // Constructor |
262 | 263 | ||
263 | field( | 264 | field( |
264 | object obj, | 265 | object obj, |
265 | type datatype, | 266 | type datatype, |
@@ -281,26 +282,26 @@ namespace verbly { | |||
281 | foreignJoinColumn_(foreignJoinColumn) | 282 | foreignJoinColumn_(foreignJoinColumn) |
282 | { | 283 | { |
283 | } | 284 | } |
284 | 285 | ||
285 | // General | 286 | // General |
286 | object object_ = object::undefined; | 287 | object object_ = object::undefined; |
287 | type type_ = type::undefined; | 288 | type type_ = type::undefined; |
288 | const char* column_ = 0; | 289 | const char* column_ = 0; |
289 | const char* table_ = 0; | 290 | const char* table_ = 0; |
290 | 291 | ||
291 | // Non-joins and belongs-to joins | 292 | // Non-joins and belongs-to joins |
292 | bool nullable_ = false; | 293 | bool nullable_ = false; |
293 | 294 | ||
294 | // Joins | 295 | // Joins |
295 | object joinObject_ = object::undefined; | 296 | object joinObject_ = object::undefined; |
296 | 297 | ||
297 | // Many-to-many joins | 298 | // Many-to-many joins |
298 | const char* foreignColumn_ = 0; | 299 | const char* foreignColumn_ = 0; |
299 | const char* joinColumn_ = 0; | 300 | const char* joinColumn_ = 0; |
300 | const char* foreignJoinColumn_ = 0; | 301 | const char* foreignJoinColumn_ = 0; |
301 | 302 | ||
302 | }; | 303 | }; |
303 | 304 | ||
304 | }; | 305 | }; |
305 | 306 | ||
306 | #endif /* end of include guard: FIELD_H_43258321 */ | 307 | #endif /* end of include guard: FIELD_H_43258321 */ |
diff --git a/lib/filter.cpp b/lib/filter.cpp index 17309f1..ceb9327 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp | |||
@@ -1283,7 +1283,9 @@ namespace verbly { | |||
1283 | { | 1283 | { |
1284 | filter normalized = child.normalize(context); | 1284 | filter normalized = child.normalize(context); |
1285 | 1285 | ||
1286 | // Notably, this does not attempt to merge hierarchal matches. | 1286 | // Notably, this does not attempt to merge hierarchal matches, |
1287 | // UNLESS they are positive matches being OR-d, or negative | ||
1288 | // matches being ANDed. | ||
1287 | switch (normalized.getType()) | 1289 | switch (normalized.getType()) |
1288 | { | 1290 | { |
1289 | case type::singleton: | 1291 | case type::singleton: |
@@ -1306,7 +1308,7 @@ namespace verbly { | |||
1306 | { | 1308 | { |
1307 | if (!negativeJoins.count(normalized.singleton_.filterField)) | 1309 | if (!negativeJoins.count(normalized.singleton_.filterField)) |
1308 | { | 1310 | { |
1309 | negativeJoins[normalized.getField()] = filter(group_.orlogic); | 1311 | negativeJoins[normalized.getField()] = filter(!group_.orlogic); |
1310 | } | 1312 | } |
1311 | 1313 | ||
1312 | negativeJoins.at(normalized.getField()) += std::move(*normalized.singleton_.join); | 1314 | negativeJoins.at(normalized.getField()) += std::move(*normalized.singleton_.join); |
@@ -1314,6 +1316,30 @@ namespace verbly { | |||
1314 | break; | 1316 | break; |
1315 | } | 1317 | } |
1316 | 1318 | ||
1319 | case comparison::hierarchally_matches: | ||
1320 | { | ||
1321 | if (group_.orlogic) | ||
1322 | { | ||
1323 | positiveJoins[normalized.getField()] |= std::move(*normalized.singleton_.join); | ||
1324 | } else { | ||
1325 | result += std::move(normalized); | ||
1326 | } | ||
1327 | |||
1328 | break; | ||
1329 | } | ||
1330 | |||
1331 | case comparison::does_not_hierarchally_match: | ||
1332 | { | ||
1333 | if (!group_.orlogic) | ||
1334 | { | ||
1335 | negativeJoins[normalized.getField()] |= std::move(*normalized.singleton_.join); | ||
1336 | } else { | ||
1337 | result += std::move(normalized); | ||
1338 | } | ||
1339 | |||
1340 | break; | ||
1341 | } | ||
1342 | |||
1317 | case comparison::int_equals: | 1343 | case comparison::int_equals: |
1318 | case comparison::int_does_not_equal: | 1344 | case comparison::int_does_not_equal: |
1319 | case comparison::int_is_at_least: | 1345 | case comparison::int_is_at_least: |
@@ -1327,8 +1353,6 @@ namespace verbly { | |||
1327 | case comparison::string_is_not_like: | 1353 | case comparison::string_is_not_like: |
1328 | case comparison::is_null: | 1354 | case comparison::is_null: |
1329 | case comparison::is_not_null: | 1355 | case comparison::is_not_null: |
1330 | case comparison::hierarchally_matches: | ||
1331 | case comparison::does_not_hierarchally_match: | ||
1332 | { | 1356 | { |
1333 | result += std::move(normalized); | 1357 | result += std::move(normalized); |
1334 | 1358 | ||