1#ifndef QX_SQLSCHEMAREPORT_H 
    2#define QX_SQLSCHEMAREPORT_H 
    5#include "qx/sql/qx_sql_export.h" 
   14#include "qx/sql/qx-sqlerror.h" 
   28class QX_SQL_EXPORT SqlSchemaReport final : 
public AbstractError<"Qx::SqlSchemaReport", 8>
 
   30    friend class SqlDatabase;
 
   42    Q_DECLARE_FLAGS(Defects, Defect);
 
   52    Q_DECLARE_FLAGS(StrictnessFlags, Strictness);
 
   58    struct unwrap_optional { 
using type = T; };
 
   61    struct unwrap_optional<std::optional<U>> { 
using type = U; };
 
   64    using unwrap_optional_t = 
typename unwrap_optional<T>::type;
 
   71        QLatin1String expected;
 
   79        QStringList missingFields{};
 
   80        QStringList extraFields{};
 
   81        QList<FieldMismatch> mismatchedFields{};
 
   86    static inline const QString PRIMARY = u
"SQL Error."_s;
 
   87    static inline const QString SECONDARY = u
"The database does not follow the expected schema."_s;
 
   93    QList<DefectiveTable> mDefTables;
 
  101    static void addDefect(SqlSchemaReport& rp, DefectiveTable& table, Defect defect);
 
  103    template<QxSql::sql_struct... Structs>
 
  104    static SqlSchemaReport generate(QSqlDatabase& db, StrictnessFlags strictness)
 
  106        Q_ASSERT(db.isValid() && db.isOpen());
 
  110        QStringList allTables = db.tables(QSql::Tables);
 
  115            constexpr auto tableView = QxSqlPrivate::getStructId<Structs>().view();
 
  116            constexpr auto tableViewQuoted = QxSqlPrivate::getStructIdQuoted<Structs>().view();
 
  117            const QString table(tableView);
 
  118            const QString tableQuoted(tableViewQuoted);
 
  119            const QSqlRecord tableRecord = db.record(tableQuoted); 
 
  122            DefectiveTable tableDefects{.name = table};
 
  125            if(!tableRecord.isEmpty())
 
  128                allTables.removeAll(table);
 
  131                constexpr auto memberMetas = QxSqlPrivate::getMemberMeta<Structs>();
 
  132                QStringList allFields;
 
  133                for(
auto i = 0; i < tableRecord.count(); ++i)
 
  134                    allFields.append(tableRecord.fieldName(i));
 
  137                std::apply([&](
auto&&... memberMeta) 
constexpr {
 
  140                        static constexpr auto memNameRaw = std::remove_reference_t<
decltype(memberMeta)>::M_NAME;
 
  141                        constexpr QLatin1StringView memName(memNameRaw);
 
  142                        using memType = 
typename std::remove_reference_t<
decltype(memberMeta)>::M_TYPE;
 
  143                        const QSqlField field = tableRecord.field(memName);
 
  149                            allFields.removeAll(memName.toString());
 
  152                            QMetaType expectedCppType = QMetaType::fromType<unwrap_optional_t<memType>>();
 
  153                            QMetaType actualCppType = field.metaType();
 
  155                            bool strict = strictness.testFlag(TypeStrict);
 
  156                            if((strict && (actualCppType != expectedCppType)) ||
 
  157                               (!strict && (!QMetaType::canConvert(actualCppType, expectedCppType))))
 
  158                                addDefect(rp, tableDefects, TypeMismatches);
 
  160                        else if constexpr(!QxSql::sql_optional<memType>)
 
  162                            addDefect(rp, tableDefects, MissingFields);
 
  163                            tableDefects.missingFields.append(memName);
 
  167                        if(strictness.testFlag(FieldStrict) && !allFields.isEmpty())
 
  169                            addDefect(rp, tableDefects, ExtraFields);
 
  170                            tableDefects.extraFields.append(allFields);
 
  176                addDefect(rp, tableDefects, MissingTables);
 
  179            if(tableDefects.defects != None)
 
  180                rp.mDefTables.append(tableDefects);
 
  184        if(strictness.testFlag(TableStrict))
 
  186            for(
const QString& tb : std::as_const(allTables))
 
  188                DefectiveTable dt{.name = tb};
 
  189                addDefect(rp, dt, ExtraTables);
 
  190                rp.mDefTables.append(dt);
 
  199    quint32 deriveValue() 
const override;
 
  200    QString derivePrimary() 
const override;
 
  201    QString deriveSecondary() 
const override;
 
  202    QString deriveDetails() 
const override;
 
  205    bool hasDefects() 
const;
 
  206    Defects defects() 
const;
 
  207    QList<DefectiveTable> defectList() 
const;
 
  208    QString database() 
const;
 
  210Q_DECLARE_OPERATORS_FOR_FLAGS(SqlSchemaReport::Defects);
 
  211Q_DECLARE_OPERATORS_FOR_FLAGS(SqlSchemaReport::StrictnessFlags);
 
The AbstractError template class completes the Error interface and acts as the base class from which ...
Definition qx-abstracterror.h:88
 
The SqlDatabase class provides straightforward access to an SQL database.
Definition qx-sqldatabase.h:36
 
SqlQuery is a base class from which all query types derive.
Definition qx-sqlquery.h:171
 
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-abstracterror.cpp:13
 
The qx-abstracterror.h header file provides access to the base class from which custom error types sh...
 
The qx-sql header file offers a straightforward interface for querying an SQL database.