QtDataSync  4.2.0
A simple offline-first synchronisation framework, to synchronize data of Qt applications between devices
datatypestore.h
1 #ifndef QTDATASYNC_DATATYPESTORE_H
2 #define QTDATASYNC_DATATYPESTORE_H
3 
4 #include <type_traits>
5 
6 #include <QtCore/qobject.h>
7 #include <QtCore/qdebug.h>
8 
9 #include "QtDataSync/qtdatasync_global.h"
10 #include "QtDataSync/datastore.h"
11 
12 namespace QtDataSync {
13 
15 class Q_DATASYNC_EXPORT DataTypeStoreBase : public QObject
16 {
17  Q_OBJECT
18 
19 public:
21  explicit DataTypeStoreBase(QObject *parent = nullptr);
22 
24  virtual DataStore *store() const = 0;
26  QString setupName() const;
27 
28 Q_SIGNALS:
30  void dataChanged(const QString &key, const QVariant &value);
32  void dataResetted();
33 };
34 
36 template <typename TType, typename TKey = QString>
38 {
39  QTDATASYNC_STORE_ASSERT(TType);
40 
41 public:
43  explicit DataTypeStore(QObject *parent = nullptr);
45  explicit DataTypeStore(const QString &setupName, QObject *parent = nullptr);
47  explicit DataTypeStore(DataStore *store, QObject *parent = nullptr);
48 
49  DataStore *store() const override;
50 
52  qint64 count() const;
54  QList<TKey> keys() const;
56  QList<TType> loadAll() const;
58  bool contains(const TKey &key) const;
60  TType load(const TKey &key) const;
62  void save(const TType &value);
64  bool remove(const TKey &key);
66  template <typename TX = TType>
67  void update(std::enable_if_t<__helpertypes::is_object<TX>::value, TX> object) const;
71  void iterate(const std::function<bool(TType)> &iterator, bool skipBroken = false);
73  void clear();
74 
76  static TKey toKey(const QString &key);
77 
78 private:
79  DataStore *_store;
80 
81  void evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted);
82 };
83 
85 template <typename TType, typename TKey = QString>
87 {
88  static_assert(__helpertypes::is_gadget<TType>::value, "TType must be a Q_GADGET");
89 
90 public:
95 
97  explicit CachingDataTypeStore(QObject *parent = nullptr);
99  explicit CachingDataTypeStore(const QString &setupName, QObject *parent = nullptr);
101  explicit CachingDataTypeStore(DataStore *store, QObject *parent = nullptr);
102 
103  DataStore *store() const override;
104 
106  qint64 count() const;
108  QList<TKey> keys() const;
110  bool contains(const TKey &key) const;
112  QList<TType> loadAll() const;
114  TType load(const TKey &key) const;
116  void save(const TType &value);
118  bool remove(const TKey &key);
120  TType take(const TKey &key);
122  void clear();
123 
125  const_iterator begin() const;
127  const_iterator end() const;
128 
130  static TKey toKey(const QString &key);
131 
132 private:
133  DataStore *_store;
134  QHash<TKey, TType> _data;
135 
136  void evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted);
137  void evalDataResetted();
138 };
139 
141 template <typename TType, typename TKey>
142 class CachingDataTypeStore<TType*, TKey> : public DataTypeStoreBase
143 {
144  static_assert(__helpertypes::is_object<TType*>::value, "TType must inherit QObject");
145 
146 public:
151 
153  explicit CachingDataTypeStore(QObject *parent = nullptr);
155  explicit CachingDataTypeStore(const QString &setupName, QObject *parent = nullptr);
157  explicit CachingDataTypeStore(DataStore *store, QObject *parent = nullptr);
158 
159  DataStore *store() const override;
160 
162  qint64 count() const;
164  QList<TKey> keys() const;
166  bool contains(const TKey &key) const;
168  QList<TType*> loadAll() const;
170  TType* load(const TKey &key) const;
172  void save(TType *value);
174  bool remove(const TKey &key);
176  TType* take(const TKey &key);
178  void clear();
179 
181  const_iterator begin() const;
183  const_iterator end() const;
184 
186  static TKey toKey(const QString &key);
187 
188 private:
189  DataStore *_store;
190  QHash<TKey, TType*> _data;
191 
192  void evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted);
193  void evalDataResetted();
194 };
195 
196 // ------------- GENERIC IMPLEMENTATION DataTypeStore -------------
197 
198 template <typename TType, typename TKey>
201 {}
202 
203 template <typename TType, typename TKey>
205  DataTypeStore{new DataStore(setupName, nullptr), parent}
206 {
207  _store->setParent(this);
208 }
209 
210 template <typename TType, typename TKey>
213  _store{store}
214 {
215  connect(_store, &DataStore::dataChanged,
216  this, &DataTypeStore::evalDataChanged);
217  connect(_store, &DataStore::dataResetted,
219 }
220 
221 template<typename TType, typename TKey>
223 {
224  return _store;
225 }
226 
227 template <typename TType, typename TKey>
229 {
230  return _store->count<TType>();
231 }
232 
233 template <typename TType, typename TKey>
235 {
236  return _store->keys<TType, TKey>();
237 }
238 
239 template <typename TType, typename TKey>
241 {
242  return _store->loadAll<TType>();
243 }
244 
245 template<typename TType, typename TKey>
246 bool DataTypeStore<TType, TKey>::contains(const TKey &key) const
247 {
248  return _store->contains<TType>(key);
249 }
250 
251 template <typename TType, typename TKey>
252 TType DataTypeStore<TType, TKey>::load(const TKey &key) const
253 {
254  return _store->load<TType>(key);
255 }
256 
257 template <typename TType, typename TKey>
258 void DataTypeStore<TType, TKey>::save(const TType &value)
259 {
260  _store->save(value);
261 }
262 
263 template <typename TType, typename TKey>
265 {
266  return _store->remove<TType>(key);
267 }
268 
269 template<typename TType, typename TKey>
270 template <typename TX>
271 void DataTypeStore<TType, TKey>::update(std::enable_if_t<__helpertypes::is_object<TX>::value, TX> object) const
272 {
273  _store->update<TType>(object);
274 }
275 
276 template<typename TType, typename TKey>
278 {
279  return _store->search<TType>(query, mode);
280 }
281 
282 template<typename TType, typename TKey>
283 void DataTypeStore<TType, TKey>::iterate(const std::function<bool (TType)> &iterator, bool skipBroken)
284 {
285  _store->iterate(iterator, skipBroken);
286 }
287 
288 template<typename TType, typename TKey>
290 {
291  _store->clear<TType>();
292 }
293 
294 template<typename TType, typename TKey>
296 {
297  return QVariant(key).value<TKey>();
298 }
299 
300 template <typename TType, typename TKey>
301 void DataTypeStore<TType, TKey>::evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted)
302 {
303  try {
304  if(metaTypeId == qMetaTypeId<TType>()) {
305  if(wasDeleted)
306  emit dataChanged(key, QVariant());
307  else
308  emit dataChanged(key, QVariant::fromValue(_store->load<TType>(key)));
309  }
310  } catch(QException &e) {
311  qWarning(QLoggingCategory{qUtf8Printable(QStringLiteral("qtdatasync.%1.DataTypeStore").arg(setupName()))})
312  << "Failed to loaded changed data with error" << e.what();
313  }
314 }
315 
316 // ------------- GENERIC IMPLEMENTATION CachingDataTypeStore -------------
317 
318 template <typename TType, typename TKey>
321 {}
322 
323 template <typename TType, typename TKey>
326 {
327  _store->setParent(this);
328 }
329 
330 template <typename TType, typename TKey>
333  _store{store}
334 {
335  connect(_store, &DataStore::dataChanged,
336  this, &CachingDataTypeStore::evalDataChanged);
337  connect(_store, &DataStore::dataResetted,
338  this, &CachingDataTypeStore::evalDataResetted);
339 
340  auto userProp = TType::staticMetaObject.userProperty();
341  store->iterate<TType>([&](const TType &data){
342  _data.insert(userProp.readOnGadget(&data).template value<TKey>(), data);
343  return true;
344  }, true);
345 }
346 
347 template<typename TType, typename TKey>
349 {
350  return _store;
351 }
352 
353 template <typename TType, typename TKey>
355 {
356  return _data.size();
357 }
358 
359 template <typename TType, typename TKey>
361 {
362  return _data.keys();
363 }
364 
365 template<typename TType, typename TKey>
367 {
368  return _data.contains(key);
369 }
370 
371 template <typename TType, typename TKey>
373 {
374  return _data.values();
375 }
376 
377 template <typename TType, typename TKey>
378 TType CachingDataTypeStore<TType, TKey>::load(const TKey &key) const
379 {
380  return _data.value(key);
381 }
382 
383 template <typename TType, typename TKey>
385 {
386  _store->save(value);
387 }
388 
389 template <typename TType, typename TKey>
391 {
392  return _store->remove<TType>(QVariant::fromValue(key).toString());
393 }
394 
395 template<typename TType, typename TKey>
397 {
398  auto mData = _data.value(key);
399  if(_store->remove<TType>(QVariant::fromValue(key).toString()))
400  return mData;
401  else
402  return {};
403 }
404 
405 template<typename TType, typename TKey>
407 {
408  _store->clear<TType>();
409 }
410 
411 template<typename TType, typename TKey>
413 {
414  return _data.constBegin();
415 }
416 
417 template<typename TType, typename TKey>
419 {
420  return _data.constEnd();
421 }
422 
423 template<typename TType, typename TKey>
425 {
426  return QVariant(key).value<TKey>();
427 }
428 
429 template <typename TType, typename TKey>
430 void CachingDataTypeStore<TType, TKey>::evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted)
431 {
432  try {
433  if(metaTypeId == qMetaTypeId<TType>()) {
434  auto rKey = toKey(key);
435  if(wasDeleted) {
436  _data.remove(rKey);
437  emit dataChanged(key, QVariant());
438  } else {
439  auto data = _store->load<TType>(key);
440  _data.insert(rKey, data);
441  emit dataChanged(key, QVariant::fromValue(data));
442  }
443  }
444  } catch(QException &e) {
445  qWarning(QLoggingCategory{qUtf8Printable(QStringLiteral("qtdatasync.%1.CachingDataTypeStore").arg(setupName()))})
446  << "Failed to loaded changed data with error" << e.what();
447  }
448 }
449 
450 template <typename TType, typename TKey>
451 void CachingDataTypeStore<TType, TKey>::evalDataResetted()
452 {
453  _data.clear();
454  emit dataResetted();
455 }
456 
457 // ------------- GENERIC IMPLEMENTATION CachingDataTypeStore<TType*, TKey> -------------
458 
459 template <typename TType, typename TKey>
462 {}
463 
464 template <typename TType, typename TKey>
467 {
468  _store->setParent(this);
469 }
470 
471 template <typename TType, typename TKey>
474  _store{store}
475 
476 {
477  connect(_store, &DataStore::dataChanged,
478  this, &CachingDataTypeStore::evalDataChanged);
479  connect(_store, &DataStore::dataResetted,
480  this, &CachingDataTypeStore::evalDataResetted);
481 
482  auto userProp = TType::staticMetaObject.userProperty();
483  store->iterate<TType*>([&](TType *data){
484  data->setParent(this);
485  _data.insert(userProp.read(data).template value<TKey>(), data);
486  return true;
487  }, true);
488 }
489 
490 template<typename TType, typename TKey>
492 {
493  return _store;
494 }
495 
496 template <typename TType, typename TKey>
498 {
499  return _data.size();
500 }
501 
502 template <typename TType, typename TKey>
504 {
505  return _data.keys();
506 }
507 
508 template<typename TType, typename TKey>
510 {
511  return _data.contains(key);
512 }
513 
514 template <typename TType, typename TKey>
516 {
517  return _data.values();
518 }
519 
520 template <typename TType, typename TKey>
521 TType *CachingDataTypeStore<TType*, TKey>::load(const TKey &key) const
522 {
523  return _data.value(key);
524 }
525 
526 template <typename TType, typename TKey>
528 {
529  _store->save(value);
530 }
531 
532 template <typename TType, typename TKey>
534 {
535  return _store->remove<TType*>(key);
536 }
537 
538 template<typename TType, typename TKey>
540 {
541  auto mData = _data.take(key);
542  try {
543  if(!_store->remove<TType*>(QVariant::fromValue(key).toString()))
544  return nullptr;
545  } catch(...) {
546  _data.insert(key, mData);
547  throw;
548  }
549  mData->setParent(nullptr);
550  emit dataChanged(QVariant(key).toString(), QVariant());//manual emit required, because not happening in change signal because removed before
551  return mData;
552 }
553 
554 template<typename TType, typename TKey>
556 {
557  _store->clear<TType*>();
558 }
559 
560 template<typename TType, typename TKey>
562 {
563  return _data.constBegin();
564 }
565 
566 template<typename TType, typename TKey>
568 {
569  return _data.constEnd();
570 }
571 
572 template<typename TType, typename TKey>
574 {
575  return QVariant(key).value<TKey>();
576 }
577 
578 template <typename TType, typename TKey>
579 void CachingDataTypeStore<TType*, TKey>::evalDataChanged(int metaTypeId, const QString &key, bool wasDeleted)
580 {
581  try {
582  if(metaTypeId == qMetaTypeId<TType*>()) {
583  auto rKey = toKey(key);
584  if(wasDeleted) {
585  auto data = _data.take(rKey);
586  if(data) {
587  emit dataChanged(key, QVariant());
588  data->deleteLater();
589  }
590  } else {
591  if(_data.contains(rKey)) {
592  _store->update(_data.value(rKey));
593  emit dataChanged(key, QVariant::fromValue(_data.value(rKey)));
594  } else {
595  auto data = _store->load<TType*>(key);
596  auto oldData = _data.take(rKey);
597  data->setParent(this);
598  _data.insert(rKey, data);
599  emit dataChanged(key, QVariant::fromValue(data));
600  if(oldData)
601  oldData->deleteLater();
602  }
603  }
604  }
605  } catch(QException &e) {
606  qWarning(QLoggingCategory{qUtf8Printable(QStringLiteral("qtdatasync.%1.CachingDataTypeStore").arg(setupName()))})
607  << "Failed to loaded changed data with error" << e.what();
608  }
609 }
610 
611 template <typename TType, typename TKey>
612 void CachingDataTypeStore<TType*, TKey>::evalDataResetted()
613 {
614  auto data = _data;
615  _data.clear();
616  emit dataResetted();
617  for(auto d : data)
618  d->deleteLater();
619 }
620 
621 }
622 
623 #endif // QTDATASYNC_DATATYPESTORE_H
void save(const TType &value)
Saves the given dataset in the store.
static TKey toKey(const QString &key)
Shortcut to convert a string to the stores key type.
void update(int metaTypeId, QObject *object) const
Loads the dataset with the given key for the given type into the existing object by updating it&#39;s pro...
bool contains(const TKey &key) const
Checks if a dataset exists in the store for the given key.
void update(std::enable_if_t< __helpertypes::is_object< TX >::value, TX > object) const
Loads the dataset with the given key for the given type into the existing object by updating it&#39;s pro...
const_iterator end() const
Returns the end iterator of the internal hash.
QList< TType > loadAll() const
Loads all existing datasets for the given type.
CachingDataTypeStore(QObject *parent=nullptr)
Constructs a store for the default setup.
QHash::iterator insert(const Key &key, const T &value)
TType load(const TKey &key) const
Loads the dataset with the given key for the given type.
QList< TType > loadAll() const
Loads all existing datasets for the given type.
Main store to generically access all stored data synchronously.
Definition: datastore.h:21
TType take(const TKey &key)
Returns the dataset for the given key and removes it from the store.
A wrapper around the DataStore limited to one type to make access simpler.
Definition: datatypestore.h:37
int size() const const
void dataChanged(const QString &key, const QVariant &value)
Will be emitted when a dataset in the store has changed.
DataTypeStore(QObject *parent=nullptr)
Constructs a store for the default setup.
void dataChanged(int metaTypeId, const QString &key, bool deleted, QPrivateSignal)
Is emitted whenever a dataset has been changed.
T value() const const
typename QHash< TKey, TType * >::const_iterator const_iterator
Typedef for QHash::const_iterator.
bool remove(const TKey &key)
Removes the dataset with the given key for the given type.
const_iterator begin() const
Returns the begin iterator of the internal hash.
void clear(int metaTypeId)
Removes all datasets of the given type from the store.
typename QHash< TKey, TType >::const_iterator const_iterator
Typedef for QHash::const_iterator.
Definition: datatypestore.h:92
QVariant load(int metaTypeId, const QString &key) const
Loads the dataset with the given key for the given type.
Base class for all DataTypeStore like classes.
Definition: datatypestore.h:15
TType load(const TKey &key) const
Loads the dataset with the given key for the given type.
const_iterator iterator
Typedef for QHash::const_iterator.
Definition: datatypestore.h:94
QHash::const_iterator constEnd() const const
bool remove(const TKey &key)
Removes the dataset with the given key for the given type.
bool contains(const TKey &key) const
Checks if a dataset exists in the store for the given key.
void dataResetted(QPrivateSignal)
Is emitted when the store is resetted due to an account reset.
bool remove(int metaTypeId, const QString &key)
Removes the dataset with the given key for the given type.
void save(int metaTypeId, QVariant value)
Saves the given dataset in the store.
The primary namespace of the QtDataSync library.
void clear()
Removes all datasets of the given type from the store.
QList< Key > keys() const const
Q_DATASYNC_EXPORT const QString DefaultSetup
The default setup name.
void clear()
const T value(const Key &key) const const
void setParent(QObject *parent)
QVariant fromValue(const T &value)
QList< TType > search(const QString &query, DataStore::SearchMode mode=DataStore::RegexpMode)
Searches the store for datasets of the given type where the key matches the query.
void iterate(const std::function< bool(TType)> &iterator, bool skipBroken=false)
Iterates over all existing datasets of the given types.
QHash::const_iterator constBegin() const const
qint64 count() const
Counts the number of datasets for the given type.
SearchMode
Possible pattern modes for the search mechanism.
Definition: datastore.h:28
T take(const Key &key)
const_iterator iterator
Typedef for QHash::const_iterator.
DataStore * store() const override
Returns a reference to the internally used DataStore.
QList< T > values() const const
qint64 count() const
Counts the number of datasets for the given type.
Interpret the search string as a regular expression. See QRegularExpression.
Definition: datastore.h:30
void clear()
Removes all datasets of the given type from the store.
bool contains(const Key &key) const const
void save(const TType &value)
Saves the given dataset in the store.
QList< TKey > keys() const
Returns all saved keys for the given type.
A DataTypeStore that caches all loaded data internally for faster access.
Definition: datatypestore.h:86
DataStore * store() const override
Returns a reference to the internally used DataStore.
QObject * parent() const const
void dataResetted()
Will be emitted when the store was reset or cleared.
static TKey toKey(const QString &key)
Shortcut to convert a string to the stores key type.
QString toString() const const
QString setupName() const
Returns the name of the setup this class operates on.
QList< TKey > keys() const
Returns all saved keys for the given type.