summaryrefslogtreecommitdiffstats
path: root/dummyresource/facade.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dummyresource/facade.cpp')
-rw-r--r--dummyresource/facade.cpp145
1 files changed, 94 insertions, 51 deletions
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp
index cd930f6..1aaec68 100644
--- a/dummyresource/facade.cpp
+++ b/dummyresource/facade.cpp
@@ -31,6 +31,7 @@
31#include "createentity_generated.h" 31#include "createentity_generated.h"
32#include "domainadaptor.h" 32#include "domainadaptor.h"
33#include <common/entitybuffer.h> 33#include <common/entitybuffer.h>
34#include <common/index.h>
34 35
35using namespace DummyCalendar; 36using namespace DummyCalendar;
36using namespace flatbuffers; 37using namespace flatbuffers;
@@ -73,11 +74,11 @@ Async::Job<void> DummyResourceFacade::remove(const Akonadi2::Domain::Event &doma
73 return Async::null<void>(); 74 return Async::null<void>();
74} 75}
75 76
76static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query) 77static std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> prepareQuery(const Akonadi2::Query &query)
77{ 78{
78 //Compose some functions to make query matching fast. 79 //Compose some functions to make query matching fast.
79 //This way we can process the query once, and convert all values into something that can be compared quickly 80 //This way we can process the query once, and convert all values into something that can be compared quickly
80 std::function<bool(const std::string &key, DummyEvent const *buffer)> preparedQuery; 81 std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery;
81 if (!query.ids.isEmpty()) { 82 if (!query.ids.isEmpty()) {
82 //Match by id 83 //Match by id
83 //TODO: for id's a direct lookup would be way faster 84 //TODO: for id's a direct lookup would be way faster
@@ -88,15 +89,26 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer)> pre
88 for (const auto &id : query.ids) { 89 for (const auto &id : query.ids) {
89 ids << id.toStdString(); 90 ids << id.toStdString();
90 } 91 }
91 preparedQuery = [ids](const std::string &key, DummyEvent const *buffer) { 92 preparedQuery = [ids](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
92 if (ids.contains(key)) { 93 if (ids.contains(key)) {
93 return true; 94 return true;
94 } 95 }
95 return false; 96 return false;
96 }; 97 };
98 } else if (!query.propertyFilter.isEmpty()) {
99 if (query.propertyFilter.contains("uid")) {
100 const QByteArray uid = query.propertyFilter.value("uid").toByteArray();
101 preparedQuery = [uid](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
102 if (local && local->uid() && (QByteArray::fromRawData(local->uid()->c_str(), local->uid()->size()) == uid)) {
103 qDebug() << "uid match";
104 return true;
105 }
106 return false;
107 };
108 }
97 } else { 109 } else {
98 //Match everything 110 //Match everything
99 preparedQuery = [](const std::string &key, DummyEvent const *buffer) { 111 preparedQuery = [](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
100 return true; 112 return true;
101 }; 113 };
102 } 114 }
@@ -121,65 +133,96 @@ Async::Job<void> DummyResourceFacade::synchronizeResource(bool sync)
121 return Async::null<void>(); 133 return Async::null<void>();
122} 134}
123 135
124Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) 136void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery)
125{ 137{
126 qDebug() << "load called"; 138 storage->scan(key.data(), key.size(), [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
127 139
128 return synchronizeResource(query.syncOnDemand).then<void>([=](Async::Future<void> &future) { 140 //Skip internals
129 qDebug() << "sync complete"; 141 if (QByteArray::fromRawData(static_cast<char*>(keyValue), keySize).startsWith("__internal")) {
130 //Now that the sync is complete we can execute the query 142 return true;
131 const auto preparedQuery = prepareQuery(query); 143 }
132
133 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
134 144
135 qDebug() << "executing query"; 145 //Extract buffers
136 //We start a transaction explicitly that we'll leave open so the values can be read. 146 Akonadi2::EntityBuffer buffer(dataValue, dataSize);
137 //The transaction will be closed automatically once the storage object is destroyed.
138 storage->startTransaction(Akonadi2::Storage::ReadOnly);
139 //Because we have no indexes yet, we always do a full scan
140 storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
141 147
142 //Skip internals 148 DummyEvent const *resourceBuffer = 0;
143 if (QByteArray::fromRawData(static_cast<char*>(keyValue), keySize).startsWith("__internal")) { 149 if (auto resourceData = buffer.entity().resource()) {
144 return true; 150 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
151 if (VerifyDummyEventBuffer(verifyer)) {
152 resourceBuffer = GetDummyEvent(resourceData->Data());
145 } 153 }
154 }
146 155
147 //Extract buffers 156 Akonadi2::Domain::Buffer::Event const *localBuffer = 0;
148 Akonadi2::EntityBuffer buffer(dataValue, dataSize); 157 if (auto localData = buffer.entity().local()) {
149 158 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
150 DummyEvent const *resourceBuffer = 0; 159 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
151 if (auto resourceData = buffer.entity().resource()) { 160 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData->Data());
152 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
153 if (VerifyDummyEventBuffer(verifyer)) {
154 resourceBuffer = GetDummyEvent(resourceData);
155 }
156 } 161 }
162 }
157 163
158 Akonadi2::Metadata const *metadataBuffer = 0; 164 Akonadi2::Metadata const *metadataBuffer = 0;
159 if (auto metadataData = buffer.entity().metadata()) { 165 if (auto metadataData = buffer.entity().metadata()) {
160 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); 166 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size());
161 if (Akonadi2::VerifyMetadataBuffer(verifyer)) { 167 if (Akonadi2::VerifyMetadataBuffer(verifyer)) {
162 metadataBuffer = Akonadi2::GetMetadata(metadataData); 168 metadataBuffer = Akonadi2::GetMetadata(metadataData->Data());
163 }
164 } 169 }
170 }
165 171
166 if (!resourceBuffer || !metadataBuffer) { 172 if (!resourceBuffer || !metadataBuffer) {
167 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); 173 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize));
168 return true; 174 return true;
169 } 175 }
176
177 //We probably only want to create all buffers after the scan
178 //TODO use adapter for query and scan?
179 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer, localBuffer)) {
180 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
181 //This only works for a 1:1 mapping of resource to domain types.
182 //Not i.e. for tags that are stored as flags in each entity of an imap store.
183 auto adaptor = mFactory->createAdaptor(buffer.entity());
184 //TODO only copy requested properties
185 auto memoryAdaptor = QSharedPointer<Akonadi2::Domain::MemoryBufferAdaptor>::create(*adaptor);
186 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor);
187 resultCallback(event);
188 }
189 return true;
190 },
191 [](const Akonadi2::Storage::Error &error) {
192 qDebug() << QString::fromStdString(error.message);
193 });
194}
195
196Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback)
197{
198 return synchronizeResource(query.syncOnDemand).then<void>([=](Async::Future<void> &future) {
199 //Now that the sync is complete we can execute the query
200 const auto preparedQuery = prepareQuery(query);
201
202 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
170 203
171 //We probably only want to create all buffers after the scan 204 QVector<QByteArray> keys;
172 //TODO use adapter for query and scan? 205 if (query.propertyFilter.contains("uid")) {
173 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer)) { 206 static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly);
174 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; 207 uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) {
175 auto adaptor = mFactory->createAdaptor(buffer.entity()); 208 keys << value;
176 //TODO only copy requested properties 209 },
177 auto memoryAdaptor = QSharedPointer<Akonadi2::Domain::MemoryBufferAdaptor>::create(*adaptor); 210 [](const Index::Error &error) {
178 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor); 211 qWarning() << "Error in index: " << QString::fromStdString(error.message);
179 resultCallback(event); 212 });
213 }
214
215 //We start a transaction explicitly that we'll leave open so the values can be read.
216 //The transaction will be closed automatically once the storage object is destroyed.
217 storage->startTransaction(Akonadi2::Storage::ReadOnly);
218 if (keys.isEmpty()) {
219 qDebug() << "full scan";
220 readValue(storage, QByteArray(), resultCallback, preparedQuery);
221 } else {
222 for (const auto &key : keys) {
223 readValue(storage, key, resultCallback, preparedQuery);
180 } 224 }
181 return true; 225 }
182 });
183 future.setFinished(); 226 future.setFinished();
184 }); 227 });
185} 228}