1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/*
* Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <QByteArray>
#include "query.h"
#include "domainadaptor.h"
#include "entitybuffer.h"
#include "log.h"
#include "storage.h"
#include "resultset.h"
#include "resultprovider.h"
#include "definitions.h"
/**
* Wraps storage, entity adaptor factory and indexes into one.
*
* TODO: customize with readEntity instead of adaptor factory
*/
class EntityStorageBase
{
protected:
EntityStorageBase(const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory)
: mResourceInstanceIdentifier(instanceIdentifier),
mDomainTypeAdaptorFactory(adaptorFactory)
{
}
virtual Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr create(const QByteArray &key, qint64 revision, const QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> &adaptor) = 0;
virtual Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr copy(const Akonadi2::ApplicationDomain::ApplicationDomainType &) = 0;
virtual ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) = 0;
/**
* Loads a single entity by uid from storage.
*
* TODO: Resources should be able to customize this for cases where an entity is not the same as a single buffer.
*/
void readEntity(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)> &resultCallback);
ResultSet getResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, qint64 baseRevision);
protected:
QByteArray mResourceInstanceIdentifier;
QByteArray mBufferType;
DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory;
private:
/**
* Returns the initial result set that still needs to be filtered.
*
* To make this efficient indexes should be chosen that are as selective as possible.
*/
ResultSet loadInitialResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters);
ResultSet filteredSet(const ResultSet &resultSet, const std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Akonadi2::Storage::Transaction &transaction, bool isInitialQuery);
};
template<typename DomainType>
class EntityStorage : public EntityStorageBase
{
public:
EntityStorage(const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory, const QByteArray &bufferType)
: EntityStorageBase(instanceIdentifier, adaptorFactory)
{
mBufferType = bufferType;
}
protected:
Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr create(const QByteArray &key, qint64 revision, const QSharedPointer<Akonadi2::ApplicationDomain::BufferAdaptor> &adaptor) Q_DECL_OVERRIDE
{
return DomainType::Ptr::create(mResourceInstanceIdentifier, key, revision, adaptor);
}
Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr copy(const Akonadi2::ApplicationDomain::ApplicationDomainType &object) Q_DECL_OVERRIDE
{
return Akonadi2::ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<DomainType>(object);
}
ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) Q_DECL_OVERRIDE
{
return Akonadi2::ApplicationDomain::TypeImplementation<DomainType>::queryIndexes(query, resourceInstanceIdentifier, appliedFilters, transaction);
}
public:
virtual qint64 read(const Akonadi2::Query &query, qint64 baseRevision, const QSharedPointer<Akonadi2::ResultProvider<typename DomainType::Ptr> > &resultProvider)
{
Akonadi2::Storage storage(Akonadi2::storageLocation(), mResourceInstanceIdentifier);
storage.setDefaultErrorHandler([](const Akonadi2::Storage::Error &error) {
Warning() << "Error during query: " << error.store << error.message;
});
auto transaction = storage.createTransaction(Akonadi2::Storage::ReadOnly);
Log() << "Querying" << baseRevision;
auto resultSet = getResultSet(query, transaction, baseRevision);
while(resultSet.next([this, resultProvider](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &value, Akonadi2::Operation operation) -> bool {
switch (operation) {
case Akonadi2::Operation_Creation:
Trace() << "Got creation";
resultProvider->add(copy(*value).template staticCast<DomainType>());
break;
case Akonadi2::Operation_Modification:
Trace() << "Got modification";
resultProvider->add(copy(*value).template staticCast<DomainType>());
break;
case Akonadi2::Operation_Removal:
Trace() << "Got removal";
break;
}
return true;
})){};
return Akonadi2::Storage::maxRevision(transaction);
}
};
|