Akonadi

querybuilder.h
1/*
2 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#ifndef AKONADI_QUERYBUILDER_H
8#define AKONADI_QUERYBUILDER_H
9
10#include "dbtype.h"
11#include "query.h"
12
13#include <QList>
14#include <QPair>
15#include <QSqlQuery>
16#include <QString>
17#include <QStringList>
18#include <QVariant>
19
20#ifdef QUERYBUILDER_UNITTEST
21class QueryBuilderTest;
22#endif
23
24namespace Akonadi
25{
26namespace Server
27{
28class DataStore;
29/**
30 Helper class to construct arbitrary SQL queries.
31*/
33{
34public:
35 enum QueryType {
36 Select,
37 Insert,
38 Update,
39 Delete,
40 };
41
42 /**
43 * When the same table gets joined as both, Inner- and LeftJoin,
44 * it will be merged into a single InnerJoin since it is more
45 * restrictive.
46 */
47 enum JoinType {
48 /// NOTE: only supported for UPDATE and SELECT queries.
50 /// NOTE: only supported for SELECT queries
52 };
53
54 /**
55 * Defines the place at which a condition should be evaluated.
56 */
58 /// add condition to WHERE part of the query
60 /// add condition to HAVING part of the query
61 /// NOTE: only supported for SELECT queries
63
64 NUM_CONDITIONS
65 };
66
67 /**
68 Creates a new query builder.
69
70 @param table The main table to operate on.
71 */
72 explicit QueryBuilder(const QString &table, QueryType type = Select);
73 QueryBuilder(DataStore *store, const QString &table, QueryType type = Select);
74
75 /**
76 Creates a new query builder with subquery in FROM clause for SELECT queries.
77 @param tableQuery must be a valid select query
78 @param tableQueryAlias alias name for table query
79 */
80 explicit QueryBuilder(const QSqlQuery &tableQuery, const QString &tableQueryAlias);
81 QueryBuilder(DataStore *store, const QSqlQuery &tableQuery, const QString &tableQueryAlias);
82
83 /**
84 Sets the database which should execute the query. Unfortunately the SQL "standard"
85 is not interpreted in the same way everywhere...
86 */
88
89 /**
90 Join a table to the query.
91
92 NOTE: make sure the @c JoinType is supported by the current @c QueryType
93 @param joinType The type of JOIN you want to add.
94 @param table The table to join.
95 @param condition the ON condition for this join.
96 */
97 void addJoin(JoinType joinType, const QString &table, const Query::Condition &condition);
98
99 /**
100 Join a table to the query.
101 This is a convenience method to create simple joins like e.g. 'LEFT JOIN t ON c1 = c2'.
102
103 NOTE: make sure the @c JoinType is supported by the current @c QueryType
104 @param joinType The type of JOIN you want to add.
105 @param table The table to join.
106 @param col1 The first column for the ON statement.
107 @param col2 The second column for the ON statement.
108 */
109 void addJoin(JoinType joinType, const QString &table, const QString &col1, const QString &col2);
110
111 /**
112 Adds the given columns to a select query.
113 @param cols The columns you want to select.
114 */
115 void addColumns(const QStringList &cols);
116
117 /**
118 Adds the given column to a select query.
119 @param col The column to add.
120 */
121 void addColumn(const QString &col);
122
123 /**
124 * Adds the given case statement to a select query.
125 * @param caseStmt The case statement to add.
126 */
127 void addColumn(const Query::Case &caseStmt);
128
129 /**
130 * Adds an aggregation statement.
131 * @param col The column to aggregate on
132 * @param aggregate The aggregation function.
133 */
134 void addAggregation(const QString &col, const QString &aggregate);
135
136 /**
137 * Adds and aggregation statement with CASE
138 * @param caseStmt The case statement to aggregate on
139 * @param aggregate The aggregation function.
140 */
141 void addAggregation(const Query::Case &caseStmt, const QString &aggregate);
142
143 /**
144 Add a WHERE or HAVING condition which compares a column with a given value.
145 @param column The column that should be compared.
146 @param op The operator used for comparison.
147 @param value The value @p column is compared to.
148 @param type Defines whether this condition should be part of the WHERE or the HAVING
149 part of the query. Defaults to WHERE.
150 */
151 void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type = WhereCondition);
152
153 /**
154 * Add a WHERE or HAVING condition which compares a column with a given value.
155 *
156 * This is an overload specially for passing a list of IDs, which is a fairly common case in Akonadi.
157 *
158 * @param column The column that should be compared.
159 * @param op The operator used for comparison.
160 * @param value The value @p column is compared to.
161 * @param type Defines whether this condition should be part of the WHERE or the HAVING
162 * part of the query. Defaults to WHERE.
163 */
165
166 /**
167 Add a WHERE or HAVING condition which compares a column with another column.
168 @param column The column that should be compared.
169 @param op The operator used for comparison.
170 @param column2 The column @p column is compared to.
171 @param type Defines whether this condition should be part of the WHERE or the HAVING
172 part of the query. Defaults to WHERE.
173 */
174 void addColumnCondition(const QString &column, Query::CompareOperator op, const QString &column2, ConditionType type = WhereCondition);
175
176 /**
177 Add a WHERE condition. Use this to build hierarchical conditions.
178 @param condition The condition that the resultset should satisfy.
179 @param type Defines whether this condition should be part of the WHERE or the HAVING
180 part of the query. Defaults to WHERE.
181 */
182 void addCondition(const Query::Condition &condition, ConditionType type = WhereCondition);
183
184 /**
185 Define how WHERE or HAVING conditions are combined.
186 @todo Give this method a better name.
187 @param op The logical operator that should be used to combine the conditions.
188 @param type Defines whether the operator should be used for WHERE or for HAVING
189 conditions. Defaults to WHERE conditions.
190 */
192
193 /**
194 Add sort column.
195 @param column Name of the column to sort.
196 @param order Sort order
197 */
198 void addSortColumn(const QString &column, Query::SortOrder order = Query::Ascending);
199
200 /**
201 Add a GROUP BY column.
202 NOTE: Only supported in SELECT queries.
203 @param column Name of the column to use for grouping.
204 */
205 void addGroupColumn(const QString &column);
206
207 /**
208 Add list of columns to GROUP BY.
209 NOTE: Only supported in SELECT queries.
210 @param columns Names of columns to use for grouping.
211 */
212 void addGroupColumns(const QStringList &columns);
213
214 /**
215 Sets a column to the given value (only valid for INSERT and UPDATE queries).
216 @param column Column to change.
217 @param value The value @p column should be set to.
218 */
219 void setColumnValue(const QString &column, const QVariant &value);
220
221 /**
222 * Specify whether duplicates should be included in the result.
223 * @param distinct @c true to remove duplicates, @c false is the default
224 */
225 void setDistinct(bool distinct);
226
227 /**
228 * Limits the amount of retrieved rows.
229 * @param limit the maximum number of rows to retrieve.
230 * @param offset offset of the first row to retrieve.
231 * The default value for @p offset is -1, indicating no offset.
232 * @note This has no effect on anything but SELECT queries.
233 */
234 void setLimit(int limit, int offset=-1);
235
236 /**
237 * Sets the column used for identification in an INSERT statement.
238 * The default is "id", only change this on tables without such a column
239 * (usually n:m helper tables).
240 * @param column Name of the identification column, empty string to disable this.
241 * @note This only affects PostgreSQL.
242 * @see insertId()
243 */
244 void setIdentificationColumn(const QString &column);
245
246 /**
247 Returns the query, only valid after exec().
248 */
249 QSqlQuery &query();
250
251 /**
252 Executes the query, returns true on success.
253 */
254 bool exec();
255
256 /**
257 Returns the ID of the newly created record (only valid for INSERT queries)
258 @note This will assert when being used with setIdentificationColumn() called
259 with an empty string.
260 @returns -1 if invalid
261 */
262 qint64 insertId();
263
264 /**
265 Indicate to the database to acquire an exclusive lock on the rows already during
266 SELECT statement.
267
268 Only makes sense in SELECT queries.
269 */
270 void setForUpdate(bool forUpdate = true);
271
272 /**
273 Returns the name of the main table or subquery.
274 */
275 QString getTable() const;
276
277 /**
278 * Returns concatenated table name with column name.
279 * @param column Column name.
280 * @note Pass only @p column that are not prefixed by table name.
281 */
282 QString getTableWithColumn(const QString &column) const;
283
284private:
285 void buildQuery(QString *query);
286 void bindValue(QString *query, const QVariant &value);
287 void buildWhereCondition(QString *query, const Query::Condition &cond);
288 void buildCaseStatement(QString *query, const Query::Case &caseStmt);
289 QString getTableQuery(const QSqlQuery &query, const QString &alias);
290
291 /**
292 * SQLite does not support JOINs with UPDATE, so we have to convert it into
293 * subqueries
294 */
295 void sqliteAdaptUpdateJoin(Query::Condition &cond);
296
297protected:
298 DataStore *dataStore() const
299 {
300 return mDataStore;
301 }
302
303private:
304 QString mTable;
305 QSqlQuery mTableSubQuery;
306 DataStore *mDataStore = nullptr;
307 DbType::Type mDatabaseType;
308 Query::Condition mRootCondition[NUM_CONDITIONS];
309 QSqlQuery mQuery;
310 QueryType mType;
311 QStringList mColumns;
312 QList<QVariant> mBindValues;
314 QStringList mGroupColumns;
315 QList<QPair<QString, QVariant>> mColumnValues;
316 QString mIdentificationColumn;
317
318 // we must make sure that the tables are joined in the correct order
319 // QMap sorts by key which might invalidate the queries
320 QStringList mJoinedTables;
322 int mLimit;
323 int mOffset;
324 bool mDistinct;
325 bool mForUpdate = false;
326#ifdef QUERYBUILDER_UNITTEST
327 QString mStatement;
328 friend class ::QueryBuilderTest;
329#endif
330};
331
332} // namespace Server
333} // namespace Akonadi
334
335#endif
This class handles all the database access.
Definition datastore.h:95
Helper class to construct arbitrary SQL queries.
void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with a given value.
void setDatabaseType(DbType::Type type)
Sets the database which should execute the query.
void addGroupColumn(const QString &column)
Add a GROUP BY column.
void addSortColumn(const QString &column, Query::SortOrder order=Query::Ascending)
Add sort column.
QString getTableWithColumn(const QString &column) const
Returns concatenated table name with column name.
void addJoin(JoinType joinType, const QString &table, const Query::Condition &condition)
Join a table to the query.
bool exec()
Executes the query, returns true on success.
void addColumns(const QStringList &cols)
Adds the given columns to a select query.
void addCondition(const Query::Condition &condition, ConditionType type=WhereCondition)
Add a WHERE condition.
void setColumnValue(const QString &column, const QVariant &value)
Sets a column to the given value (only valid for INSERT and UPDATE queries).
void setDistinct(bool distinct)
Specify whether duplicates should be included in the result.
void addColumnCondition(const QString &column, Query::CompareOperator op, const QString &column2, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with another column.
void addGroupColumns(const QStringList &columns)
Add list of columns to GROUP BY.
void setForUpdate(bool forUpdate=true)
Indicate to the database to acquire an exclusive lock on the rows already during SELECT statement.
QSqlQuery & query()
Returns the query, only valid after exec().
ConditionType
Defines the place at which a condition should be evaluated.
@ HavingCondition
add condition to HAVING part of the query NOTE: only supported for SELECT queries
@ WhereCondition
add condition to WHERE part of the query
void setIdentificationColumn(const QString &column)
Sets the column used for identification in an INSERT statement.
qint64 insertId()
Returns the ID of the newly created record (only valid for INSERT queries)
void setSubQueryMode(Query::LogicOperator op, ConditionType type=WhereCondition)
Define how WHERE or HAVING conditions are combined.
void addAggregation(const QString &col, const QString &aggregate)
Adds an aggregation statement.
void addColumn(const QString &col)
Adds the given column to a select query.
QueryBuilder(const QString &table, QueryType type=Select)
Creates a new query builder.
JoinType
When the same table gets joined as both, Inner- and LeftJoin, it will be merged into a single InnerJo...
@ InnerJoin
NOTE: only supported for UPDATE and SELECT queries.
@ LeftJoin
NOTE: only supported for SELECT queries.
QString getTable() const
Returns the name of the main table or subquery.
void setLimit(int limit, int offset=-1)
Limits the amount of retrieved rows.
Represents a WHERE condition tree.
Definition query.h:62
Type
Supported database types.
Definition dbtype.h:19
CompareOperator
Compare operators to be used in query conditions.
Definition query.h:28
SortOrder
Sort orders.
Definition query.h:53
LogicOperator
Logic operations used to combine multiple query conditions.
Definition query.h:45
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.