diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-01-27 16:56:17 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-01-31 19:38:57 +0100 |
commit | 871a048580d5a464fb697713a5e0e2c52dee5208 (patch) | |
tree | 3cdc2bff1e9267b75448b9ca52b84fe46841e23e | |
parent | 8ddf4c9d2967ba4acc4121f8e845c07e421d9b23 (diff) | |
download | sink-871a048580d5a464fb697713a5e0e2c52dee5208.tar.gz sink-871a048580d5a464fb697713a5e0e2c52dee5208.zip |
Ensure blooming queries filter as they should
After the initial bloom, it should turn into a regular filter.
-rw-r--r-- | common/datastorequery.cpp | 46 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.cpp | 1 | ||||
-rw-r--r-- | tests/querytest.cpp | 92 |
3 files changed, 122 insertions, 17 deletions
diff --git a/common/datastorequery.cpp b/common/datastorequery.cpp index d90d546..087f405 100644 --- a/common/datastorequery.cpp +++ b/common/datastorequery.cpp | |||
@@ -101,7 +101,7 @@ public: | |||
101 | 101 | ||
102 | virtual ~Filter(){} | 102 | virtual ~Filter(){} |
103 | 103 | ||
104 | bool next(const std::function<void(const ResultSet::Result &result)> &callback) Q_DECL_OVERRIDE { | 104 | virtual bool next(const std::function<void(const ResultSet::Result &result)> &callback) Q_DECL_OVERRIDE { |
105 | bool foundValue = false; | 105 | bool foundValue = false; |
106 | while(!foundValue && mSource->next([this, callback, &foundValue](const ResultSet::Result &result) { | 106 | while(!foundValue && mSource->next([this, callback, &foundValue](const ResultSet::Result &result) { |
107 | SinkTrace() << "Filter: " << result.entity.identifier() << result.operation; | 107 | SinkTrace() << "Filter: " << result.entity.identifier() << result.operation; |
@@ -273,14 +273,14 @@ public: | |||
273 | } | 273 | } |
274 | }; | 274 | }; |
275 | 275 | ||
276 | class Bloom : public FilterBase { | 276 | class Bloom : public Filter { |
277 | public: | 277 | public: |
278 | typedef QSharedPointer<Bloom> Ptr; | 278 | typedef QSharedPointer<Bloom> Ptr; |
279 | 279 | ||
280 | QByteArray mBloomProperty; | 280 | QByteArray mBloomProperty; |
281 | 281 | ||
282 | Bloom(const QByteArray &bloomProperty, FilterBase::Ptr source, DataStoreQuery *store) | 282 | Bloom(const QByteArray &bloomProperty, FilterBase::Ptr source, DataStoreQuery *store) |
283 | : FilterBase(source, store), | 283 | : Filter(source, store), |
284 | mBloomProperty(bloomProperty) | 284 | mBloomProperty(bloomProperty) |
285 | { | 285 | { |
286 | 286 | ||
@@ -289,21 +289,33 @@ public: | |||
289 | virtual ~Bloom(){} | 289 | virtual ~Bloom(){} |
290 | 290 | ||
291 | bool next(const std::function<void(const ResultSet::Result &result)> &callback) Q_DECL_OVERRIDE { | 291 | bool next(const std::function<void(const ResultSet::Result &result)> &callback) Q_DECL_OVERRIDE { |
292 | bool foundValue = false; | 292 | if (!mBloomed) { |
293 | while(!foundValue && mSource->next([this, callback, &foundValue](const ResultSet::Result &result) { | 293 | //Initially we bloom on the first value that matches. |
294 | auto bloomValue = result.entity.getProperty(mBloomProperty); | 294 | //From there on we just filter. |
295 | auto results = indexLookup(mBloomProperty, bloomValue); | 295 | bool foundValue = false; |
296 | for (const auto &r : results) { | 296 | while(!foundValue && mSource->next([this, callback, &foundValue](const ResultSet::Result &result) { |
297 | readEntity(r, [&, this](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation operation) { | 297 | mBloomValue = result.entity.getProperty(mBloomProperty); |
298 | callback({entity, Sink::Operation_Creation}); | 298 | auto results = indexLookup(mBloomProperty, mBloomValue); |
299 | foundValue = true; | 299 | SinkWarning() << "Bloomed on value " << mBloomValue << " and found " << results.size(); |
300 | }); | 300 | for (const auto &r : results) { |
301 | } | 301 | readEntity(r, [&, this](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation operation) { |
302 | return false; | 302 | callback({entity, Sink::Operation_Creation}); |
303 | })) | 303 | foundValue = true; |
304 | {} | 304 | }); |
305 | return foundValue; | 305 | } |
306 | return false; | ||
307 | })) | ||
308 | {} | ||
309 | mBloomed = true; | ||
310 | propertyFilter.insert(mBloomProperty, mBloomValue); | ||
311 | return foundValue; | ||
312 | } else { | ||
313 | //Filter on bloom value | ||
314 | return Filter::next(callback); | ||
315 | } | ||
306 | } | 316 | } |
317 | QVariant mBloomValue; | ||
318 | bool mBloomed = false; | ||
307 | }; | 319 | }; |
308 | 320 | ||
309 | DataStoreQuery::DataStoreQuery(const Sink::QueryBase &query, const QByteArray &type, EntityStore &store) | 321 | DataStoreQuery::DataStoreQuery(const Sink::QueryBase &query, const QByteArray &type, EntityStore &store) |
diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 6d16a3c..57d0f2d 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp | |||
@@ -30,6 +30,7 @@ namespace Sink { | |||
30 | namespace ApplicationDomain { | 30 | namespace ApplicationDomain { |
31 | 31 | ||
32 | constexpr const char *Mail::ThreadId::name; | 32 | constexpr const char *Mail::ThreadId::name; |
33 | constexpr const char *Mail::Folder::name; | ||
33 | 34 | ||
34 | static const int foo = [] { | 35 | static const int foo = [] { |
35 | QMetaType::registerEqualsComparator<Reference>(); | 36 | QMetaType::registerEqualsComparator<Reference>(); |
diff --git a/tests/querytest.cpp b/tests/querytest.cpp index 92fc1f7..10f5567 100644 --- a/tests/querytest.cpp +++ b/tests/querytest.cpp | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "modelresult.h" | 11 | #include "modelresult.h" |
12 | #include "test.h" | 12 | #include "test.h" |
13 | #include "testutils.h" | 13 | #include "testutils.h" |
14 | #include "applicationdomaintype.h" | ||
14 | 15 | ||
15 | using namespace Sink; | 16 | using namespace Sink; |
16 | using namespace Sink::ApplicationDomain; | 17 | using namespace Sink::ApplicationDomain; |
@@ -632,6 +633,7 @@ private slots: | |||
632 | auto folders = Sink::Store::read<Folder>(query); | 633 | auto folders = Sink::Store::read<Folder>(query); |
633 | QCOMPARE(folders.size(), 1); | 634 | QCOMPARE(folders.size(), 1); |
634 | } | 635 | } |
636 | |||
635 | void testLivequeryUnmatchInThread() | 637 | void testLivequeryUnmatchInThread() |
636 | { | 638 | { |
637 | // Setup | 639 | // Setup |
@@ -707,6 +709,96 @@ private slots: | |||
707 | auto mail = model->data(model->index(0, 0, QModelIndex{}), Sink::Store::DomainObjectRole).value<Mail::Ptr>(); | 709 | auto mail = model->data(model->index(0, 0, QModelIndex{}), Sink::Store::DomainObjectRole).value<Mail::Ptr>(); |
708 | QCOMPARE(mail->getUnread(), true); | 710 | QCOMPARE(mail->getUnread(), true); |
709 | } | 711 | } |
712 | |||
713 | void testBloom() | ||
714 | { | ||
715 | // Setup | ||
716 | auto folder1 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
717 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
718 | |||
719 | auto folder2 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
720 | VERIFYEXEC(Sink::Store::create<Folder>(folder2)); | ||
721 | |||
722 | auto mail1 = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
723 | mail1.setUid("mail1"); | ||
724 | mail1.setFolder(folder1); | ||
725 | VERIFYEXEC(Sink::Store::create(mail1)); | ||
726 | |||
727 | // Ensure all local data is processed | ||
728 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
729 | |||
730 | { | ||
731 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
732 | mail.setUid("mail2"); | ||
733 | mail.setFolder(folder1); | ||
734 | VERIFYEXEC(Sink::Store::create(mail)); | ||
735 | } | ||
736 | { | ||
737 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
738 | mail.setUid("mail3"); | ||
739 | mail.setFolder(folder2); | ||
740 | VERIFYEXEC(Sink::Store::create(mail)); | ||
741 | } | ||
742 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
743 | |||
744 | Query query; | ||
745 | query.setId("testFilterCreationInThread"); | ||
746 | query.filter(mail1.identifier()); | ||
747 | query.bloom<Mail::Folder>(); | ||
748 | query.request<Mail::Folder>(); | ||
749 | |||
750 | auto model = Sink::Store::loadModel<Mail>(query); | ||
751 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); | ||
752 | QCOMPARE(model->rowCount(), 2); | ||
753 | } | ||
754 | |||
755 | void testLivequeryFilterCreationInThread() | ||
756 | { | ||
757 | // Setup | ||
758 | auto folder1 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
759 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
760 | |||
761 | auto folder2 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
762 | VERIFYEXEC(Sink::Store::create<Folder>(folder2)); | ||
763 | |||
764 | auto mail1 = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
765 | mail1.setUid("mail1"); | ||
766 | mail1.setFolder(folder1); | ||
767 | VERIFYEXEC(Sink::Store::create(mail1)); | ||
768 | |||
769 | // Ensure all local data is processed | ||
770 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
771 | |||
772 | Query query; | ||
773 | query.setId("testFilterCreationInThread"); | ||
774 | query.filter(mail1.identifier()); | ||
775 | query.bloom<Mail::Folder>(); | ||
776 | query.sort<Mail::Date>(); | ||
777 | query.setFlags(Query::LiveQuery); | ||
778 | query.request<Mail::Unread>(); | ||
779 | query.request<Mail::Folder>(); | ||
780 | |||
781 | auto model = Sink::Store::loadModel<Mail>(query); | ||
782 | QTRY_COMPARE(model->rowCount(), 1); | ||
783 | |||
784 | { | ||
785 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
786 | mail.setUid("mail2"); | ||
787 | mail.setFolder(folder1); | ||
788 | VERIFYEXEC(Sink::Store::create(mail)); | ||
789 | } | ||
790 | { | ||
791 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
792 | mail.setUid("mail3"); | ||
793 | mail.setFolder(folder2); | ||
794 | VERIFYEXEC(Sink::Store::create(mail)); | ||
795 | } | ||
796 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
797 | |||
798 | QTRY_COMPARE(model->rowCount(), 2); | ||
799 | QTest::qWait(100); | ||
800 | QCOMPARE(model->rowCount(), 2); | ||
801 | } | ||
710 | }; | 802 | }; |
711 | 803 | ||
712 | QTEST_MAIN(QueryTest) | 804 | QTEST_MAIN(QueryTest) |