diff options
25 files changed, 452 insertions, 69 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 2f779b5..25ea667 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt | |||
@@ -34,6 +34,7 @@ set(command_SRCS | |||
34 | resourceconfig.cpp | 34 | resourceconfig.cpp |
35 | domain/applicationdomaintype.cpp | 35 | domain/applicationdomaintype.cpp |
36 | domain/event.cpp | 36 | domain/event.cpp |
37 | domain/mail.cpp | ||
37 | ${storage_SRCS}) | 38 | ${storage_SRCS}) |
38 | 39 | ||
39 | add_library(${PROJECT_NAME} SHARED ${command_SRCS}) | 40 | add_library(${PROJECT_NAME} SHARED ${command_SRCS}) |
@@ -51,6 +52,7 @@ generate_flatbuffers( | |||
51 | commands/synchronize | 52 | commands/synchronize |
52 | commands/notification | 53 | commands/notification |
53 | domain/event | 54 | domain/event |
55 | domain/mail | ||
54 | entity | 56 | entity |
55 | metadata | 57 | metadata |
56 | queuedcommand | 58 | queuedcommand |
diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 47ff0c3..3cc075b 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp | |||
@@ -40,6 +40,18 @@ QByteArray getTypeName<AkonadiResource>() | |||
40 | return "akonadiresource"; | 40 | return "akonadiresource"; |
41 | } | 41 | } |
42 | 42 | ||
43 | template<> | ||
44 | QByteArray getTypeName<Mail>() | ||
45 | { | ||
46 | return "mail"; | ||
47 | } | ||
48 | |||
49 | template<> | ||
50 | QByteArray getTypeName<Folder>() | ||
51 | { | ||
52 | return "folder"; | ||
53 | } | ||
54 | |||
43 | } | 55 | } |
44 | } | 56 | } |
45 | 57 | ||
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 29bebcf..e0a6de0 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h | |||
@@ -112,10 +112,14 @@ struct Calendar : public ApplicationDomainType { | |||
112 | using ApplicationDomainType::ApplicationDomainType; | 112 | using ApplicationDomainType::ApplicationDomainType; |
113 | }; | 113 | }; |
114 | 114 | ||
115 | class Mail : public ApplicationDomainType { | 115 | struct Mail : public ApplicationDomainType { |
116 | typedef QSharedPointer<Mail> Ptr; | ||
117 | using ApplicationDomainType::ApplicationDomainType; | ||
116 | }; | 118 | }; |
117 | 119 | ||
118 | class Folder : public ApplicationDomainType { | 120 | struct Folder : public ApplicationDomainType { |
121 | typedef QSharedPointer<Folder> Ptr; | ||
122 | using ApplicationDomainType::ApplicationDomainType; | ||
119 | }; | 123 | }; |
120 | 124 | ||
121 | /** | 125 | /** |
@@ -146,6 +150,12 @@ QByteArray getTypeName<Todo>(); | |||
146 | template<> | 150 | template<> |
147 | QByteArray getTypeName<AkonadiResource>(); | 151 | QByteArray getTypeName<AkonadiResource>(); |
148 | 152 | ||
153 | template<> | ||
154 | QByteArray getTypeName<Mail>(); | ||
155 | |||
156 | template<> | ||
157 | QByteArray getTypeName<Folder>(); | ||
158 | |||
149 | /** | 159 | /** |
150 | * Type implementation. | 160 | * Type implementation. |
151 | * | 161 | * |
diff --git a/common/domain/mail.cpp b/common/domain/mail.cpp new file mode 100644 index 0000000..c52bfe0 --- /dev/null +++ b/common/domain/mail.cpp | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #include "mail.h" | ||
20 | |||
21 | #include <QVector> | ||
22 | #include <QByteArray> | ||
23 | #include <QString> | ||
24 | |||
25 | #include "../resultset.h" | ||
26 | #include "../index.h" | ||
27 | #include "../storage.h" | ||
28 | #include "../log.h" | ||
29 | #include "../propertymapper.h" | ||
30 | #include "../query.h" | ||
31 | #include "../definitions.h" | ||
32 | |||
33 | #include "mail_generated.h" | ||
34 | |||
35 | using namespace Akonadi2::ApplicationDomain; | ||
36 | |||
37 | ResultSet TypeImplementation<Mail>::queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) | ||
38 | { | ||
39 | QVector<QByteArray> keys; | ||
40 | if (query.propertyFilter.contains("uid")) { | ||
41 | Index uidIndex("mail.index.uid", transaction); | ||
42 | uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) { | ||
43 | keys << value; | ||
44 | }, | ||
45 | [](const Index::Error &error) { | ||
46 | Warning() << "Error in uid index: " << error.message; | ||
47 | }); | ||
48 | appliedFilters << "uid"; | ||
49 | } | ||
50 | return ResultSet(keys); | ||
51 | } | ||
52 | |||
53 | void TypeImplementation<Mail>::index(const Mail &type, Akonadi2::Storage::Transaction &transaction) | ||
54 | { | ||
55 | const auto uid = type.getProperty("uid"); | ||
56 | if (uid.isValid()) { | ||
57 | Index uidIndex("mail.index.uid", transaction); | ||
58 | uidIndex.add(uid.toByteArray(), type.identifier()); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | QSharedPointer<ReadPropertyMapper<TypeImplementation<Mail>::Buffer> > TypeImplementation<Mail>::initializeReadPropertyMapper() | ||
63 | { | ||
64 | auto propertyMapper = QSharedPointer<ReadPropertyMapper<Buffer> >::create(); | ||
65 | propertyMapper->addMapping("uid", [](Buffer const *buffer) -> QVariant { | ||
66 | return propertyToVariant<QString>(buffer->uid()); | ||
67 | }); | ||
68 | propertyMapper->addMapping("sender", [](Buffer const *buffer) -> QVariant { | ||
69 | return propertyToVariant<QString>(buffer->sender()); | ||
70 | }); | ||
71 | propertyMapper->addMapping("senderName", [](Buffer const *buffer) -> QVariant { | ||
72 | return propertyToVariant<QString>(buffer->senderName()); | ||
73 | }); | ||
74 | propertyMapper->addMapping("subject", [](Buffer const *buffer) -> QVariant { | ||
75 | return propertyToVariant<QString>(buffer->subject()); | ||
76 | }); | ||
77 | propertyMapper->addMapping("date", [](Buffer const *buffer) -> QVariant { | ||
78 | return propertyToVariant<QString>(buffer->date()); | ||
79 | }); | ||
80 | propertyMapper->addMapping("unread", [](Buffer const *buffer) -> QVariant { | ||
81 | return propertyToVariant<bool>(buffer->unread()); | ||
82 | }); | ||
83 | propertyMapper->addMapping("important", [](Buffer const *buffer) -> QVariant { | ||
84 | return propertyToVariant<bool>(buffer->important()); | ||
85 | }); | ||
86 | return propertyMapper; | ||
87 | } | ||
88 | |||
89 | QSharedPointer<WritePropertyMapper<TypeImplementation<Mail>::BufferBuilder> > TypeImplementation<Mail>::initializeWritePropertyMapper() | ||
90 | { | ||
91 | auto propertyMapper = QSharedPointer<WritePropertyMapper<BufferBuilder> >::create(); | ||
92 | // propertyMapper->addMapping("summary", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { | ||
93 | // auto offset = variantToProperty<QString>(value, fbb); | ||
94 | // return [offset](BufferBuilder &builder) { builder.add_summary(offset); }; | ||
95 | // }); | ||
96 | propertyMapper->addMapping("uid", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { | ||
97 | auto offset = variantToProperty<QString>(value, fbb); | ||
98 | return [offset](BufferBuilder &builder) { builder.add_uid(offset); }; | ||
99 | }); | ||
100 | return propertyMapper; | ||
101 | } | ||
diff --git a/common/domain/mail.fbs b/common/domain/mail.fbs new file mode 100644 index 0000000..654f49c --- /dev/null +++ b/common/domain/mail.fbs | |||
@@ -0,0 +1,14 @@ | |||
1 | namespace Akonadi2.ApplicationDomain.Buffer; | ||
2 | |||
3 | table Mail { | ||
4 | uid:string; | ||
5 | sender:string; | ||
6 | senderName:string; | ||
7 | subject:string; | ||
8 | date:string; | ||
9 | unread:bool = false; | ||
10 | important:bool = false; | ||
11 | } | ||
12 | |||
13 | root_type Mail; | ||
14 | file_identifier "AKFB"; | ||
diff --git a/common/domain/mail.h b/common/domain/mail.h new file mode 100644 index 0000000..b58ce44 --- /dev/null +++ b/common/domain/mail.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #pragma once | ||
20 | |||
21 | #include "applicationdomaintype.h" | ||
22 | |||
23 | #include "storage.h" | ||
24 | |||
25 | class ResultSet; | ||
26 | class QByteArray; | ||
27 | |||
28 | template<typename T> | ||
29 | class ReadPropertyMapper; | ||
30 | template<typename T> | ||
31 | class WritePropertyMapper; | ||
32 | |||
33 | namespace Akonadi2 { | ||
34 | class Query; | ||
35 | |||
36 | namespace ApplicationDomain { | ||
37 | namespace Buffer { | ||
38 | struct Mail; | ||
39 | struct MailBuilder; | ||
40 | } | ||
41 | |||
42 | template<> | ||
43 | class TypeImplementation<Akonadi2::ApplicationDomain::Mail> { | ||
44 | public: | ||
45 | typedef Akonadi2::ApplicationDomain::Buffer::Mail Buffer; | ||
46 | typedef Akonadi2::ApplicationDomain::Buffer::MailBuilder BufferBuilder; | ||
47 | static QSet<QByteArray> indexedProperties(); | ||
48 | /** | ||
49 | * Returns the potential result set based on the indexes. | ||
50 | * | ||
51 | * An empty result set indicates that a full scan is required. | ||
52 | */ | ||
53 | static ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction); | ||
54 | static void index(const Mail &type, Akonadi2::Storage::Transaction &transaction); | ||
55 | static QSharedPointer<ReadPropertyMapper<Buffer> > initializeReadPropertyMapper(); | ||
56 | static QSharedPointer<WritePropertyMapper<BufferBuilder> > initializeWritePropertyMapper(); | ||
57 | }; | ||
58 | |||
59 | } | ||
60 | } | ||
diff --git a/common/domainadaptor.h b/common/domainadaptor.h index f9dcc79..4943cc0 100644 --- a/common/domainadaptor.h +++ b/common/domainadaptor.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include "domain/applicationdomaintype.h" | 26 | #include "domain/applicationdomaintype.h" |
27 | #include "domain/event.h" | 27 | #include "domain/event.h" |
28 | #include "domain/mail.h" | ||
28 | #include "entity_generated.h" | 29 | #include "entity_generated.h" |
29 | #include "metadata_generated.h" | 30 | #include "metadata_generated.h" |
30 | #include "entitybuffer.h" | 31 | #include "entitybuffer.h" |
diff --git a/common/entitystorage.cpp b/common/entitystorage.cpp index 8a3391e..bcc3562 100644 --- a/common/entitystorage.cpp +++ b/common/entitystorage.cpp | |||
@@ -19,9 +19,9 @@ | |||
19 | 19 | ||
20 | #include "entitystorage.h" | 20 | #include "entitystorage.h" |
21 | 21 | ||
22 | static void scan(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, std::function<bool(const QByteArray &key, const Akonadi2::Entity &entity)> callback) | 22 | static void scan(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, std::function<bool(const QByteArray &key, const Akonadi2::Entity &entity)> callback, const QByteArray &bufferType) |
23 | { | 23 | { |
24 | transaction.openDatabase().scan(key, [=](const QByteArray &key, const QByteArray &value) -> bool { | 24 | transaction.openDatabase(bufferType + ".main").scan(key, [=](const QByteArray &key, const QByteArray &value) -> bool { |
25 | //Skip internals | 25 | //Skip internals |
26 | if (Akonadi2::Storage::isInternalKey(key)) { | 26 | if (Akonadi2::Storage::isInternalKey(key)) { |
27 | return true; | 27 | return true; |
@@ -58,17 +58,17 @@ void EntityStorageBase::readValue(const Akonadi2::Storage::Transaction &transact | |||
58 | auto domainObject = create(key, revision, mDomainTypeAdaptorFactory->createAdaptor(entity)); | 58 | auto domainObject = create(key, revision, mDomainTypeAdaptorFactory->createAdaptor(entity)); |
59 | resultCallback(domainObject); | 59 | resultCallback(domainObject); |
60 | return true; | 60 | return true; |
61 | }); | 61 | }, mBufferType); |
62 | } | 62 | } |
63 | 63 | ||
64 | static ResultSet fullScan(const Akonadi2::Storage::Transaction &transaction) | 64 | static ResultSet fullScan(const Akonadi2::Storage::Transaction &transaction, const QByteArray &bufferType) |
65 | { | 65 | { |
66 | //TODO use a result set with an iterator, to read values on demand | 66 | //TODO use a result set with an iterator, to read values on demand |
67 | QVector<QByteArray> keys; | 67 | QVector<QByteArray> keys; |
68 | scan(transaction, QByteArray(), [=, &keys](const QByteArray &key, const Akonadi2::Entity &) { | 68 | scan(transaction, QByteArray(), [=, &keys](const QByteArray &key, const Akonadi2::Entity &) { |
69 | keys << key; | 69 | keys << key; |
70 | return true; | 70 | return true; |
71 | }); | 71 | }, bufferType); |
72 | Trace() << "Full scan found " << keys.size() << " results"; | 72 | Trace() << "Full scan found " << keys.size() << " results"; |
73 | return ResultSet(keys); | 73 | return ResultSet(keys); |
74 | } | 74 | } |
@@ -99,7 +99,7 @@ ResultSet EntityStorageBase::getResultSet(const Akonadi2::Query &query, Akonadi2 | |||
99 | 99 | ||
100 | //We do a full scan if there were no indexes available to create the initial set. | 100 | //We do a full scan if there were no indexes available to create the initial set. |
101 | if (appliedFilters.isEmpty()) { | 101 | if (appliedFilters.isEmpty()) { |
102 | resultSet = fullScan(transaction); | 102 | resultSet = fullScan(transaction, mBufferType); |
103 | } | 103 | } |
104 | 104 | ||
105 | auto filter = [remainingFilters, query, baseRevision, topRevision](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool { | 105 | auto filter = [remainingFilters, query, baseRevision, topRevision](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool { |
diff --git a/common/entitystorage.h b/common/entitystorage.h index 8256938..9d928b8 100644 --- a/common/entitystorage.h +++ b/common/entitystorage.h | |||
@@ -52,6 +52,7 @@ protected: | |||
52 | 52 | ||
53 | protected: | 53 | protected: |
54 | QByteArray mResourceInstanceIdentifier; | 54 | QByteArray mResourceInstanceIdentifier; |
55 | QByteArray mBufferType; | ||
55 | DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory; | 56 | DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory; |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -60,10 +61,10 @@ class EntityStorage : public EntityStorageBase | |||
60 | { | 61 | { |
61 | 62 | ||
62 | public: | 63 | public: |
63 | EntityStorage(const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory) | 64 | EntityStorage(const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory, const QByteArray &bufferType) |
64 | : EntityStorageBase(instanceIdentifier, adaptorFactory) | 65 | : EntityStorageBase(instanceIdentifier, adaptorFactory) |
65 | { | 66 | { |
66 | 67 | mBufferType = bufferType; | |
67 | } | 68 | } |
68 | 69 | ||
69 | protected: | 70 | protected: |
@@ -84,7 +85,7 @@ protected: | |||
84 | 85 | ||
85 | public: | 86 | public: |
86 | 87 | ||
87 | virtual void read(const Akonadi2::Query &query, const QPair<qint64, qint64> &revisionRange, const QSharedPointer<Akonadi2::ResultProvider<typename DomainType::Ptr> > &resultProvider) | 88 | virtual void read(const Akonadi2::Query &query, const QPair<qint64, qint64> &revisionRange, const QSharedPointer<Akonadi2::ResultProvider<typename DomainType::Ptr> > &resultProvider) |
88 | { | 89 | { |
89 | Akonadi2::Storage storage(Akonadi2::storageLocation(), mResourceInstanceIdentifier); | 90 | Akonadi2::Storage storage(Akonadi2::storageLocation(), mResourceInstanceIdentifier); |
90 | storage.setDefaultErrorHandler([](const Akonadi2::Storage::Error &error) { | 91 | storage.setDefaultErrorHandler([](const Akonadi2::Storage::Error &error) { |
diff --git a/common/facade.h b/common/facade.h index be053f6..d53ec4a 100644 --- a/common/facade.h +++ b/common/facade.h | |||
@@ -109,7 +109,7 @@ public: | |||
109 | GenericFacade(const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory = DomainTypeAdaptorFactoryInterface::Ptr(), const QSharedPointer<EntityStorage<DomainType> > storage = QSharedPointer<EntityStorage<DomainType> >(), const QSharedPointer<Akonadi2::ResourceAccessInterface> resourceAccess = QSharedPointer<Akonadi2::ResourceAccessInterface>()) | 109 | GenericFacade(const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory = DomainTypeAdaptorFactoryInterface::Ptr(), const QSharedPointer<EntityStorage<DomainType> > storage = QSharedPointer<EntityStorage<DomainType> >(), const QSharedPointer<Akonadi2::ResourceAccessInterface> resourceAccess = QSharedPointer<Akonadi2::ResourceAccessInterface>()) |
110 | : Akonadi2::StoreFacade<DomainType>(), | 110 | : Akonadi2::StoreFacade<DomainType>(), |
111 | mResourceAccess(resourceAccess), | 111 | mResourceAccess(resourceAccess), |
112 | mStorage(storage ? storage : QSharedPointer<EntityStorage<DomainType> >::create(resourceIdentifier, adaptorFactory)), | 112 | mStorage(storage ? storage : QSharedPointer<EntityStorage<DomainType> >::create(resourceIdentifier, adaptorFactory, bufferTypeForDomainType())), |
113 | mDomainTypeAdaptorFactory(adaptorFactory), | 113 | mDomainTypeAdaptorFactory(adaptorFactory), |
114 | mResourceInstanceIdentifier(resourceIdentifier) | 114 | mResourceInstanceIdentifier(resourceIdentifier) |
115 | { | 115 | { |
diff --git a/common/pipeline.cpp b/common/pipeline.cpp index 8ef6187..33e5d5c 100644 --- a/common/pipeline.cpp +++ b/common/pipeline.cpp | |||
@@ -143,7 +143,7 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size) | |||
143 | auto createEntity = Akonadi2::Commands::GetCreateEntity(command); | 143 | auto createEntity = Akonadi2::Commands::GetCreateEntity(command); |
144 | 144 | ||
145 | //TODO rename createEntitiy->domainType to bufferType | 145 | //TODO rename createEntitiy->domainType to bufferType |
146 | const QString entityType = QString::fromUtf8(reinterpret_cast<char const*>(createEntity->domainType()->Data()), createEntity->domainType()->size()); | 146 | const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(createEntity->domainType()->Data()), createEntity->domainType()->size()); |
147 | { | 147 | { |
148 | flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size()); | 148 | flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size()); |
149 | if (!Akonadi2::VerifyEntityBuffer(verifyer)) { | 149 | if (!Akonadi2::VerifyEntityBuffer(verifyer)) { |
@@ -152,6 +152,10 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size) | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | auto entity = Akonadi2::GetEntity(createEntity->delta()->Data()); | 154 | auto entity = Akonadi2::GetEntity(createEntity->delta()->Data()); |
155 | if (!entity->resource()->size() && !entity->local()->size()) { | ||
156 | Warning() << "No local and no resource buffer while trying to create entity."; | ||
157 | return KAsync::error<void>(); | ||
158 | } | ||
155 | 159 | ||
156 | //Add metadata buffer | 160 | //Add metadata buffer |
157 | flatbuffers::FlatBufferBuilder metadataFbb; | 161 | flatbuffers::FlatBufferBuilder metadataFbb; |
@@ -165,14 +169,14 @@ KAsync::Job<void> Pipeline::newEntity(void const *command, size_t size) | |||
165 | flatbuffers::FlatBufferBuilder fbb; | 169 | flatbuffers::FlatBufferBuilder fbb; |
166 | EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), entity->resource()->Data(), entity->resource()->size(), entity->local()->Data(), entity->local()->size()); | 170 | EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), entity->resource()->Data(), entity->resource()->size(), entity->local()->Data(), entity->local()->size()); |
167 | 171 | ||
168 | d->transaction.openDatabase().write(key, QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); | 172 | d->transaction.openDatabase(bufferType + ".main").write(key, QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); |
169 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); | 173 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); |
170 | Log() << "Pipeline: wrote entity: " << key << newRevision; | 174 | Log() << "Pipeline: wrote entity: " << key << newRevision << bufferType; |
171 | 175 | ||
172 | return KAsync::start<void>([this, key, entityType, newRevision](KAsync::Future<void> &future) { | 176 | return KAsync::start<void>([this, key, bufferType, newRevision](KAsync::Future<void> &future) { |
173 | PipelineState state(this, NewPipeline, key, d->newPipeline[entityType], newRevision, [&future]() { | 177 | PipelineState state(this, NewPipeline, key, d->newPipeline[bufferType], newRevision, [&future]() { |
174 | future.setFinished(); | 178 | future.setFinished(); |
175 | }); | 179 | }, bufferType); |
176 | d->activePipelines << state; | 180 | d->activePipelines << state; |
177 | state.step(); | 181 | state.step(); |
178 | }); | 182 | }); |
@@ -195,10 +199,10 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size) | |||
195 | Q_ASSERT(modifyEntity); | 199 | Q_ASSERT(modifyEntity); |
196 | 200 | ||
197 | //TODO rename modifyEntity->domainType to bufferType | 201 | //TODO rename modifyEntity->domainType to bufferType |
198 | const QByteArray entityType = QByteArray(reinterpret_cast<char const*>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size()); | 202 | const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size()); |
199 | const QByteArray key = QByteArray(reinterpret_cast<char const*>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size()); | 203 | const QByteArray key = QByteArray(reinterpret_cast<char const*>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size()); |
200 | if (entityType.isEmpty() || key.isEmpty()) { | 204 | if (bufferType.isEmpty() || key.isEmpty()) { |
201 | Warning() << "entity type or key " << entityType << key; | 205 | Warning() << "entity type or key " << bufferType << key; |
202 | return KAsync::error<void>(); | 206 | return KAsync::error<void>(); |
203 | } | 207 | } |
204 | { | 208 | { |
@@ -209,9 +213,9 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size) | |||
209 | } | 213 | } |
210 | } | 214 | } |
211 | 215 | ||
212 | auto adaptorFactory = d->adaptorFactory.value(entityType); | 216 | auto adaptorFactory = d->adaptorFactory.value(bufferType); |
213 | if (!adaptorFactory) { | 217 | if (!adaptorFactory) { |
214 | Warning() << "no adaptor factory for type " << entityType; | 218 | Warning() << "no adaptor factory for type " << bufferType; |
215 | return KAsync::error<void>(); | 219 | return KAsync::error<void>(); |
216 | } | 220 | } |
217 | 221 | ||
@@ -220,7 +224,7 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size) | |||
220 | auto diff = adaptorFactory->createAdaptor(*diffEntity); | 224 | auto diff = adaptorFactory->createAdaptor(*diffEntity); |
221 | 225 | ||
222 | QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> current; | 226 | QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> current; |
223 | storage().createTransaction(Akonadi2::Storage::ReadOnly).openDatabase().scan(key, [¤t, adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool { | 227 | storage().createTransaction(Akonadi2::Storage::ReadOnly).openDatabase(bufferType + ".main").scan(key, [¤t, adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool { |
224 | Akonadi2::EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); | 228 | Akonadi2::EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); |
225 | if (!buffer.isValid()) { | 229 | if (!buffer.isValid()) { |
226 | Warning() << "Read invalid buffer from disk"; | 230 | Warning() << "Read invalid buffer from disk"; |
@@ -228,6 +232,9 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size) | |||
228 | current = adaptorFactory->createAdaptor(buffer.entity()); | 232 | current = adaptorFactory->createAdaptor(buffer.entity()); |
229 | } | 233 | } |
230 | return false; | 234 | return false; |
235 | }, | ||
236 | [](const Storage::Error &error) { | ||
237 | Warning() << "Failed to read value from storage: " << error.message; | ||
231 | }); | 238 | }); |
232 | //TODO error handler | 239 | //TODO error handler |
233 | 240 | ||
@@ -265,13 +272,13 @@ KAsync::Job<void> Pipeline::modifiedEntity(void const *command, size_t size) | |||
265 | adaptorFactory->createBuffer(*newObject, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); | 272 | adaptorFactory->createBuffer(*newObject, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); |
266 | 273 | ||
267 | //TODO don't overwrite the old entry, but instead store a new revision | 274 | //TODO don't overwrite the old entry, but instead store a new revision |
268 | d->transaction.openDatabase().write(key, QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); | 275 | d->transaction.openDatabase(bufferType + ".main").write(key, QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); |
269 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); | 276 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); |
270 | 277 | ||
271 | return KAsync::start<void>([this, key, entityType, newRevision](KAsync::Future<void> &future) { | 278 | return KAsync::start<void>([this, key, bufferType, newRevision](KAsync::Future<void> &future) { |
272 | PipelineState state(this, ModifiedPipeline, key, d->modifiedPipeline[entityType], newRevision, [&future]() { | 279 | PipelineState state(this, ModifiedPipeline, key, d->modifiedPipeline[bufferType], newRevision, [&future]() { |
273 | future.setFinished(); | 280 | future.setFinished(); |
274 | }); | 281 | }, bufferType); |
275 | d->activePipelines << state; | 282 | d->activePipelines << state; |
276 | state.step(); | 283 | state.step(); |
277 | }); | 284 | }); |
@@ -292,18 +299,18 @@ KAsync::Job<void> Pipeline::deletedEntity(void const *command, size_t size) | |||
292 | } | 299 | } |
293 | auto deleteEntity = Akonadi2::Commands::GetDeleteEntity(command); | 300 | auto deleteEntity = Akonadi2::Commands::GetDeleteEntity(command); |
294 | 301 | ||
295 | const QByteArray entityType = QByteArray(reinterpret_cast<char const*>(deleteEntity->domainType()->Data()), deleteEntity->domainType()->size()); | 302 | const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(deleteEntity->domainType()->Data()), deleteEntity->domainType()->size()); |
296 | const QByteArray key = QByteArray(reinterpret_cast<char const*>(deleteEntity->entityId()->Data()), deleteEntity->entityId()->size()); | 303 | const QByteArray key = QByteArray(reinterpret_cast<char const*>(deleteEntity->entityId()->Data()), deleteEntity->entityId()->size()); |
297 | 304 | ||
298 | //TODO instead of deleting the entry, a new revision should be created that marks the entity as deleted | 305 | //TODO instead of deleting the entry, a new revision should be created that marks the entity as deleted |
299 | d->transaction.openDatabase().remove(key); | 306 | d->transaction.openDatabase(bufferType + ".main").remove(key); |
300 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); | 307 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); |
301 | Log() << "Pipeline: deleted entity: "<< newRevision; | 308 | Log() << "Pipeline: deleted entity: "<< newRevision; |
302 | 309 | ||
303 | return KAsync::start<void>([this, key, entityType, newRevision](KAsync::Future<void> &future) { | 310 | return KAsync::start<void>([this, key, bufferType, newRevision](KAsync::Future<void> &future) { |
304 | PipelineState state(this, DeletedPipeline, key, d->deletedPipeline[entityType], newRevision, [&future](){ | 311 | PipelineState state(this, DeletedPipeline, key, d->deletedPipeline[bufferType], newRevision, [&future](){ |
305 | future.setFinished(); | 312 | future.setFinished(); |
306 | }); | 313 | }, bufferType); |
307 | d->activePipelines << state; | 314 | d->activePipelines << state; |
308 | state.step(); | 315 | state.step(); |
309 | }); | 316 | }); |
@@ -354,14 +361,15 @@ void Pipeline::pipelineCompleted(PipelineState state) | |||
354 | class PipelineState::Private : public QSharedData | 361 | class PipelineState::Private : public QSharedData |
355 | { | 362 | { |
356 | public: | 363 | public: |
357 | Private(Pipeline *p, Pipeline::Type t, const QByteArray &k, QVector<Preprocessor *> filters, const std::function<void()> &c, qint64 r) | 364 | Private(Pipeline *p, Pipeline::Type t, const QByteArray &k, QVector<Preprocessor *> filters, const std::function<void()> &c, qint64 r, const QByteArray &b) |
358 | : pipeline(p), | 365 | : pipeline(p), |
359 | type(t), | 366 | type(t), |
360 | key(k), | 367 | key(k), |
361 | filterIt(filters), | 368 | filterIt(filters), |
362 | idle(true), | 369 | idle(true), |
363 | callback(c), | 370 | callback(c), |
364 | revision(r) | 371 | revision(r), |
372 | bufferType(b) | ||
365 | {} | 373 | {} |
366 | 374 | ||
367 | Private() | 375 | Private() |
@@ -378,6 +386,7 @@ public: | |||
378 | bool idle; | 386 | bool idle; |
379 | std::function<void()> callback; | 387 | std::function<void()> callback; |
380 | qint64 revision; | 388 | qint64 revision; |
389 | QByteArray bufferType; | ||
381 | }; | 390 | }; |
382 | 391 | ||
383 | PipelineState::PipelineState() | 392 | PipelineState::PipelineState() |
@@ -386,8 +395,8 @@ PipelineState::PipelineState() | |||
386 | 395 | ||
387 | } | 396 | } |
388 | 397 | ||
389 | PipelineState::PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters, qint64 revision, const std::function<void()> &callback) | 398 | PipelineState::PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters, qint64 revision, const std::function<void()> &callback, const QByteArray &bufferType) |
390 | : d(new Private(pipeline, type, key, filters, callback, revision)) | 399 | : d(new Private(pipeline, type, key, filters, callback, revision, bufferType)) |
391 | { | 400 | { |
392 | } | 401 | } |
393 | 402 | ||
@@ -431,6 +440,11 @@ qint64 PipelineState::revision() const | |||
431 | return d->revision; | 440 | return d->revision; |
432 | } | 441 | } |
433 | 442 | ||
443 | QByteArray PipelineState::bufferType() const | ||
444 | { | ||
445 | return d->bufferType; | ||
446 | } | ||
447 | |||
434 | void PipelineState::step() | 448 | void PipelineState::step() |
435 | { | 449 | { |
436 | if (!d->pipeline) { | 450 | if (!d->pipeline) { |
diff --git a/common/pipeline.h b/common/pipeline.h index a3b3735..573af73 100644 --- a/common/pipeline.h +++ b/common/pipeline.h | |||
@@ -85,7 +85,7 @@ class AKONADI2COMMON_EXPORT PipelineState | |||
85 | { | 85 | { |
86 | public: | 86 | public: |
87 | PipelineState(); | 87 | PipelineState(); |
88 | PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters, qint64 revision, const std::function<void()> &callback); | 88 | PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters, qint64 revision, const std::function<void()> &callback, const QByteArray &bufferType); |
89 | PipelineState(const PipelineState &other); | 89 | PipelineState(const PipelineState &other); |
90 | ~PipelineState(); | 90 | ~PipelineState(); |
91 | 91 | ||
@@ -96,7 +96,7 @@ public: | |||
96 | QByteArray key() const; | 96 | QByteArray key() const; |
97 | Pipeline::Type type() const; | 97 | Pipeline::Type type() const; |
98 | qint64 revision() const; | 98 | qint64 revision() const; |
99 | //TODO expose command | 99 | QByteArray bufferType() const; |
100 | 100 | ||
101 | void step(); | 101 | void step(); |
102 | void processingCompleted(Preprocessor *filter); | 102 | void processingCompleted(Preprocessor *filter); |
@@ -114,7 +114,6 @@ public: | |||
114 | Preprocessor(); | 114 | Preprocessor(); |
115 | virtual ~Preprocessor(); | 115 | virtual ~Preprocessor(); |
116 | 116 | ||
117 | //TODO pass actual command as well, for changerecording | ||
118 | virtual void process(const PipelineState &state, Akonadi2::Storage::Transaction &transaction); | 117 | virtual void process(const PipelineState &state, Akonadi2::Storage::Transaction &transaction); |
119 | //TODO to record progress | 118 | //TODO to record progress |
120 | virtual QString id() const; | 119 | virtual QString id() const; |
@@ -142,7 +141,7 @@ public: | |||
142 | 141 | ||
143 | void process(const PipelineState &state, Akonadi2::Storage::Transaction &transaction) Q_DECL_OVERRIDE | 142 | void process(const PipelineState &state, Akonadi2::Storage::Transaction &transaction) Q_DECL_OVERRIDE |
144 | { | 143 | { |
145 | transaction.openDatabase().scan(state.key(), [this, &state, &transaction](const QByteArray &key, const QByteArray &value) -> bool { | 144 | transaction.openDatabase(state.bufferType() + ".main").scan(state.key(), [this, &state, &transaction](const QByteArray &key, const QByteArray &value) -> bool { |
146 | auto entity = Akonadi2::GetEntity(value); | 145 | auto entity = Akonadi2::GetEntity(value); |
147 | mFunction(state, *entity, transaction); | 146 | mFunction(state, *entity, transaction); |
148 | processingCompleted(state); | 147 | processingCompleted(state); |
diff --git a/common/propertymapper.cpp b/common/propertymapper.cpp index 89495ae..7ff072a 100644 --- a/common/propertymapper.cpp +++ b/common/propertymapper.cpp | |||
@@ -38,3 +38,9 @@ QVariant propertyToVariant<QString>(const flatbuffers::String *property) | |||
38 | return QVariant(); | 38 | return QVariant(); |
39 | } | 39 | } |
40 | 40 | ||
41 | template <> | ||
42 | QVariant propertyToVariant<bool>(uint8_t property) | ||
43 | { | ||
44 | return static_cast<bool>(property); | ||
45 | } | ||
46 | |||
diff --git a/common/propertymapper.h b/common/propertymapper.h index 0c6c16f..72468e2 100644 --- a/common/propertymapper.h +++ b/common/propertymapper.h | |||
@@ -35,6 +35,8 @@ flatbuffers::uoffset_t variantToProperty(const QVariant &, flatbuffers::FlatBuff | |||
35 | */ | 35 | */ |
36 | template <typename T> | 36 | template <typename T> |
37 | QVariant propertyToVariant(const flatbuffers::String *); | 37 | QVariant propertyToVariant(const flatbuffers::String *); |
38 | template <typename T> | ||
39 | QVariant propertyToVariant(uint8_t); | ||
38 | 40 | ||
39 | 41 | ||
40 | /** | 42 | /** |
diff --git a/examples/dummyresource/domainadaptor.cpp b/examples/dummyresource/domainadaptor.cpp index 4cc592e..d08a783 100644 --- a/examples/dummyresource/domainadaptor.cpp +++ b/examples/dummyresource/domainadaptor.cpp | |||
@@ -45,3 +45,9 @@ DummyEventAdaptorFactory::DummyEventAdaptorFactory() | |||
45 | }); | 45 | }); |
46 | } | 46 | } |
47 | 47 | ||
48 | DummyMailAdaptorFactory::DummyMailAdaptorFactory() | ||
49 | : DomainTypeAdaptorFactory() | ||
50 | { | ||
51 | |||
52 | } | ||
53 | |||
diff --git a/examples/dummyresource/domainadaptor.h b/examples/dummyresource/domainadaptor.h index 8b6d96b..add3e8e 100644 --- a/examples/dummyresource/domainadaptor.h +++ b/examples/dummyresource/domainadaptor.h | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "common/domainadaptor.h" | 21 | #include "common/domainadaptor.h" |
22 | #include "event_generated.h" | 22 | #include "event_generated.h" |
23 | #include "mail_generated.h" | ||
23 | #include "dummycalendar_generated.h" | 24 | #include "dummycalendar_generated.h" |
24 | #include "entity_generated.h" | 25 | #include "entity_generated.h" |
25 | 26 | ||
@@ -29,3 +30,11 @@ public: | |||
29 | DummyEventAdaptorFactory(); | 30 | DummyEventAdaptorFactory(); |
30 | virtual ~DummyEventAdaptorFactory() {}; | 31 | virtual ~DummyEventAdaptorFactory() {}; |
31 | }; | 32 | }; |
33 | |||
34 | //TODO replace the resource specific event class by a mail class or a dummy class if no resource type is required. | ||
35 | class DummyMailAdaptorFactory : public DomainTypeAdaptorFactory<Akonadi2::ApplicationDomain::Mail, DummyCalendar::DummyEvent, DummyCalendar::DummyEventBuilder> | ||
36 | { | ||
37 | public: | ||
38 | DummyMailAdaptorFactory(); | ||
39 | virtual ~DummyMailAdaptorFactory() {}; | ||
40 | }; | ||
diff --git a/examples/dummyresource/dummystore.cpp b/examples/dummyresource/dummystore.cpp index 5a3f74b..41b48ed 100644 --- a/examples/dummyresource/dummystore.cpp +++ b/examples/dummyresource/dummystore.cpp | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <QString> | 21 | #include <QString> |
22 | 22 | ||
23 | #include "dummycalendar_generated.h" | 23 | #include "dummycalendar_generated.h" |
24 | #include "mail_generated.h" | ||
24 | 25 | ||
25 | static std::string createEvent(int i) | 26 | static std::string createEvent(int i) |
26 | { | 27 | { |
@@ -43,6 +44,20 @@ static std::string createEvent(int i) | |||
43 | return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); | 44 | return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); |
44 | } | 45 | } |
45 | 46 | ||
47 | static std::string createMail(int i) | ||
48 | { | ||
49 | static flatbuffers::FlatBufferBuilder fbb; | ||
50 | fbb.Clear(); | ||
51 | { | ||
52 | auto subject = fbb.CreateString("summary" + std::to_string(i)); | ||
53 | Akonadi2::ApplicationDomain::Buffer::MailBuilder mailBuilder(fbb); | ||
54 | mailBuilder.add_subject(subject); | ||
55 | Akonadi2::ApplicationDomain::Buffer::FinishMailBuffer(fbb, mailBuilder.Finish()); | ||
56 | } | ||
57 | |||
58 | return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); | ||
59 | } | ||
60 | |||
46 | QMap<QString, QString> populate() | 61 | QMap<QString, QString> populate() |
47 | { | 62 | { |
48 | QMap<QString, QString> content; | 63 | QMap<QString, QString> content; |
@@ -53,10 +68,24 @@ QMap<QString, QString> populate() | |||
53 | return content; | 68 | return content; |
54 | } | 69 | } |
55 | 70 | ||
56 | static QMap<QString, QString> s_dataSource = populate(); | 71 | QMap<QString, QString> populateMails() |
72 | { | ||
73 | QMap<QString, QString> content; | ||
74 | for (int i = 0; i < 2; i++) { | ||
75 | content.insert(QString("key%1").arg(i), QString::fromStdString(createMail(i))); | ||
76 | } | ||
77 | return content; | ||
78 | } | ||
57 | 79 | ||
80 | static QMap<QString, QString> s_dataSource = populate(); | ||
81 | static QMap<QString, QString> s_mailSource = populateMails(); | ||
58 | 82 | ||
59 | QMap<QString, QString> DummyStore::data() const | 83 | QMap<QString, QString> DummyStore::events() const |
60 | { | 84 | { |
61 | return s_dataSource; | 85 | return s_dataSource; |
62 | } | 86 | } |
87 | |||
88 | QMap<QString, QString> DummyStore::mails() const | ||
89 | { | ||
90 | return s_mailSource; | ||
91 | } | ||
diff --git a/examples/dummyresource/dummystore.h b/examples/dummyresource/dummystore.h index 6a404ae..ba1c0ae 100644 --- a/examples/dummyresource/dummystore.h +++ b/examples/dummyresource/dummystore.h | |||
@@ -29,6 +29,6 @@ public: | |||
29 | return instance; | 29 | return instance; |
30 | } | 30 | } |
31 | 31 | ||
32 | QMap<QString, QString> data() const; | 32 | QMap<QString, QString> events() const; |
33 | 33 | QMap<QString, QString> mails() const; | |
34 | }; | 34 | }; |
diff --git a/examples/dummyresource/facade.cpp b/examples/dummyresource/facade.cpp index d20d12d..63f84f2 100644 --- a/examples/dummyresource/facade.cpp +++ b/examples/dummyresource/facade.cpp | |||
@@ -30,3 +30,11 @@ DummyResourceFacade::~DummyResourceFacade() | |||
30 | { | 30 | { |
31 | } | 31 | } |
32 | 32 | ||
33 | DummyResourceMailFacade::DummyResourceMailFacade(const QByteArray &instanceIdentifier) | ||
34 | : Akonadi2::GenericFacade<Akonadi2::ApplicationDomain::Mail>(instanceIdentifier, QSharedPointer<DummyMailAdaptorFactory>::create()) | ||
35 | { | ||
36 | } | ||
37 | |||
38 | DummyResourceMailFacade::~DummyResourceMailFacade() | ||
39 | { | ||
40 | } | ||
diff --git a/examples/dummyresource/facade.h b/examples/dummyresource/facade.h index dde0dc2..87f68c3 100644 --- a/examples/dummyresource/facade.h +++ b/examples/dummyresource/facade.h | |||
@@ -28,3 +28,10 @@ public: | |||
28 | DummyResourceFacade(const QByteArray &instanceIdentifier); | 28 | DummyResourceFacade(const QByteArray &instanceIdentifier); |
29 | virtual ~DummyResourceFacade(); | 29 | virtual ~DummyResourceFacade(); |
30 | }; | 30 | }; |
31 | |||
32 | class DummyResourceMailFacade : public Akonadi2::GenericFacade<Akonadi2::ApplicationDomain::Mail> | ||
33 | { | ||
34 | public: | ||
35 | DummyResourceMailFacade(const QByteArray &instanceIdentifier); | ||
36 | virtual ~DummyResourceMailFacade(); | ||
37 | }; | ||
diff --git a/examples/dummyresource/resourcefactory.cpp b/examples/dummyresource/resourcefactory.cpp index 0e18282..8d605b9 100644 --- a/examples/dummyresource/resourcefactory.cpp +++ b/examples/dummyresource/resourcefactory.cpp | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "entitybuffer.h" | 23 | #include "entitybuffer.h" |
24 | #include "pipeline.h" | 24 | #include "pipeline.h" |
25 | #include "dummycalendar_generated.h" | 25 | #include "dummycalendar_generated.h" |
26 | #include "mail_generated.h" | ||
26 | #include "queuedcommand_generated.h" | 27 | #include "queuedcommand_generated.h" |
27 | #include "createentity_generated.h" | 28 | #include "createentity_generated.h" |
28 | #include "domainadaptor.h" | 29 | #include "domainadaptor.h" |
@@ -30,21 +31,23 @@ | |||
30 | #include "index.h" | 31 | #include "index.h" |
31 | #include "log.h" | 32 | #include "log.h" |
32 | #include "domain/event.h" | 33 | #include "domain/event.h" |
34 | #include "domain/mail.h" | ||
33 | #include "dummystore.h" | 35 | #include "dummystore.h" |
34 | #include "definitions.h" | 36 | #include "definitions.h" |
35 | #include "facadefactory.h" | 37 | #include "facadefactory.h" |
36 | 38 | ||
37 | //This is the resources entity type, and not the domain type | 39 | //This is the resources entity type, and not the domain type |
38 | #define ENTITY_TYPE_EVENT "event" | 40 | #define ENTITY_TYPE_EVENT "event" |
41 | #define ENTITY_TYPE_MAIL "mail" | ||
39 | 42 | ||
40 | DummyResource::DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Akonadi2::Pipeline> &pipeline) | 43 | DummyResource::DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Akonadi2::Pipeline> &pipeline) |
41 | : Akonadi2::GenericResource(instanceIdentifier, pipeline) | 44 | : Akonadi2::GenericResource(instanceIdentifier, pipeline) |
42 | { | 45 | { |
43 | auto eventFactory = QSharedPointer<DummyEventAdaptorFactory>::create(); | 46 | auto eventFactory = QSharedPointer<DummyEventAdaptorFactory>::create(); |
44 | const auto resourceIdentifier = mResourceInstanceIdentifier; | 47 | const auto resourceIdentifier = mResourceInstanceIdentifier; |
48 | |||
45 | auto eventIndexer = new Akonadi2::SimpleProcessor("eventIndexer", [eventFactory, resourceIdentifier](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity, Akonadi2::Storage::Transaction &transaction) { | 49 | auto eventIndexer = new Akonadi2::SimpleProcessor("eventIndexer", [eventFactory, resourceIdentifier](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity, Akonadi2::Storage::Transaction &transaction) { |
46 | auto adaptor = eventFactory->createAdaptor(entity); | 50 | auto adaptor = eventFactory->createAdaptor(entity); |
47 | //FIXME set revision? | ||
48 | Akonadi2::ApplicationDomain::Event event(resourceIdentifier, state.key(), -1, adaptor); | 51 | Akonadi2::ApplicationDomain::Event event(resourceIdentifier, state.key(), -1, adaptor); |
49 | Akonadi2::ApplicationDomain::TypeImplementation<Akonadi2::ApplicationDomain::Event>::index(event, transaction); | 52 | Akonadi2::ApplicationDomain::TypeImplementation<Akonadi2::ApplicationDomain::Event>::index(event, transaction); |
50 | 53 | ||
@@ -58,15 +61,75 @@ DummyResource::DummyResource(const QByteArray &instanceIdentifier, const QShared | |||
58 | mPipeline->setPreprocessors(ENTITY_TYPE_EVENT, Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer); | 61 | mPipeline->setPreprocessors(ENTITY_TYPE_EVENT, Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer); |
59 | mPipeline->setAdaptorFactory(ENTITY_TYPE_EVENT, eventFactory); | 62 | mPipeline->setAdaptorFactory(ENTITY_TYPE_EVENT, eventFactory); |
60 | //TODO cleanup indexes during removal | 63 | //TODO cleanup indexes during removal |
64 | |||
65 | { | ||
66 | auto mailFactory = QSharedPointer<DummyMailAdaptorFactory>::create(); | ||
67 | auto mailIndexer = new Akonadi2::SimpleProcessor("mailIndexer", [mailFactory, resourceIdentifier](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity, Akonadi2::Storage::Transaction &transaction) { | ||
68 | auto adaptor = mailFactory->createAdaptor(entity); | ||
69 | Akonadi2::ApplicationDomain::Mail mail(resourceIdentifier, state.key(), -1, adaptor); | ||
70 | Akonadi2::ApplicationDomain::TypeImplementation<Akonadi2::ApplicationDomain::Mail>::index(mail, transaction); | ||
71 | |||
72 | Index ridIndex("mail.index.rid", transaction); | ||
73 | const auto rid = mail.getProperty("remoteId"); | ||
74 | if (rid.isValid()) { | ||
75 | ridIndex.add(rid.toByteArray(), mail.identifier()); | ||
76 | } | ||
77 | }); | ||
78 | |||
79 | mPipeline->setPreprocessors(ENTITY_TYPE_MAIL, Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << mailIndexer); | ||
80 | mPipeline->setAdaptorFactory(ENTITY_TYPE_MAIL, mailFactory); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void DummyResource::createEvent(const QByteArray &ridBuffer, const QByteArray &data, flatbuffers::FlatBufferBuilder &entityFbb) | ||
85 | { | ||
86 | auto eventBuffer = DummyCalendar::GetDummyEvent(data.data()); | ||
87 | |||
88 | //Map the source format to the buffer format (which happens to be an exact copy here) | ||
89 | auto summary = m_fbb.CreateString(eventBuffer->summary()->c_str()); | ||
90 | auto rid = m_fbb.CreateString(std::string(ridBuffer.constData(), ridBuffer.size())); | ||
91 | auto description = m_fbb.CreateString(std::string(ridBuffer.constData(), ridBuffer.size())); | ||
92 | static uint8_t rawData[100]; | ||
93 | auto attachment = Akonadi2::EntityBuffer::appendAsVector(m_fbb, rawData, 100); | ||
94 | |||
95 | auto builder = DummyCalendar::DummyEventBuilder(m_fbb); | ||
96 | builder.add_summary(summary); | ||
97 | builder.add_remoteId(rid); | ||
98 | builder.add_description(description); | ||
99 | builder.add_attachment(attachment); | ||
100 | auto buffer = builder.Finish(); | ||
101 | DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); | ||
102 | Akonadi2::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, m_fbb.GetBufferPointer(), m_fbb.GetSize(), 0, 0); | ||
103 | } | ||
104 | |||
105 | void DummyResource::createMail(const QByteArray &ridBuffer, const QByteArray &data, flatbuffers::FlatBufferBuilder &entityFbb) | ||
106 | { | ||
107 | auto mailBuffer = Akonadi2::ApplicationDomain::Buffer::GetMail(data.data()); | ||
108 | |||
109 | //Map the source format to the buffer format (which happens to be an exact copy here) | ||
110 | auto subject = m_fbb.CreateString(mailBuffer->subject()->c_str()); | ||
111 | auto rid = m_fbb.CreateString(std::string(ridBuffer.constData(), ridBuffer.size())); | ||
112 | // auto description = m_fbb.CreateString(std::string(ridBuffer.constData(), ridBuffer.size())); | ||
113 | // static uint8_t rawData[100]; | ||
114 | // auto attachment = Akonadi2::EntityBuffer::appendAsVector(m_fbb, rawData, 100); | ||
115 | |||
116 | auto builder = Akonadi2::ApplicationDomain::Buffer::MailBuilder(m_fbb); | ||
117 | builder.add_subject(subject); | ||
118 | // builder.add(rid); | ||
119 | // builder.add_description(description); | ||
120 | // builder.add_attachment(attachment); | ||
121 | auto buffer = builder.Finish(); | ||
122 | Akonadi2::ApplicationDomain::Buffer::FinishMailBuffer(m_fbb, buffer); | ||
123 | Akonadi2::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, 0, 0, m_fbb.GetBufferPointer(), m_fbb.GetSize()); | ||
61 | } | 124 | } |
62 | 125 | ||
63 | KAsync::Job<void> DummyResource::synchronizeWithSource() | 126 | KAsync::Job<void> DummyResource::synchronizeWithSource() |
64 | { | 127 | { |
65 | return KAsync::start<void>([this](KAsync::Future<void> &f) { | 128 | return KAsync::start<void>([this](KAsync::Future<void> &f) { |
66 | auto transaction = Akonadi2::Storage(Akonadi2::storageLocation(), mResourceInstanceIdentifier + ".index.uid", Akonadi2::Storage::ReadOnly).createTransaction(Akonadi2::Storage::ReadOnly); | 129 | auto transaction = Akonadi2::Storage(Akonadi2::storageLocation(), mResourceInstanceIdentifier, Akonadi2::Storage::ReadOnly).createTransaction(Akonadi2::Storage::ReadOnly); |
67 | Index uidIndex("index.uid", transaction); | 130 | Index uidIndex("index.uid", transaction); |
68 | 131 | ||
69 | const auto data = DummyStore::instance().data(); | 132 | const auto data = DummyStore::instance().events(); |
70 | for (auto it = data.constBegin(); it != data.constEnd(); it++) { | 133 | for (auto it = data.constBegin(); it != data.constEnd(); it++) { |
71 | bool isNew = true; | 134 | bool isNew = true; |
72 | uidIndex.lookup(it.key().toLatin1(), [&](const QByteArray &value) { | 135 | uidIndex.lookup(it.key().toLatin1(), [&](const QByteArray &value) { |
@@ -80,25 +143,8 @@ KAsync::Job<void> DummyResource::synchronizeWithSource() | |||
80 | if (isNew) { | 143 | if (isNew) { |
81 | m_fbb.Clear(); | 144 | m_fbb.Clear(); |
82 | 145 | ||
83 | const QByteArray data = it.value().toUtf8(); | ||
84 | auto eventBuffer = DummyCalendar::GetDummyEvent(data.data()); | ||
85 | |||
86 | //Map the source format to the buffer format (which happens to be an exact copy here) | ||
87 | auto summary = m_fbb.CreateString(eventBuffer->summary()->c_str()); | ||
88 | auto rid = m_fbb.CreateString(it.key().toStdString().c_str()); | ||
89 | auto description = m_fbb.CreateString(it.key().toStdString().c_str()); | ||
90 | static uint8_t rawData[100]; | ||
91 | auto attachment = Akonadi2::EntityBuffer::appendAsVector(m_fbb, rawData, 100); | ||
92 | |||
93 | auto builder = DummyCalendar::DummyEventBuilder(m_fbb); | ||
94 | builder.add_summary(summary); | ||
95 | builder.add_remoteId(rid); | ||
96 | builder.add_description(description); | ||
97 | builder.add_attachment(attachment); | ||
98 | auto buffer = builder.Finish(); | ||
99 | DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); | ||
100 | flatbuffers::FlatBufferBuilder entityFbb; | 146 | flatbuffers::FlatBufferBuilder entityFbb; |
101 | Akonadi2::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, m_fbb.GetBufferPointer(), m_fbb.GetSize(), 0, 0); | 147 | createEvent(it.key().toUtf8(), it.value().toUtf8(), entityFbb); |
102 | 148 | ||
103 | flatbuffers::FlatBufferBuilder fbb; | 149 | flatbuffers::FlatBufferBuilder fbb; |
104 | //This is the resource type and not the domain type | 150 | //This is the resource type and not the domain type |
@@ -113,6 +159,43 @@ KAsync::Job<void> DummyResource::synchronizeWithSource() | |||
113 | } | 159 | } |
114 | } | 160 | } |
115 | //TODO find items to remove | 161 | //TODO find items to remove |
162 | |||
163 | const auto mails = DummyStore::instance().mails(); | ||
164 | for (auto it = mails.constBegin(); it != mails.constEnd(); it++) { | ||
165 | bool isNew = true; | ||
166 | uidIndex.lookup(it.key().toLatin1(), [&](const QByteArray &value) { | ||
167 | isNew = false; | ||
168 | }, | ||
169 | [](const Index::Error &error) { | ||
170 | if (error.code != Index::IndexNotAvailable) { | ||
171 | Warning() << "Error in uid index: " << error.message; | ||
172 | } | ||
173 | }); | ||
174 | if (isNew) { | ||
175 | m_fbb.Clear(); | ||
176 | |||
177 | flatbuffers::FlatBufferBuilder entityFbb; | ||
178 | createMail(it.key().toUtf8(), it.value().toUtf8(), entityFbb); | ||
179 | |||
180 | flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(entityFbb.GetBufferPointer()), entityFbb.GetSize()); | ||
181 | if (!Akonadi2::ApplicationDomain::Buffer::VerifyMailBuffer(verifyer)) { | ||
182 | Warning() << "invalid buffer, not a mail buffer"; | ||
183 | } | ||
184 | |||
185 | flatbuffers::FlatBufferBuilder fbb; | ||
186 | //This is the resource type and not the domain type | ||
187 | auto type = fbb.CreateString(ENTITY_TYPE_MAIL); | ||
188 | auto delta = Akonadi2::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
189 | auto location = Akonadi2::Commands::CreateCreateEntity(fbb, type, delta); | ||
190 | Akonadi2::Commands::FinishCreateEntityBuffer(fbb, location); | ||
191 | |||
192 | enqueueCommand(mSynchronizerQueue, Akonadi2::Commands::CreateEntityCommand, QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); | ||
193 | } else { //modification | ||
194 | //TODO diff and create modification if necessary | ||
195 | } | ||
196 | } | ||
197 | //TODO find items to remove | ||
198 | |||
116 | f.setFinished(); | 199 | f.setFinished(); |
117 | }); | 200 | }); |
118 | } | 201 | } |
@@ -132,6 +215,7 @@ Akonadi2::Resource *DummyResourceFactory::createResource(const QByteArray &insta | |||
132 | void DummyResourceFactory::registerFacades(Akonadi2::FacadeFactory &factory) | 215 | void DummyResourceFactory::registerFacades(Akonadi2::FacadeFactory &factory) |
133 | { | 216 | { |
134 | factory.registerFacade<Akonadi2::ApplicationDomain::Event, DummyResourceFacade>(PLUGIN_NAME); | 217 | factory.registerFacade<Akonadi2::ApplicationDomain::Event, DummyResourceFacade>(PLUGIN_NAME); |
218 | factory.registerFacade<Akonadi2::ApplicationDomain::Mail, DummyResourceMailFacade>(PLUGIN_NAME); | ||
135 | } | 219 | } |
136 | 220 | ||
137 | #include "resourcefactory.moc" | 221 | #include "resourcefactory.moc" |
diff --git a/examples/dummyresource/resourcefactory.h b/examples/dummyresource/resourcefactory.h index 4baafa7..cf0f624 100644 --- a/examples/dummyresource/resourcefactory.h +++ b/examples/dummyresource/resourcefactory.h | |||
@@ -34,6 +34,9 @@ class DummyResource : public Akonadi2::GenericResource | |||
34 | public: | 34 | public: |
35 | DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Akonadi2::Pipeline> &pipeline = QSharedPointer<Akonadi2::Pipeline>()); | 35 | DummyResource(const QByteArray &instanceIdentifier, const QSharedPointer<Akonadi2::Pipeline> &pipeline = QSharedPointer<Akonadi2::Pipeline>()); |
36 | KAsync::Job<void> synchronizeWithSource() Q_DECL_OVERRIDE; | 36 | KAsync::Job<void> synchronizeWithSource() Q_DECL_OVERRIDE; |
37 | private: | ||
38 | void createEvent(const QByteArray &rid, const QByteArray &data, flatbuffers::FlatBufferBuilder &entityFbb); | ||
39 | void createMail(const QByteArray &rid, const QByteArray &data, flatbuffers::FlatBufferBuilder &entityFbb); | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | class DummyResourceFactory : public Akonadi2::ResourceFactory | 42 | class DummyResourceFactory : public Akonadi2::ResourceFactory |
diff --git a/tests/dummyresourcetest.cpp b/tests/dummyresourcetest.cpp index e3b3f07..a28e071 100644 --- a/tests/dummyresourcetest.cpp +++ b/tests/dummyresourcetest.cpp | |||
@@ -164,6 +164,21 @@ private Q_SLOTS: | |||
164 | qDebug() << value->getProperty("summary").toString(); | 164 | qDebug() << value->getProperty("summary").toString(); |
165 | } | 165 | } |
166 | 166 | ||
167 | void testSyncAndFacadeMail() | ||
168 | { | ||
169 | Akonadi2::Query query; | ||
170 | query.resources << "org.kde.dummy.instance1"; | ||
171 | query.syncOnDemand = true; | ||
172 | query.processAll = true; | ||
173 | |||
174 | async::SyncListResult<Akonadi2::ApplicationDomain::Mail::Ptr> result(Akonadi2::Store::load<Akonadi2::ApplicationDomain::Mail>(query)); | ||
175 | result.exec(); | ||
176 | QVERIFY(!result.isEmpty()); | ||
177 | auto value = result.first(); | ||
178 | QVERIFY(!value->getProperty("subject").toString().isEmpty()); | ||
179 | qDebug() << value->getProperty("subject").toString(); | ||
180 | } | ||
181 | |||
167 | void testWriteModifyDelete() | 182 | void testWriteModifyDelete() |
168 | { | 183 | { |
169 | Akonadi2::ApplicationDomain::Event event; | 184 | Akonadi2::ApplicationDomain::Event event; |
diff --git a/tests/genericfacadebenchmark.cpp b/tests/genericfacadebenchmark.cpp index 483a597..7cd6c75 100644 --- a/tests/genericfacadebenchmark.cpp +++ b/tests/genericfacadebenchmark.cpp | |||
@@ -88,7 +88,7 @@ private Q_SLOTS: | |||
88 | QBENCHMARK { | 88 | QBENCHMARK { |
89 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); | 89 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); |
90 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | 90 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); |
91 | auto storage = QSharedPointer<EntityStorage<Akonadi2::ApplicationDomain::Event> >::create("identifier", domainTypeAdaptorFactory); | 91 | auto storage = QSharedPointer<EntityStorage<Akonadi2::ApplicationDomain::Event> >::create("identifier", domainTypeAdaptorFactory, "bufferType"); |
92 | TestResourceFacade facade(identifier, storage, resourceAccess); | 92 | TestResourceFacade facade(identifier, storage, resourceAccess); |
93 | 93 | ||
94 | async::SyncListResult<Akonadi2::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); | 94 | async::SyncListResult<Akonadi2::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); |
diff --git a/tests/genericfacadetest.cpp b/tests/genericfacadetest.cpp index 7aaec23..45ca54d 100644 --- a/tests/genericfacadetest.cpp +++ b/tests/genericfacadetest.cpp | |||
@@ -74,7 +74,7 @@ private Q_SLOTS: | |||
74 | query.liveQuery = false; | 74 | query.liveQuery = false; |
75 | 75 | ||
76 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); | 76 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); |
77 | auto storage = QSharedPointer<TestEntityStorage>::create("identifier", QSharedPointer<TestEventAdaptorFactory>::create()); | 77 | auto storage = QSharedPointer<TestEntityStorage>::create("identifier", QSharedPointer<TestEventAdaptorFactory>::create(), "bufferType"); |
78 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | 78 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); |
79 | storage->mResults << Akonadi2::ApplicationDomain::Event::Ptr::create(); | 79 | storage->mResults << Akonadi2::ApplicationDomain::Event::Ptr::create(); |
80 | TestResourceFacade facade("identifier", storage, resourceAccess); | 80 | TestResourceFacade facade("identifier", storage, resourceAccess); |
@@ -96,7 +96,7 @@ private Q_SLOTS: | |||
96 | query.liveQuery = true; | 96 | query.liveQuery = true; |
97 | 97 | ||
98 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); | 98 | auto resultSet = QSharedPointer<Akonadi2::ResultProvider<Akonadi2::ApplicationDomain::Event::Ptr> >::create(); |
99 | auto storage = QSharedPointer<TestEntityStorage>::create("identifier", QSharedPointer<TestEventAdaptorFactory>::create()); | 99 | auto storage = QSharedPointer<TestEntityStorage>::create("identifier", QSharedPointer<TestEventAdaptorFactory>::create(), "bufferType"); |
100 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | 100 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); |
101 | storage->mResults << Akonadi2::ApplicationDomain::Event::Ptr::create(); | 101 | storage->mResults << Akonadi2::ApplicationDomain::Event::Ptr::create(); |
102 | TestResourceFacade facade("identifier", storage, resourceAccess); | 102 | TestResourceFacade facade("identifier", storage, resourceAccess); |