Added support for database maintenance. Added core plugin.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
QT += core gui sql
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
|
||||
+11
-30
@@ -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<T> entA, QSharedPointer<T> 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);
|
||||
|
||||
std::sort(m_list.begin(), m_list.end(), c);
|
||||
QObject *rawEntity = (QObject*)m_list.at(0).data();
|
||||
const char *prop = rawEntity->metaObject()->property(column + 1).name();
|
||||
|
||||
std::sort(m_list.begin(), m_list.end(), [prop, order](QSharedPointer<T> entA, QSharedPointer<T> 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);
|
||||
}
|
||||
});
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include <QDir>
|
||||
#include <QApplication>
|
||||
#include <QPluginLoader>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlResult>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
|
||||
#include <odb/sqlite/database.hxx>
|
||||
|
||||
#include "core.h"
|
||||
#include "coreplugin.h"
|
||||
|
||||
Context &Context::instance()
|
||||
{
|
||||
@@ -17,8 +23,22 @@ QList<IPlugin *> Context::plugins()
|
||||
return m_plugins;
|
||||
}
|
||||
|
||||
IPlugin *Context::plugin(const QString &pluginId)
|
||||
{
|
||||
QList<IPlugin*>::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<QString, int> schemas;
|
||||
while (q.next())
|
||||
{
|
||||
schemas[q.value("pluginId").toString()] = q.value("schemaVersion").toInt();
|
||||
}
|
||||
checkSchema(db, schemas);
|
||||
}
|
||||
else
|
||||
{
|
||||
q.exec(createSysSql);
|
||||
checkSchema(db, QMap<QString, int>());
|
||||
}
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
void Context::checkSchema(const QSqlDatabase &db, const QMap<QString, int> &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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#define CONTEXT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "core_global.h"
|
||||
#include "transaction.h"
|
||||
|
||||
@@ -14,6 +18,7 @@ class CORESHARED_EXPORT Context
|
||||
public:
|
||||
static Context &instance();
|
||||
QList<IPlugin*> 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<IPlugin*> m_plugins;
|
||||
odb::database *m_db;
|
||||
|
||||
void checkDb(const QString &path);
|
||||
void checkSchema(const QSqlDatabase &db, const QMap<QString, int> &schemaMap);
|
||||
};
|
||||
|
||||
#endif // CONTEXT_H
|
||||
|
||||
+11
-3
@@ -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
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "coreplugin.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QFile>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "imetadataplugin.h"
|
||||
|
||||
#include <QJsonValue>
|
||||
#include <QJsonArray>
|
||||
#include <QLocale>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <QWidget>
|
||||
#include <QtPlugin>
|
||||
#include <QJsonObject>
|
||||
#include <QStringList>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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" : []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>metaData.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
#include <odb/core.hxx>
|
||||
#include <odb/transaction.hxx>
|
||||
@@ -39,6 +40,9 @@ public:
|
||||
|
||||
void save(QSharedPointer<T> entity) {
|
||||
odb::database *db = Context::instance().db();
|
||||
|
||||
Q_ASSERT(db);
|
||||
|
||||
Transaction tx;
|
||||
db->persist(entity);
|
||||
tx.commit();
|
||||
@@ -46,11 +50,21 @@ public:
|
||||
|
||||
QSharedPointer<T> loadById(int id) {
|
||||
odb::database *db = Context::instance().db();
|
||||
|
||||
Q_ASSERT(db);
|
||||
|
||||
Transaction tx;
|
||||
QSharedPointer<T> entity = db->template load<T>(id);
|
||||
tx.commit();
|
||||
return entity;
|
||||
}
|
||||
|
||||
void setPluginId(const QString &pluginId) {
|
||||
m_pluginId = pluginId;
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_pluginId;
|
||||
};
|
||||
|
||||
#endif // SERVICE_H
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user