summaryrefslogtreecommitdiffstats
path: root/common/clientapi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/clientapi.cpp')
-rw-r--r--common/clientapi.cpp210
1 files changed, 1 insertions, 209 deletions
diff --git a/common/clientapi.cpp b/common/clientapi.cpp
index cbbfdd8..01411c2 100644
--- a/common/clientapi.cpp
+++ b/common/clientapi.cpp
@@ -46,115 +46,6 @@
46namespace Sink 46namespace Sink
47{ 47{
48 48
49QString Store::storageLocation()
50{
51 return Sink::storageLocation();
52}
53
54static QList<QByteArray> getResources(const QList<QByteArray> &resourceFilter, const QByteArray &type)
55{
56 //Return the global resource (signified by an empty name) for types that don't eblong to a specific resource
57 if (type == "sinkresource") {
58 return QList<QByteArray>() << "";
59 }
60 QList<QByteArray> resources;
61 const auto configuredResources = ResourceConfig::getResources();
62 if (resourceFilter.isEmpty()) {
63 for (const auto &res : configuredResources.keys()) {
64 //TODO filter by entity type
65 resources << res;
66 }
67 } else {
68 for (const auto &res : resourceFilter) {
69 if (configuredResources.contains(res)) {
70 resources << res;
71 } else {
72 qWarning() << "Resource is not existing: " << res;
73 }
74 }
75 }
76 Trace() << "Found resources: " << resources;
77 return resources;
78}
79
80template <class DomainType>
81QSharedPointer<QAbstractItemModel> Store::loadModel(Query query)
82{
83 Trace() << "Query: ";
84 Trace() << " Requested: " << query.requestedProperties;
85 Trace() << " Filter: " << query.propertyFilter;
86 Trace() << " Parent: " << query.parentProperty;
87 Trace() << " Ids: " << query.ids;
88 Trace() << " IsLive: " << query.liveQuery;
89 auto model = QSharedPointer<ModelResult<DomainType, typename DomainType::Ptr> >::create(query, query.requestedProperties);
90
91 //* Client defines lifetime of model
92 //* The model lifetime defines the duration of live-queries
93 //* The facade needs to life for the duration of any calls being made (assuming we get rid of any internal callbacks
94 //* The emitter needs to live or the duration of query (respectively, the model)
95 //* The result provider needs to live for as long as results are provided (until the last thread exits).
96
97 // Query all resources and aggregate results
98 auto resources = getResources(query.resources, ApplicationDomain::getTypeName<DomainType>());
99 auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create();
100 model->setEmitter(aggregatingEmitter);
101 KAsync::iterate(resources)
102 .template each<void, QByteArray>([query, aggregatingEmitter](const QByteArray &resource, KAsync::Future<void> &future) {
103 auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resource), resource);
104 if (facade) {
105 Trace() << "Trying to fetch from resource " << resource;
106 auto result = facade->load(query);
107 aggregatingEmitter->addEmitter(result.second);
108 result.first.template then<void>([&future](){future.setFinished();}).exec();
109 } else {
110 Trace() << "Couldn' find a facade for " << resource;
111 //Ignore the error and carry on
112 future.setFinished();
113 }
114 }).exec();
115 model->fetchMore(QModelIndex());
116
117 return model;
118}
119
120template <class DomainType>
121static std::shared_ptr<StoreFacade<DomainType> > getFacade(const QByteArray &resourceInstanceIdentifier)
122{
123 if (auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resourceInstanceIdentifier), resourceInstanceIdentifier)) {
124 return facade;
125 }
126 return std::make_shared<NullFacade<DomainType> >();
127}
128
129template <class DomainType>
130KAsync::Job<void> Store::create(const DomainType &domainObject) {
131 //Potentially move to separate thread as well
132 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
133 return facade->create(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) {
134 Warning() << "Failed to create";
135 });
136}
137
138template <class DomainType>
139KAsync::Job<void> Store::modify(const DomainType &domainObject)
140{
141 //Potentially move to separate thread as well
142 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
143 return facade->modify(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) {
144 Warning() << "Failed to modify";
145 });
146}
147
148template <class DomainType>
149KAsync::Job<void> Store::remove(const DomainType &domainObject)
150{
151 //Potentially move to separate thread as well
152 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
153 return facade->remove(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) {
154 Warning() << "Failed to remove";
155 });
156}
157
158KAsync::Job<void> ResourceControl::shutdown(const QByteArray &identifier) 49KAsync::Job<void> ResourceControl::shutdown(const QByteArray &identifier)
159{ 50{
160 Trace() << "shutdown " << identifier; 51 Trace() << "shutdown " << identifier;
@@ -190,37 +81,6 @@ KAsync::Job<void> ResourceControl::start(const QByteArray &identifier)
190 }); 81 });
191} 82}
192 83
193KAsync::Job<void> Store::removeDataFromDisk(const QByteArray &identifier)
194{
195 //All databases are going to become invalid, nuke the environments
196 //TODO: all clients should react to a notification the resource
197 Sink::Storage::clearEnv();
198 Trace() << "Remove data from disk " << identifier;
199 auto time = QSharedPointer<QTime>::create();
200 time->start();
201 auto resourceAccess = QSharedPointer<Sink::ResourceAccess>::create(identifier);
202 resourceAccess->open();
203 return resourceAccess->sendCommand(Sink::Commands::RemoveFromDiskCommand).then<void>([resourceAccess, time]() {
204 Trace() << "Remove from disk complete." << Log::TraceTime(time->elapsed());
205 });
206}
207
208KAsync::Job<void> Store::synchronize(const Sink::Query &query)
209{
210 Trace() << "synchronize" << query.resources;
211 return KAsync::iterate(query.resources)
212 .template each<void, QByteArray>([query](const QByteArray &resource, KAsync::Future<void> &future) {
213 Trace() << "Synchronizing " << resource;
214 auto resourceAccess = QSharedPointer<Sink::ResourceAccess>::create(resource);
215 resourceAccess->open();
216 resourceAccess->synchronizeResource(true, false).then<void>([&future, resourceAccess]() {
217 future.setFinished();
218 }).exec();
219 })
220 //FIXME JOBAPI this is only required because we don't care about the return value of each (and each shouldn't even have a return value)
221 .template then<void>([](){});
222}
223
224KAsync::Job<void> ResourceControl::flushMessageQueue(const QByteArrayList &resourceIdentifier) 84KAsync::Job<void> ResourceControl::flushMessageQueue(const QByteArrayList &resourceIdentifier)
225{ 85{
226 Trace() << "flushMessageQueue" << resourceIdentifier; 86 Trace() << "flushMessageQueue" << resourceIdentifier;
@@ -243,67 +103,6 @@ KAsync::Job<void> ResourceControl::flushReplayQueue(const QByteArrayList &resour
243} 103}
244 104
245template <class DomainType> 105template <class DomainType>
246KAsync::Job<DomainType> Store::fetchOne(const Sink::Query &query)
247{
248 return KAsync::start<DomainType>([query](KAsync::Future<DomainType> &future) {
249 //FIXME We could do this more elegantly if composed jobs would have the correct type (In that case we'd simply return the value from then continuation, and could avoid the outer job entirely)
250 fetch<DomainType>(query, 1)
251 .template then<void, QList<typename DomainType::Ptr> >([&future](const QList<typename DomainType::Ptr> &list){
252 future.setValue(*list.first());
253 future.setFinished();
254 }, [&future](int errorCode, const QString &errorMessage) {
255 future.setError(errorCode, errorMessage);
256 future.setFinished();
257 }).exec();
258 });
259}
260
261template <class DomainType>
262KAsync::Job<QList<typename DomainType::Ptr> > Store::fetchAll(const Sink::Query &query)
263{
264 return fetch<DomainType>(query);
265}
266
267template <class DomainType>
268KAsync::Job<QList<typename DomainType::Ptr> > Store::fetch(const Sink::Query &query, int minimumAmount)
269{
270 auto model = loadModel<DomainType>(query);
271 auto list = QSharedPointer<QList<typename DomainType::Ptr> >::create();
272 auto context = QSharedPointer<QObject>::create();
273 return KAsync::start<QList<typename DomainType::Ptr> >([model, list, context, minimumAmount](KAsync::Future<QList<typename DomainType::Ptr> > &future) {
274 if (model->rowCount() >= 1) {
275 for (int i = 0; i < model->rowCount(); i++) {
276 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>());
277 }
278 } else {
279 QObject::connect(model.data(), &QAbstractItemModel::rowsInserted, context.data(), [model, &future, list](const QModelIndex &index, int start, int end) {
280 for (int i = start; i <= end; i++) {
281 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>());
282 }
283 });
284 QObject::connect(model.data(), &QAbstractItemModel::dataChanged, context.data(), [model, &future, list, minimumAmount](const QModelIndex &, const QModelIndex &, const QVector<int> &roles) {
285 if (roles.contains(ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole)) {
286 if (list->size() < minimumAmount) {
287 future.setError(1, "Not enough values.");
288 } else {
289 future.setValue(*list);
290 }
291 future.setFinished();
292 }
293 });
294 }
295 if (model->data(QModelIndex(), ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole).toBool()) {
296 if (list->size() < minimumAmount) {
297 future.setError(1, "Not enough values.");
298 } else {
299 future.setValue(*list);
300 }
301 future.setFinished();
302 }
303 });
304}
305
306template <class DomainType>
307KAsync::Job<void> ResourceControl::inspect(const Inspection &inspectionCommand) 106KAsync::Job<void> ResourceControl::inspect(const Inspection &inspectionCommand)
308{ 107{
309 auto resource = inspectionCommand.resourceIdentifier; 108 auto resource = inspectionCommand.resourceIdentifier;
@@ -371,14 +170,7 @@ void Notifier::registerHandler(std::function<void(const Notification &)> handler
371 d->handler << handler; 170 d->handler << handler;
372} 171}
373 172
374#define REGISTER_TYPE(T) template KAsync::Job<void> Store::remove<T>(const T &domainObject); \ 173#define REGISTER_TYPE(T) template KAsync::Job<void> ResourceControl::inspect<T>(const Inspection &); \
375 template KAsync::Job<void> Store::create<T>(const T &domainObject); \
376 template KAsync::Job<void> Store::modify<T>(const T &domainObject); \
377 template QSharedPointer<QAbstractItemModel> Store::loadModel<T>(Query query); \
378 template KAsync::Job<void> ResourceControl::inspect<T>(const Inspection &); \
379 template KAsync::Job<T> Store::fetchOne<T>(const Query &); \
380 template KAsync::Job<QList<T::Ptr> > Store::fetchAll<T>(const Query &); \
381 template KAsync::Job<QList<T::Ptr> > Store::fetch<T>(const Query &, int); \
382 174
383REGISTER_TYPE(ApplicationDomain::Event); 175REGISTER_TYPE(ApplicationDomain::Event);
384REGISTER_TYPE(ApplicationDomain::Mail); 176REGISTER_TYPE(ApplicationDomain::Mail);