Adding database Table class for automated handling tables

This commit is contained in:
Filip Bucek 2019-11-11 18:04:56 +01:00
parent b04332059f
commit d98ddf6c5f
15 changed files with 432 additions and 20 deletions

View File

@ -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

View 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

View 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

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -33,4 +33,4 @@ void DatabaseTest::createDb_test()
QTEST_APPLESS_MAIN(DatabaseTest) QTEST_APPLESS_MAIN(DatabaseTest)
#include "tst_databasetest.moc" #include "tst_databasemanager.moc"

View 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)

View 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"

View File

@ -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)

View 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"

View 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)