File indexing completed on 2024-11-24 05:00:12
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 #ifndef COMMON_DATABASE_H 0008 #define COMMON_DATABASE_H 0009 0010 #include <QRegularExpression> 0011 #include <QSqlQuery> 0012 #include <memory> 0013 0014 namespace Common 0015 { 0016 class Database 0017 { 0018 public: 0019 typedef std::shared_ptr<Database> Ptr; 0020 0021 enum Source { 0022 ResourcesDatabase, 0023 }; 0024 0025 enum OpenMode { 0026 ReadWrite, 0027 ReadOnly, 0028 }; 0029 0030 static Ptr instance(Source source, OpenMode openMode); 0031 0032 QSqlQuery execQueries(const QStringList &queries) const; 0033 QSqlQuery execQuery(const QString &query) const; 0034 QSqlQuery createQuery() const; 0035 0036 void setPragma(const QString &pragma); 0037 QVariant pragma(const QString &pragma) const; 0038 QVariant value(const QString &query) const; 0039 0040 ~Database(); 0041 Database(); 0042 0043 friend class Locker; 0044 class Locker 0045 { 0046 public: 0047 Locker(Database &database); 0048 ~Locker(); 0049 0050 private: 0051 QSqlDatabase &m_database; 0052 }; 0053 0054 #define DATABASE_TRANSACTION(A) \ 0055 /* enable this for debugging only: qDebug() << "Location:" << __FILE__ << __LINE__; */ \ 0056 Common::Database::Locker lock(A) 0057 0058 private: 0059 class Private; 0060 std::unique_ptr<Private> d; 0061 }; 0062 0063 template<typename EscapeFunction> 0064 QString parseStarPattern(const QString &pattern, const QString &joker, EscapeFunction escape) 0065 { 0066 const auto begin = pattern.constBegin(); 0067 const auto end = pattern.constEnd(); 0068 0069 auto currentStart = pattern.constBegin(); 0070 auto currentPosition = pattern.constBegin(); 0071 0072 bool isEscaped = false; 0073 0074 // This should be available in the QString class... 0075 auto stringFromIterators = [&](const QString::const_iterator ¤tStart, const QString::const_iterator ¤tPosition) { 0076 return pattern.mid(std::distance(begin, currentStart), std::distance(currentStart, currentPosition)); 0077 }; 0078 0079 // Escaping % and _ for sql like 0080 // auto escape = [] (QString str) { 0081 // return str.replace("%", "\\%").replace("_", "\\_"); 0082 // }; 0083 0084 QString resultPattern; 0085 resultPattern.reserve(pattern.size() * 1.5); 0086 0087 for (; currentPosition != end; ++currentPosition) { 0088 if (isEscaped) { 0089 // Just skip the current character 0090 isEscaped = false; 0091 0092 } else if (*currentPosition == QLatin1Char('\\')) { 0093 // Skip two characters 0094 isEscaped = true; 0095 0096 } else if (*currentPosition == QLatin1Char('*')) { 0097 // Replacing the star with the sql like joker - % 0098 resultPattern.append(escape(stringFromIterators(currentStart, currentPosition)) + joker); 0099 currentStart = currentPosition + 1; 0100 0101 } else { 0102 // This one is boring, nothing to do 0103 } 0104 } 0105 0106 if (currentStart != currentPosition) { 0107 resultPattern.append(escape(stringFromIterators(currentStart, currentPosition))); 0108 } 0109 0110 return resultPattern; 0111 } 0112 0113 inline QString escapeSqliteLikePattern(QString pattern) 0114 { 0115 return pattern.replace(QLatin1String("%"), QLatin1String("\\%")) 0116 .replace(QLatin1String("_"), QLatin1String("\\_")) 0117 .replace(QLatin1String("'"), QLatin1String("\\'")); 0118 } 0119 0120 inline QString starPatternToLike(const QString &pattern) 0121 { 0122 return parseStarPattern(pattern, QStringLiteral("%"), escapeSqliteLikePattern); 0123 } 0124 0125 inline QRegularExpression starPatternToRegex(const QString &pattern) 0126 { 0127 const QString parsed = parseStarPattern(pattern, QStringLiteral(".*"), QOverload<const QString &>::of(&QRegularExpression::escape)); 0128 return QRegularExpression(QRegularExpression::anchoredPattern(parsed)); 0129 } 0130 0131 } // namespace Common 0132 0133 #endif // COMMON_DATABASE_H