File indexing completed on 2025-01-05 04:46:57
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org> * 0003 * * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later * 0005 ***************************************************************************/ 0006 0007 #pragma once 0008 0009 #include "dbintrospector.h" 0010 #include "schematypes.h" 0011 0012 #include <QHash> 0013 #include <QSharedPointer> 0014 #include <QSqlDatabase> 0015 #include <QStringList> 0016 0017 class DbInitializerTest; 0018 0019 namespace Akonadi 0020 { 0021 namespace Server 0022 { 0023 class Schema; 0024 class DbUpdater; 0025 0026 class TestInterface 0027 { 0028 public: 0029 virtual ~TestInterface() = default; 0030 0031 virtual void execStatement(const QString &statement) = 0; 0032 0033 protected: 0034 explicit TestInterface() = default; 0035 0036 private: 0037 Q_DISABLE_COPY_MOVE(TestInterface) 0038 }; 0039 0040 /** 0041 * A helper class which takes a reference to a database object and 0042 * the file name of a template file and initializes the database 0043 * according to the rules in the template file. 0044 * 0045 * TODO: Refactor this to be easily reusable for updater too 0046 */ 0047 class DbInitializer 0048 { 0049 friend class DbUpdater; 0050 0051 public: 0052 using Ptr = QSharedPointer<DbInitializer>; 0053 0054 /** 0055 Returns an initializer instance for a given backend. 0056 */ 0057 static DbInitializer::Ptr createInstance(const QSqlDatabase &database, Schema *schema = nullptr); 0058 0059 /** 0060 * Destroys the database initializer. 0061 */ 0062 virtual ~DbInitializer(); 0063 0064 /** 0065 * Starts the initialization process. 0066 * On success true is returned, false otherwise. 0067 * 0068 * If something went wrong @see errorMsg() can be used to retrieve more 0069 * information. 0070 */ 0071 bool run(); 0072 0073 /** 0074 * Returns the textual description of an occurred error. 0075 */ 0076 QString errorMsg() const; 0077 0078 /** 0079 * Checks and creates missing indexes. 0080 * 0081 * This method is run after DbUpdater to ensure that data in new columns 0082 * are populated and creation of indexes and foreign keys does not fail. 0083 */ 0084 bool updateIndexesAndConstraints(); 0085 0086 /** 0087 * Returns a backend-specific CREATE TABLE SQL query describing given table 0088 */ 0089 virtual QString buildCreateTableStatement(const TableDescription &tableDescription) const = 0; 0090 0091 protected: 0092 /** 0093 * Creates a new database initializer. 0094 * 0095 * @param database The reference to the database. 0096 */ 0097 DbInitializer(const QSqlDatabase &database); 0098 0099 /** 0100 * Overwrite in backend-specific sub-classes to return the SQL type for a given C++ type. 0101 * @param type Name of the C++ type. 0102 * @param size Optional size hint for the column, if -1 use the default SQL type for @p type. 0103 */ 0104 virtual QString sqlType(const ColumnDescription &col, int size) const; 0105 /** Overwrite in backend-specific sub-classes to return the SQL value for a given C++ value. */ 0106 virtual QString sqlValue(const ColumnDescription &col, const QString &value) const; 0107 0108 virtual QString buildColumnStatement(const ColumnDescription &columnDescription, const TableDescription &tableDescription) const = 0; 0109 virtual QString buildAddColumnStatement(const TableDescription &tableDescription, const ColumnDescription &columnDescription) const; 0110 virtual QString buildCreateIndexStatement(const TableDescription &tableDescription, const IndexDescription &indexDescription) const; 0111 virtual QString buildInsertValuesStatement(const TableDescription &tableDescription, const DataDescription &dataDescription) const = 0; 0112 0113 /** 0114 * Returns an SQL statements to add a foreign key constraint to an existing column @p column. 0115 * The default implementation returns an empty string, so any backend supporting foreign key constraints 0116 * must reimplement this. 0117 */ 0118 virtual QStringList buildAddForeignKeyConstraintStatements(const TableDescription &table, const ColumnDescription &column) const; 0119 0120 /** 0121 * Returns an SQL statements to remove the foreign key constraint @p fk from table @p table. 0122 * The default implementation returns an empty string, so any backend supporting foreign key constraints 0123 * must reimplement this. 0124 */ 0125 virtual QStringList buildRemoveForeignKeyConstraintStatements(const DbIntrospector::ForeignKey &fk, const TableDescription &table) const; 0126 0127 static QString buildReferentialAction(ColumnDescription::ReferentialAction onUpdate, ColumnDescription::ReferentialAction onDelete); 0128 /// Use for multi-column primary keys during table creation 0129 static QString buildPrimaryKeyStatement(const TableDescription &table); 0130 0131 private: 0132 friend class ::DbInitializerTest; 0133 Q_DISABLE_COPY_MOVE(DbInitializer) 0134 0135 /** 0136 * Sets the debug @p interface that shall be used on unit test run. 0137 */ 0138 void setTestInterface(TestInterface *interface); 0139 0140 /** 0141 * Sets a different DbIntrospector. This allows unit tests to simulate certain 0142 * states of the database. 0143 */ 0144 void setIntrospector(const DbIntrospector::Ptr &introspector); 0145 0146 /** Helper method for executing a query. 0147 * If a debug interface is set for testing, that gets the queries instead. 0148 * @throws DbException if something went wrong. 0149 */ 0150 void execQuery(const QString &queryString); 0151 0152 bool checkTable(const TableDescription &tableDescription); 0153 /** 0154 * Checks foreign key constraints on table @p tableDescription and fixes them if necessary. 0155 */ 0156 void checkForeignKeys(const TableDescription &tableDescription); 0157 void checkIndexes(const TableDescription &tableDescription); 0158 bool checkRelation(const RelationDescription &relationDescription); 0159 0160 static QString referentialActionToString(ColumnDescription::ReferentialAction action); 0161 0162 void execPendingQueries(const QStringList &queries); 0163 0164 QSqlDatabase mDatabase; 0165 Schema *mSchema = nullptr; 0166 QString mErrorMsg; 0167 TestInterface *mTestInterface = nullptr; 0168 DbIntrospector::Ptr m_introspector; 0169 QStringList m_pendingIndexes; 0170 QStringList m_pendingForeignKeys; 0171 QStringList m_removedForeignKeys; 0172 }; 0173 0174 } // namespace Server 0175 } // namespace Akonadi