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.