diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/datastorequery.cpp | 31 | ||||
-rw-r--r-- | common/query.h | 108 | ||||
-rw-r--r-- | common/test.cpp | 2 |
3 files changed, 64 insertions, 77 deletions
diff --git a/common/datastorequery.cpp b/common/datastorequery.cpp index 0fc9234..3c4ae00 100644 --- a/common/datastorequery.cpp +++ b/common/datastorequery.cpp | |||
@@ -146,6 +146,7 @@ public: | |||
146 | typedef QSharedPointer<Reduce> Ptr; | 146 | typedef QSharedPointer<Reduce> Ptr; |
147 | 147 | ||
148 | QHash<QByteArray, QVariant> mAggregateValues; | 148 | QHash<QByteArray, QVariant> mAggregateValues; |
149 | QSet<QByteArray> mReducedValues; | ||
149 | QByteArray mReductionProperty; | 150 | QByteArray mReductionProperty; |
150 | QByteArray mSelectionProperty; | 151 | QByteArray mSelectionProperty; |
151 | Query::Reduce::Selector::Comparator mSelectionComparator; | 152 | Query::Reduce::Selector::Comparator mSelectionComparator; |
@@ -184,7 +185,9 @@ public: | |||
184 | bool foundValue = false; | 185 | bool foundValue = false; |
185 | while(!foundValue && mSource->next([this, callback, &foundValue](Sink::Operation operation, const QByteArray &uid, const Sink::EntityBuffer &entityBuffer) { | 186 | while(!foundValue && mSource->next([this, callback, &foundValue](Sink::Operation operation, const QByteArray &uid, const Sink::EntityBuffer &entityBuffer) { |
186 | auto reductionValue = getProperty(entityBuffer.entity(), mReductionProperty); | 187 | auto reductionValue = getProperty(entityBuffer.entity(), mReductionProperty); |
187 | if (!mAggregateValues.contains(getByteArray(reductionValue))) { | 188 | if (!mReducedValues.contains(getByteArray(reductionValue))) { |
189 | //Only reduce every value once. | ||
190 | mReducedValues.insert(getByteArray(reductionValue)); | ||
188 | QVariant selectionResultValue; | 191 | QVariant selectionResultValue; |
189 | QByteArray selectionResult; | 192 | QByteArray selectionResult; |
190 | auto results = indexLookup(mReductionProperty, reductionValue); | 193 | auto results = indexLookup(mReductionProperty, reductionValue); |
@@ -373,17 +376,16 @@ QVector<QByteArray> DataStoreQuery::indexLookup(const QByteArray &property, cons | |||
373 | void DataStoreQuery::setupQuery() | 376 | void DataStoreQuery::setupQuery() |
374 | { | 377 | { |
375 | FilterBase::Ptr baseSet; | 378 | FilterBase::Ptr baseSet; |
376 | QSet<QByteArray> remainingFilters; | 379 | QSet<QByteArray> remainingFilters = mQuery.getBaseFilters().keys().toSet(); |
377 | QByteArray appliedSorting; | 380 | QByteArray appliedSorting; |
378 | if (!mQuery.ids.isEmpty()) { | 381 | if (!mQuery.ids.isEmpty()) { |
379 | mSource = Source::Ptr::create(mQuery.ids.toVector(), this); | 382 | mSource = Source::Ptr::create(mQuery.ids.toVector(), this); |
380 | baseSet = mSource; | 383 | baseSet = mSource; |
381 | remainingFilters = mQuery.propertyFilter.keys().toSet(); | ||
382 | } else { | 384 | } else { |
383 | QSet<QByteArray> appliedFilters; | 385 | QSet<QByteArray> appliedFilters; |
384 | 386 | ||
385 | auto resultSet = mTypeIndex.query(mQuery, appliedFilters, appliedSorting, mTransaction); | 387 | auto resultSet = mTypeIndex.query(mQuery, appliedFilters, appliedSorting, mTransaction); |
386 | remainingFilters = mQuery.propertyFilter.keys().toSet() - appliedFilters; | 388 | remainingFilters = remainingFilters - appliedFilters; |
387 | 389 | ||
388 | // We do a full scan if there were no indexes available to create the initial set. | 390 | // We do a full scan if there were no indexes available to create the initial set. |
389 | if (appliedFilters.isEmpty()) { | 391 | if (appliedFilters.isEmpty()) { |
@@ -394,12 +396,12 @@ void DataStoreQuery::setupQuery() | |||
394 | } | 396 | } |
395 | baseSet = mSource; | 397 | baseSet = mSource; |
396 | } | 398 | } |
397 | if (!mQuery.propertyFilter.isEmpty()) { | 399 | if (!mQuery.getBaseFilters().isEmpty()) { |
398 | auto filter = Filter::Ptr::create(baseSet, this); | 400 | auto filter = Filter::Ptr::create(baseSet, this); |
399 | filter->propertyFilter = mQuery.propertyFilter; | 401 | //For incremental queries the remaining filters are not sufficient |
400 | /* for (const auto &f : remainingFilters) { */ | 402 | for (const auto &f : mQuery.getBaseFilters().keys()) { |
401 | /* filter->propertyFilter.insert(f, mQuery.propertyFilter.value(f)); */ | 403 | filter->propertyFilter.insert(f, mQuery.getFilter(f)); |
402 | /* } */ | 404 | } |
403 | baseSet = filter; | 405 | baseSet = filter; |
404 | } | 406 | } |
405 | /* if (appliedSorting.isEmpty() && !mQuery.sortProperty.isEmpty()) { */ | 407 | /* if (appliedSorting.isEmpty() && !mQuery.sortProperty.isEmpty()) { */ |
@@ -407,15 +409,16 @@ void DataStoreQuery::setupQuery() | |||
407 | /* baseSet = Sort::Ptr::create(baseSet, mQuery.sortProperty); */ | 409 | /* baseSet = Sort::Ptr::create(baseSet, mQuery.sortProperty); */ |
408 | /* } */ | 410 | /* } */ |
409 | 411 | ||
412 | //Setup the rest of the filter stages on top of the base set | ||
410 | for (const auto &stage : mQuery.filterStages) { | 413 | for (const auto &stage : mQuery.filterStages) { |
411 | if (auto filter = stage.dynamicCast<Query::Filter>()) { | 414 | if (auto filter = stage.dynamicCast<Query::Filter>()) { |
412 | 415 | auto f = Filter::Ptr::create(baseSet, this); | |
416 | f->propertyFilter = filter->propertyFilter; | ||
417 | baseSet = f; | ||
413 | } else if (auto filter = stage.dynamicCast<Query::Reduce>()) { | 418 | } else if (auto filter = stage.dynamicCast<Query::Reduce>()) { |
414 | auto reduce = Reduce::Ptr::create(filter->property, filter->selector.property, filter->selector.comparator, baseSet, this); | 419 | baseSet = Reduce::Ptr::create(filter->property, filter->selector.property, filter->selector.comparator, baseSet, this); |
415 | baseSet = reduce; | ||
416 | } else if (auto filter = stage.dynamicCast<Query::Bloom>()) { | 420 | } else if (auto filter = stage.dynamicCast<Query::Bloom>()) { |
417 | auto reduce = Bloom::Ptr::create(filter->property, baseSet, this); | 421 | baseSet = Bloom::Ptr::create(filter->property, baseSet, this); |
418 | baseSet = reduce; | ||
419 | } | 422 | } |
420 | } | 423 | } |
421 | 424 | ||
diff --git a/common/query.h b/common/query.h index 0c6260b..3362ac7 100644 --- a/common/query.h +++ b/common/query.h | |||
@@ -58,26 +58,6 @@ public: | |||
58 | Comparators comparator; | 58 | Comparators comparator; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | |||
62 | static Query PropertyFilter(const QByteArray &key, const QVariant &value) | ||
63 | { | ||
64 | Query query; | ||
65 | query.propertyFilter.insert(key, Comparator(value)); | ||
66 | return query; | ||
67 | } | ||
68 | |||
69 | static Query PropertyContainsFilter(const QByteArray &key, const QVariant &value) | ||
70 | { | ||
71 | Query query; | ||
72 | query.propertyFilter.insert(key, Comparator(value, Comparator::Contains)); | ||
73 | return query; | ||
74 | } | ||
75 | |||
76 | static Query PropertyFilter(const QByteArray &key, const ApplicationDomain::Entity &entity) | ||
77 | { | ||
78 | return PropertyFilter(key, QVariant::fromValue(entity.identifier())); | ||
79 | } | ||
80 | |||
81 | static Query ResourceFilter(const QByteArray &identifier) | 61 | static Query ResourceFilter(const QByteArray &identifier) |
82 | { | 62 | { |
83 | Query query; | 63 | Query query; |
@@ -97,33 +77,6 @@ public: | |||
97 | return ResourceFilter(entity.identifier()); | 77 | return ResourceFilter(entity.identifier()); |
98 | } | 78 | } |
99 | 79 | ||
100 | static Query AccountFilter(const QByteArray &identifier) | ||
101 | { | ||
102 | Query query; | ||
103 | query.accounts.append(identifier); | ||
104 | return query; | ||
105 | } | ||
106 | |||
107 | static Query CapabilityFilter(const QByteArray &capability) | ||
108 | { | ||
109 | Query query; | ||
110 | query.propertyFilter.insert("capabilities", Comparator(capability, Comparator::Contains)); | ||
111 | return query; | ||
112 | } | ||
113 | |||
114 | static Query AccountFilter(const QByteArrayList &identifier) | ||
115 | { | ||
116 | Q_ASSERT(!identifier.isEmpty()); | ||
117 | Query query; | ||
118 | query.accounts = identifier; | ||
119 | return query; | ||
120 | } | ||
121 | |||
122 | static Query AccountFilter(const ApplicationDomain::SinkAccount &entity) | ||
123 | { | ||
124 | return AccountFilter(entity.identifier()); | ||
125 | } | ||
126 | |||
127 | static Query IdentityFilter(const QByteArray &identifier) | 80 | static Query IdentityFilter(const QByteArray &identifier) |
128 | { | 81 | { |
129 | Q_ASSERT(!identifier.isEmpty()); | 82 | Q_ASSERT(!identifier.isEmpty()); |
@@ -146,24 +99,17 @@ public: | |||
146 | return query; | 99 | return query; |
147 | } | 100 | } |
148 | 101 | ||
149 | static Query RequestedProperties(const QByteArrayList &properties) | 102 | template <typename T> |
150 | { | 103 | Query &request() |
151 | Query query; | ||
152 | query.requestedProperties = properties; | ||
153 | return query; | ||
154 | } | ||
155 | |||
156 | static Query RequestTree(const QByteArray &parentProperty) | ||
157 | { | 104 | { |
158 | Query query; | 105 | requestedProperties << T::name; |
159 | query.parentProperty = parentProperty; | 106 | return *this; |
160 | return query; | ||
161 | } | 107 | } |
162 | 108 | ||
163 | template <typename T> | 109 | template <typename T> |
164 | Query &request() | 110 | Query &requestTree() |
165 | { | 111 | { |
166 | requestedProperties << T::name; | 112 | parentProperty = T::name; |
167 | return *this; | 113 | return *this; |
168 | } | 114 | } |
169 | 115 | ||
@@ -227,9 +173,8 @@ public: | |||
227 | * Filters | 173 | * Filters |
228 | */ | 174 | */ |
229 | class Filter : public FilterStage { | 175 | class Filter : public FilterStage { |
230 | QByteArrayList ids; | 176 | public: |
231 | QHash<QByteArray, Comparator> propertyFilter; | 177 | QHash<QByteArray, Comparator> propertyFilter; |
232 | QByteArray sortProperty; | ||
233 | }; | 178 | }; |
234 | 179 | ||
235 | template <typename T> | 180 | template <typename T> |
@@ -239,6 +184,12 @@ public: | |||
239 | } | 184 | } |
240 | 185 | ||
241 | template <typename T> | 186 | template <typename T> |
187 | Query &containsFilter(const QVariant &value) | ||
188 | { | ||
189 | return filter(T::name, Comparator(value, Comparator::Contains)); | ||
190 | } | ||
191 | |||
192 | template <typename T> | ||
242 | Query &filter(const Comparator &comparator) | 193 | Query &filter(const Comparator &comparator) |
243 | { | 194 | { |
244 | return filter(T::name, comparator); | 195 | return filter(T::name, comparator); |
@@ -362,6 +313,39 @@ public: | |||
362 | filterStages << bloom; | 313 | filterStages << bloom; |
363 | } | 314 | } |
364 | 315 | ||
316 | //Query fixtures | ||
317 | |||
318 | /** | ||
319 | * Returns the complete thread, containing all mails from all folders. | ||
320 | */ | ||
321 | static Query completeThread(const ApplicationDomain::Mail &mail) | ||
322 | { | ||
323 | Sink::Query query; | ||
324 | if (!mail.resourceInstanceIdentifier().isEmpty()) { | ||
325 | query.filter(ApplicationDomain::SinkResource(mail.resourceInstanceIdentifier())); | ||
326 | } | ||
327 | query.ids << mail.identifier(); | ||
328 | query.sort<ApplicationDomain::Mail::Date>(); | ||
329 | query.bloom<ApplicationDomain::Mail::ThreadId>(); | ||
330 | return query; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * Returns thread leaders only, sorted by date. | ||
335 | */ | ||
336 | static Query threadLeaders(const ApplicationDomain::Folder &folder) | ||
337 | { | ||
338 | Sink::Query query; | ||
339 | if (!folder.resourceInstanceIdentifier().isEmpty()) { | ||
340 | query.filter(ApplicationDomain::SinkResource(folder.resourceInstanceIdentifier())); | ||
341 | } | ||
342 | query.filter<ApplicationDomain::Mail::Folder>(folder); | ||
343 | query.sort<ApplicationDomain::Mail::Date>(); | ||
344 | query.reduce<ApplicationDomain::Mail::ThreadId>(Query::Reduce::Selector::max<ApplicationDomain::Mail::Date>()); | ||
345 | return query; | ||
346 | } | ||
347 | |||
348 | |||
365 | }; | 349 | }; |
366 | 350 | ||
367 | } | 351 | } |
diff --git a/common/test.cpp b/common/test.cpp index 1a8e11d..97c42ef 100644 --- a/common/test.cpp +++ b/common/test.cpp | |||
@@ -147,7 +147,7 @@ public: | |||
147 | } | 147 | } |
148 | SinkTrace() << "-------------------------."; | 148 | SinkTrace() << "-------------------------."; |
149 | for (const auto &res : mTestAccount->entities<T>()) { | 149 | for (const auto &res : mTestAccount->entities<T>()) { |
150 | qDebug() << "Parent filter " << query.propertyFilter.value("parent").value.toByteArray() << res->identifier() << res->getProperty("parent").toByteArray(); | 150 | qDebug() << "Parent filter " << query.getFilter("parent").value.toByteArray() << res->identifier() << res->getProperty("parent").toByteArray(); |
151 | auto parentProperty = res->getProperty("parent").toByteArray(); | 151 | auto parentProperty = res->getProperty("parent").toByteArray(); |
152 | if ((!parent && parentProperty.isEmpty()) || (parent && parentProperty == parent->identifier()) || query.parentProperty.isEmpty()) { | 152 | if ((!parent && parentProperty.isEmpty()) || (parent && parentProperty == parent->identifier()) || query.parentProperty.isEmpty()) { |
153 | qDebug() << "Found a match" << res->identifier(); | 153 | qDebug() << "Found a match" << res->identifier(); |