summaryrefslogtreecommitdiffstats
path: root/examples/dummyresource/facade.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-05-25 17:00:51 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-05-25 17:00:51 +0200
commit2c0315f31e322c3a951e5aad8816723440ae860d (patch)
tree37fab916e4dcd9e5260968ee6682e0d78ad3cd4c /examples/dummyresource/facade.cpp
parenteddacfc5aff36eb3b16f12cba12ba1a88f5ee6e2 (diff)
downloadsink-2c0315f31e322c3a951e5aad8816723440ae860d.tar.gz
sink-2c0315f31e322c3a951e5aad8816723440ae860d.zip
Refactored query in facade
First prepare the result set, then retrieve it.
Diffstat (limited to 'examples/dummyresource/facade.cpp')
-rw-r--r--examples/dummyresource/facade.cpp96
1 files changed, 56 insertions, 40 deletions
diff --git a/examples/dummyresource/facade.cpp b/examples/dummyresource/facade.cpp
index c0143c0..5e0bada 100644
--- a/examples/dummyresource/facade.cpp
+++ b/examples/dummyresource/facade.cpp
@@ -86,10 +86,9 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer, Akon
86 return preparedQuery; 86 return preparedQuery;
87} 87}
88 88
89void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> preparedQuery) 89static 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)
90{ 90{
91 storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 91 storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
92
93 //Skip internals 92 //Skip internals
94 if (Akonadi2::Storage::isInternalKey(keyValue, keySize)) { 93 if (Akonadi2::Storage::isInternalKey(keyValue, keySize)) {
95 return true; 94 return true;
@@ -106,65 +105,82 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c
106 qWarning() << "invalid buffer " << QByteArray::fromRawData(static_cast<char*>(keyValue), keySize); 105 qWarning() << "invalid buffer " << QByteArray::fromRawData(static_cast<char*>(keyValue), keySize);
107 return true; 106 return true;
108 } 107 }
109 108 return callback(QByteArray::fromRawData(static_cast<char*>(keyValue), keySize), buffer.entity(), resourceBuffer, localBuffer, metadataBuffer);
110 //We probably only want to create all buffers after the scan
111 //TODO use adapter for query and scan?
112 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer, localBuffer)) {
113 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
114 //This only works for a 1:1 mapping of resource to domain types.
115 //Not i.e. for tags that are stored as flags in each entity of an imap store.
116 auto adaptor = mDomainTypeAdaptorFactory->createAdaptor(buffer.entity());
117 //TODO only copy requested properties
118 auto memoryAdaptor = QSharedPointer<Akonadi2::ApplicationDomain::MemoryBufferAdaptor>::create(*adaptor);
119 // here we could copy additional properties that don't have a 1:1 mapping, such as separately stored tags.
120 auto event = QSharedPointer<Akonadi2::ApplicationDomain::Event>::create("org.kde.dummy", QByteArray::fromRawData(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor);
121 resultCallback(event);
122 }
123 return true;
124 }, 109 },
125 [](const Akonadi2::Storage::Error &error) { 110 [](const Akonadi2::Storage::Error &error) {
126 qWarning() << "Error during query: " << error.message; 111 qWarning() << "Error during query: " << error.message;
127 }); 112 });
128} 113}
129 114
115void DummyResourceFacade::readValue(const QSharedPointer<Akonadi2::Storage> &storage, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback)
116{
117 scan(storage, key, [=](const QByteArray &key, const Akonadi2::Entity &entity, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local, Akonadi2::Metadata const *metadataBuffer) {
118 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
119 //This only works for a 1:1 mapping of resource to domain types.
120 //Not i.e. for tags that are stored as flags in each entity of an imap store.
121 //additional properties that don't have a 1:1 mapping (such as separately stored tags),
122 //could be added to the adaptor
123 auto event = QSharedPointer<Akonadi2::ApplicationDomain::Event>::create("org.kde.dummy", key, revision, mDomainTypeAdaptorFactory->createAdaptor(entity));
124 resultCallback(event);
125 return true;
126 });
127}
128
129//TODO this should return an iterator to the result set so we can lazy load
130static QVector<QByteArray> getResultSet(const Akonadi2::Query &query, const QSharedPointer<Akonadi2::Storage> &storage)
131{
132 //Now that the sync is complete we can execute the query
133 const auto preparedQuery = prepareQuery(query);
134
135 //Index lookups
136 //TODO query standard indexes
137 QVector<QByteArray> keys;
138 if (query.propertyFilter.contains("uid")) {
139 static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly);
140 uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) {
141 keys << value;
142 },
143 [](const Index::Error &error) {
144 Warning() << "Error in index: " << error.message;
145 });
146 }
147
148 //Scan for where we don't have an index
149 if (keys.isEmpty()) {
150 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) {
151 //TODO use adapter for query and scan?
152 if (preparedQuery && preparedQuery(std::string(key.constData(), key.size()), buffer, local)) {
153 keys << key;
154 }
155 return true;
156 });
157 }
158
159 return keys;
160}
161
130KAsync::Job<qint64> DummyResourceFacade::load(const Akonadi2::Query &query, const QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> > &resultProvider, qint64 oldRevision, qint64 newRevision) 162KAsync::Job<qint64> DummyResourceFacade::load(const Akonadi2::Query &query, const QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> > &resultProvider, qint64 oldRevision, qint64 newRevision)
131{ 163{
132 return KAsync::start<qint64>([=]() { 164 return KAsync::start<qint64>([=]() {
133 //Now that the sync is complete we can execute the query
134 const auto preparedQuery = prepareQuery(query);
135
136 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy"); 165 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
137 storage->setDefaultErrorHandler([](const Akonadi2::Storage::Error &error) { 166 storage->setDefaultErrorHandler([](const Akonadi2::Storage::Error &error) {
138 Warning() << "Error during query: " << error.store << error.message; 167 Warning() << "Error during query: " << error.store << error.message;
139 }); 168 });
140 169
141 storage->startTransaction(Akonadi2::Storage::ReadOnly); 170 storage->startTransaction(Akonadi2::Storage::ReadOnly);
171 //TODO start transaction on indexes as well
142 const qint64 revision = storage->maxRevision(); 172 const qint64 revision = storage->maxRevision();
143 173
144 //Index lookups 174 auto resultSet = getResultSet(query, storage);
145 QVector<QByteArray> keys;
146 if (query.propertyFilter.contains("uid")) {
147 static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly);
148 uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) {
149 keys << value;
150 },
151 [](const Index::Error &error) {
152 Warning() << "Error in index: " << error.message;
153 });
154 }
155 175
156 // TODO only emit changes and don't replace everything 176 // TODO only emit changes and don't replace everything
157 resultProvider->clear(); 177 resultProvider->clear();
158 // rerun query
159 auto resultCallback = std::bind(&Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr>::add, resultProvider, std::placeholders::_1); 178 auto resultCallback = std::bind(&Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr>::add, resultProvider, std::placeholders::_1);
160 179 for (const auto &key : resultSet) {
161 if (keys.isEmpty()) { 180 readValue(storage, key, [resultCallback](const Akonadi2::ApplicationDomain::Event::Ptr &event) {
162 Log() << "Executing a full scan"; 181 //We create an in-memory copy because the result provider will store the value, and the result we get back is only valid during the callback
163 readValue(storage, QByteArray(), resultCallback, preparedQuery); 182 resultCallback(Akonadi2::ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<Akonadi2::ApplicationDomain::Event>(event));
164 } else { 183 });
165 for (const auto &key : keys) {
166 readValue(storage, key, resultCallback, preparedQuery);
167 }
168 } 184 }
169 storage->abortTransaction(); 185 storage->abortTransaction();
170 return revision; 186 return revision;