From 6f1d3437b3bdd3ccde1243ceddf19f0c0fb5afda Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 9 Oct 2015 18:51:04 +0200 Subject: Modification and removal in results Now we just need to ensure that equality is tested using the ApplicationDomainType::identifier --- common/domain/applicationdomaintype.h | 9 ++++ common/entitystorage.h | 3 +- common/resultprovider.h | 49 +++++++++++++++++++++- common/synclistresult.h | 18 ++++++++ tests/genericfacadetest.cpp | 79 ++++++++++++++++++++++++++++++++++- 5 files changed, 154 insertions(+), 4 deletions(-) diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index e0a6de0..b583a6e 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -97,6 +97,15 @@ private: qint64 mRevision; }; +/* + * Should this be specific to the synclistresultset, in other cases we may want to take revision and resource into account. + */ +inline bool operator==(const ApplicationDomainType& lhs, const ApplicationDomainType& rhs) +{ + return lhs.identifier() == rhs.identifier() + && lhs.resourceInstanceIdentifier() == rhs.resourceInstanceIdentifier(); +} + struct Event : public ApplicationDomainType { typedef QSharedPointer Ptr; using ApplicationDomainType::ApplicationDomainType; diff --git a/common/entitystorage.h b/common/entitystorage.h index 78dbcda..6b09cad 100644 --- a/common/entitystorage.h +++ b/common/entitystorage.h @@ -118,10 +118,11 @@ public: break; case Akonadi2::Operation_Modification: Trace() << "Got modification"; - resultProvider->add(copy(*value).template staticCast()); + resultProvider->modify(copy(*value).template staticCast()); break; case Akonadi2::Operation_Removal: Trace() << "Got removal"; + resultProvider->remove(copy(*value).template staticCast()); break; } return true; diff --git a/common/resultprovider.h b/common/resultprovider.h index 841fd01..bc03152 100644 --- a/common/resultprovider.h +++ b/common/resultprovider.h @@ -81,6 +81,28 @@ public: }); } + void modify(const T &value) + { + //Because I don't know how to use bind + auto weakEmitter = mResultEmitter; + callInMainThreadOnEmitter([weakEmitter, value](){ + if (auto strongRef = weakEmitter.toStrongRef()) { + strongRef->modifyHandler(value); + } + }); + } + + void remove(const T &value) + { + //Because I don't know how to use bind + auto weakEmitter = mResultEmitter; + callInMainThreadOnEmitter([weakEmitter, value](){ + if (auto strongRef = weakEmitter.toStrongRef()) { + strongRef->removeHandler(value); + } + }); + } + void initialResultSetComplete() { callInMainThreadOnEmitter(&ResultEmitter::initialResultSetComplete); @@ -176,15 +198,27 @@ public: { addHandler = handler; } - // void onRemoved(const std::function &handler); + + void onModified(const std::function &handler) + { + modifyHandler = handler; + } + + void onRemoved(const std::function &handler) + { + removeHandler = handler; + } + void onInitialResultSetComplete(const std::function &handler) { initialResultSetCompleteHandler = handler; } + void onComplete(const std::function &handler) { completeHandler = handler; } + void onClear(const std::function &handler) { clearHandler = handler; @@ -195,6 +229,16 @@ public: addHandler(value); } + void modify(const DomainType &value) + { + modifyHandler(value); + } + + void remove(const DomainType &value) + { + removeHandler(value); + } + void initialResultSetComplete() { initialResultSetCompleteHandler(); @@ -214,7 +258,8 @@ private: friend class ResultProvider; std::function addHandler; - // std::function removeHandler; + std::function modifyHandler; + std::function removeHandler; std::function initialResultSetCompleteHandler; std::function completeHandler; std::function clearHandler; diff --git a/common/synclistresult.h b/common/synclistresult.h index 865d3e0..3ae2bed 100644 --- a/common/synclistresult.h +++ b/common/synclistresult.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "resultprovider.h" namespace async { @@ -25,6 +26,23 @@ public: emitter->onAdded([this](const T &value) { this->append(value); }); + emitter->onModified([this](const T &value) { + for (auto it = this->begin(); it != this->end(); it++) { + if (**it == *value) { + it = this->erase(it); + this->insert(it, value); + break; + } + } + }); + emitter->onRemoved([this](const T &value) { + for (auto it = this->begin(); it != this->end(); it++) { + if (**it == *value) { + this->erase(it); + break; + } + } + }); emitter->onInitialResultSetComplete([this]() { if (eventLoopAborter) { eventLoopAborter(); diff --git a/tests/genericfacadetest.cpp b/tests/genericfacadetest.cpp index f21de70..e9c1a94 100644 --- a/tests/genericfacadetest.cpp +++ b/tests/genericfacadetest.cpp @@ -30,10 +30,18 @@ public: for (const auto &res : mResults) { resultProvider->add(res); } + for (const auto &res : mModifications) { + resultProvider->modify(res); + } + for (const auto &res : mRemovals) { + resultProvider->remove(res); + } return mLatestRevision; } QList mResults; + QList mModifications; + QList mRemovals; qint64 mLatestRevision; }; @@ -126,9 +134,78 @@ private Q_SLOTS: resultSet->initialResultSetComplete(); result.exec(); - // QTRY_COMPARE(result.size(), 2); QCOMPARE(result.size(), 2); } + + void testLiveQueryModify() + { + Akonadi2::Query query; + query.liveQuery = true; + + auto resultSet = QSharedPointer >::create(); + auto storage = QSharedPointer::create("identifier", QSharedPointer::create(), "bufferType"); + auto resourceAccess = QSharedPointer::create(); + auto entity = QSharedPointer::create("resource", "id2", 0, QSharedPointer::create()); + entity->setProperty("test", "test1"); + storage->mResults << entity; + TestResourceFacade facade("identifier", storage, resourceAccess); + + async::SyncListResult result(resultSet->emitter()); + + facade.load(query, resultSet).exec().waitForFinished(); + resultSet->initialResultSetComplete(); + + result.exec(); + QCOMPARE(result.size(), 1); + + //Modify the entity again + storage->mResults.clear(); + entity = QSharedPointer::create("resource", "id2", 0, QSharedPointer::create()); + entity->setProperty("test", "test2"); + storage->mModifications << entity; + storage->mLatestRevision = 2; + resourceAccess->emit revisionChanged(2); + + //Hack to get event loop in synclistresult to abort again + resultSet->initialResultSetComplete(); + result.exec(); + + QCOMPARE(result.size(), 1); + QCOMPARE(result.first()->getProperty("test").toByteArray(), QByteArray("test2")); + } + + void testLiveQueryRemove() + { + Akonadi2::Query query; + query.liveQuery = true; + + auto resultSet = QSharedPointer >::create(); + auto storage = QSharedPointer::create("identifier", QSharedPointer::create(), "bufferType"); + auto resourceAccess = QSharedPointer::create(); + auto entity = QSharedPointer::create("resource", "id2", 0, QSharedPointer()); + storage->mResults << entity; + TestResourceFacade facade("identifier", storage, resourceAccess); + + async::SyncListResult result(resultSet->emitter()); + + facade.load(query, resultSet).exec().waitForFinished(); + resultSet->initialResultSetComplete(); + + result.exec(); + QCOMPARE(result.size(), 1); + + //Remove the entity again + storage->mResults.clear(); + storage->mRemovals << entity; + storage->mLatestRevision = 2; + resourceAccess->emit revisionChanged(2); + + //Hack to get event loop in synclistresult to abort again + resultSet->initialResultSetComplete(); + result.exec(); + + QCOMPARE(result.size(), 0); + } }; QTEST_MAIN(GenericFacadeTest) -- cgit v1.2.3