cutelyst  3.7.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
sql.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2015-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "sql.h"
6 
7 #include <QLoggingCategory>
8 #include <QThread>
9 
10 #include <QJsonObject>
11 #include <QJsonArray>
12 #include <QJsonValue>
13 
14 #include <QtSql/QSqlQuery>
15 #include <QtSql/QSqlError>
16 #include <QtSql/QSqlRecord>
17 
18 Q_LOGGING_CATEGORY(C_SQL, "cutelyst.utils.sql", QtWarningMsg)
19 
20 using namespace Cutelyst;
21 
22 QVariantHash Sql::queryToHashObject(QSqlQuery &query)
23 {
24  QVariantHash ret;
25  if (query.next()) {
26  const QSqlRecord record = query.record();
27  const int columns = record.count();
28  for (int i = 0; i < columns; ++i) {
29  ret.insert(record.fieldName(i), query.value(i));
30  }
31  }
32  return ret;
33 }
34 
35 QVariantList Sql::queryToHashList(QSqlQuery &query)
36 {
37  QVariantList ret;
38  const QSqlRecord record = query.record();
39  const int columns = record.count();
40  QStringList cols;
41  for (int i = 0; i < columns; ++i) {
42  cols.append(record.fieldName(i));
43  }
44 
45  while (query.next()) {
46  QVariantHash line;
47  for (int i = 0; i < columns; ++i) {
48  line.insert(cols.at(i), query.value(i));
49  }
50  ret.append(line);
51  }
52  return ret;
53 }
54 
55 QVariantMap Sql::queryToMapObject(QSqlQuery &query)
56 {
57  QVariantMap ret;
58  if (query.next()) {
59  const QSqlRecord record = query.record();
60  const int columns = record.count();
61  for (int i = 0; i < columns; ++i) {
62  ret.insert(record.fieldName(i), query.value(i));
63  }
64  }
65  return ret;
66 }
67 
68 QJsonObject Sql::queryToJsonObject(QSqlQuery &query)
69 {
70  QJsonObject ret;
71  if (query.next()) {
72  const QSqlRecord record = query.record();
73  const int columns = record.count();
74  for (int i = 0; i < columns; ++i) {
75  ret.insert(record.fieldName(i), QJsonValue::fromVariant(query.value(i)));
76  }
77  }
78  return ret;
79 }
80 
81 QVariantList Sql::queryToMapList(QSqlQuery &query)
82 {
83  QVariantList ret;
84  const QSqlRecord record = query.record();
85  const int columns = record.count();
86  QStringList cols;
87  for (int i = 0; i < columns; ++i) {
88  cols.append(record.fieldName(i));
89  }
90 
91  while (query.next()) {
92  QVariantMap line;
93  for (int i = 0; i < columns; ++i) {
94  line.insert(cols.at(i), query.value(i));
95  }
96  ret.append(line);
97  }
98  return ret;
99 }
100 
101 QJsonArray Sql::queryToJsonObjectArray(QSqlQuery &query)
102 {
103  QJsonArray ret;
104  const QSqlRecord record = query.record();
105  const int columns = record.count();
106  QStringList cols;
107  for (int i = 0; i < columns; ++i) {
108  cols.append(record.fieldName(i));
109  }
110 
111  while (query.next()) {
112  QJsonObject line;
113  for (int i = 0; i < columns; ++i) {
114  line.insert(cols.at(i), QJsonValue::fromVariant(query.value(i)));
115  }
116  ret.append(line);
117  }
118  return ret;
119 }
120 
121 QVariantList Sql::queryToList(QSqlQuery &query)
122 {
123  QVariantList ret;
124 
125  const int columns = query.record().count();
126  while (query.next()) {
127  QVariantList line;
128  for (int i = 0; i < columns; ++i) {
129  line.append(query.value(i));
130  }
131  ret.append(QVariant::fromValue(line));
132  }
133 
134  return ret;
135 }
136 
137 QJsonArray Sql::queryToJsonArray(QSqlQuery &query)
138 {
139  QJsonArray ret;
140 
141  const int columns = query.record().count();
142  while (query.next()) {
143  QJsonArray array;
144  for (int i = 0; i < columns; ++i) {
145  array.append(QJsonValue::fromVariant(query.value(i)));
146  }
147  ret.append(array);
148  }
149 
150  return ret;
151 }
152 
153 QVariantHash Sql::queryToIndexedHash(QSqlQuery &query, const QString &key)
154 {
155  QVariantHash ret;
156 
157  const QSqlRecord record = query.record();
158  int index = record.indexOf(key);
159  if (index == -1) {
160  qCCritical(C_SQL) << "Field Name " << key <<
161  " not found in result set";
162  return ret;
163  }
164 
165  const int columns = record.count();
166  QStringList cols;
167 
168  for (int i = 0; i < columns; ++i) {
169  cols.append(record.fieldName(i));
170  }
171 
172  while (query.next()) {
173  QVariantHash line;
174  for (int i = 0; i < columns; ++i) {
175  if (i != index) {
176  line.insert(cols.at(i), query.value(i));
177  }
178  }
179 
180  ret.insert(query.value(index).toString(), line);
181  }
182 
183  return ret;
184 }
185 
186 QJsonObject Sql::queryToIndexedJsonObject(QSqlQuery &query, const QString &key)
187 {
188  QJsonObject ret;
189 
190  const QSqlRecord record = query.record();
191  int index = record.indexOf(key);
192  if (index == -1) {
193  qCCritical(C_SQL) << "Field Name " << key <<
194  " not found in result set";
195  return ret;
196  }
197 
198  const int columns = record.count();
199  QStringList cols;
200 
201  for (int i = 0; i < columns; ++i) {
202  cols.append(record.fieldName(i));
203  }
204 
205  while (query.next()) {
206  QJsonObject obj;
207  for (int i = 0; i < columns; ++i) {
208  if (i != index) {
209  obj.insert(cols.at(i), QJsonValue::fromVariant(query.value(i)));
210  }
211  }
212 
213  ret.insert(query.value(index).toString(), obj);
214  }
215 
216  return ret;
217 }
218 
219 void Sql::bindParamsToQuery(QSqlQuery &query, const Cutelyst::ParamsMultiMap &params, bool htmlEscaped)
220 {
221  auto it = params.constBegin();
222  if (htmlEscaped) {
223  while (it != params.constEnd()) {
224  if (it.value().isNull()) {
225  query.bindValue(u':' + it.key(), QVariant());
226  } else {
227  query.bindValue(u':' + it.key(), it.value().toHtmlEscaped());
228  }
229  ++it;
230  }
231  } else {
232  while (it != params.constEnd()) {
233  if (it.value().isNull()) {
234  query.bindValue(u':' + it.key(), QVariant());
235  } else {
236  query.bindValue(u':' + it.key(), it.value());
237  }
238  ++it;
239  }
240  }
241 }
242 
243 QSqlQuery Sql::preparedQuery(const QString &query, QSqlDatabase db, bool forwardOnly)
244 {
245  QSqlQuery sqlQuery(db);
246  sqlQuery.setForwardOnly(forwardOnly);
247  if (!sqlQuery.prepare(query)) {
248  qCCritical(C_SQL) << "Failed to prepare query:" << query << sqlQuery.lastError().databaseText();
249  }
250  return sqlQuery;
251 }
252 
253 QSqlQuery Sql::preparedQueryThread(const QString &query, const QString &dbName, bool forwardOnly)
254 {
255  QSqlQuery sqlQuery(QSqlDatabase::database(databaseNameThread(dbName)));
256  sqlQuery.setForwardOnly(forwardOnly);
257  if (!sqlQuery.prepare(query)) {
258  qCCritical(C_SQL) << "Failed to prepare query:" << query << sqlQuery.lastError().databaseText();
259  }
260  return sqlQuery;
261 }
262 
263 QString Sql::databaseNameThread(const QString &dbName)
264 {
265  return dbName + u'-' + QThread::currentThread()->objectName();
266 }
267 
268 QSqlDatabase Sql::databaseThread(const QString &dbName)
269 {
270  return QSqlDatabase::database(databaseNameThread(dbName));
271 }
272 
273 Sql::Transaction::Transaction(const QString &databaseName) : m_db(databaseThread(databaseName))
274 {
275  m_transactionRunning = m_db.transaction();
276 }
277 
278 Sql::Transaction::Transaction(const QSqlDatabase &database) : m_db(database)
279 {
280  m_transactionRunning = m_db.transaction();
281 }
282 
283 Sql::Transaction::~Transaction()
284 {
285  if (m_transactionRunning) {
286  m_db.rollback();
287  }
288 }
289 
290 bool Sql::Transaction::transaction() const
291 {
292  return m_transactionRunning;
293 }
294 
295 bool Sql::Transaction::commit()
296 {
297  // In case we fail to commit we will still call rollback, not sure it's really needed
298  m_transactionRunning = !m_db.commit();
299  return !m_transactionRunning;
300 }
301 
302 bool Sql::Transaction::rollback()
303 {
304  m_transactionRunning = false;
305  return m_db.rollback();
306 }
Transaction(const QString &databaseName=QString())
Definition: sql.cpp:273
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8
QMultiMap< QString, QString > ParamsMultiMap