From 7c90c66468c2a8b9b9605edb322d4a5420cf448d Mon Sep 17 00:00:00 2001 From: Josef Rokos Date: Fri, 13 Nov 2015 15:11:47 +0100 Subject: [PATCH] Added support for database maintenance. Added core plugin. --- application/application.pro | 2 +- core/autotablemodel.h | 39 +++++------------ core/context.cpp | 86 +++++++++++++++++++++++++++++++++++++ core/context.h | 8 ++++ core/core.pro | 14 ++++-- core/coreplugin.cpp | 25 +++++++++++ core/coreplugin.h | 17 ++++++++ core/imetadataplugin.cpp | 16 +++++++ core/imetadataplugin.h | 4 ++ core/iplugin.h | 3 ++ core/metaData.json | 73 +++++++++++++++++++++++++++++++ core/rc.qrc | 5 +++ core/service.h | 14 ++++++ core/transaction.cpp | 4 ++ 14 files changed, 277 insertions(+), 33 deletions(-) create mode 100644 core/coreplugin.cpp create mode 100644 core/coreplugin.h create mode 100644 core/metaData.json create mode 100644 core/rc.qrc diff --git a/application/application.pro b/application/application.pro index 5ec912f..a1e2144 100644 --- a/application/application.pro +++ b/application/application.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui +QT += core gui sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets diff --git a/core/autotablemodel.h b/core/autotablemodel.h index 9293e59..206079d 100644 --- a/core/autotablemodel.h +++ b/core/autotablemodel.h @@ -20,33 +20,6 @@ public: virtual ~AutoTableModel() {} -private: - class Comparator - { - public: - Comparator(const QString &property, Qt::SortOrder order) - { - m_property = property; - m_order = order; - } - - bool operator()(QSharedPointer entA, QSharedPointer entB) { - QObject *rawEntityA = (QObject*)entA.data(); - QObject *rawEntityB = (QObject*)entB.data(); - - if (m_order == Qt::AscendingOrder) { - return rawEntityA->property(m_property.toStdString().c_str()) < rawEntityB->property(m_property.toStdString().c_str()); - } else { - return rawEntityB->property(m_property.toStdString().c_str()) < rawEntityA->property(m_property.toStdString().c_str()); - } - } - - private: - QString m_property; - Qt::SortOrder m_order; - }; - - // QAbstractItemModel interface public: int rowCount(const QModelIndex &parent = QModelIndex()) const @@ -117,10 +90,18 @@ public: } beginResetModel(); + QObject *rawEntity = (QObject*)m_list.at(0).data(); - Comparator c(rawEntity->metaObject()->property(column + 1).name(), order); + const char *prop = rawEntity->metaObject()->property(column + 1).name(); + + std::sort(m_list.begin(), m_list.end(), [prop, order](QSharedPointer entA, QSharedPointer entB) -> bool { + if (order == Qt::AscendingOrder) { + return ((QObject*)entA.data())->property(prop) < ((QObject*)entB.data())->property(prop); + } else { + return ((QObject*)entB.data())->property(prop) < ((QObject*)entA.data())->property(prop); + } + }); - std::sort(m_list.begin(), m_list.end(), c); endResetModel(); } diff --git a/core/context.cpp b/core/context.cpp index 5e20837..4346eaf 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -1,10 +1,16 @@ #include #include #include +#include +#include +#include +#include +#include #include #include "core.h" +#include "coreplugin.h" Context &Context::instance() { @@ -17,8 +23,22 @@ QList Context::plugins() return m_plugins; } +IPlugin *Context::plugin(const QString &pluginId) +{ + QList::iterator it = std::find_if(m_plugins.begin(), m_plugins.end(), [&pluginId](IPlugin *p) { return p->pluginId() == pluginId; }); + if (it != m_plugins.end()) + { + return *it; + } + + return NULL; +} + void Context::loadPlugins() { + IPlugin *corePlugin = new CorePlugin(); + m_plugins.append(corePlugin); + QDir pluginsDir(qApp->applicationDirPath() + "/../../plugins"); foreach (QString fileName, pluginsDir.entryList(QStringList() << "*.so" << "*.dll")) { @@ -41,6 +61,7 @@ void Context::openDb(const QString &path) delete m_db; } + checkDb(path); m_db = new odb::sqlite::database(path.toStdString()); } @@ -48,3 +69,68 @@ Context::Context() { m_db = NULL; } + +void Context::checkDb(const QString &path) +{ + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(path); + db.open(); + QSqlQuery q(db); + QString verSql = "SELECT pluginId, schemaVersion FROM system"; + QString createSysSql = "CREATE TABLE \"system\" (\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \"pluginId\" TEXT NULL, \"schemaVersion\" TEXT NULL)"; + + if (q.exec(verSql)) + { + QMap schemas; + while (q.next()) + { + schemas[q.value("pluginId").toString()] = q.value("schemaVersion").toInt(); + } + checkSchema(db, schemas); + } + else + { + q.exec(createSysSql); + checkSchema(db, QMap()); + } + + db.close(); +} + +void Context::checkSchema(const QSqlDatabase &db, const QMap &schemaMap) +{ + foreach (IPlugin *plugin, m_plugins) { + if (!schemaMap.contains(plugin->pluginId()) || schemaMap[plugin->pluginId()] < plugin->schemaVersion()) + { + int ver = schemaMap[plugin->pluginId()]; + + for (int i = 0; i < plugin->schemas().count(); i++) + { + if (!schemaMap.contains(plugin->pluginId()) || i >= ver) + { + QString sql = plugin->schemas()[i]; + QSqlQuery q(db); + + QStringList sqlList = sql.split(";"); + + foreach (QString s, sqlList) { + if (!q.exec(s)) + { + qDebug() << q.lastError().text(); + } + } + + if (ver == 0) + { + sql = "INSERT INTO system(pluginId, schemaVersion) VALUES('" + plugin->pluginId() + "', 1)"; + } + else + { + sql = "UPDATE system SET schemaVersion = " + QString::number(i + 1) + " WHERE pluginId = '" + plugin->pluginId() + "'"; + } + q.exec(sql); + } + } + } + } +} diff --git a/core/context.h b/core/context.h index b398680..6ce07b3 100644 --- a/core/context.h +++ b/core/context.h @@ -2,6 +2,10 @@ #define CONTEXT_H #include +#include +#include +#include + #include "core_global.h" #include "transaction.h" @@ -14,6 +18,7 @@ class CORESHARED_EXPORT Context public: static Context &instance(); QList plugins(); + IPlugin *plugin(const QString &pluginId); void loadPlugins(); void openDb(const QString &path); odb::database *db() { return m_db; } @@ -22,6 +27,9 @@ private: Context(); QList m_plugins; odb::database *m_db; + + void checkDb(const QString &path); + void checkSchema(const QSqlDatabase &db, const QMap &schemaMap); }; #endif // CONTEXT_H diff --git a/core/core.pro b/core/core.pro index 688fad0..b4b03d4 100644 --- a/core/core.pro +++ b/core/core.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += widgets +QT += widgets sql TARGET = core TEMPLATE = lib @@ -18,7 +18,8 @@ SOURCES += \ transaction.cpp \ emptystringvalidator.cpp \ data/role.cpp \ - data/permission.cpp + data/permission.cpp \ + coreplugin.cpp HEADERS += core.h\ core_global.h \ @@ -34,7 +35,8 @@ HEADERS += core.h\ emptystringvalidator.h \ data/role.h \ data/permission.h \ - data/core-data.h + data/core-data.h \ + coreplugin.h unix { target.path = /usr/lib @@ -45,3 +47,9 @@ ODB_FILES = core/data/core-data.h H_DIR = $$PWD/data/*.h include(../odb.pri) + +RESOURCES += \ + rc.qrc + +DISTFILES += \ + metaData.json diff --git a/core/coreplugin.cpp b/core/coreplugin.cpp new file mode 100644 index 0000000..ad7026b --- /dev/null +++ b/core/coreplugin.cpp @@ -0,0 +1,25 @@ +#include "coreplugin.h" +#include +#include + +CorePlugin::CorePlugin() +{ + Q_INIT_RESOURCE(rc); + + QFile f(":/metaData.json"); + f.open(QIODevice::ReadOnly | QIODevice::Text); + QJsonDocument d = QJsonDocument::fromJson(f.readAll()); + init(d.object()); + f.close(); +} + +CorePlugin::~CorePlugin() +{ +} + +void CorePlugin::initServiceUi() +{ + m_service = NULL; + m_ui = NULL; +} + diff --git a/core/coreplugin.h b/core/coreplugin.h new file mode 100644 index 0000000..c1b1f29 --- /dev/null +++ b/core/coreplugin.h @@ -0,0 +1,17 @@ +#ifndef COREPLUGIN_H +#define COREPLUGIN_H + +#include "imetadataplugin.h" + +class CorePlugin : public IMetaDataPlugin +{ +public: + CorePlugin(); + ~CorePlugin(); + + // IMetaDataPlugin interface +protected: + virtual void initServiceUi(); +}; + +#endif // COREPLUGIN_H diff --git a/core/imetadataplugin.cpp b/core/imetadataplugin.cpp index ef96efc..f14760d 100644 --- a/core/imetadataplugin.cpp +++ b/core/imetadataplugin.cpp @@ -1,6 +1,7 @@ #include "imetadataplugin.h" #include +#include #include #include @@ -27,6 +28,16 @@ QString IMetaDataPlugin::pluginDescription() return m_description; } +int IMetaDataPlugin::schemaVersion() +{ + return m_schemaVersion; +} + +QStringList IMetaDataPlugin::schemas() +{ + return m_schemas; +} + void IMetaDataPlugin::init(const QJsonObject &metaData) { parseMetaData(metaData); @@ -44,6 +55,11 @@ void IMetaDataPlugin::parseMetaData(const QJsonObject &metaData) m_name = parseLocaleText(data.toObject()["name"].toObject()); m_description = parseLocaleText(data.toObject()["description"].toObject()); m_id = data.toObject()["id"].toString(); + m_schemaVersion = data.toObject()["schemaVersion"].toInt(); + + foreach (QJsonValue schVal, data.toObject()["sql"].toArray()) { + m_schemas.append(schVal.toString()); + } } QString IMetaDataPlugin::parseLocaleText(const QJsonObject &object) diff --git a/core/imetadataplugin.h b/core/imetadataplugin.h index 463f5aa..5ee3c0a 100644 --- a/core/imetadataplugin.h +++ b/core/imetadataplugin.h @@ -17,6 +17,8 @@ public: virtual QString pluginName(); virtual QString pluginId(); virtual QString pluginDescription(); + virtual int schemaVersion(); + virtual QStringList schemas(); virtual void init(const QJsonObject &metaData); protected: @@ -27,6 +29,8 @@ private: QString m_name; QString m_id; QString m_description; + int m_schemaVersion; + QStringList m_schemas; QString parseLocaleText(const QJsonObject &object); }; diff --git a/core/iplugin.h b/core/iplugin.h index 0682550..96ad791 100644 --- a/core/iplugin.h +++ b/core/iplugin.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "service.h" @@ -20,6 +21,8 @@ public: virtual QString pluginName() = 0; virtual QString pluginId() = 0; virtual QString pluginDescription() = 0; + virtual int schemaVersion() = 0; + virtual QStringList schemas() = 0; virtual void init(const QJsonObject &metaData) = 0; virtual QWidget *ui() { return m_ui; diff --git a/core/metaData.json b/core/metaData.json new file mode 100644 index 0000000..7a513dc --- /dev/null +++ b/core/metaData.json @@ -0,0 +1,73 @@ +{ + "MetaData" : { + "id" : "CORE", + "name" : { + "default" : "Core plugin", + "CZ" : "Jádro" + }, + "descriptoin" : { + "default" : "", + "CZ" : "" + }, + "schemaVersion" : 1, + "sql" : [ + "CREATE TABLE \"User\" ( + \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + \"login\" TEXT NULL, + \"password\" TEXT NULL, + \"name\" TEXT NULL, + \"lastModDate\" TEXT NULL, + \"createDate\" TEXT NULL, + \"active\" INTEGER NOT NULL, + \"isAdmin\" INTEGER NOT NULL); + + CREATE TABLE \"User_listRoles\" ( + \"object_id\" INTEGER NOT NULL, + \"value\" INTEGER NOT NULL, + CONSTRAINT \"object_id_fk\" + FOREIGN KEY (\"object_id\") + REFERENCES \"User\" (\"id\") + ON DELETE CASCADE, + CONSTRAINT \"value_fk\" + FOREIGN KEY (\"value\") + REFERENCES \"Role\" (\"id\") + DEFERRABLE INITIALLY DEFERRED); + + CREATE INDEX \"User_listRoles_object_id_i\" + ON \"User_listRoles\" (\"object_id\"); + + CREATE TABLE \"Role\" ( + \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + \"name\" TEXT NULL, + \"lastModDate\" TEXT NULL, + \"createDate\" TEXT NULL, + \"active\" INTEGER NOT NULL); + + CREATE TABLE \"Role_listPermissions\" ( + \"object_id\" INTEGER NOT NULL, + \"value\" INTEGER NOT NULL, + CONSTRAINT \"object_id_fk\" + FOREIGN KEY (\"object_id\") + REFERENCES \"Role\" (\"id\") + ON DELETE CASCADE, + CONSTRAINT \"value_fk\" + FOREIGN KEY (\"value\") + REFERENCES \"Permission\" (\"id\") + DEFERRABLE INITIALLY DEFERRED); + + CREATE INDEX \"Role_listPermissions_object_id_i\" + ON \"Role_listPermissions\" (\"object_id\"); + + CREATE TABLE \"Permission\" ( + \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + \"pluginId\" TEXT NULL, + \"permissionName\" TEXT NULL, + \"lastModDate\" TEXT NULL, + \"createDate\" TEXT NULL, + \"active\" INTEGER NOT NULL);" + + + ], + "dependencies" : [] + } +} diff --git a/core/rc.qrc b/core/rc.qrc new file mode 100644 index 0000000..681c9be --- /dev/null +++ b/core/rc.qrc @@ -0,0 +1,5 @@ + + + metaData.json + + diff --git a/core/service.h b/core/service.h index 821756d..ab353e9 100644 --- a/core/service.h +++ b/core/service.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -39,6 +40,9 @@ public: void save(QSharedPointer entity) { odb::database *db = Context::instance().db(); + + Q_ASSERT(db); + Transaction tx; db->persist(entity); tx.commit(); @@ -46,11 +50,21 @@ public: QSharedPointer loadById(int id) { odb::database *db = Context::instance().db(); + + Q_ASSERT(db); + Transaction tx; QSharedPointer entity = db->template load(id); tx.commit(); return entity; } + + void setPluginId(const QString &pluginId) { + m_pluginId = pluginId; + } + +private: + QString m_pluginId; }; #endif // SERVICE_H diff --git a/core/transaction.cpp b/core/transaction.cpp index 8090274..412d450 100644 --- a/core/transaction.cpp +++ b/core/transaction.cpp @@ -11,6 +11,10 @@ Transaction::Transaction() m_tr = new odb::transaction(Context::instance().db()->begin()); Transaction::m_inTransaction = true; } + else + { + m_tr = NULL; + } } Transaction::~Transaction()