1 /***************************************************************************
2  *   SPDX-FileCopyrightText: 2006 Andreas Gungl <a.gungl@gmx.de>           *
3  *                                                                         *
4  *   SPDX-License-Identifier: LGPL-2.0-or-later                            *
5  ***************************************************************************/
6 
7 #pragma once
8 
9 #include <QString>
10 #include <QStringList>
11 
12 class QVariant;
13 class QSqlDatabase;
14 
15 namespace Akonadi
16 {
17 namespace Server
18 {
19 /**
20   Base class for classes representing database records. It also contains
21   low-level data access and manipulation template methods.
22 */
23 class Entity
24 {
25 public:
26     using Id = qint64;
27 
28 protected:
29     qint64 id() const;
30     void setId(qint64 id);
31 
32     bool isValid() const;
33 
34 public:
joinByName(const QVector<T> & list,const QString & sep)35     template<typename T> static QString joinByName(const QVector<T> &list, const QString &sep)
36     {
37         QStringList tmp;
38         tmp.reserve(list.count());
39         for (const T &t : list) {
40             tmp << t.name();
41         }
42         return tmp.join(sep);
43     }
44 
45     /**
46       Returns the number of records having @p value in @p column.
47       @param column The name of the key column.
48       @param value The value used to identify the record.
49     */
count(const QString & column,const QVariant & value)50     template<typename T> inline static int count(const QString &column, const QVariant &value)
51     {
52         return Entity::countImpl(T::tableName(), column, value);
53     }
54 
55     /**
56       Deletes all records having @p value in @p column.
57     */
remove(const QString & column,const QVariant & value)58     template<typename T> inline static bool remove(const QString &column, const QVariant &value)
59     {
60         return Entity::removeImpl(T::tableName(), column, value);
61     }
62 
63     /**
64       Checks whether an entry in a n:m relation table exists.
65       @param leftId Identifier of the left part of the relation.
66       @param rightId Identifier of the right part of the relation.
67      */
relatesTo(qint64 leftId,qint64 rightId)68     template<typename T> inline static bool relatesTo(qint64 leftId, qint64 rightId)
69     {
70         return Entity::relatesToImpl(T::tableName(), T::leftColumn(), T::rightColumn(), leftId, rightId);
71     }
72 
73     /**
74       Adds an entry to a n:m relation table (specified by the template parameter).
75       @param leftId Identifier of the left part of the relation.
76       @param rightId Identifier of the right part of the relation.
77     */
addToRelation(qint64 leftId,qint64 rightId)78     template<typename T> inline static bool addToRelation(qint64 leftId, qint64 rightId)
79     {
80         return Entity::addToRelationImpl(T::tableName(), T::leftColumn(), T::rightColumn(), leftId, rightId);
81     }
82 
83     /**
84       Removes an entry from a n:m relation table (specified by the template parameter).
85       @param leftId Identifier of the left part of the relation.
86       @param rightId Identifier of the right part of the relation.
87     */
removeFromRelation(qint64 leftId,qint64 rightId)88     template<typename T> inline static bool removeFromRelation(qint64 leftId, qint64 rightId)
89     {
90         return Entity::removeFromRelationImpl(T::tableName(), T::leftColumn(), T::rightColumn(), leftId, rightId);
91     }
92 
93     enum RelationSide {
94         Left,
95         Right,
96     };
97 
98     /**
99       Clears all entries from a n:m relation table (specified by the given template parameter).
100       @param id Identifier on the relation side.
101       @param side The side of the relation.
102     */
103     template<typename T> inline static bool clearRelation(qint64 id, RelationSide side = Left)
104     {
105         return Entity::clearRelationImpl(T::tableName(), T::leftColumn(), T::rightColumn(), id, side);
106     }
107 
108 protected:
109     Entity();
110     explicit Entity(qint64 id);
111     ~Entity();
112 
113 private:
114     static int countImpl(const QString &tableName, const QString &column, const QVariant &value);
115     static bool removeImpl(const QString &tableName, const QString &column, const QVariant &value);
116     static bool relatesToImpl(const QString &tableName, const QString &leftColumn, const QString &rightColumn, qint64 leftId, qint64 rightId);
117     static bool addToRelationImpl(const QString &tableName, const QString &leftColumn, const QString &rightColumn, qint64 leftId, qint64 rightId);
118     static bool removeFromRelationImpl(const QString &tableName, const QString &leftColumn, const QString &rightColumn, qint64 leftId, qint64 rightId);
119     static bool clearRelationImpl(const QString &tableName, const QString &leftColumn, const QString &rightColumn, qint64 id, RelationSide side);
120 
121 private:
122     static QSqlDatabase database();
123     qint64 m_id;
124 };
125 
126 namespace _detail
127 {
128 /*!
129   Binary predicate to sort collections of Entity subclasses by
130   their id.
131 
132   Example for sorting:
133   \code
134   std::sort( coll.begin(), coll.end(), _detail::ById<std::less>() );
135   \endcode
136 
137   Example for finding by id:
138   \code
139   // linear:
140   std::find_if( coll.begin(), coll.end(), bind( _detail::ById<std::equal_to>(), _1, myId ) );
141   // binary:
142   std::lower_bound( coll.begin(), coll.end(), myId, _detail::ById<std::less>() );
143   \endcode
144 */
145 template<template<typename U> class Op> struct ById {
146     using result_type = bool;
operatorById147     bool operator()(Entity::Id lhs, Entity::Id rhs) const
148     {
149         return Op<Entity::Id>()(lhs, rhs);
150     }
operatorById151     template<typename E> bool operator()(const E &lhs, const E &rhs) const
152     {
153         return this->operator()(lhs.id(), rhs.id());
154     }
operatorById155     template<typename E> bool operator()(const E &lhs, Entity::Id rhs) const
156     {
157         return this->operator()(lhs.id(), rhs);
158     }
operatorById159     template<typename E> bool operator()(Entity::Id lhs, const E &rhs) const
160     {
161         return this->operator()(lhs, rhs.id());
162     }
163 };
164 }
165 
166 } // namespace Server
167 } // namespace Akonadi
168 
169