diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-04 17:12:02 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-04 17:12:02 +0200 |
commit | 3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7 (patch) | |
tree | 5ac341b501dae0a5e7d5addb8114535de53979cf | |
parent | 7757d32b5a820623c469b7851354374427142598 (diff) | |
download | sink-3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7.tar.gz sink-3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7.zip |
Resource subqueries
-rw-r--r-- | common/datastorequery.cpp | 6 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.h | 75 | ||||
-rw-r--r-- | common/store.cpp | 25 | ||||
-rw-r--r-- | 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) | |||
408 | void DataStoreQuery::setupQuery() | 408 | void DataStoreQuery::setupQuery() |
409 | { | 409 | { |
410 | for (const auto &k : mQuery.propertyFilter.keys()) { | 410 | for (const auto &k : mQuery.propertyFilter.keys()) { |
411 | if (k == ApplicationDomain::Entity::Resource::name) { | ||
412 | continue; | ||
413 | } | ||
411 | const auto comparator = mQuery.propertyFilter.value(k); | 414 | const auto comparator = mQuery.propertyFilter.value(k); |
412 | if (comparator.value.canConvert<Query>()) { | 415 | if (comparator.value.canConvert<Query>()) { |
413 | SinkTrace() << "Executing subquery for property: " << k; | 416 | SinkTrace() << "Executing subquery for property: " << k; |
@@ -441,6 +444,9 @@ void DataStoreQuery::setupQuery() | |||
441 | auto filter = Filter::Ptr::create(baseSet, this); | 444 | auto filter = Filter::Ptr::create(baseSet, this); |
442 | //For incremental queries the remaining filters are not sufficient | 445 | //For incremental queries the remaining filters are not sufficient |
443 | for (const auto &f : mQuery.getBaseFilters().keys()) { | 446 | for (const auto &f : mQuery.getBaseFilters().keys()) { |
447 | if (f == ApplicationDomain::Entity::Resource::name) { | ||
448 | continue; | ||
449 | } | ||
444 | filter->propertyFilter.insert(f, mQuery.getFilter(f)); | 450 | filter->propertyFilter.insert(f, mQuery.getFilter(f)); |
445 | } | 451 | } |
446 | baseSet = filter; | 452 | 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) | |||
201 | return d; | 201 | return d; |
202 | } | 202 | } |
203 | 203 | ||
204 | struct SINK_EXPORT SinkAccount : public ApplicationDomainType { | ||
205 | typedef QSharedPointer<SinkAccount> Ptr; | ||
206 | explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); | ||
207 | explicit SinkAccount(const QByteArray &identifier); | ||
208 | SinkAccount(); | ||
209 | virtual ~SinkAccount(); | ||
210 | |||
211 | SINK_PROPERTY(QString, Name, name); | ||
212 | SINK_PROPERTY(QString, Icon, icon); | ||
213 | SINK_PROPERTY(QString, AccountType, type); | ||
214 | SINK_STATUS_PROPERTY(int, Status, status); | ||
215 | SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); | ||
216 | SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); | ||
217 | }; | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Represents an sink resource. | ||
222 | * | ||
223 | * This type is used for configuration of resources, | ||
224 | * and for creating and removing resource instances. | ||
225 | */ | ||
226 | struct SINK_EXPORT SinkResource : public ApplicationDomainType { | ||
227 | typedef QSharedPointer<SinkResource> Ptr; | ||
228 | explicit SinkResource(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); | ||
229 | explicit SinkResource(const QByteArray &identifier); | ||
230 | SinkResource(); | ||
231 | virtual ~SinkResource(); | ||
232 | |||
233 | SINK_REFERENCE_PROPERTY(SinkAccount, Account, account); | ||
234 | SINK_PROPERTY(QByteArray, ResourceType, type); | ||
235 | SINK_PROPERTY(QByteArrayList, Capabilities, capabilities); | ||
236 | SINK_STATUS_PROPERTY(int, Status, status); | ||
237 | SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); | ||
238 | SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); | ||
239 | }; | ||
240 | |||
204 | struct SINK_EXPORT Entity : public ApplicationDomainType { | 241 | struct SINK_EXPORT Entity : public ApplicationDomainType { |
205 | typedef QSharedPointer<Entity> Ptr; | 242 | typedef QSharedPointer<Entity> Ptr; |
206 | using ApplicationDomainType::ApplicationDomainType; | 243 | using ApplicationDomainType::ApplicationDomainType; |
207 | virtual ~Entity(); | 244 | virtual ~Entity(); |
245 | SINK_REFERENCE_PROPERTY(SinkResource, Resource, resource); | ||
208 | }; | 246 | }; |
209 | 247 | ||
210 | struct SINK_EXPORT Event : public Entity { | 248 | struct SINK_EXPORT Event : public Entity { |
@@ -266,43 +304,6 @@ enum SINK_EXPORT Status { | |||
266 | ErrorStatus | 304 | ErrorStatus |
267 | }; | 305 | }; |
268 | 306 | ||
269 | struct SINK_EXPORT SinkAccount : public ApplicationDomainType { | ||
270 | typedef QSharedPointer<SinkAccount> Ptr; | ||
271 | explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); | ||
272 | explicit SinkAccount(const QByteArray &identifier); | ||
273 | SinkAccount(); | ||
274 | virtual ~SinkAccount(); | ||
275 | |||
276 | SINK_PROPERTY(QString, Name, name); | ||
277 | SINK_PROPERTY(QString, Icon, icon); | ||
278 | SINK_PROPERTY(QString, AccountType, type); | ||
279 | SINK_STATUS_PROPERTY(int, Status, status); | ||
280 | SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); | ||
281 | SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); | ||
282 | }; | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Represents an sink resource. | ||
287 | * | ||
288 | * This type is used for configuration of resources, | ||
289 | * and for creating and removing resource instances. | ||
290 | */ | ||
291 | struct SINK_EXPORT SinkResource : public ApplicationDomainType { | ||
292 | typedef QSharedPointer<SinkResource> Ptr; | ||
293 | explicit SinkResource(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); | ||
294 | explicit SinkResource(const QByteArray &identifier); | ||
295 | SinkResource(); | ||
296 | virtual ~SinkResource(); | ||
297 | |||
298 | SINK_REFERENCE_PROPERTY(SinkAccount, Account, account); | ||
299 | SINK_PROPERTY(QByteArray, ResourceType, type); | ||
300 | SINK_PROPERTY(QByteArrayList, Capabilities, capabilities); | ||
301 | SINK_STATUS_PROPERTY(int, Status, status); | ||
302 | SINK_STATUS_PROPERTY(ApplicationDomain::Error, Error, error); | ||
303 | SINK_STATUS_PROPERTY(ApplicationDomain::Progress, Progress, progress); | ||
304 | }; | ||
305 | |||
306 | struct SINK_EXPORT Identity : public ApplicationDomainType { | 307 | struct SINK_EXPORT Identity : public ApplicationDomainType { |
307 | typedef QSharedPointer<Identity> Ptr; | 308 | typedef QSharedPointer<Identity> Ptr; |
308 | explicit Identity(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); | 309 | explicit Identity(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &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() | |||
57 | /* | 57 | /* |
58 | * Returns a map of resource instance identifiers and resource type | 58 | * Returns a map of resource instance identifiers and resource type |
59 | */ | 59 | */ |
60 | static QMap<QByteArray, QByteArray> getResources(const QList<QByteArray> &resourceFilter, const QList<QByteArray> &accountFilter,const QByteArray &type = QByteArray()) | 60 | static QMap<QByteArray, QByteArray> getResources(const Sink::Query &query, const QByteArray &type = QByteArray()) |
61 | { | 61 | { |
62 | const QList<QByteArray> resourceFilter = query.resources; | ||
63 | const QList<QByteArray> accountFilter = query.accounts; | ||
64 | |||
65 | auto resourceComparator = query.getFilter(Sink::ApplicationDomain::Entity::Resource::name); | ||
66 | |||
62 | const auto filterResource = [&](const QByteArray &res) { | 67 | const auto filterResource = [&](const QByteArray &res) { |
63 | const auto configuration = ResourceConfig::getConfiguration(res); | 68 | const auto configuration = ResourceConfig::getConfiguration(res); |
64 | if (!accountFilter.isEmpty() && !accountFilter.contains(configuration.value("account").toByteArray())) { | 69 | if (!accountFilter.isEmpty() && !accountFilter.contains(configuration.value(ApplicationDomain::SinkResource::Account::name).toByteArray())) { |
65 | return true; | 70 | return true; |
66 | } | 71 | } |
72 | //Subquery for the resource | ||
73 | if (resourceComparator.value.canConvert<Query>()) { | ||
74 | auto subquery = resourceComparator.value.value<Query>(); | ||
75 | for (const auto &filterProperty : subquery.propertyFilter.keys()) { | ||
76 | const auto filter = subquery.propertyFilter.value(filterProperty); | ||
77 | if (!filter.matches(configuration.value(filterProperty))) { | ||
78 | return true; | ||
79 | } | ||
80 | } | ||
81 | } | ||
67 | return false; | 82 | return false; |
68 | }; | 83 | }; |
69 | 84 | ||
@@ -139,7 +154,7 @@ QSharedPointer<QAbstractItemModel> Store::loadModel(Query query) | |||
139 | //* The result provider needs to live for as long as results are provided (until the last thread exits). | 154 | //* The result provider needs to live for as long as results are provided (until the last thread exits). |
140 | 155 | ||
141 | // Query all resources and aggregate results | 156 | // Query all resources and aggregate results |
142 | auto resources = getResources(query.resources, query.accounts, ApplicationDomain::getTypeName<DomainType>()); | 157 | auto resources = getResources(query, ApplicationDomain::getTypeName<DomainType>()); |
143 | auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create(); | 158 | auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create(); |
144 | model->setEmitter(aggregatingEmitter); | 159 | model->setEmitter(aggregatingEmitter); |
145 | 160 | ||
@@ -252,7 +267,7 @@ KAsync::Job<void> Store::removeDataFromDisk(const QByteArray &identifier) | |||
252 | KAsync::Job<void> Store::synchronize(const Sink::Query &query) | 267 | KAsync::Job<void> Store::synchronize(const Sink::Query &query) |
253 | { | 268 | { |
254 | SinkTrace() << "synchronize" << query.resources; | 269 | SinkTrace() << "synchronize" << query.resources; |
255 | auto resources = getResources(query.resources, query.accounts).keys(); | 270 | auto resources = getResources(query).keys(); |
256 | //FIXME only necessary because each doesn't propagate errors | 271 | //FIXME only necessary because each doesn't propagate errors |
257 | auto errorFlag = new bool; | 272 | auto errorFlag = new bool; |
258 | return KAsync::value(resources) | 273 | return KAsync::value(resources) |
@@ -352,7 +367,7 @@ QList<DomainType> Store::read(const Sink::Query &q) | |||
352 | query.synchronousQuery = true; | 367 | query.synchronousQuery = true; |
353 | query.liveQuery = false; | 368 | query.liveQuery = false; |
354 | QList<DomainType> list; | 369 | QList<DomainType> list; |
355 | auto resources = getResources(query.resources, query.accounts, ApplicationDomain::getTypeName<DomainType>()); | 370 | auto resources = getResources(query, ApplicationDomain::getTypeName<DomainType>()); |
356 | auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create(); | 371 | auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create(); |
357 | aggregatingEmitter->onAdded([&list](const typename DomainType::Ptr &value){ | 372 | aggregatingEmitter->onAdded([&list](const typename DomainType::Ptr &value){ |
358 | SinkTrace() << "Found value: " << value->identifier(); | 373 | 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: | |||
528 | QCOMPARE(mails.size(), 1); | 528 | QCOMPARE(mails.size(), 1); |
529 | QCOMPARE(mails.first().getUid().toLatin1(), QByteArray("mail1")); | 529 | QCOMPARE(mails.first().getUid().toLatin1(), QByteArray("mail1")); |
530 | } | 530 | } |
531 | |||
532 | void testResourceSubQuery() | ||
533 | { | ||
534 | using namespace Sink; | ||
535 | using namespace Sink::ApplicationDomain; | ||
536 | |||
537 | //Setup | ||
538 | auto resource1 = ApplicationDomainType::createEntity<SinkResource>(); | ||
539 | resource1.setResourceType("sink.dummy"); | ||
540 | resource1.setCapabilities(QByteArrayList() << "cap1"); | ||
541 | Store::create(resource1).exec().waitForFinished(); | ||
542 | |||
543 | auto resource2 = ApplicationDomainType::createEntity<SinkResource>(); | ||
544 | resource2.setCapabilities(QByteArrayList() << "cap2"); | ||
545 | resource2.setResourceType("sink.dummy"); | ||
546 | Store::create(resource2).exec().waitForFinished(); | ||
547 | |||
548 | Folder folder1(resource1.identifier()); | ||
549 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
550 | Folder folder2(resource2.identifier()); | ||
551 | VERIFYEXEC(Sink::Store::create<Folder>(folder2)); | ||
552 | |||
553 | // Test | ||
554 | Sink::Query query; | ||
555 | query.filter<Folder::Resource>(Sink::Query().containsFilter<SinkResource::Capabilities>("cap1")); | ||
556 | |||
557 | // We fetch before the data is available and rely on the live query mechanism to deliver the actual data | ||
558 | auto folders = Sink::Store::read<Folder>(query); | ||
559 | QCOMPARE(folders.size(), 1); | ||
560 | } | ||
531 | }; | 561 | }; |
532 | 562 | ||
533 | QTEST_MAIN(QueryTest) | 563 | QTEST_MAIN(QueryTest) |