Skip to content

Commit b9f8d6b

Browse files
committed
WIP
1 parent 05d733d commit b9f8d6b

File tree

14 files changed

+1666
-53
lines changed

14 files changed

+1666
-53
lines changed

lib/core/include/qx/core/qx-abstracterror.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ class QX_CORE_EXPORT IError
3333
static inline const QString T_NAME_DUPE = u"Error type name %1 is already claimed!"_s;
3434
static inline const QString T_CODE_RESERVED = u"Error type code %1 is reserved!"_s;
3535
static inline constinit QHash<quint16, const QString*> codeRegistry;
36-
static constexpr std::array<QStringView, 8> RESERVED_NAMES{
36+
static constexpr std::array<QStringView, 10> RESERVED_NAMES{
3737
u"Qx::InternalError",
3838
u"Qx::GenericError",
3939
u"Qx::IoOpReport",
4040
u"Qx::SystemError",
4141
u"Qx::DownloadManagerReport",
4242
u"Qx::DownloadOpReport",
4343
u"Qx::JsonError",
44-
u"QJsonParseError"
44+
u"QJsonParseError",
45+
u"Qx::SqlError",
46+
u"Qx::SqlSchemaReport",
4547
};
4648
// TODO: If this becomes sufficiently large, move to a constexpr set (hopefully available in std by that time)
4749

lib/sql/CMakeLists.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
#================= Add Component ==========================
22
qx_add_component("Sql"
33
HEADERS_API
4-
qx-common-sql.h
4+
qx-sqldatabase.h
5+
qx-sqlerror.h
6+
qx-sqlquery.h
7+
qx-sqlschemareport.h
8+
qx-sqlstring.h
59
IMPLEMENTATION
6-
qx-common-sql.cpp
10+
qx-sqldatabase.cpp
11+
qx-sqlerror.cpp
12+
qx-sqlquery.cpp
13+
qx-sqlstring.cpp
14+
qx-sqlschemareport.cpp
715
#DOC_ONLY
816
LINKS
917
PUBLIC

lib/sql/include/qx/sql/qx-common-sql.h

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#ifndef QX_SQLDATABASE_H
2+
#define QX_SQLDATABASE_H
3+
4+
// Shared Lib Support
5+
#include "qx/sql/qx_sql_export.h"
6+
7+
// Qt Includes
8+
#include <QSqlDatabase>
9+
#include <QReadWriteLock>
10+
#include <QUuid>
11+
12+
// Intra-component Includes
13+
#include "qx/sql/qx-sqlquery.h"
14+
#include "qx/sql/qx-sqlschemareport.h"
15+
16+
// Extra-component Includes
17+
18+
using namespace Qt::StringLiterals;
19+
20+
class QThread;
21+
22+
namespace Qx
23+
{
24+
25+
/* Careful use of the thread safe static functions of QSqlDatabase here allow us to avoid
26+
* needing our own lock and connection tracker, AND ensure that a lambda can be used to
27+
* handle connection closures due to thread-termination without having a potential dangling
28+
* reference to the this pointer in the capture, thereby avoiding the overhead of needing
29+
* to make this a QObject in order to disconnect when this is destroyed.
30+
*
31+
* This introduces a small amount of overhead, particularly when it comes to closing all
32+
* connections at destruction, but the added simplicity is worth it..
33+
*/
34+
35+
class QX_SQL_EXPORT SqlDatabase
36+
{
37+
//-Class Variables-----------------------------------------------------------------------------------------------
38+
private:
39+
static inline const QString ID_NAMESPACE = u"Qx::SqlDatabase"_s;
40+
41+
//-Instance Variables-----------------------------------------------------------------------------------------------
42+
private:
43+
// NOTE: These are not const to allow move semantics, but DO NOT write to them after construction, or else this
44+
// isn't thread safe.
45+
QString mDatabaseName; /* TODO: Have opt in ctor var for shared connections in the same thread; that is,
46+
* shared instances don't salt their pointer and reuse the same connection as long
47+
* as they're in the same thread, then non-shared instances (default) will only use
48+
* the same connection through the same instance, as is now. Perhaps specify this by
49+
* an optional connection name input that defaults to empty, which will cause this
50+
* class to use the db name as part of the connection name by default, then if the
51+
* connection name is different, that is used instead of the
52+
*/
53+
QString mDriver;
54+
QString mId;
55+
56+
//-Constructor-------------------------------------------------------------------------------------------------
57+
public:
58+
// TODO: Instead of passing only the driver and db name, allow passing a struct that holds those
59+
// and all of the stuff there are setters for in QSqlDatabase so that we can allow full customization
60+
// before/at construction time, but dont need to allow setting the values after and therefore don't need
61+
// our own mutex.
62+
explicit SqlDatabase(const QString& databaseName, const QString& driver);
63+
SqlDatabase(const SqlDatabase& other);
64+
SqlDatabase(SqlDatabase&& other);
65+
66+
//-Destructor-------------------------------------------------------------------------------------------------
67+
public:
68+
~SqlDatabase();
69+
70+
//-Class Functions------------------------------------------------------------------------------------------------------
71+
private:
72+
static QString connectionName(QStringView id, const QThread* thread);
73+
static bool closeConnection(const QString& connectionName);
74+
static bool closeConnection(QStringView id, const QThread* thread);
75+
76+
//-Instance Functions------------------------------------------------------------------------------------------------------
77+
private:
78+
void closeAllConnections();
79+
QString connectionName(const QThread* thread) const;
80+
81+
public:
82+
SqlError database(QSqlDatabase& db, bool connect = true);
83+
SqlError connect();
84+
QString driver() const;
85+
QString databaseName() const;
86+
bool isConnected() const;
87+
bool closeConnection();
88+
89+
template<QxSql::sql_struct First, QxSql::sql_struct... Rest>
90+
SqlError checkSchema(SqlSchemaReport& report, bool strict = false)
91+
{
92+
QSqlDatabase db;
93+
if(auto err = database(db))
94+
return err;
95+
96+
report = SqlSchemaReport::generate<First, Rest...>(db, strict);
97+
return SqlError();
98+
}
99+
100+
// SQL
101+
template<sql_string First, sql_string ...Rest>
102+
SqlDqlQuery SELECT(First&& fs, Rest&&... s)
103+
{
104+
SqlDqlQuery q(*this);
105+
q.SELECT(std::forward<First>(fs), std::forward(s)...);
106+
return q;
107+
}
108+
109+
template<QxSql::sql_struct First, QxSql::sql_struct... Rest>
110+
SqlDqlQuery SELECT()
111+
{
112+
SqlDqlQuery q(*this);
113+
q.SELECT<First, Rest...>();
114+
return q;
115+
}
116+
117+
template<sql_string First, sql_string ...Rest>
118+
SqlDqlQuery SELECT_DISTINCT(First&& fs, Rest&&... s)
119+
{
120+
SqlDqlQuery q(*this);
121+
q.SELECT_DISTINCT(std::forward<First>(fs), std::forward(s)...);
122+
return q;
123+
}
124+
125+
template<QxSql::sql_struct First, QxSql::sql_struct... Rest>
126+
SqlDqlQuery SELECT_DISTINCT()
127+
{
128+
SqlDqlQuery q(*this);
129+
q.SELECT<First, Rest...>();
130+
return q;
131+
}
132+
133+
//-Operators------------------------------------------------------------------------------------------------------
134+
public:
135+
SqlDatabase& operator=(const SqlDatabase& other);
136+
SqlDatabase& operator=(SqlDatabase&& other);
137+
};
138+
139+
}
140+
141+
#endif // QX_SQLDATABASE_H
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#ifndef QX_SQLERROR_H
2+
#define QX_SQLERROR_H
3+
4+
// Shared Lib Support
5+
#include "qx/sql/qx_sql_export.h"
6+
7+
// Extra-component Includes
8+
#include "qx/core/qx-abstracterror.h"
9+
10+
class QSqlError;
11+
12+
namespace QxSqlPrivate {template<typename T> struct FieldMatchChecker; }
13+
14+
namespace Qx
15+
{
16+
17+
class SqlQuery;
18+
class SqlDatabase;
19+
20+
class QX_SQL_EXPORT SqlError final : public AbstractError<"Qx::SqlError", 7>
21+
{
22+
template<typename T>
23+
friend struct QxSqlPrivate::FieldMatchChecker;
24+
//-Class Enums-------------------------------------------------------------
25+
public:
26+
enum Form
27+
{
28+
NoError,
29+
EngineError,
30+
TypeMismatch,
31+
MissingField
32+
};
33+
34+
//-Class Variables-------------------------------------------------------------
35+
private:
36+
static inline const QHash<Form, QString> ERR_STRINGS{
37+
{NoError, u"No error occurred."_s},
38+
{EngineError, u"Engine error."_s},
39+
{TypeMismatch, u"A field value did not match the expected type."_s},
40+
{MissingField, u"An expected field is missing."_s},
41+
};
42+
static inline const QString DATABASE_INFO_TEMPLATE =
43+
u"Connected: %1\n"_s
44+
u"Database Name: %2\n"_s
45+
u"Driver: %3"_s;
46+
47+
//-Instance Variables-------------------------------------------------------------
48+
private:
49+
Form mForm;
50+
QString mCause;
51+
QString mQuery;
52+
QString mDatabase;
53+
54+
//-Constructor---------------------------------------------------------------------
55+
private:
56+
SqlError(const QString& fromType, const QString& toType, const QString& field = {}); // Convenience for TypeMismatch
57+
58+
public:
59+
SqlError();
60+
SqlError(Form f, const QString& c);
61+
SqlError(const QSqlError& engineError);
62+
63+
//-Instance Functions-------------------------------------------------------------
64+
private:
65+
quint32 deriveValue() const override;
66+
QString derivePrimary() const override;
67+
QString deriveSecondary() const override;
68+
QString deriveDetails() const override;
69+
70+
public:
71+
bool isValid() const;
72+
Form form() const;
73+
QString cause() const;
74+
QString query() const;
75+
QString databaseInfo() const;
76+
77+
SqlError& withQuery(const SqlQuery& q); // Auto-adds database
78+
SqlError& withQuery(const QString& q);
79+
SqlError& withDatabase(const SqlDatabase& db);
80+
};
81+
82+
}
83+
84+
#endif // QX_SQLERROR_H

0 commit comments

Comments
 (0)