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 &currentStart, const QString::const_iterator &currentPosition) {
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