diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-17 15:16:29 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-17 15:16:29 +0200 |
commit | 93c9ebb5d0654626cb8bf2e6b00a5845b210f82c (patch) | |
tree | d333bf90e2a2e25c43b1bc6f514a8df5efa6c38f | |
parent | 493aae46b3aeffcdb001f697efdc5a42eba672d8 (diff) | |
download | sink-93c9ebb5d0654626cb8bf2e6b00a5845b210f82c.tar.gz sink-93c9ebb5d0654626cb8bf2e6b00a5845b210f82c.zip |
Fixed a readEntity call with empty uid
Filtered entites are still passed through as removal, but if
there is no other value for the reduction, the reduction result is
empty.
-rw-r--r-- | common/datastorequery.cpp | 7 | ||||
-rw-r--r-- | tests/querytest.cpp | 54 |
2 files changed, 61 insertions, 0 deletions
diff --git a/common/datastorequery.cpp b/common/datastorequery.cpp index b77dfc9..276a10a 100644 --- a/common/datastorequery.cpp +++ b/common/datastorequery.cpp | |||
@@ -327,6 +327,10 @@ public: | |||
327 | mReducedValues.insert(reductionValueBa); | 327 | mReducedValues.insert(reductionValueBa); |
328 | auto reductionResult = reduceOnValue(reductionValue); | 328 | auto reductionResult = reduceOnValue(reductionValue); |
329 | 329 | ||
330 | //This can happen if we get a removal message from a filtered entity and all entites of the reduction are filtered. | ||
331 | if (reductionResult.selection.isEmpty()) { | ||
332 | return; | ||
333 | } | ||
330 | mSelectedValues.insert(reductionValueBa, reductionResult.selection); | 334 | mSelectedValues.insert(reductionValueBa, reductionResult.selection); |
331 | readEntity(reductionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation operation) { | 335 | readEntity(reductionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation operation) { |
332 | callback({entity, operation, reductionResult.aggregateValues, reductionResult.aggregateIds}); | 336 | callback({entity, operation, reductionResult.aggregateValues, reductionResult.aggregateIds}); |
@@ -345,11 +349,13 @@ public: | |||
345 | auto oldSelectionResult = mSelectedValues.take(reductionValueBa); | 349 | auto oldSelectionResult = mSelectedValues.take(reductionValueBa); |
346 | if (oldSelectionResult == selectionResult.selection) { | 350 | if (oldSelectionResult == selectionResult.selection) { |
347 | mSelectedValues.insert(reductionValueBa, selectionResult.selection); | 351 | mSelectedValues.insert(reductionValueBa, selectionResult.selection); |
352 | Q_ASSERT(!selectionResult.selection.isEmpty()); | ||
348 | readEntity(selectionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { | 353 | readEntity(selectionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { |
349 | callback({entity, Sink::Operation_Modification, selectionResult.aggregateValues, selectionResult.aggregateIds}); | 354 | callback({entity, Sink::Operation_Modification, selectionResult.aggregateValues, selectionResult.aggregateIds}); |
350 | }); | 355 | }); |
351 | } else { | 356 | } else { |
352 | //remove old result | 357 | //remove old result |
358 | Q_ASSERT(!oldSelectionResult.isEmpty()); | ||
353 | readEntity(oldSelectionResult, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { | 359 | readEntity(oldSelectionResult, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { |
354 | callback({entity, Sink::Operation_Removal}); | 360 | callback({entity, Sink::Operation_Removal}); |
355 | }); | 361 | }); |
@@ -358,6 +364,7 @@ public: | |||
358 | if (!selectionResult.selection.isEmpty()) { | 364 | if (!selectionResult.selection.isEmpty()) { |
359 | //add new result | 365 | //add new result |
360 | mSelectedValues.insert(reductionValueBa, selectionResult.selection); | 366 | mSelectedValues.insert(reductionValueBa, selectionResult.selection); |
367 | Q_ASSERT(!selectionResult.selection.isEmpty()); | ||
361 | readEntity(selectionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { | 368 | readEntity(selectionResult.selection, [&](const Sink::ApplicationDomain::ApplicationDomainType &entity, Sink::Operation) { |
362 | callback({entity, Sink::Operation_Creation, selectionResult.aggregateValues, selectionResult.aggregateIds}); | 369 | callback({entity, Sink::Operation_Creation, selectionResult.aggregateValues, selectionResult.aggregateIds}); |
363 | }); | 370 | }); |
diff --git a/tests/querytest.cpp b/tests/querytest.cpp index 26564b5..fa016a2 100644 --- a/tests/querytest.cpp +++ b/tests/querytest.cpp | |||
@@ -954,6 +954,60 @@ private slots: | |||
954 | QCOMPARE(resetSpy.size(), 0); | 954 | QCOMPARE(resetSpy.size(), 0); |
955 | } | 955 | } |
956 | 956 | ||
957 | void testFilteredReductionUpdate() | ||
958 | { | ||
959 | // Setup | ||
960 | auto folder1 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
961 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
962 | |||
963 | auto folder2 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
964 | VERIFYEXEC(Sink::Store::create<Folder>(folder2)); | ||
965 | |||
966 | // Ensure all local data is processed | ||
967 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
968 | |||
969 | Query query; | ||
970 | query.setId("testFilteredReductionUpdate"); | ||
971 | query.setFlags(Query::LiveQuery); | ||
972 | query.filter<Mail::Folder>(folder1); | ||
973 | query.reduce<Mail::Folder>(Query::Reduce::Selector::max<Mail::Date>()).count("count").collect<Mail::Folder>("folders"); | ||
974 | query.sort<Mail::Date>(); | ||
975 | |||
976 | auto model = Sink::Store::loadModel<Mail>(query); | ||
977 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); | ||
978 | QCOMPARE(model->rowCount(), 0); | ||
979 | |||
980 | QSignalSpy insertedSpy(model.data(), &QAbstractItemModel::rowsInserted); | ||
981 | QSignalSpy removedSpy(model.data(), &QAbstractItemModel::rowsRemoved); | ||
982 | QSignalSpy changedSpy(model.data(), &QAbstractItemModel::dataChanged); | ||
983 | QSignalSpy layoutChangedSpy(model.data(), &QAbstractItemModel::layoutChanged); | ||
984 | QSignalSpy resetSpy(model.data(), &QAbstractItemModel::modelReset); | ||
985 | |||
986 | //Ensure we don't end up with a mail in the thread that was filtered | ||
987 | //This tests the case of an otherwise emtpy thread on purpose. | ||
988 | { | ||
989 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
990 | mail.setExtractedMessageId("filtered"); | ||
991 | mail.setFolder(folder2); | ||
992 | mail.setExtractedDate(QDateTime{QDate{2017, 2, 3}, QTime{11, 0, 0}}); | ||
993 | VERIFYEXEC(Sink::Store::create(mail)); | ||
994 | } | ||
995 | |||
996 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
997 | QCOMPARE(model->rowCount(), 0); | ||
998 | |||
999 | //Ensure the non-filtered still get through. | ||
1000 | { | ||
1001 | auto mail = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
1002 | mail.setExtractedMessageId("not-filtered"); | ||
1003 | mail.setFolder(folder1); | ||
1004 | mail.setExtractedDate(QDateTime{QDate{2017, 2, 3}, QTime{11, 0, 0}}); | ||
1005 | VERIFYEXEC(Sink::Store::create(mail)); | ||
1006 | } | ||
1007 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
1008 | QTRY_COMPARE(model->rowCount(), 1); | ||
1009 | } | ||
1010 | |||
957 | void testBloom() | 1011 | void testBloom() |
958 | { | 1012 | { |
959 | // Setup | 1013 | // Setup |