diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.cpp | 12 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.h | 14 | ||||
-rw-r--r-- | common/domain/mail.cpp | 104 | ||||
-rw-r--r-- | common/domain/mail.fbs | 15 | ||||
-rw-r--r-- | common/domain/mail.h | 60 | ||||
-rw-r--r-- | common/domainadaptor.h | 1 | ||||
-rw-r--r-- | common/entitystorage.cpp | 12 | ||||
-rw-r--r-- | common/entitystorage.h | 7 | ||||
-rw-r--r-- | common/facade.h | 2 | ||||
-rw-r--r-- | common/pipeline.cpp | 64 | ||||
-rw-r--r-- | common/pipeline.h | 7 | ||||
-rw-r--r-- | common/propertymapper.cpp | 6 | ||||
-rw-r--r-- | common/propertymapper.h | 2 | ||||
-rw-r--r-- | common/storage.h | 2 | ||||
-rw-r--r-- | common/storage_common.cpp | 12 |
16 files changed, 267 insertions, 55 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..230ef31 --- /dev/null +++ b/common/domain/mail.cpp | |||
@@ -0,0 +1,104 @@ | |||
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 | propertyMapper->addMapping("folder", [](Buffer const *buffer) -> QVariant { | ||
87 | return propertyToVariant<QString>(buffer->folder()); | ||
88 | }); | ||
89 | return propertyMapper; | ||
90 | } | ||
91 | |||
92 | QSharedPointer<WritePropertyMapper<TypeImplementation<Mail>::BufferBuilder> > TypeImplementation<Mail>::initializeWritePropertyMapper() | ||
93 | { | ||
94 | auto propertyMapper = QSharedPointer<WritePropertyMapper<BufferBuilder> >::create(); | ||
95 | // propertyMapper->addMapping("summary", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { | ||
96 | // auto offset = variantToProperty<QString>(value, fbb); | ||
97 | // return [offset](BufferBuilder &builder) { builder.add_summary(offset); }; | ||
98 | // }); | ||
99 | propertyMapper->addMapping("uid", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { | ||
100 | auto offset = variantToProperty<QString>(value, fbb); | ||
101 | return [offset](BufferBuilder &builder) { builder.add_uid(offset); }; | ||
102 | }); | ||
103 | return propertyMapper; | ||
104 | } | ||
diff --git a/common/domain/mail.fbs b/common/domain/mail.fbs new file mode 100644 index 0000000..13aa36d --- /dev/null +++ b/common/domain/mail.fbs | |||
@@ -0,0 +1,15 @@ | |||
1 | namespace Akonadi2.ApplicationDomain.Buffer; | ||
2 | |||
3 | table Mail { | ||
4 | uid:string; | ||
5 | folder:string; | ||
6 | sender:string; | ||
7 | senderName:string; | ||
8 | subject:string; | ||
9 | date:string; | ||
10 | unread:bool = false; | ||
11 | important:bool = false; | ||
12 | } | ||
13 | |||
14 | root_type Mail; | ||
15 | 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/common/storage.h b/common/storage.h index 191f535..d186b2e 100644 --- a/common/storage.h +++ b/common/storage.h | |||
@@ -161,8 +161,6 @@ public: | |||
161 | qint64 diskUsage() const; | 161 | qint64 diskUsage() const; |
162 | void removeFromDisk() const; | 162 | void removeFromDisk() const; |
163 | 163 | ||
164 | qint64 maxRevision(); | ||
165 | void setMaxRevision(qint64 revision); | ||
166 | static qint64 maxRevision(const Akonadi2::Storage::Transaction &); | 164 | static qint64 maxRevision(const Akonadi2::Storage::Transaction &); |
167 | static void setMaxRevision(Akonadi2::Storage::Transaction &, qint64 revision); | 165 | static void setMaxRevision(Akonadi2::Storage::Transaction &, qint64 revision); |
168 | 166 | ||
diff --git a/common/storage_common.cpp b/common/storage_common.cpp index a506cf8..f22150a 100644 --- a/common/storage_common.cpp +++ b/common/storage_common.cpp | |||
@@ -54,23 +54,11 @@ std::function<void(const Storage::Error &error)> Storage::defaultErrorHandler() | |||
54 | return basicErrorHandler(); | 54 | return basicErrorHandler(); |
55 | } | 55 | } |
56 | 56 | ||
57 | void Storage::setMaxRevision(qint64 revision) | ||
58 | { | ||
59 | auto transaction = createTransaction(Akonadi2::Storage::ReadWrite); | ||
60 | setMaxRevision(transaction, revision); | ||
61 | } | ||
62 | |||
63 | void Storage::setMaxRevision(Akonadi2::Storage::Transaction &transaction, qint64 revision) | 57 | void Storage::setMaxRevision(Akonadi2::Storage::Transaction &transaction, qint64 revision) |
64 | { | 58 | { |
65 | transaction.openDatabase().write("__internal_maxRevision", QByteArray::number(revision)); | 59 | transaction.openDatabase().write("__internal_maxRevision", QByteArray::number(revision)); |
66 | } | 60 | } |
67 | 61 | ||
68 | qint64 Storage::maxRevision() | ||
69 | { | ||
70 | auto transaction = createTransaction(Akonadi2::Storage::ReadOnly); | ||
71 | return maxRevision(transaction); | ||
72 | } | ||
73 | |||
74 | qint64 Storage::maxRevision(const Akonadi2::Storage::Transaction &transaction) | 62 | qint64 Storage::maxRevision(const Akonadi2::Storage::Transaction &transaction) |
75 | { | 63 | { |
76 | qint64 r = 0; | 64 | qint64 r = 0; |