summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-10-04 17:12:02 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-10-04 17:12:02 +0200
commit3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7 (patch)
tree5ac341b501dae0a5e7d5addb8114535de53979cf
parent7757d32b5a820623c469b7851354374427142598 (diff)
downloadsink-3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7.tar.gz
sink-3ae3ef9676bd7fdcb45064f9a1b397c90478b4b7.zip
Resource subqueries
-rw-r--r--common/datastorequery.cpp6
-rw-r--r--common/domain/applicationdomaintype.h75
-rw-r--r--common/store.cpp25
-rw-r--r--tests/querytest.cpp30
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)
408void DataStoreQuery::setupQuery() 408void 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
204struct 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 */
226struct 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
204struct SINK_EXPORT Entity : public ApplicationDomainType { 241struct 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
210struct SINK_EXPORT Event : public Entity { 248struct SINK_EXPORT Event : public Entity {
@@ -266,43 +304,6 @@ enum SINK_EXPORT Status {
266 ErrorStatus 304 ErrorStatus
267}; 305};
268 306
269struct 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 */
291struct 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
306struct SINK_EXPORT Identity : public ApplicationDomainType { 307struct 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 */
60static QMap<QByteArray, QByteArray> getResources(const QList<QByteArray> &resourceFilter, const QList<QByteArray> &accountFilter,const QByteArray &type = QByteArray()) 60static 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)
252KAsync::Job<void> Store::synchronize(const Sink::Query &query) 267KAsync::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
533QTEST_MAIN(QueryTest) 563QTEST_MAIN(QueryTest)