From 3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 4 Oct 2016 17:12:02 +0200 Subject: Resource subqueries --- common/datastorequery.cpp | 6 +++ common/domain/applicationdomaintype.h | 75 ++++++++++++++++++----------------- common/store.cpp | 25 +++++++++--- tests/querytest.cpp | 30 ++++++++++++++ 4 files changed, 94 insertions(+), 42 deletions(-) diff --git a/common/datastorequery.cpp b/common/datastorequery.cpp index c4fbe13..dac171c 100644 --- a/common/datastorequery.cpp +++ b/common/datastorequery.cpp @@ -408,6 +408,9 @@ QByteArrayList DataStoreQuery::executeSubquery(const Query &subquery) void DataStoreQuery::setupQuery() { for (const auto &k : mQuery.propertyFilter.keys()) { + if (k == ApplicationDomain::Entity::Resource::name) { + continue; + } const auto comparator = mQuery.propertyFilter.value(k); if (comparator.value.canConvert()) { SinkTrace() << "Executing subquery for property: " << k; @@ -441,6 +444,9 @@ void DataStoreQuery::setupQuery() auto filter = Filter::Ptr::create(baseSet, this); //For incremental queries the remaining filters are not sufficient for (const auto &f : mQuery.getBaseFilters().keys()) { + if (f == ApplicationDomain::Entity::Resource::name) { + continue; + } filter->propertyFilter.insert(f, mQuery.getFilter(f)); } baseSet = filter; diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 2c8b2ee..1c8b45a 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -201,10 +201,48 @@ inline QDebug operator<< (QDebug d, const ApplicationDomainType &type) return d; } +struct SINK_EXPORT SinkAccount : public ApplicationDomainType { + typedef QSharedPointer Ptr; + explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); + explicit SinkAccount(const QByteArray &identifier); + SinkAccount(); + virtual ~SinkAccount(); + + SINK_PROPERTY(QString, Name, name); + SINK_PROPERTY(QString, Icon, icon); + SINK_PROPERTY(QString, AccountType, type); + SINK_STATUS_PROPERTY(int, Status, status); + SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); + SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); +}; + + +/** + * Represents an sink resource. + * + * This type is used for configuration of resources, + * and for creating and removing resource instances. + */ +struct SINK_EXPORT SinkResource : public ApplicationDomainType { + typedef QSharedPointer Ptr; + explicit SinkResource(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); + explicit SinkResource(const QByteArray &identifier); + SinkResource(); + virtual ~SinkResource(); + + SINK_REFERENCE_PROPERTY(SinkAccount, Account, account); + SINK_PROPERTY(QByteArray, ResourceType, type); + SINK_PROPERTY(QByteArrayList, Capabilities, capabilities); + SINK_STATUS_PROPERTY(int, Status, status); + SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); + SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); +}; + struct SINK_EXPORT Entity : public ApplicationDomainType { typedef QSharedPointer Ptr; using ApplicationDomainType::ApplicationDomainType; virtual ~Entity(); + SINK_REFERENCE_PROPERTY(SinkResource, Resource, resource); }; struct SINK_EXPORT Event : public Entity { @@ -266,43 +304,6 @@ enum SINK_EXPORT Status { ErrorStatus }; -struct SINK_EXPORT SinkAccount : public ApplicationDomainType { - typedef QSharedPointer Ptr; - explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); - explicit SinkAccount(const QByteArray &identifier); - SinkAccount(); - virtual ~SinkAccount(); - - SINK_PROPERTY(QString, Name, name); - SINK_PROPERTY(QString, Icon, icon); - SINK_PROPERTY(QString, AccountType, type); - SINK_STATUS_PROPERTY(int, Status, status); - SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); - SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); -}; - - -/** - * Represents an sink resource. - * - * This type is used for configuration of resources, - * and for creating and removing resource instances. - */ -struct SINK_EXPORT SinkResource : public ApplicationDomainType { - typedef QSharedPointer Ptr; - explicit SinkResource(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); - explicit SinkResource(const QByteArray &identifier); - SinkResource(); - virtual ~SinkResource(); - - SINK_REFERENCE_PROPERTY(SinkAccount, Account, account); - SINK_PROPERTY(QByteArray, ResourceType, type); - SINK_PROPERTY(QByteArrayList, Capabilities, capabilities); - SINK_STATUS_PROPERTY(int, Status, status); - SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); - SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); -}; - struct SINK_EXPORT Identity : public ApplicationDomainType { typedef QSharedPointer Ptr; explicit Identity(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); diff --git a/common/store.cpp b/common/store.cpp index a1b3c17..efe1179 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -57,13 +57,28 @@ QString Store::getTemporaryFilePath() /* * Returns a map of resource instance identifiers and resource type */ -static QMap getResources(const QList &resourceFilter, const QList &accountFilter,const QByteArray &type = QByteArray()) +static QMap getResources(const Sink::Query &query, const QByteArray &type = QByteArray()) { + const QList resourceFilter = query.resources; + const QList accountFilter = query.accounts; + + auto resourceComparator = query.getFilter(Sink::ApplicationDomain::Entity::Resource::name); + const auto filterResource = [&](const QByteArray &res) { const auto configuration = ResourceConfig::getConfiguration(res); - if (!accountFilter.isEmpty() && !accountFilter.contains(configuration.value("account").toByteArray())) { + if (!accountFilter.isEmpty() && !accountFilter.contains(configuration.value(ApplicationDomain::SinkResource::Account::name).toByteArray())) { return true; } + //Subquery for the resource + if (resourceComparator.value.canConvert()) { + auto subquery = resourceComparator.value.value(); + for (const auto &filterProperty : subquery.propertyFilter.keys()) { + const auto filter = subquery.propertyFilter.value(filterProperty); + if (!filter.matches(configuration.value(filterProperty))) { + return true; + } + } + } return false; }; @@ -139,7 +154,7 @@ QSharedPointer Store::loadModel(Query query) //* The result provider needs to live for as long as results are provided (until the last thread exits). // Query all resources and aggregate results - auto resources = getResources(query.resources, query.accounts, ApplicationDomain::getTypeName()); + auto resources = getResources(query, ApplicationDomain::getTypeName()); auto aggregatingEmitter = AggregatingResultEmitter::Ptr::create(); model->setEmitter(aggregatingEmitter); @@ -252,7 +267,7 @@ KAsync::Job Store::removeDataFromDisk(const QByteArray &identifier) KAsync::Job Store::synchronize(const Sink::Query &query) { SinkTrace() << "synchronize" << query.resources; - auto resources = getResources(query.resources, query.accounts).keys(); + auto resources = getResources(query).keys(); //FIXME only necessary because each doesn't propagate errors auto errorFlag = new bool; return KAsync::value(resources) @@ -352,7 +367,7 @@ QList Store::read(const Sink::Query &q) query.synchronousQuery = true; query.liveQuery = false; QList list; - auto resources = getResources(query.resources, query.accounts, ApplicationDomain::getTypeName()); + auto resources = getResources(query, ApplicationDomain::getTypeName()); auto aggregatingEmitter = AggregatingResultEmitter::Ptr::create(); aggregatingEmitter->onAdded([&list](const typename DomainType::Ptr &value){ SinkTrace() << "Found value: " << value->identifier(); diff --git a/tests/querytest.cpp b/tests/querytest.cpp index 6011a99..6348316 100644 --- a/tests/querytest.cpp +++ b/tests/querytest.cpp @@ -528,6 +528,36 @@ private slots: QCOMPARE(mails.size(), 1); QCOMPARE(mails.first().getUid().toLatin1(), QByteArray("mail1")); } + + void testResourceSubQuery() + { + using namespace Sink; + using namespace Sink::ApplicationDomain; + + //Setup + auto resource1 = ApplicationDomainType::createEntity(); + resource1.setResourceType("sink.dummy"); + resource1.setCapabilities(QByteArrayList() << "cap1"); + Store::create(resource1).exec().waitForFinished(); + + auto resource2 = ApplicationDomainType::createEntity(); + resource2.setCapabilities(QByteArrayList() << "cap2"); + resource2.setResourceType("sink.dummy"); + Store::create(resource2).exec().waitForFinished(); + + Folder folder1(resource1.identifier()); + VERIFYEXEC(Sink::Store::create(folder1)); + Folder folder2(resource2.identifier()); + VERIFYEXEC(Sink::Store::create(folder2)); + + // Test + Sink::Query query; + query.filter(Sink::Query().containsFilter("cap1")); + + // We fetch before the data is available and rely on the live query mechanism to deliver the actual data + auto folders = Sink::Store::read(query); + QCOMPARE(folders.size(), 1); + } }; QTEST_MAIN(QueryTest) -- cgit v1.2.3