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