diff options
-rw-r--r-- | common/domain/event.cpp | 3 | ||||
-rw-r--r-- | common/domain/event.h | 5 | ||||
-rw-r--r-- | examples/dummyresource/facade.cpp | 57 |
3 files changed, 12 insertions, 53 deletions
diff --git a/common/domain/event.cpp b/common/domain/event.cpp index 776fa50..c435c6b 100644 --- a/common/domain/event.cpp +++ b/common/domain/event.cpp | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | using namespace Akonadi2::ApplicationDomain; | 33 | using namespace Akonadi2::ApplicationDomain; |
34 | 34 | ||
35 | ResultSet TypeImplementation<Event>::queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier) | 35 | ResultSet TypeImplementation<Event>::queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters) |
36 | { | 36 | { |
37 | QVector<QByteArray> keys; | 37 | QVector<QByteArray> keys; |
38 | if (query.propertyFilter.contains("uid")) { | 38 | if (query.propertyFilter.contains("uid")) { |
@@ -43,6 +43,7 @@ ResultSet TypeImplementation<Event>::queryIndexes(const Akonadi2::Query &query, | |||
43 | [](const Index::Error &error) { | 43 | [](const Index::Error &error) { |
44 | Warning() << "Error in index: " << error.message; | 44 | Warning() << "Error in index: " << error.message; |
45 | }); | 45 | }); |
46 | appliedFilters << "uid"; | ||
46 | } | 47 | } |
47 | return ResultSet(keys); | 48 | return ResultSet(keys); |
48 | } | 49 | } |
diff --git a/common/domain/event.h b/common/domain/event.h index d40e55d..68c684a 100644 --- a/common/domain/event.h +++ b/common/domain/event.h | |||
@@ -39,18 +39,21 @@ namespace ApplicationDomain { | |||
39 | 39 | ||
40 | /** | 40 | /** |
41 | * Implements all type-specific code such as updating and querying indexes. | 41 | * Implements all type-specific code such as updating and querying indexes. |
42 | * | ||
43 | * These are type specifiy default implementations. Theoretically a resource could implement it's own implementation. | ||
42 | */ | 44 | */ |
43 | template<> | 45 | template<> |
44 | class TypeImplementation<Akonadi2::ApplicationDomain::Event> { | 46 | class TypeImplementation<Akonadi2::ApplicationDomain::Event> { |
45 | public: | 47 | public: |
46 | typedef Akonadi2::ApplicationDomain::Buffer::Event Buffer; | 48 | typedef Akonadi2::ApplicationDomain::Buffer::Event Buffer; |
47 | typedef Akonadi2::ApplicationDomain::Buffer::EventBuilder BufferBuilder; | 49 | typedef Akonadi2::ApplicationDomain::Buffer::EventBuilder BufferBuilder; |
50 | static QSet<QByteArray> indexedProperties(); | ||
48 | /** | 51 | /** |
49 | * Returns the potential result set based on the indexes. | 52 | * Returns the potential result set based on the indexes. |
50 | * | 53 | * |
51 | * An empty result set indicates that a full scan is required. | 54 | * An empty result set indicates that a full scan is required. |
52 | */ | 55 | */ |
53 | static ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier); | 56 | static ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters); |
54 | static void index(const Event &type); | 57 | static void index(const Event &type); |
55 | static QSharedPointer<ReadPropertyMapper<Buffer> > initializeReadPropertyMapper(); | 58 | static QSharedPointer<ReadPropertyMapper<Buffer> > initializeReadPropertyMapper(); |
56 | static QSharedPointer<WritePropertyMapper<BufferBuilder> > initializeWritePropertyMapper(); | 59 | static QSharedPointer<WritePropertyMapper<BufferBuilder> > initializeWritePropertyMapper(); |
diff --git a/examples/dummyresource/facade.cpp b/examples/dummyresource/facade.cpp index e678214..9849a92 100644 --- a/examples/dummyresource/facade.cpp +++ b/examples/dummyresource/facade.cpp | |||
@@ -48,46 +48,6 @@ DummyResourceFacade::~DummyResourceFacade() | |||
48 | { | 48 | { |
49 | } | 49 | } |
50 | 50 | ||
51 | static std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> prepareQuery(const Akonadi2::Query &query) | ||
52 | { | ||
53 | //Compose some functions to make query matching fast. | ||
54 | //This way we can process the query once, and convert all values into something that can be compared quickly | ||
55 | std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> preparedQuery; | ||
56 | if (!query.ids.isEmpty()) { | ||
57 | //Match by id | ||
58 | //TODO: for id's a direct lookup would be way faster | ||
59 | |||
60 | //We convert the id's to std::string so we don't have to convert each key during the scan. (This runs only once, and the query will be run for every key) | ||
61 | //Probably a premature optimization, but perhaps a useful technique to be investigated. | ||
62 | QVector<std::string> ids; | ||
63 | for (const auto &id : query.ids) { | ||
64 | ids << id.toStdString(); | ||
65 | } | ||
66 | preparedQuery = [ids](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { | ||
67 | if (ids.contains(key)) { | ||
68 | return true; | ||
69 | } | ||
70 | return false; | ||
71 | }; | ||
72 | } else if (!query.propertyFilter.isEmpty()) { | ||
73 | if (query.propertyFilter.contains("uid")) { | ||
74 | const QByteArray uid = query.propertyFilter.value("uid").toByteArray(); | ||
75 | preparedQuery = [uid](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { | ||
76 | if (local && local->uid() && (QByteArray::fromRawData(local->uid()->c_str(), local->uid()->size()) == uid)) { | ||
77 | return true; | ||
78 | } | ||
79 | return false; | ||
80 | }; | ||
81 | } | ||
82 | } else { | ||
83 | //Match everything | ||
84 | preparedQuery = [](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { | ||
85 | return true; | ||
86 | }; | ||
87 | } | ||
88 | return preparedQuery; | ||
89 | } | ||
90 | |||
91 | static void scan(const QSharedPointer<Akonadi2::Storage> &storage, const QByteArray &key, std::function<bool(const QByteArray &key, const Akonadi2::Entity &entity, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local, Akonadi2::Metadata const *metadata)> callback) | 51 | static void scan(const QSharedPointer<Akonadi2::Storage> &storage, const QByteArray &key, std::function<bool(const QByteArray &key, const Akonadi2::Entity &entity, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local, Akonadi2::Metadata const *metadata)> callback) |
92 | { | 52 | { |
93 | storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { | 53 | storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { |
@@ -130,22 +90,17 @@ void DummyResourceFacade::readValue(const QSharedPointer<Akonadi2::Storage> &sto | |||
130 | 90 | ||
131 | static ResultSet getResultSet(const Akonadi2::Query &query, const QSharedPointer<Akonadi2::Storage> &storage) | 91 | static ResultSet getResultSet(const Akonadi2::Query &query, const QSharedPointer<Akonadi2::Storage> &storage) |
132 | { | 92 | { |
133 | auto resultSet = Akonadi2::ApplicationDomain::TypeImplementation<Akonadi2::ApplicationDomain::Event>::queryIndexes(query, "org.kde.dummy"); | 93 | QSet<QByteArray> appliedFilters; |
94 | ResultSet resultSet = Akonadi2::ApplicationDomain::TypeImplementation<Akonadi2::ApplicationDomain::Event>::queryIndexes(query, "org.kde.dummy", appliedFilters); | ||
95 | const auto remainingFilters = query.propertyFilter.keys().toSet() - appliedFilters; | ||
134 | 96 | ||
135 | //Scan for where we don't have an index | ||
136 | //TODO: we may want a way for queryIndexes to indicate that the resultSet is not final, and that a scan over the remaining set is required | ||
137 | //TODO: the prepared query should be generalized in TypeImplementation on top of domain adaptors | ||
138 | if (resultSet.isEmpty()) { | 97 | if (resultSet.isEmpty()) { |
139 | QVector<QByteArray> keys; | 98 | QVector<QByteArray> keys; |
140 | const auto preparedQuery = prepareQuery(query); | 99 | scan(storage, QByteArray(), [=, &keys](const QByteArray &key, const Akonadi2::Entity &entity, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local, Akonadi2::Metadata const *metadataBuffer) { |
141 | scan(storage, QByteArray(), [preparedQuery, &keys](const QByteArray &key, const Akonadi2::Entity &entity, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local, Akonadi2::Metadata const *metadataBuffer) { | 100 | keys << key; |
142 | //TODO use adapter for query and scan? | ||
143 | if (preparedQuery && preparedQuery(std::string(key.constData(), key.size()), buffer, local)) { | ||
144 | keys << key; | ||
145 | } | ||
146 | return true; | 101 | return true; |
147 | }); | 102 | }); |
148 | return ResultSet(keys); | 103 | resultSet = ResultSet(keys); |
149 | } | 104 | } |
150 | 105 | ||
151 | return resultSet; | 106 | return resultSet; |