forked from ondra/server-sdk
Adding database Table class for automated handling tables
This commit is contained in:
parent
b04332059f
commit
d98ddf6c5f
@ -26,6 +26,7 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$SDKDIR/debug/ -lserversdk
|
|||||||
else:unix: LIBS += -L$$SDKDIR/ -lserversdk -lz
|
else:unix: LIBS += -L$$SDKDIR/ -lserversdk -lz
|
||||||
|
|
||||||
QT += network sql
|
QT += network sql
|
||||||
|
CONFIG += c++14
|
||||||
INCLUDEPATH += $$PWD/src/
|
INCLUDEPATH += $$PWD/src/
|
||||||
DEPENDPATH += $$PWD/src/serversdk
|
DEPENDPATH += $$PWD/src/serversdk
|
||||||
|
|
||||||
|
|||||||
61
src/serversdk/databasetable.cpp
Normal file
61
src/serversdk/databasetable.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "databasetable.h"
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <QMetaProperty>
|
||||||
|
|
||||||
|
namespace serversdk {
|
||||||
|
|
||||||
|
DatabaseTable::DatabaseTable(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Creates universal variant structure to hold key / value pairs */
|
||||||
|
QVariantMap DatabaseTable::toVariantMap()
|
||||||
|
{
|
||||||
|
QVariantMap variantMap;
|
||||||
|
|
||||||
|
const QMetaObject *metaObj = this->metaObject();
|
||||||
|
qDebug() << "properties: ";
|
||||||
|
for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
|
||||||
|
QMetaProperty prop = metaObj->property(i);
|
||||||
|
// Skip non USER so -> ( Q_PROPERTY( ...... USER false ) only
|
||||||
|
if (!prop.isUser())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get key -> value pairs
|
||||||
|
QString name = prop.name();
|
||||||
|
QVariant::Type type = prop.type();
|
||||||
|
QVariant value(type);
|
||||||
|
value.setValue(prop.read(this));
|
||||||
|
|
||||||
|
variantMap.insert(name, value);
|
||||||
|
}
|
||||||
|
return variantMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DatabaseTable::createTableSQL() const
|
||||||
|
{
|
||||||
|
QString sql = QString("CREATE TABLE %1").arg(this->metaObject()->className());
|
||||||
|
|
||||||
|
QVariantMap variantMap;
|
||||||
|
|
||||||
|
const QMetaObject *metaObj = this->metaObject();
|
||||||
|
qDebug() << "properties: ";
|
||||||
|
for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
|
||||||
|
QMetaProperty prop = metaObj->property(i);
|
||||||
|
// Skip non USER so -> ( Q_PROPERTY( ...... USER false ) only
|
||||||
|
if (!prop.isUser())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QString name = prop.name();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace serversdk
|
||||||
40
src/serversdk/databasetable.h
Normal file
40
src/serversdk/databasetable.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
|
||||||
|
// Default TABLE_PROPERTY
|
||||||
|
#define TABLE_PROPERTY(TYPE, NAME, SETNAME, INITVAL) \
|
||||||
|
Q_PROPERTY(TYPE NAME READ NAME WRITE SETNAME NOTIFY NAME ## Changed USER true) \
|
||||||
|
public: \
|
||||||
|
TYPE NAME() const { return a_ ## NAME ; } \
|
||||||
|
Q_SLOT void SETNAME(TYPE value) { \
|
||||||
|
if (a_ ## NAME == value) return; \
|
||||||
|
a_ ## NAME = value; \
|
||||||
|
emit NAME ## Changed(value); \
|
||||||
|
} \
|
||||||
|
Q_SIGNAL void NAME ## Changed(TYPE value);\
|
||||||
|
protected: \
|
||||||
|
TYPE a_ ## NAME = INITVAL;
|
||||||
|
|
||||||
|
namespace serversdk {
|
||||||
|
|
||||||
|
class DatabaseTable : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
TABLE_PROPERTY(int, id, setId, 0);
|
||||||
|
TABLE_PROPERTY(QString, name, setName, QString());
|
||||||
|
public:
|
||||||
|
explicit DatabaseTable(QObject *parent = nullptr);
|
||||||
|
QVariantMap toVariantMap();
|
||||||
|
QString createTableSQL() const;
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace serversdk
|
||||||
|
|
||||||
134
src/serversdk/databaseutils.cpp
Normal file
134
src/serversdk/databaseutils.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include "databaseutils.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <QMetaProperty>
|
||||||
|
|
||||||
|
namespace serversdk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DatabaseUtils::createTableSQL
|
||||||
|
* @param table
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @code{sql}
|
||||||
|
* "CREATE TABLE colnod_subject ("
|
||||||
|
"id character(36) primary key NOT NULL,"
|
||||||
|
"description character varying(255),"
|
||||||
|
"last_update timestamp NOT NULL,"
|
||||||
|
"name character varying(255),"
|
||||||
|
"pin character varying(255),"
|
||||||
|
"last_modified timestamp,"
|
||||||
|
"deleted BOOLEAN)"
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Default types:
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseUtils::DatabaseUtils(const QString type)
|
||||||
|
: mSqlType(type)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DatabaseUtils::createTableSQL(const DatabaseTable *table, const QString tableName) const
|
||||||
|
{
|
||||||
|
QString userData;
|
||||||
|
|
||||||
|
if (tableName.isEmpty())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
// out: "CREATE TABLE colnod_subject ( "
|
||||||
|
QString sql = QString("CREATE TABLE %1 ( ").arg(tableName);
|
||||||
|
|
||||||
|
const QMetaObject *metaObj = table->metaObject();
|
||||||
|
int total = metaObj->propertyCount();
|
||||||
|
int first = true;
|
||||||
|
for (int i = metaObj->propertyOffset(); i < total; ++i) {
|
||||||
|
QMetaProperty prop = metaObj->property(i);
|
||||||
|
// Skip non USER so -> ( Q_PROPERTY( ...... USER false ) only
|
||||||
|
if (!prop.isUser())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QString name = prop.name();
|
||||||
|
QVariant::Type type = prop.type();
|
||||||
|
QString textType;
|
||||||
|
|
||||||
|
|
||||||
|
// Getting correct type based on QVariant
|
||||||
|
if (sqlType() == "SQLITE") {
|
||||||
|
textType = this->textSQLIteType(type);
|
||||||
|
} else if (sqlType() == "PSQL") {
|
||||||
|
qCDebug(sdkdb) << "Implemented only for SQLITE";
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qCDebug(sdkdb) << "Implemented only for SQLITE";
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// in: id TEXT
|
||||||
|
// out: "CREATE TABLE colnod_subject ( id TEXT "
|
||||||
|
sql += QString("%1 %2").arg(name,textType);
|
||||||
|
|
||||||
|
// in: PRIMARY KEY
|
||||||
|
// out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY"
|
||||||
|
if (first) { // first row
|
||||||
|
sql += " PRIMARY KEY";
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in: NOT NULL
|
||||||
|
// out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY NOT NULL"
|
||||||
|
if (!userData.isEmpty()) {
|
||||||
|
sql += " " + userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY NOT NULL,"
|
||||||
|
if (i < (total-1)) { // second last
|
||||||
|
sql += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// out: ".. subject_id TEXT)"
|
||||||
|
sql+= " )";
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DatabaseUtils::sqlType() const
|
||||||
|
{
|
||||||
|
return mSqlType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseUtils::setSqlType(const QString &sqlType)
|
||||||
|
{
|
||||||
|
mSqlType = sqlType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DatabaseUtils::textSQLIteType(QVariant::Type type) const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case QVariant::Int:
|
||||||
|
return QStringLiteral("INTEGER");
|
||||||
|
break;
|
||||||
|
case QVariant::Uuid:
|
||||||
|
return QStringLiteral("TEXT");
|
||||||
|
break;
|
||||||
|
case QVariant::String:
|
||||||
|
return QStringLiteral("TEXT");
|
||||||
|
break;
|
||||||
|
case QVariant::DateTime:
|
||||||
|
return QStringLiteral("INTEGER");
|
||||||
|
break;
|
||||||
|
case QVariant::Bool:
|
||||||
|
return QStringLiteral("INTEGER");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return QString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace serversdk
|
||||||
26
src/serversdk/databaseutils.h
Normal file
26
src/serversdk/databaseutils.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "databasetable.h"
|
||||||
|
|
||||||
|
namespace serversdk {
|
||||||
|
|
||||||
|
class DatabaseUtils : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DatabaseUtils(const QString type = "SQLITE");
|
||||||
|
QString createTableSQL(const DatabaseTable *table, const QString table_name) const;
|
||||||
|
|
||||||
|
QString sqlType() const;
|
||||||
|
void setSqlType(const QString &sqlType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString textSQLIteType(QVariant::Type type) const;
|
||||||
|
private:
|
||||||
|
QString mSqlType;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace serversdk
|
||||||
|
|
||||||
@ -8,21 +8,25 @@ CONFIG += c++14
|
|||||||
INCLUDEPATH += $$PWD
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/core.cpp \
|
core.cpp \
|
||||||
$$PWD/databasemanager.cpp \
|
databasemanager.cpp \
|
||||||
$$PWD/logger.cpp \
|
databaseutils.cpp \
|
||||||
$$PWD/loggermessage.cpp \
|
logger.cpp \
|
||||||
$$PWD/requestmanager.cpp \
|
loggermessage.cpp \
|
||||||
$$PWD/request.cpp \
|
requestmanager.cpp \
|
||||||
$$PWD/utils.cpp \
|
request.cpp \
|
||||||
$$PWD/soaprequest.cpp
|
utils.cpp \
|
||||||
|
soaprequest.cpp \
|
||||||
|
databasetable.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/core.h \
|
core.h \
|
||||||
$$PWD/databasemanager.h \
|
databasemanager.h \
|
||||||
$$PWD/logger.h \
|
databaseutils.h \
|
||||||
$$PWD/loggermessage.h \
|
logger.h \
|
||||||
$$PWD/requestmanager.h \
|
loggermessage.h \
|
||||||
$$PWD/request.h \
|
requestmanager.h \
|
||||||
$$PWD/utils.h \
|
request.h \
|
||||||
$$PWD/soaprequest.h
|
utils.h \
|
||||||
|
soaprequest.h \
|
||||||
|
databasetable.h
|
||||||
|
|||||||
@ -3,6 +3,8 @@ TEMPLATE = subdirs
|
|||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
tst_soap \
|
tst_soap \
|
||||||
tst_request \
|
tst_request \
|
||||||
tst_database/tst_database.pro \
|
database/tst_databasemanager.pro \
|
||||||
tst_database/tst_sqlite.pro \
|
database/tst_sqlite.pro \
|
||||||
|
database/tst_databasetable.pro \
|
||||||
|
database/tst_databaseutils.pro \
|
||||||
tst_utils
|
tst_utils
|
||||||
|
|||||||
@ -33,4 +33,4 @@ void DatabaseTest::createDb_test()
|
|||||||
|
|
||||||
QTEST_APPLESS_MAIN(DatabaseTest)
|
QTEST_APPLESS_MAIN(DatabaseTest)
|
||||||
|
|
||||||
#include "tst_databasetest.moc"
|
#include "tst_databasemanager.moc"
|
||||||
11
test/auto/database/tst_databasemanager.pro
Normal file
11
test/auto/database/tst_databasemanager.pro
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
QT += testlib
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
CONFIG += qt console warn_on depend_includepath testcase
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
SOURCES += tst_databasemanager.cpp
|
||||||
|
|
||||||
|
include(../../test.pri)
|
||||||
54
test/auto/database/tst_databasetable.cpp
Normal file
54
test/auto/database/tst_databasetable.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "serversdk/databasetable.h"
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
|
||||||
|
class BookTable : public serversdk::DatabaseTable
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
TABLE_PROPERTY(QUuid, uuid, setUuid, QUuid());
|
||||||
|
TABLE_PROPERTY(int, id, setId, 0);
|
||||||
|
TABLE_PROPERTY(QString, name, setName, "Test");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseTableTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DatabaseTableTest();
|
||||||
|
~DatabaseTableTest();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void constructor_test();
|
||||||
|
void qvariant_test();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DatabaseTableTest::DatabaseTableTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseTableTest::~DatabaseTableTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseTableTest::constructor_test()
|
||||||
|
{
|
||||||
|
auto table = std::make_unique<BookTable>();
|
||||||
|
QCOMPARE(table->id(), 0);
|
||||||
|
QCOMPARE(table->name(), QStringLiteral("Test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseTableTest::qvariant_test()
|
||||||
|
{
|
||||||
|
auto table = std::make_unique<BookTable>();
|
||||||
|
QVariantMap map = table->toVariantMap();
|
||||||
|
QCOMPARE(map.count(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(DatabaseTableTest)
|
||||||
|
|
||||||
|
#include "tst_databasetable.moc"
|
||||||
@ -6,6 +6,6 @@ CONFIG -= app_bundle
|
|||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
SOURCES += tst_databasetest.cpp
|
SOURCES += tst_databasetable.cpp
|
||||||
|
|
||||||
include(../../test.pri)
|
include(../../test.pri)
|
||||||
68
test/auto/database/tst_databaseutils.cpp
Normal file
68
test/auto/database/tst_databaseutils.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "serversdk/databaseutils.h"
|
||||||
|
#include "serversdk/databasetable.h"
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
|
||||||
|
class BookTable : public serversdk::DatabaseTable
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_CLASSINFO("default_table", "books")
|
||||||
|
TABLE_PROPERTY(QUuid, id, set_id, QUuid());
|
||||||
|
TABLE_PROPERTY(QString, description, set_description, "");
|
||||||
|
TABLE_PROPERTY(QDateTime, last_update, set_last_update, QDateTime::fromSecsSinceEpoch(0));
|
||||||
|
TABLE_PROPERTY(QString, name, set_name, QString());
|
||||||
|
TABLE_PROPERTY(QString, pin, set_pin, QString());
|
||||||
|
TABLE_PROPERTY(QDateTime, last_modified, set_last_modified, QDateTime::fromSecsSinceEpoch(0));
|
||||||
|
TABLE_PROPERTY(bool, deleted, set_deleted, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseUtilsTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DatabaseUtilsTest();
|
||||||
|
~DatabaseUtilsTest();
|
||||||
|
QString uuid() const;
|
||||||
|
void setUuid(QString value);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void createTable_test();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DatabaseUtilsTest::DatabaseUtilsTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseUtilsTest::~DatabaseUtilsTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseUtilsTest::createTable_test()
|
||||||
|
{
|
||||||
|
auto table = std::make_unique<BookTable>();
|
||||||
|
|
||||||
|
serversdk::DatabaseUtils utils;
|
||||||
|
QString sql = utils.createTableSQL(table.get(), "subjects");
|
||||||
|
|
||||||
|
QString expected = "CREATE TABLE subjects ( "
|
||||||
|
"id TEXT PRIMARY KEY, "
|
||||||
|
"description TEXT, "
|
||||||
|
"last_update INTEGER, "
|
||||||
|
"name TEXT, "
|
||||||
|
"pin TEXT, "
|
||||||
|
"last_modified INTEGER, "
|
||||||
|
"deleted INTEGER )";
|
||||||
|
|
||||||
|
QCOMPARE(sql, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(DatabaseUtilsTest)
|
||||||
|
|
||||||
|
#include "tst_databaseutils.moc"
|
||||||
11
test/auto/database/tst_databaseutils.pro
Normal file
11
test/auto/database/tst_databaseutils.pro
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
QT += testlib
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
CONFIG += qt console warn_on depend_includepath testcase
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
SOURCES += tst_databaseutils.cpp
|
||||||
|
|
||||||
|
include(../../test.pri)
|
||||||
Loading…
x
Reference in New Issue
Block a user