File indexing completed on 2024-05-26 05:30:52
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #pragma once 0008 0009 #include <QObject> 0010 #include <QRegularExpression> 0011 #include <QSqlQuery> 0012 #include <memory> 0013 #include <utils/d_ptr.h> 0014 0015 namespace Common 0016 { 0017 class Database : public QObject 0018 { 0019 Q_OBJECT 0020 0021 public: 0022 typedef std::shared_ptr<Database> Ptr; 0023 0024 enum Source { 0025 ResourcesDatabase, 0026 }; 0027 0028 enum OpenMode { 0029 ReadWrite, 0030 ReadOnly, 0031 }; 0032 0033 static Ptr instance(Source source, OpenMode openMode); 0034 0035 QSqlQuery execQueries(const QStringList &queries) const; 0036 QSqlQuery execQuery(const QString &query, bool ignoreErrors = false) const; 0037 QSqlQuery createQuery() const; 0038 0039 void setPragma(const QString &pragma); 0040 QVariant pragma(const QString &pragma) const; 0041 QVariant value(const QString &query) const; 0042 0043 // For debugging purposes only 0044 QString lastQuery() const; 0045 0046 ~Database() override; 0047 Database(); 0048 0049 friend class Locker; 0050 class Locker 0051 { 0052 public: 0053 explicit Locker(Database &database); 0054 ~Locker(); 0055 0056 private: 0057 QSqlDatabase &m_database; 0058 }; 0059 0060 void reportError(const QSqlError &error); 0061 0062 #define DATABASE_TRANSACTION(A) \ 0063 /* enable this for debugging only: qCDebug(KAMD_LOG_RESOURCES) << "Location:" << __FILE__ << __LINE__; */ \ 0064 Common::Database::Locker lock(A) 0065 0066 Q_SIGNALS: 0067 void error(const QSqlError &error) const; 0068 0069 private: 0070 D_PTR; 0071 }; 0072 0073 template<typename EscapeFunction> 0074 QString parseStarPattern(const QString &pattern, const QString &joker, EscapeFunction escape) 0075 { 0076 const auto begin = pattern.constBegin(); 0077 const auto end = pattern.constEnd(); 0078 0079 auto currentStart = pattern.constBegin(); 0080 auto currentPosition = pattern.constBegin(); 0081 0082 bool isEscaped = false; 0083 0084 // This should be available in the QString class... 0085 auto stringFromIterators = [&](const QString::const_iterator ¤tStart, const QString::const_iterator ¤tPosition) { 0086 return pattern.mid(std::distance(begin, currentStart), std::distance(currentStart, currentPosition)); 0087 }; 0088 0089 // Escaping % and _ for sql like 0090 // auto escape = [] (QString str) { 0091 // return str.replace("%", "\\%").replace("_", "\\_"); 0092 // }; 0093 0094 QString resultPattern; 0095 resultPattern.reserve(pattern.size() * 1.5); 0096 0097 for (; currentPosition != end; ++currentPosition) { 0098 if (isEscaped) { 0099 // Just skip the current character 0100 isEscaped = false; 0101 0102 } else if (*currentPosition == QLatin1Char('\\')) { 0103 // Skip two characters 0104 isEscaped = true; 0105 0106 } else if (*currentPosition == QLatin1Char('*')) { 0107 // Replacing the star with the sql like joker - % 0108 resultPattern.append(escape(stringFromIterators(currentStart, currentPosition)) + joker); 0109 currentStart = currentPosition + 1; 0110 0111 } else { 0112 // This one is boring, nothing to do 0113 } 0114 } 0115 0116 if (currentStart != currentPosition) { 0117 resultPattern.append(escape(stringFromIterators(currentStart, currentPosition))); 0118 } 0119 0120 return resultPattern; 0121 } 0122 0123 inline QString escapeSqliteLikePattern(QString pattern) 0124 { 0125 return pattern.replace(QLatin1String("%"), QLatin1String("\\%")).replace(QLatin1String("_"), QLatin1String("\\_")); 0126 } 0127 0128 inline QString starPatternToLike(const QString &pattern) 0129 { 0130 return parseStarPattern(pattern, QStringLiteral("%"), escapeSqliteLikePattern); 0131 } 0132 0133 inline QRegularExpression starPatternToRegex(const QString &pattern) 0134 { 0135 return QRegularExpression(parseStarPattern(pattern, QStringLiteral(".*"), [](QString pattern) { return QRegularExpression::escape(QRegularExpression::anchoredPattern(pattern)); })); 0136 } 0137 0138 } // namespace Common