summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-12-06 19:01:03 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-12-06 19:01:03 +0100
commit303a3cf5ba48dd9857a1fb9600cedd604c71de8d (patch)
treeb7607eb58b7fbda5dbd49133bb316fe109edc44a
parent46570dd9684990846cfd4c3dc5be71498c5a6278 (diff)
downloadsink-303a3cf5ba48dd9857a1fb9600cedd604c71de8d.tar.gz
sink-303a3cf5ba48dd9857a1fb9600cedd604c71de8d.zip
Added TypeIndex
A central location for all types to specify what properties are indexed, and how to query them.
-rw-r--r--common/CMakeLists.txt1
-rw-r--r--common/domain/mail.cpp39
-rw-r--r--common/typeindex.cpp105
-rw-r--r--common/typeindex.h45
-rw-r--r--tests/querytest.cpp25
5 files changed, 195 insertions, 20 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index e56ece9..8312f13 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -32,6 +32,7 @@ set(command_SRCS
32 threadboundary.cpp 32 threadboundary.cpp
33 messagequeue.cpp 33 messagequeue.cpp
34 index.cpp 34 index.cpp
35 typeindex.cpp
35 resourcefacade.cpp 36 resourcefacade.cpp
36 resourceconfig.cpp 37 resourceconfig.cpp
37 domain/applicationdomaintype.cpp 38 domain/applicationdomaintype.cpp
diff --git a/common/domain/mail.cpp b/common/domain/mail.cpp
index 0170357..1a877cb 100644
--- a/common/domain/mail.cpp
+++ b/common/domain/mail.cpp
@@ -29,41 +29,40 @@
29#include "../propertymapper.h" 29#include "../propertymapper.h"
30#include "../query.h" 30#include "../query.h"
31#include "../definitions.h" 31#include "../definitions.h"
32#include "../typeindex.h"
32 33
33#include "mail_generated.h" 34#include "mail_generated.h"
34 35
35using namespace Akonadi2::ApplicationDomain; 36using namespace Akonadi2::ApplicationDomain;
36 37
37ResultSet TypeImplementation<Mail>::queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) 38static TypeIndex &getIndex()
38{ 39{
39 QVector<QByteArray> keys; 40 static TypeIndex *index = 0;
40 if (query.propertyFilter.contains("uid")) { 41 if (!index) {
41 Index uidIndex("mail.index.uid", transaction); 42 index = new TypeIndex("mail");
42 uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) { 43 index->addProperty<QByteArray>("uid");
43 keys << value; 44 index->addProperty<QByteArray>("sender");
44 }, 45 index->addProperty<QByteArray>("senderName");
45 [](const Index::Error &error) { 46 index->addProperty<QString>("subject");
46 Warning() << "Error in uid index: " << error.message; 47 index->addProperty<QDateTime>("date");
47 });
48 appliedFilters << "uid";
49 } 48 }
50 return ResultSet(keys); 49 return *index;
50}
51
52ResultSet TypeImplementation<Mail>::queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction)
53{
54 return getIndex().query(query, appliedFilters, transaction);
51} 55}
52 56
53void TypeImplementation<Mail>::index(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction) 57void TypeImplementation<Mail>::index(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction)
54{ 58{
55 const auto uid = bufferAdaptor.getProperty("uid"); 59 Trace() << "Indexing " << identifier;
56 if (uid.isValid()) { 60 getIndex().add(identifier, bufferAdaptor, transaction);
57 Index("mail.index.uid", transaction).add(uid.toByteArray(), identifier);
58 }
59} 61}
60 62
61void TypeImplementation<Mail>::removeIndex(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction) 63void TypeImplementation<Mail>::removeIndex(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction)
62{ 64{
63 const auto uid = bufferAdaptor.getProperty("uid"); 65 getIndex().remove(identifier, bufferAdaptor, transaction);
64 if (uid.isValid()) {
65 Index("mail.index.uid", transaction).remove(uid.toByteArray(), identifier);
66 }
67} 66}
68 67
69QSharedPointer<ReadPropertyMapper<TypeImplementation<Mail>::Buffer> > TypeImplementation<Mail>::initializeReadPropertyMapper() 68QSharedPointer<ReadPropertyMapper<TypeImplementation<Mail>::Buffer> > TypeImplementation<Mail>::initializeReadPropertyMapper()
diff --git a/common/typeindex.cpp b/common/typeindex.cpp
new file mode 100644
index 0000000..0a0dc33
--- /dev/null
+++ b/common/typeindex.cpp
@@ -0,0 +1,105 @@
1/*
2 Copyright (c) 2015 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#include "typeindex.h"
20
21#include "log.h"
22#include "index.h"
23
24TypeIndex::TypeIndex(const QByteArray &type)
25 : mType(type)
26{
27
28}
29
30template<>
31void TypeIndex::addProperty<QByteArray>(const QByteArray &property)
32{
33 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Akonadi2::Storage::Transaction &transaction) {
34 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray();
35 Index(mType + ".index." + property, transaction).add(value.toByteArray(), identifier);
36 };
37 mIndexer.insert(property, indexer);
38 mProperties << property;
39}
40
41template<>
42void TypeIndex::addProperty<QString>(const QByteArray &property)
43{
44 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Akonadi2::Storage::Transaction &transaction) {
45 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray();
46 Index(mType + ".index." + property, transaction).add(value.toByteArray(), identifier);
47 };
48 mIndexer.insert(property, indexer);
49 mProperties << property;
50}
51
52template<>
53void TypeIndex::addProperty<QDateTime>(const QByteArray &property)
54{
55 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Akonadi2::Storage::Transaction &transaction) {
56 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray();
57 Index(mType + ".index." + property, transaction).add(value.toByteArray(), identifier);
58 };
59 mIndexer.insert(property, indexer);
60 mProperties << property;
61}
62
63void TypeIndex::add(const QByteArray &identifier, const Akonadi2::ApplicationDomain::BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction)
64{
65 for (const auto &property : mProperties) {
66 const auto value = bufferAdaptor.getProperty(property);
67 if (value.isValid()) {
68 auto indexer = mIndexer.value(property);
69 indexer(identifier, value, transaction);
70 }
71 }
72}
73
74void TypeIndex::remove(const QByteArray &identifier, const Akonadi2::ApplicationDomain::BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction)
75{
76 for (const auto &property : mProperties) {
77 const auto value = bufferAdaptor.getProperty(property);
78 if (value.isValid()) {
79 //FIXME don't always convert to byte array
80 Index(mType + ".index." + property, transaction).remove(value.toByteArray(), identifier);
81 }
82 }
83}
84
85ResultSet TypeIndex::query(const Akonadi2::Query &query, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction)
86{
87 QVector<QByteArray> keys;
88 for (const auto &property : mProperties) {
89 if (query.propertyFilter.contains(property)) {
90 Index index(mType + ".index." + property, transaction);
91 index.lookup(query.propertyFilter.value(property).toByteArray(), [&](const QByteArray &value) {
92 keys << value;
93 },
94 [property](const Index::Error &error) {
95 Warning() << "Error in index: " << error.message << property;
96 });
97 appliedFilters << property;
98 }
99 Trace() << "Index lookup found keys: " << keys.size();
100 return ResultSet(keys);
101 }
102 Trace() << "No matching index";
103 return ResultSet(keys);
104}
105
diff --git a/common/typeindex.h b/common/typeindex.h
new file mode 100644
index 0000000..fb66c2c
--- /dev/null
+++ b/common/typeindex.h
@@ -0,0 +1,45 @@
1/*
2 Copyright (c) 2015 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#pragma once
20
21#include "resultset.h"
22#include "bufferadaptor.h"
23#include "storage.h"
24#include "query.h"
25#include <QByteArray>
26
27class TypeIndex
28{
29public:
30 TypeIndex(const QByteArray &type);
31
32 template<typename T>
33 void addProperty(const QByteArray &property);
34
35 void add(const QByteArray &identifier, const Akonadi2::ApplicationDomain::BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction);
36 void remove(const QByteArray &identifier, const Akonadi2::ApplicationDomain::BufferAdaptor &bufferAdaptor, Akonadi2::Storage::Transaction &transaction);
37
38 ResultSet query(const Akonadi2::Query &query, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction);
39
40private:
41 QByteArray mType;
42 QByteArrayList mProperties;
43 QHash<QByteArray, std::function<void(const QByteArray &identifier, const QVariant &value, Akonadi2::Storage::Transaction &transaction)> > mIndexer;
44};
45
diff --git a/tests/querytest.cpp b/tests/querytest.cpp
index 669bf58..516af35 100644
--- a/tests/querytest.cpp
+++ b/tests/querytest.cpp
@@ -154,6 +154,31 @@ private Q_SLOTS:
154 QTRY_COMPARE(model->rowCount(), 1); 154 QTRY_COMPARE(model->rowCount(), 1);
155 model->fetchMore(model->index(0, 0)); 155 model->fetchMore(model->index(0, 0));
156 QTRY_COMPARE(model->rowCount(model->index(0, 0)), 1); 156 QTRY_COMPARE(model->rowCount(model->index(0, 0)), 1);
157 void testMailByUid()
158 {
159 //Setup
160 {
161 Akonadi2::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
162 mail.setProperty("uid", "test1");
163 mail.setProperty("sender", "doe@example.org");
164 Akonadi2::Store::create<Akonadi2::ApplicationDomain::Mail>(mail).exec().waitForFinished();
165 }
166
167 //Test
168 Akonadi2::Query query;
169 query.resources << "org.kde.dummy.instance1";
170 query.syncOnDemand = false;
171 query.processAll = true;
172 query.liveQuery = false;
173 query.propertyFilter.insert("uid", "test1");
174
175 //Ensure all local data is processed
176 Akonadi2::Store::synchronize(query).exec().waitForFinished();
177
178 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data
179 auto model = Akonadi2::Store::loadModel<Akonadi2::ApplicationDomain::Mail>(query);
180 QTRY_VERIFY(model->data(QModelIndex(), Akonadi2::Store::ChildrenFetchedRole).toBool());
181 QCOMPARE(model->rowCount(), 1);
157 } 182 }
158}; 183};
159 184