summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2014-11-27 16:42:33 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2014-11-27 16:42:33 +0100
commit0bcfc57f24adf8ce8dfb2fad33b294b5f0110a89 (patch)
treebcc9572b698b694875cc2454aa5559244f4869af
parent3d2359416b09aaf363a8e1f959c087fded51765f (diff)
downloadsink-0bcfc57f24adf8ce8dfb2fad33b294b5f0110a89.tar.gz
sink-0bcfc57f24adf8ce8dfb2fad33b294b5f0110a89.zip
Updated ClientAPI draft.
-rw-r--r--client/clientapi.h242
1 files changed, 190 insertions, 52 deletions
diff --git a/client/clientapi.h b/client/clientapi.h
index b035708..8924328 100644
--- a/client/clientapi.h
+++ b/client/clientapi.h
@@ -2,20 +2,45 @@
2 2
3#include <QString> 3#include <QString>
4#include <QSet> 4#include <QSet>
5#include <QSharedPointer>
6#include <functional>
7#include "store/database.h"
5 8
6namespace ClientAPI { 9namespace ClientAPI {
7 10
8template<class T> 11/**
9class Set { 12 * Standardized Domain Types
13 *
14 * The don't adhere to any standard and can be freely extended
15 * Their sole purpose is providing a standardized interface to access data.
16 *
17 * This is necessary to decouple resource-backends from application domain containers (otherwise each resource would have to provide a faceade for each application domain container).
18 *
19 * These types will be frequently modified (for every new feature that should be exposed to the any client)
20 */
10 21
22class AkonadiDomainType {
23 /*
24 * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location.
25 */
26 QString identifier;
27 QString resource;
28 qint64 revision;
11}; 29};
12 30
13template<class T> 31class Event : public AkonadiDomainType {
14class TreeSet : public Set<T> {
15 32
16}; 33};
34class Todo : public AkonadiDomainType {
17 35
18class DomainObject { 36};
37class Calendar : public AkonadiDomainType {
38
39};
40class Mail : public AkonadiDomainType {
41
42};
43class Folder : public AkonadiDomainType {
19 44
20}; 45};
21 46
@@ -26,7 +51,7 @@ class DomainObject {
26 * ** dummy domain object that is a wrapper? 51 * ** dummy domain object that is a wrapper?
27 * ** domain adapter has an accessor for the domain object to hide subclassing 52 * ** domain adapter has an accessor for the domain object to hide subclassing
28 */ 53 */
29class DomainAdapter : public DomainObject { 54class EventDomainAdapter : public Event {
30 // virtual void setFoo(const QString &value) 55 // virtual void setFoo(const QString &value)
31 // { 56 // {
32 // mBuffer.setFoo(value); 57 // mBuffer.setFoo(value);
@@ -41,17 +66,86 @@ class DomainAdapter : public DomainObject {
41}; 66};
42 67
43 68
69
70/**
71 * Query result set
72 *
73 * This should probably become part of a generic kasync library.
74 *
75 * Functional is nice because we don't have to store data in the emitter
76 * Non functional and storing may be the right thing because we want an in-memory representation of the set
77 * non-functional also allows us to batch move data across thread boundaries.
78 */
79
80template<class T>
81class ResultEmitter;
82
83/*
84 * The promise side for the result provider
85 */
86template<class T>
87class ResultProvider {
88public:
89 void add(const T &value)
90 {
91 //the handler will be called in the other thread, protect
92 mResultEmitter->addHandler(value);
93 }
94
95 QSharedPointer<ResultEmitter<T> > emitter()
96 {
97 mResultEmitter = QSharedPointer<ResultEmitter<T> >(new ResultEmitter<T>());
98 return emitter;
99 }
100
101private:
102 QSharedPointer<ResultEmitter<T> > mResultEmitter;
103};
104
105/*
106 * The future side for the client.
107 *
108 * It does not directly hold the state.
109 */
110template<class T>
111class ResultEmitter {
112public:
113 void onAdded(const std::function<void(const T&)> &handler);
114 // void onRemoved(const std::function<void(const T&)> &handler);
115
116private:
117 friend class SetSource;
118 std::function<void(const T&)> addHandler;
119 // std::function<void(const T&)> removeHandler;
120};
121
122// template<class T>
123// class TreeSet : public Set<T> {
124//
125// };
126
127
128
44/** 129/**
45 * A query that matches a set of objects 130 * A query that matches a set of objects
131 *
132 * The query will have to be updated regularly similary to the domain objects.
133 * It probably also makes sense to have a domain specific part of the query,
134 * such as what properties we're interested in (necessary information for on-demand
135 * loading of data).
46 */ 136 */
47class Query 137class Query
48{ 138{
49public: 139public:
140 //Resources to search
50 QSet<QString> resources() const { return QSet<QString>(); } 141 QSet<QString> resources() const { return QSet<QString>(); }
51}; 142};
52 143
144
53/** 145/**
54 * Interface for the store facade 146 * Interface for the store facade
147 *
148 * All methods are synchronous.
55 */ 149 */
56template<class DomainType> 150template<class DomainType>
57class StoreFacade { 151class StoreFacade {
@@ -59,14 +153,10 @@ public:
59 virtual void create(const DomainType &domainObject) = 0; 153 virtual void create(const DomainType &domainObject) = 0;
60 virtual void modify(const DomainType &domainObject) = 0; 154 virtual void modify(const DomainType &domainObject) = 0;
61 virtual void remove(const DomainType &domainObject) = 0; 155 virtual void remove(const DomainType &domainObject) = 0;
62 virtual void load(const Query &query) = 0; 156 virtual void load(const Query &query, const std::function<void(const DomainType &)> &resultCallback) = 0;
63}; 157};
64 158
65 159
66class ResourceImpl {
67
68};
69
70/** 160/**
71 * Actual implementation of the store facade that is provided by the resource plugin. 161 * Actual implementation of the store facade that is provided by the resource plugin.
72 * 162 *
@@ -74,48 +164,78 @@ class ResourceImpl {
74 * 164 *
75 * A resource must provide this facade for each domain type it knows. 165 * A resource must provide this facade for each domain type it knows.
76 * => is reimplemented a lot 166 * => is reimplemented a lot
167 * => we should have a base implementation
77 * 168 *
78 * This interface should be executed in a thread so we can synchronously retrieve data from the store. 169 * This interface should be executed in a thread so we can synchronously retrieve data from the store.
170 *
171 * TODO: perhaps we should also allow async access and leave the thread/non-thread decision up to the implementation?
79 */ 172 */
80template<class DomainType> 173template<typename DomainType>
81class StoreFacadeImpl : public StoreFacade<DomainType> { 174class StoreFacadeImpl : public StoreFacade<Event> {
175};
176
177template<>
178class StoreFacadeImpl<Event> : public StoreFacade<Event> {
82public: 179public:
83 void create(const DomainType &domainObject) { 180 void create(const Event &domainObject) {
84 //FIXME here we would need to cast to DomainAdapter 181 //FIXME here we would need to cast to DomainAdapter
85 //Do actual work 182 //Do actual work
183 //transformFromDomainType(domainObject);
184 //Ideally we have an adapter
185 //getAdater(domainObject).buffer();
186 //domainObject.key(); => The domain object needs to provide the id
187 //writeToDb();
86 } 188 }
87 189
88 void modify(const DomainType &domainObject) { 190 void modify(const Event &domainObject) {
89 //Do actual work 191 //Do actual work
90 } 192 }
91 193
92 void remove(const DomainType &domainObject) { 194 void remove(const Event &domainObject) {
93 //Do actual work 195 //Do actual work
94 } 196 }
95 197
96 Set<DomainType> load(Query) { 198 class EventBuffer {
97 Set<DomainType> resultSet; 199 QString value;
98 200 };
99 //retrieve results from store and fill into result set 201
100 202 static Event transformToDomainType(const EventBuffer &buffer) {
101 resultSet << 203 //We may want to avoid copies here
102 204 Event event;
103 return resultSet; 205 // //Ideally we don't have to copy and can use an adaptor instead
206 // return DomainAdaptor
207 return event;
208 };
209
210 void load(const Query &query, const std::function<void(const Event &)> &resultCallback) {
211 //retrieve buffers from storage
212 QList<EventBuffer> queryresult;
213 foreach(const EventBuffer &buffer, queryresult) {
214 resultCallback(transformToDomainType(buffer));
215 }
104 } 216 }
105 217
106private: 218private:
219 //Dummy implementation
220 class ResourceImpl {};
107 ResourceImpl resource; 221 ResourceImpl resource;
222 Database mDb;
108}; 223};
109 224
110/** 225/**
111 * Facade factory that returns a store facade implementation, by loading a plugin and providing the relevant implementation. 226 * Facade factory that returns a store facade implementation, by loading a plugin and providing the relevant implementation.
227 *
228 * If we were to provide default implementations for certain capabilities. Here would be the place to do so.
229 *
230 * TODO: pluginmechansims for resources to provide their implementations.
112 */ 231 */
113class FacadeFactory { 232class FacadeFactory {
114public: 233public:
115 template<class DomainType> 234 template<class DomainType>
116 static StoreFacade<DomainType> getFacade(const QString &resource) 235 static StoreFacade<DomainType> getFacade(const QString &resource)
117 { 236 {
118 if (resource == "resourceX") { 237 //TODO errorhandling in case the resource doesn't support the domain type
238 if (resource == "dummyresource") {
119 return StoreFacadeImpl<DomainType>(); 239 return StoreFacadeImpl<DomainType>();
120 } 240 }
121 return StoreFacadeImpl<DomainType>(); 241 return StoreFacadeImpl<DomainType>();
@@ -127,48 +247,66 @@ public:
127 */ 247 */
128class Store { 248class Store {
129public: 249public:
250 /**
251 * Asynchronusly load a dataset
252 */
130 template <class DomainType> 253 template <class DomainType>
131 static Set<DomainType> load(Query) 254 static QSharedPointer<ResultEmitter<DomainType> > load(Query query)
132 { 255 {
133 //Query all resources and aggregate results 256 QSharedPointer<ResultProvider<DomainType> > resultSet(new ResultProvider<DomainType>);
134 //Query tells us in which resources we're interested 257
135 Set<DomainType> resultSet; 258 //Create a job that executes the search function.
136 259 //We must guarantee that the emitter is returned before the first result is emitted.
137 //FIXME this should run in a thread. 260 //The thread boundary handling is implemented in the result provider.
138 //The result set is immediately returned and a "promise"/"resultprovider", 261 // QtConcurrent::run([provider, resultSet](){
139 //is passed to the actual query. The resultset is threadsafe so the query thread can safely move data 262 // // Query all resources and aggregate results
140 //via the promise to the mainthread. 263 // // query tells us in which resources we're interested
141 for(auto resource, query.resources()) { 264 // for(const auto &resource, query.resources()) {
142 auto facade = FacadeFactory::getFacade(resource); 265 // auto facade = FacadeFactory::getFacade(resource);
143 resultSet += facade.load<DomainType>(query); 266 // facade.load<DomainType>(query, resultSet.add);
144 } 267 // }
145 return resultSet; 268 // });
269 return resultSet->emitter();
146 } 270 }
147 271
148 //Future load(id); => Set with single value 272 /**
149 273 * Asynchronusly load a dataset with tree structure information
150 template <class DomainType> 274 */
151 static TreeSet<DomainType> loadTree(Query) 275 // template <class DomainType>
152 { 276 // static TreeSet<DomainType> loadTree(Query)
277 // {
153 278
154 } 279 // }
155 280
156 //Sync methods for modifications 281 /**
282 * Create a new entity.
283 */
157 template <class DomainType> 284 template <class DomainType>
158 static void create(const DomainType &domainObject) { 285 static void create(const DomainType &domainObject, const QString &resourceIdentifier) {
159 auto facade = FacadeFactory::getFacade(domainObject.resource()); 286 //Potentially move to separate thread as well
287 auto facade = FacadeFactory::getFacade<DomainType>(resourceIdentifier);
160 facade.create(domainObject); 288 facade.create(domainObject);
161 } 289 }
162 290
291 /**
292 * Modify an entity.
293 *
294 * This includes moving etc. since these are also simple settings on a property.
295 */
163 template <class DomainType> 296 template <class DomainType>
164 static void modify(const DomainType &domainObject) { 297 static void modify(const DomainType &domainObject, const QString &resourceIdentifier) {
165 auto facade = FacadeFactory::getFacade(domainObject.resource()); 298 //Potentially move to separate thread as well
299 auto facade = FacadeFactory::getFacade<DomainType>(resourceIdentifier);
166 facade.modify(domainObject); 300 facade.modify(domainObject);
167 } 301 }
168 302
303 /**
304 * Remove an entity.
305 */
169 template <class DomainType> 306 template <class DomainType>
170 static void remove(const DomainType &domainObject) { 307 static void remove(const DomainType &domainObject, const QString &resourceIdentifier) {
171 auto facade = FacadeFactory::getFacade(domainObject.resource()); 308 //Potentially move to separate thread as well
309 auto facade = FacadeFactory::getFacade<DomainType>(resourceIdentifier);
172 facade.remove(domainObject); 310 facade.remove(domainObject);
173 } 311 }
174}; 312};