Akonadi

datastore.h
1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2006 Andreas Gungl <[email protected]> *
3  * *
4  * SPDX-License-Identifier: LGPL-2.0-or-later *
5  ***************************************************************************/
6 
7 #pragma once
8 
9 #include <QList>
10 #include <QMutex>
11 #include <QObject>
12 #include <QSqlDatabase>
13 #include <QThreadStorage>
14 
15 class QSqlQuery;
16 class QTimer;
17 
18 #include "entities.h"
19 #include "notificationcollector.h"
20 
21 #include <memory>
22 
23 namespace Akonadi
24 {
25 namespace Server
26 {
27 class DataStore;
28 class DataStoreFactory
29 {
30 public:
31  virtual ~DataStoreFactory() = default;
32  virtual DataStore *createStore() = 0;
33 
34 protected:
35  explicit DataStoreFactory() = default;
36 
37 private:
38  Q_DISABLE_COPY_MOVE(DataStoreFactory)
39 };
40 
41 class NotificationCollector;
42 
43 /**
44  This class handles all the database access.
45 
46  <h4>Database configuration</h4>
47 
48  You can select between various database backends during runtime using the
49  @c $HOME/.config/akonadi/akonadiserverrc configuration file.
50 
51  Example:
52 @verbatim
53 [%General]
54 Driver=QMYSQL
55 
56 [QMYSQL_EMBEDDED]
57 Name=akonadi
58 Options=SERVER_DATADIR=/home/foo/.local/share/akonadi/db_data
59 
60 [QMYSQL]
61 Name=akonadi
62 Host=localhost
63 User=foo
64 Password=*****
65 #Options=UNIX_SOCKET=/home/foo/.local/share/akonadi/socket-bar/mysql.socket
66 StartServer=true
67 ServerPath=/usr/sbin/mysqld
68 
69 [QSQLITE]
70 Name=/home/foo/.local/share/akonadi/akonadi.db
71 @endverbatim
72 
73  Use @c General/Driver to select the QSql driver to use for database
74  access. The following drivers are currently supported, other might work
75  but are untested:
76 
77  - QMYSQL
78  - QMYSQL_EMBEDDED
79  - QSQLITE
80 
81  The options for each driver are read from the corresponding group.
82  The following options are supported, dependent on the driver not all of them
83  might have an effect:
84 
85  - Name: Database name, for sqlite that's the file name of the database.
86  - Host: Hostname of the database server
87  - User: Username for the database server
88  - Password: Password for the database server
89  - Options: Additional options, format is driver-dependent
90  - StartServer: Start the database locally just for Akonadi instead of using an existing one
91  - ServerPath: Path to the server executable
92 */
93 class DataStore : public QObject
94 {
95  Q_OBJECT
96 public:
97  const constexpr static bool Silent = true;
98 
99  static void setFactory(std::unique_ptr<DataStoreFactory> factory);
100 
101  /**
102  Closes the database connection and destroys the DataStore object.
103  */
104  ~DataStore() override;
105 
106  /**
107  Opens the database connection.
108  */
109  virtual void open();
110 
111  /**
112  Closes the database connection.
113  */
114  void close();
115 
116  /**
117  Initializes the database. Should be called during startup by the main thread.
118  */
119  virtual bool init();
120 
121  /**
122  Per thread singleton.
123  */
124  static DataStore *self();
125 
126  /**
127  * Returns whether per thread DataStore has been created.
128  */
129  static bool hasDataStore();
130 
131  /* --- ItemFlags ----------------------------------------------------- */
132  virtual bool setItemsFlags(const PimItem::List &items,
133  const QList<Flag> *currentFlags,
134  const QList<Flag> &newFlags,
135  bool *flagsChanged = nullptr,
136  const Collection &col = Collection(),
137  bool silent = false);
138  virtual bool appendItemsFlags(const PimItem::List &items,
139  const QList<Flag> &flags,
140  bool *flagsChanged = nullptr,
141  bool checkIfExists = true,
142  const Collection &col = Collection(),
143  bool silent = false);
144  virtual bool removeItemsFlags(const PimItem::List &items,
145  const QList<Flag> &flags,
146  bool *tagsChanged = nullptr,
147  const Collection &collection = Collection(),
148  bool silent = false);
149 
150  /* --- ItemTags ----------------------------------------------------- */
151  virtual bool setItemsTags(const PimItem::List &items, const Tag::List &tags, bool *tagsChanged = nullptr, bool silent = false);
152  virtual bool appendItemsTags(const PimItem::List &items,
153  const Tag::List &tags,
154  bool *tagsChanged = nullptr,
155  bool checkIfExists = true,
156  const Collection &col = Collection(),
157  bool silent = false);
158  virtual bool removeItemsTags(const PimItem::List &items, const Tag::List &tags, bool *tagsChanged = nullptr, bool silent = false);
159  virtual bool removeTags(const Tag::List &tags, bool silent = false);
160 
161  /* --- ItemParts ----------------------------------------------------- */
162  virtual bool removeItemParts(const PimItem &item, const QSet<QByteArray> &parts);
163 
164  // removes all payload parts for this item.
165  virtual bool invalidateItemCache(const PimItem &item);
166 
167  /* --- Collection ------------------------------------------------------ */
168  virtual bool appendCollection(Collection &collection, const QStringList &mimeTypes, const QMap<QByteArray, QByteArray> &attributes);
169 
170  /// removes the given collection and all its content
171  virtual bool cleanupCollection(Collection &collection);
172 
173  /// moves the collection @p collection to @p newParent.
174  virtual bool moveCollection(Collection &collection, const Collection &newParent);
175 
176  virtual bool appendMimeTypeForCollection(qint64 collectionId, const QStringList &mimeTypes);
177 
178  static QString collectionDelimiter()
179  {
180  return QStringLiteral("/");
181  }
182 
183  /**
184  Determines the active cache policy for this Collection.
185  The active cache policy is set in the corresponding Collection fields.
186  */
187  virtual void activeCachePolicy(Collection &col);
188 
189  /// Returns all virtual collections the @p item is linked to
190  QList<Collection> virtualCollections(const PimItem &item);
191 
192  QMap<Server::Entity::Id, QList<PimItem>> virtualCollections(const Akonadi::Server::PimItem::List &items);
193 
194  /* --- PimItem ------------------------------------------------------- */
195  virtual bool appendPimItem(QList<Part> &parts,
196  const QList<Flag> &flags,
197  const MimeType &mimetype,
198  const Collection &collection,
199  const QDateTime &dateTime,
200  const QString &remote_id,
201  const QString &remoteRevision,
202  const QString &gid,
203  PimItem &pimItem);
204  /**
205  * Removes the pim item and all referenced data ( e.g. flags )
206  */
207  virtual bool cleanupPimItems(const PimItem::List &items, bool silent = false);
208 
209  /**
210  * Unhides the specified PimItem. Emits the itemAdded() notification as
211  * the hidden flag is assumed to have been set by appendPimItem() before
212  * pushing the item to the preprocessor chain. The hidden item had his
213  * notifications disabled until now (so for the clients the "unhide" operation
214  * is actually a new item arrival).
215  *
216  * This function does NOT verify if the item was *really* hidden: this is
217  * responsibility of the caller.
218  */
219  virtual bool unhidePimItem(PimItem &pimItem);
220 
221  /**
222  * Unhides all the items which have the "hidden" flag set.
223  * This function doesn't emit any notification about the items
224  * being unhidden so it's meant to be called only in rare circumstances.
225  * The most notable call to this function is at server startup
226  * when we attempt to restore a clean state of the database.
227  */
228  virtual bool unhideAllPimItems();
229 
230  /* --- Collection attributes ------------------------------------------ */
231  virtual bool addCollectionAttribute(const Collection &col, const QByteArray &key, const QByteArray &value, bool silent = false);
232  /**
233  * Removes the given collection attribute for @p col.
234  * @throws HandlerException on database errors
235  * @returns @c true if the attribute existed, @c false otherwise
236  */
237  virtual bool removeCollectionAttribute(const Collection &col, const QByteArray &key);
238 
239  /* --- Helper functions ---------------------------------------------- */
240 
241  /**
242  Begins a transaction. No changes will be written to the database and
243  no notification signal will be emitted unless you call commitTransaction().
244  @return @c true if successful.
245  */
246  virtual bool beginTransaction(const QString &name);
247 
248  /**
249  Reverts all changes within the current transaction.
250  */
251  virtual bool rollbackTransaction();
252 
253  /**
254  Commits all changes within the current transaction and emits all
255  collected notification signals. If committing fails, the transaction
256  will be rolled back.
257  */
258  virtual bool commitTransaction();
259 
260  /**
261  Returns true if there is a transaction in progress.
262  */
263  bool inTransaction() const;
264 
265  /**
266  Returns the notification collector of this DataStore object.
267  Use this to listen to change notification signals.
268  */
270 
271  /**
272  Returns the QSqlDatabase object. Use this for generating queries yourself.
273 
274  Will [re-]open the database, if it is closed.
275  */
277 
278  /**
279  Sets the current session id.
280  */
281  void setSessionId(const QByteArray &sessionId)
282  {
283  mSessionId = sessionId;
284  }
285 
286  /**
287  Returns if the database is currently open
288  */
289  bool isOpened() const
290  {
291  return m_dbOpened;
292  }
293 
294  bool doRollback();
295  void transactionKilledByDB();
296 
297 Q_SIGNALS:
298  /**
299  Emitted if a transaction has been successfully committed.
300  */
301  void transactionCommitted();
302  /**
303  Emitted if a transaction has been aborted.
304  */
305  void transactionRolledBack();
306 
307 protected:
308  /**
309  Creates a new DataStore object and opens it.
310  */
311  DataStore(AkonadiServer &akonadi);
312 
313  void debugLastDbError(const char *actionDescription) const;
314  void debugLastQueryError(const QSqlQuery &query, const char *actionDescription) const;
315 
316 private:
317  bool doAppendItemsFlag(const PimItem::List &items, const Flag &flag, const QSet<PimItem::Id> &existing, const Collection &col, bool silent);
318 
319  bool doAppendItemsTag(const PimItem::List &items, const Tag &tag, const QSet<Entity::Id> &existing, const Collection &col, bool silent);
320 
321  /** Converts the given date/time to the database format, i.e.
322  "YYYY-MM-DD HH:MM:SS".
323  @param dateTime the date/time in UTC
324  @return the date/time in database format
325  @see dateTimeToQDateTime
326  */
327  static QString dateTimeFromQDateTime(const QDateTime &dateTime);
328 
329  /** Converts the given date/time from database format to QDateTime.
330  @param dateTime the date/time in database format
331  @return the date/time as QDateTime
332  @see dateTimeFromQDateTime
333  */
334  static QDateTime dateTimeToQDateTime(const QByteArray &dateTime);
335 
336 private Q_SLOTS:
337  void sendKeepAliveQuery();
338 
339 protected:
340  static std::unique_ptr<DataStoreFactory> sFactory;
341  std::unique_ptr<NotificationCollector> mNotificationCollector;
342  AkonadiServer &m_akonadi;
343 
344 private:
346 
347  void cleanupAfterRollback();
348  QString m_connectionName;
349  QSqlDatabase m_database;
350  bool m_dbOpened;
351  bool m_transactionKilledByDB = false;
352  uint m_transactionLevel;
353  struct TransactionQuery {
354  QString query;
355  QList<QVariant> boundValues;
356  bool isBatch;
357  };
358  QByteArray mSessionId;
359  QTimer *m_keepAliveTimer = nullptr;
360 
361  friend class DataStoreFactory;
362 };
363 
364 } // namespace Server
365 } // namespace Akonadi
Q_OBJECTQ_OBJECT
NotificationCollector * notificationCollector()
Returns the notification collector of this DataStore object.
Definition: datastore.cpp:198
This class handles all the database access.
Definition: datastore.h:93
virtual void open()
Opens the database connection.
Definition: datastore.cpp:91
Q_SLOTSQ_SLOTS
Part of the DataStore, collects change notifications and emits them after the current transaction has...
bool inTransaction() const
Returns true if there is a transaction in progress.
Definition: datastore.cpp:1376
An Akonadi Tag.
Definition: tag.h:25
QSqlDatabase database()
Returns the QSqlDatabase object.
Definition: datastore.cpp:128
Represents a collection of PIM items.
Definition: collection.h:61
void close()
Closes the database connection.
Definition: datastore.cpp:136
Definition: item.h:29
virtual bool beginTransaction(const QString &name)
Begins a transaction.
Definition: datastore.cpp:1279
virtual bool unhidePimItem(PimItem &pimItem)
Unhides the specified PimItem.
Definition: datastore.cpp:1089
Q_DISABLE_COPY_MOVE(Class)
virtual bool rollbackTransaction()
Reverts all changes within the current transaction.
Definition: datastore.cpp:1319
QList< Collection > virtualCollections(const PimItem &item)
Returns all virtual collections the item is linked to.
Definition: datastore.cpp:964
virtual void activeCachePolicy(Collection &col)
Determines the active cache policy for this Collection.
Definition: datastore.cpp:939
virtual bool cleanupPimItems(const PimItem::List &items, bool silent=false)
Removes the pim item and all referenced data ( e.g.
Definition: datastore.cpp:1117
void transactionRolledBack()
Emitted if a transaction has been aborted.
virtual bool commitTransaction()
Commits all changes within the current transaction and emits all collected notification signals.
Definition: datastore.cpp:1341
void transactionCommitted()
Emitted if a transaction has been successfully committed.
DataStore(AkonadiServer &akonadi)
Creates a new DataStore object and opens it.
Definition: datastore.cpp:70
~DataStore() override
Closes the database connection and destroys the DataStore object.
Definition: datastore.cpp:86
Q_SIGNALSQ_SIGNALS
virtual bool moveCollection(Collection &collection, const Collection &newParent)
moves the collection collection to newParent.
Definition: datastore.cpp:873
virtual bool cleanupCollection(Collection &collection)
removes the given collection and all its content
Definition: datastore.cpp:793
bool isOpened() const
Returns if the database is currently open.
Definition: datastore.h:289
virtual bool removeCollectionAttribute(const Collection &col, const QByteArray &key)
Removes the given collection attribute for col.
Definition: datastore.cpp:1197
static bool hasDataStore()
Returns whether per thread DataStore has been created.
Definition: datastore.cpp:215
void setSessionId(const QByteArray &sessionId)
Sets the current session id.
Definition: datastore.h:281
virtual bool unhideAllPimItems()
Unhides all the items which have the "hidden" flag set.
Definition: datastore.cpp:1101
virtual bool init()
Initializes the database.
Definition: datastore.cpp:163
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Sep 30 2023 04:01:51 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.