First commit
This commit is contained in:
parent
1be874513c
commit
e369e9b5d8
|
|
@ -0,0 +1,7 @@
|
|||
[Dolphin]
|
||||
Timestamp=2016,5,12,10,37,46
|
||||
Version=3
|
||||
ViewMode=1
|
||||
|
||||
[Settings]
|
||||
HiddenFilesShown=true
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/database.h"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
#include "../src/table.h"
|
||||
#include "../src/database.h"
|
||||
#include "../src/tableset.h"
|
||||
#include "../src/query.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/query.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/table.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/tableset.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/database.h"
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
exec 3< <(egrep -o "class\sNUT_EXPORT\s(\S+)" ../src -R 2>&1)
|
||||
|
||||
pattern="\.\.\/src\/([a-z]+)\.h\:class\sNUT_EXPORT\s(\w+)"
|
||||
|
||||
echo "" > "Nut"
|
||||
echo "" > "nut.h"
|
||||
|
||||
while read line; do
|
||||
if [[ $line =~ $pattern ]]; then
|
||||
header=${BASH_REMATCH[1]}
|
||||
class=${BASH_REMATCH[2]}
|
||||
|
||||
echo "#include \"../src/$header.h\"" > $class
|
||||
echo "#include \"../src/$header.h\"" > "$header.h"
|
||||
|
||||
echo "#include \"../src/$header.h\"" >> "Nut"
|
||||
echo "#include \"../src/$header.h\"" >> "nut.h"
|
||||
fi
|
||||
done <&3
|
||||
exec 3<&-
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
#include "../src/table.h"
|
||||
#include "../src/database.h"
|
||||
#include "../src/tableset.h"
|
||||
#include "../src/query.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/query.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/table.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/tableset.h"
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
QT += core widgets sql
|
||||
|
||||
INCLUDEPATH += $$PWD/include
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/src/database.h \
|
||||
$$PWD/src/table.h \
|
||||
$$PWD/src/tableset.h \
|
||||
$$PWD/src/database_p.h \
|
||||
$$PWD/src/defines_p.h \
|
||||
$$PWD/src/defines.h \
|
||||
$$PWD/src/query.h \
|
||||
$$PWD/src/tablescheema.h \
|
||||
$$PWD/src/databasemodel.h \
|
||||
$$PWD/src/sqlgeneratorbase_p.h \
|
||||
$$PWD/src/postgresqlgenerator.h \
|
||||
$$PWD/src/changelogtable.h \
|
||||
$$PWD/src/tablesetbase_p.h \
|
||||
$$PWD/src/querybase_p.h \
|
||||
$$PWD/src/mysqlgenerator.h \
|
||||
$$PWD/src/sqlitegenerator.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/src/database.cpp \
|
||||
$$PWD/src/table.cpp \
|
||||
$$PWD/src/tableset.cpp \
|
||||
$$PWD/src/query.cpp \
|
||||
$$PWD/src/tablescheema.cpp \
|
||||
$$PWD/src/databasemodel.cpp \
|
||||
$$PWD/src/tablesetbase.cpp \
|
||||
$$PWD/src/sqlgeneratorbase.cpp \
|
||||
$$PWD/src/postgresqlgenerator.cpp \
|
||||
$$PWD/src/changelogtable.cpp \
|
||||
$$PWD/src/querybase.cpp \
|
||||
$$PWD/src/mysqlgenerator.cpp \
|
||||
$$PWD/src/sqlitegenerator.cpp
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "changelogtable.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
ChangeLogTable::ChangeLogTable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef CHANGELOGTABLE_H
|
||||
#define CHANGELOGTABLE_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include "table.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class ChangeLogTable : public Table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
|
||||
NUT_DECLARE_FIELD(QByteArray, data, data, setData)
|
||||
|
||||
NUT_DECLARE_FIELD(int, versionMajor, versionMajor, setVersionMajor)
|
||||
|
||||
NUT_DECLARE_FIELD(int, versionMinor, versionMinor, setVersionMinor)
|
||||
|
||||
public:
|
||||
ChangeLogTable();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // CHANGELOGTABLE_H
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <QtCore/QMetaProperty>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <QtSql/QSqlDatabase>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <QtSql/QSqlQuery>
|
||||
#include <QtSql/QSqlResult>
|
||||
|
||||
#include "database.h"
|
||||
#include "table.h"
|
||||
#include "tableset.h"
|
||||
#include "database_p.h"
|
||||
#include "defines_p.h"
|
||||
#include "tablescheema.h"
|
||||
#include "postgresqlgenerator.h"
|
||||
#include "mysqlgenerator.h"
|
||||
#include "sqlitegenerator.h"
|
||||
#include "query.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdarg>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
DatabasePrivate::DatabasePrivate(Database *parent) : q_ptr(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool DatabasePrivate::open()
|
||||
{
|
||||
getCurrectScheema();
|
||||
|
||||
db = QSqlDatabase::addDatabase(driver, connectionName);
|
||||
db.setHostName(hostName);
|
||||
db.setDatabaseName(databaseName);
|
||||
db.setUserName(userName);
|
||||
db.setPassword(password);
|
||||
bool ok = db.open();
|
||||
|
||||
if(!ok){
|
||||
qWarning("Could not connect to database");
|
||||
qWarning(db.lastError().text().toLocal8Bit().data());
|
||||
|
||||
if(db.lastError().text().contains("database \"" + databaseName + "\" does not exist")){
|
||||
db.setDatabaseName("");
|
||||
ok = db.open();
|
||||
qInfo("Creating database");
|
||||
if(ok){
|
||||
db.exec("CREATE DATABASE " + databaseName);
|
||||
db.close();
|
||||
return open();
|
||||
}else{
|
||||
qWarning(db.lastError().text().toLatin1().data());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return updateDatabase();
|
||||
}
|
||||
|
||||
bool DatabasePrivate::updateDatabase()
|
||||
{
|
||||
DatabaseModel last = getLastScheema();
|
||||
|
||||
if(last == currentModel){
|
||||
qInfo("Databse is up-to-date");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!last.size()){
|
||||
qInfo("Databse is new");
|
||||
createChangeLogs();
|
||||
}else{
|
||||
qInfo("Databse is changed");
|
||||
}
|
||||
|
||||
QStringList sql = sqlGenertor->getDiff(last, currentModel);
|
||||
db.transaction();
|
||||
foreach (QString s, sql){
|
||||
qDebug() << "going to exec " << s;
|
||||
db.exec(s);
|
||||
|
||||
if(db.lastError().type() != QSqlError::NoError)
|
||||
qWarning(db.lastError().text().toLatin1().data());
|
||||
}
|
||||
bool ok = db.commit();
|
||||
|
||||
if(ok){
|
||||
storeScheemaInDB();
|
||||
}else{
|
||||
qWarning("Unable update database");
|
||||
qWarning(db.lastError().text().toLatin1().data());
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
QVariantMap DatabasePrivate::getCurrectScheema()
|
||||
{
|
||||
Q_Q(Database);
|
||||
tables.clear();
|
||||
|
||||
int changeLogTypeId = qRegisterMetaType<ChangeLogTable*>();
|
||||
currentModel.append(new TableScheema(changeLogTypeId, "__change_logs"));
|
||||
tables.insert("ChangeLogTable", "__change_logs");
|
||||
|
||||
for(int i = 0; i < q->metaObject()->classInfoCount(); i++){
|
||||
QMetaClassInfo ci = q->metaObject()->classInfo(i);
|
||||
if(QString(ci.name()).startsWith(__nut_TABLE))
|
||||
tables.insert(QString(ci.name()).replace(__nut_NAME_PERFIX, "").split(" ").at(1), ci.value());
|
||||
}
|
||||
|
||||
QVariantMap databaseVariant;
|
||||
for(int i = 1; i < q->metaObject()->propertyCount(); i++){
|
||||
QMetaProperty tableProperty = q->metaObject()->property(i);
|
||||
int typeId = QMetaType::type(tableProperty.typeName());
|
||||
|
||||
if(tables.values().contains(tableProperty.name()) && typeId >= QVariant::UserType){
|
||||
TableScheema *sch = new TableScheema(typeId, tableProperty.name());
|
||||
currentModel.append(sch);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (TableScheema *sch, currentModel)
|
||||
foreach (Relation *fk, sch->foregionKeys())
|
||||
fk->table = currentModel.scheemaByClass(fk->className);
|
||||
|
||||
return databaseVariant;
|
||||
}
|
||||
|
||||
DatabaseModel DatabasePrivate::getLastScheema()
|
||||
{
|
||||
// ChangeLogTable *changeLog = FROM(_changeLogs)
|
||||
// ORDERBY_DESC(id)
|
||||
// FIRST();
|
||||
|
||||
auto u = changeLogs->createQuery()->orderBy("id", "desc")->first();
|
||||
|
||||
// QSqlQuery q = db.exec("select data from __change_logs order by id desc limit 1");
|
||||
DatabaseModel ret;
|
||||
|
||||
if(u){
|
||||
QJsonObject json = QJsonDocument::fromJson(u->data()).object();
|
||||
|
||||
foreach (QString key, json.keys()) {
|
||||
TableScheema *sch = new TableScheema(json.value(key).toObject(), key);
|
||||
ret.append(sch);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DatabasePrivate::storeScheemaInDB()
|
||||
{
|
||||
/*int changeLogTypeId = qRegisterMetaType<ChangeLogTable>();
|
||||
TableScheema *changeLogModel = new TableScheema(changeLogTypeId, "__change_logs");
|
||||
|
||||
sqlGenertor->getDiff(0, changeLogModel);*/
|
||||
|
||||
/*Q_Q(Database);
|
||||
ChangeLogTable *changeLog = new ChangeLogTable();
|
||||
changeLog->setData(QJsonDocument(currentModel.toJson()).toJson());
|
||||
q->saveChanges();*/
|
||||
|
||||
QSqlQuery q(db);
|
||||
q.prepare("insert into __change_logs (data) values (:data)");
|
||||
q.bindValue(":data", QString(QJsonDocument(currentModel.toJson()).toJson()));
|
||||
bool ret = q.exec();
|
||||
if(q.lastError().type() != QSqlError::NoError)
|
||||
qWarning(q.lastError().text().toLatin1().data());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DatabasePrivate::createChangeLogs()
|
||||
{
|
||||
Q_Q(Database);
|
||||
|
||||
QString diff = sqlGenertor->getDiff(0, currentModel.scheema("__change_logs"));
|
||||
|
||||
db.exec(diff);
|
||||
}
|
||||
|
||||
Database::Database(QObject *parent) : QObject(parent), d_ptr(new DatabasePrivate(this))
|
||||
{
|
||||
Q_D(Database);
|
||||
d->changeLogs = new TableSet<ChangeLogTable>(this);
|
||||
}
|
||||
|
||||
QString Database::databaseName() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->databaseName;
|
||||
}
|
||||
|
||||
QString Database::hostName() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->hostName;
|
||||
}
|
||||
|
||||
int Database::port() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->port;
|
||||
}
|
||||
|
||||
QString Database::userName() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->userName;
|
||||
}
|
||||
|
||||
QString Database::password() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->password;
|
||||
}
|
||||
|
||||
QString Database::connectionName() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->connectionName;
|
||||
}
|
||||
|
||||
QString Database::driver() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->driver;
|
||||
}
|
||||
|
||||
DatabaseModel Database::model() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->currentModel;
|
||||
}
|
||||
|
||||
QString Database::tableName(QString className)
|
||||
{
|
||||
Q_D(Database);
|
||||
return d->tables[className];
|
||||
}
|
||||
|
||||
void Database::setDatabaseName(QString databaseName)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->databaseName = databaseName;
|
||||
}
|
||||
|
||||
void Database::setHostName(QString hostName)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->hostName = hostName;
|
||||
}
|
||||
|
||||
void Database::setPort(int port)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->port = port;
|
||||
}
|
||||
|
||||
void Database::setUserName(QString username)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->userName = username;
|
||||
}
|
||||
|
||||
void Database::setPassword(QString password)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->password = password;
|
||||
}
|
||||
|
||||
void Database::setConnectionName(QString connectionName)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->connectionName = connectionName;
|
||||
}
|
||||
|
||||
void Database::setDriver(QString driver)
|
||||
{
|
||||
Q_D(Database);
|
||||
d->driver = driver;
|
||||
}
|
||||
|
||||
SqlGeneratorBase *Database::sqlGenertor() const
|
||||
{
|
||||
Q_D(const Database);
|
||||
return d->sqlGenertor;
|
||||
}
|
||||
|
||||
bool Database::open()
|
||||
{
|
||||
Q_D(Database);
|
||||
|
||||
if(driver() == "QPSQL")
|
||||
d->sqlGenertor = new PostgreSqlGenerator;
|
||||
else if (driver() == "QMYSQL")
|
||||
d->sqlGenertor = new MySqlGenerator;
|
||||
else if (driver() == "QSQLITE")
|
||||
d->sqlGenertor = new SqliteGenerator;
|
||||
|
||||
if(!d->sqlGenertor){
|
||||
qWarning(QString("Sql generator for driver " + driver() + " not found").toLatin1().data());
|
||||
return false;
|
||||
}else{
|
||||
return d->open();
|
||||
}
|
||||
}
|
||||
|
||||
QString Database::decodeQuery(QString sql)
|
||||
{
|
||||
Q_D(Database);
|
||||
|
||||
sql = sql
|
||||
.replace("::", ".")
|
||||
.replace("()", "")
|
||||
.replace("==", "=")
|
||||
.replace("!=", "<>");
|
||||
|
||||
foreach (QString tableName, d->tables.keys())
|
||||
sql = sql.replace(tableName + ".", d->tables[tableName] + ".");
|
||||
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QSqlQuery Database::exec(QString sql)
|
||||
{
|
||||
Q_D(Database);
|
||||
QSqlQuery q = d->db.exec(sql);
|
||||
if(d->db.lastError().type() != QSqlError::NoError)
|
||||
qWarning(d->db.lastError().text().toLatin1().data());
|
||||
return q;
|
||||
}
|
||||
|
||||
void Database::add(TableSetBase *t)
|
||||
{
|
||||
tableSets.insert(t);
|
||||
}
|
||||
|
||||
void Database::saveChanges()
|
||||
{
|
||||
Q_D(Database);
|
||||
|
||||
foreach(TableSetBase *ts, tableSets)
|
||||
ts->save(this);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QList>
|
||||
#include <QtSql/QSqlDatabase>
|
||||
|
||||
#include "defines.h"
|
||||
#include "tableset.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class DatabaseModel;
|
||||
class DatabasePrivate;
|
||||
class TableSetBase;
|
||||
class SqlGeneratorBase;
|
||||
class NUT_EXPORT Database : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
DatabasePrivate *d_ptr;
|
||||
Q_DECLARE_PRIVATE(Database)
|
||||
|
||||
public:
|
||||
Database(QObject *parent = 0);
|
||||
|
||||
bool open();
|
||||
|
||||
QString decodeQuery(QString sql);
|
||||
|
||||
QSqlQuery exec(QString sql);
|
||||
|
||||
void add(TableSetBase *);
|
||||
void saveChanges();
|
||||
|
||||
QString databaseName() const;
|
||||
QString hostName() const;
|
||||
int port() const;
|
||||
QString userName() const;
|
||||
QString password() const;
|
||||
QString connectionName() const;
|
||||
QString driver() const;
|
||||
|
||||
DatabaseModel model() const;
|
||||
QString tableName(QString className);
|
||||
|
||||
SqlGeneratorBase *sqlGenertor() const;
|
||||
|
||||
public slots:
|
||||
void setDatabaseName(QString databaseName);
|
||||
void setHostName(QString hostName);
|
||||
void setPort(int port);
|
||||
void setUserName(QString userName);
|
||||
void setPassword(QString password);
|
||||
void setConnectionName(QString connectionName);
|
||||
void setDriver(QString driver);
|
||||
|
||||
private:
|
||||
QSet<TableSetBase*> tableSets;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // DATABASE_H
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DATABASE_P_H
|
||||
#define DATABASE_P_H
|
||||
|
||||
#include "database.h"
|
||||
#include "databasemodel.h"
|
||||
#include "changelogtable.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class DatabasePrivate
|
||||
{
|
||||
Database *q_ptr;
|
||||
Q_DECLARE_PUBLIC(Database)
|
||||
|
||||
public:
|
||||
DatabasePrivate(Database *parent);
|
||||
|
||||
|
||||
bool open();
|
||||
|
||||
bool updateDatabase();
|
||||
void createChangeLogs();
|
||||
bool storeScheemaInDB();
|
||||
DatabaseModel getLastScheema();
|
||||
QVariantMap getCurrectScheema();
|
||||
|
||||
QSqlDatabase db;
|
||||
|
||||
QString hostName;
|
||||
QString databaseName;
|
||||
int port;
|
||||
QString userName;
|
||||
QString password;
|
||||
QString connectionName;
|
||||
QString driver;
|
||||
|
||||
QHash<QString, QString> tables;
|
||||
|
||||
SqlGeneratorBase *sqlGenertor;
|
||||
DatabaseModel currentModel;
|
||||
|
||||
TableSet<ChangeLogTable> *changeLogs;
|
||||
};
|
||||
|
||||
#endif // DATABASE_P_H
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "databasemodel.h"
|
||||
#include "tablescheema.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
DatabaseModel::DatabaseModel() : QList<TableScheema*>()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TableScheema *DatabaseModel::scheema(QString tableName) const
|
||||
{
|
||||
for(int i = 0; i < size(); i++){
|
||||
TableScheema *s = at(i);
|
||||
if(s->name() == tableName)
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TableScheema *DatabaseModel::scheemaByClass(QString className) const
|
||||
{
|
||||
for(int i = 0; i < size(); i++){
|
||||
TableScheema *s = at(i);
|
||||
if(s->className() == className)
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DatabaseModel::operator ==(const DatabaseModel &other) const
|
||||
{
|
||||
if(size() != other.size())
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < size(); i++){
|
||||
TableScheema *mine = at(i);
|
||||
TableScheema *others = other.scheema(mine->name());
|
||||
|
||||
if(!others)
|
||||
return false;
|
||||
|
||||
if(*mine != *others)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonObject DatabaseModel::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
|
||||
for(int i = 0; i < size(); i++){
|
||||
TableScheema *s = at(i);
|
||||
obj.insert(s->name(), s->toJson());
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
Relation *DatabaseModel::relationByClassNames(QString masterClassName, QString childClassName)
|
||||
{
|
||||
TableScheema *childTable = scheemaByClass(childClassName);
|
||||
|
||||
if(!childTable)
|
||||
return 0;
|
||||
|
||||
foreach (Relation *rel, childTable->foregionKeys())
|
||||
if(rel->className == masterClassName)
|
||||
return rel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Relation *DatabaseModel::relationByTableNames(QString masterTableName, QString childTableName)
|
||||
{
|
||||
TableScheema *childTable = scheema(childTableName);
|
||||
|
||||
if(!childTable)
|
||||
return 0;
|
||||
|
||||
foreach (Relation *rel, childTable->foregionKeys())
|
||||
if(rel->table->name() == masterTableName)
|
||||
return rel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DatabaseModel DatabaseModel::fromJson(QJsonObject &json)
|
||||
{
|
||||
DatabaseModel model;
|
||||
foreach (QString key, json.keys()) {
|
||||
TableScheema *sch = new TableScheema(json.value(key).toObject(), key);
|
||||
model.append(sch);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DATABASEMODEL_H
|
||||
#define DATABASEMODEL_H
|
||||
|
||||
#include <QtCore/QList>
|
||||
|
||||
class TableScheema;
|
||||
struct Relation;
|
||||
class QJsonObject;
|
||||
class DatabaseModel : public QList<TableScheema*>
|
||||
{
|
||||
public:
|
||||
DatabaseModel();
|
||||
|
||||
TableScheema *scheema(QString tableName) const;
|
||||
TableScheema *scheemaByClass(QString className) const;
|
||||
|
||||
Relation *relationByClassNames(QString masterClassName, QString childClassName);
|
||||
Relation *relationByTableNames(QString masterTableName, QString childTableName);
|
||||
|
||||
bool operator ==(const DatabaseModel &other) const;
|
||||
|
||||
static DatabaseModel fromJson(QJsonObject &json);
|
||||
QJsonObject toJson() const;
|
||||
|
||||
};
|
||||
|
||||
#endif // DATABASEMODEL_H
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SYNTAX_DEFINES_H
|
||||
#define SYNTAX_DEFINES_H
|
||||
|
||||
|
||||
#include "defines_p.h"
|
||||
|
||||
#define QT_NAMESPACE Nut
|
||||
|
||||
#ifdef NUT_COMPILE_STATIC
|
||||
# define NUT_EXPORT
|
||||
#else
|
||||
# define NUT_EXPORT Q_DECL_EXPORT
|
||||
#endif
|
||||
|
||||
// Database
|
||||
#define NUT_DB_VERSION(major, minor) Q_CLASSINFO(__nut_NAME_PERFIX " " __nut_DB_VERSION, #major "." #minor)
|
||||
|
||||
#define NUT_DECLARE_TABLE(type, name) \
|
||||
Q_CLASSINFO(__nut_TABLE " " #type, #name) \
|
||||
Q_PROPERTY(type* name READ name) \
|
||||
Q_PROPERTY(TableSet<type> name##s READ name##s) \
|
||||
type* m_##name; \
|
||||
TableSet<type> *m_##name##s; \
|
||||
public: \
|
||||
static const type _##name; \
|
||||
type* name() const{ return m_##name; } \
|
||||
TableSet<type> *name##s() const { return m_##name##s; }
|
||||
|
||||
//Table
|
||||
#define NUT_DECLARE_FIELD(type, name, read, write) \
|
||||
Q_PROPERTY(type name READ read WRITE write) \
|
||||
Q_CLASSINFO(__nut_NAME_PERFIX #name " " __nut_FIELD, #name) \
|
||||
type m_##name; \
|
||||
public: \
|
||||
static type type_##name; \
|
||||
type read() const{ \
|
||||
return m_##name; \
|
||||
} \
|
||||
void write(type name){ \
|
||||
m_##name = name; \
|
||||
propertyChanged(#name); \
|
||||
}
|
||||
|
||||
#define NUT_FOREGION_KEY(type, keytype, name, read, write) \
|
||||
Q_PROPERTY(type* name READ read WRITE write) \
|
||||
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
|
||||
Q_CLASSINFO(__nut_NAME_PERFIX #name "Id " __nut_FOREGION_KEY, #type) \
|
||||
type *m_##name; \
|
||||
public: \
|
||||
type *read() const { return m_##name ; } \
|
||||
void write(type *name){ \
|
||||
m_##name = name; \
|
||||
}
|
||||
|
||||
#define NUT_DECLARE_CHILD_TABLE(type, n) \
|
||||
private: \
|
||||
TableSet<type> *m_##n; \
|
||||
public: \
|
||||
TableSet<type> *n(){ \
|
||||
return m_##n; \
|
||||
}
|
||||
|
||||
|
||||
#define NUT_INDEX(name, field, order)
|
||||
#define NUT_PRIMARY_KEY(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_PRIMARY_KEY, #x)
|
||||
#define NUT_AUTO_INCREMENT(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_AUTO_INCREMENT, #x)
|
||||
#define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_PRIMARY_KEY(x) \
|
||||
NUT_AUTO_INCREMENT(x)
|
||||
#define NUT_LEN(x, n) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_LEN, #n)
|
||||
#define NUT_DEFAULT_VALUE(x, n) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_DEFAULT_VALUE, #n)
|
||||
#define NUT_NOT_NULL(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_NOT_NULL, "1")
|
||||
|
||||
#ifndef NUT_NO_KEYWORDS
|
||||
//Query
|
||||
# define LIKE
|
||||
# define BETWEEN(min,max) BETWEEN min AND max
|
||||
# define IS
|
||||
# ifndef NULL
|
||||
# define NULL
|
||||
# endif
|
||||
|
||||
# define FROM(x) /*QScopedPointer<QueryBase*>*/(x->createQuery())
|
||||
# define WHERE(x) ->setWhere(#x)
|
||||
# define BIND(...) ->bindValues(__VA_ARGS__)
|
||||
# define JOIN(x) ->join(#x)
|
||||
# define SELECT() ->toList()
|
||||
# define COUNT() ->count()
|
||||
# define DELETE() ->remove()
|
||||
# define FIRST() ->first()
|
||||
# define ORDERBY(x) ->orderBy(#x, "ASC");
|
||||
# define ORDERBY_DESC(x) ->orderBy(#x, "DESC");
|
||||
#endif // NUT_NO_KEYWORDS
|
||||
|
||||
#endif // SYNTAX_DEFINES_H
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DEFINES_P_H
|
||||
#define DEFINES_P_H
|
||||
|
||||
#define __NAME "name"
|
||||
#define __TYPE "type"
|
||||
#define __FIELDS "fields"
|
||||
#define __nut_FIELD "field"
|
||||
|
||||
#define __nut_DB_VERSION "database_version"
|
||||
#define __nut_NAME_PERFIX "nut_db_key:"
|
||||
#define __nut_PRIMARY_KEY "primary_key"
|
||||
#define __nut_AUTO_INCREMENT "auto_increment"
|
||||
#define __nut_TABLE "table"
|
||||
#define __nut_TABLE_NAME "table_name"
|
||||
|
||||
#define __nut_LEN "len"
|
||||
#define __nut_DEFAULT_VALUE "def"
|
||||
#define __nut_NOT_NULL "notnull"
|
||||
|
||||
#define __nut_FOREGION_KEY "foregion_key"
|
||||
#define __nut_NEW "new"
|
||||
#define __nut_REMOVE "remove"
|
||||
#define __nut_CHANGE "change"
|
||||
|
||||
#endif // DEFINES_P_H
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#include "mysqlgenerator.h"
|
||||
#include "tablescheema.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
MySqlGenerator::MySqlGenerator() : SqlGeneratorBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString MySqlGenerator::getColumnDef(Field *field)
|
||||
{
|
||||
QString ret = field->name + " ";
|
||||
QString dbType;
|
||||
|
||||
switch (field->type) {
|
||||
case QVariant::Bool:
|
||||
dbType = "boolean";
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
dbType = "blob";
|
||||
break;
|
||||
case QVariant::Double:
|
||||
dbType = "real";
|
||||
break;
|
||||
case QVariant::Int:
|
||||
dbType = "int(4)";
|
||||
if(field->isAutoIncrement)
|
||||
dbType += " auto_increment";
|
||||
|
||||
break;
|
||||
case QVariant::String:
|
||||
if(field->length)
|
||||
dbType = QString("varchar(%1)").arg(field->length);
|
||||
else
|
||||
dbType = "text";
|
||||
break;
|
||||
case QVariant::DateTime:
|
||||
dbType = "datetime";
|
||||
break;
|
||||
|
||||
case QVariant::Date:
|
||||
dbType = "date";
|
||||
break;
|
||||
|
||||
case QVariant::Time:
|
||||
dbType = "time";
|
||||
break;
|
||||
default:
|
||||
dbType = "";
|
||||
}
|
||||
ret.append(dbType);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef MYSQLGENERATOR_H
|
||||
#define MYSQLGENERATOR_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class MySqlGenerator : public SqlGeneratorBase
|
||||
{
|
||||
public:
|
||||
MySqlGenerator();
|
||||
|
||||
QString getColumnDef(Field *field);
|
||||
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // MYSQLGENERATOR_H
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#include "postgresqlgenerator.h"
|
||||
#include "table.h"
|
||||
#include "tablescheema.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
PostgreSqlGenerator::PostgreSqlGenerator() : SqlGeneratorBase ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString PostgreSqlGenerator::getColumnDef(Field *field)
|
||||
{
|
||||
QString ret = field->name + " ";
|
||||
QString dbType;
|
||||
|
||||
switch (field->type) {
|
||||
case QVariant::Bool:
|
||||
dbType = "boolean";
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
dbType = "bytea";
|
||||
break;
|
||||
case QVariant::Date:
|
||||
dbType = "date";
|
||||
break;
|
||||
case QVariant::DateTime:
|
||||
dbType = "timestamp";
|
||||
break;
|
||||
case QVariant::Double:
|
||||
dbType = "real";
|
||||
break;
|
||||
case QVariant::Int:
|
||||
if(field->isAutoIncrement)
|
||||
dbType = "serial";
|
||||
else
|
||||
dbType = "integer";
|
||||
break;
|
||||
case QVariant::String:
|
||||
if(field->length)
|
||||
dbType = QString("varchar(%1)").arg(field->length);
|
||||
else
|
||||
dbType = "text";
|
||||
break;
|
||||
case QVariant::Time:
|
||||
dbType = "time";
|
||||
break;
|
||||
default:
|
||||
dbType = "";
|
||||
}
|
||||
ret.append(dbType);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//QString PostgreSqlGenerator::saveSql(Table *t, QString tableName)
|
||||
//{
|
||||
// switch(t->status()){
|
||||
// case Table::Added:
|
||||
// return insertCommand(t, tableName) + " RETURNING " + t->primaryKey();
|
||||
|
||||
// default:
|
||||
// return SqlGeneratorBase::saveSql(t, tableName);
|
||||
// }
|
||||
//}
|
||||
|
||||
QString PostgreSqlGenerator::deleteTableRows(QString tableName, QString where)
|
||||
{
|
||||
return SqlGeneratorBase::deleteTableRows(tableName, where) + " RETURNING *";
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef POSTGRESQLGENERATOR_H
|
||||
#define POSTGRESQLGENERATOR_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Field;
|
||||
class PostgreSqlGenerator : public SqlGeneratorBase
|
||||
{
|
||||
public:
|
||||
PostgreSqlGenerator();
|
||||
|
||||
QString getColumnDef(Field *field);
|
||||
// QString saveSql(Table *t, QString tableName);
|
||||
|
||||
QString deleteTableRows(QString tableName, QString where);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // POSTGRESQLGENERATOR_H
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "query.h"
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QUERY_H
|
||||
#define QUERY_H
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
#include "database.h"
|
||||
#include "databasemodel.h"
|
||||
#include "tablesetbase_p.h"
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
#include "querybase_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
template<class T>
|
||||
class NUT_EXPORT Query : public QueryBase
|
||||
{
|
||||
QString _tableName;
|
||||
QString _select;
|
||||
QString _where;
|
||||
QString _joinClassName;
|
||||
Database *_database;
|
||||
TableSetBase *_tableSet;
|
||||
public:
|
||||
Query(Database *database, TableSetBase *tableSet);
|
||||
|
||||
QList<T *> toList(int count = -1);
|
||||
T *first();
|
||||
int count();
|
||||
int remove();
|
||||
|
||||
void bind(QVariant v);
|
||||
void bind(QString name, QVariant v);
|
||||
|
||||
Query<T> *join(const QString &tableName);
|
||||
Query<T> *setWhere(const QString &where);
|
||||
Query<T> *bindValues(QVariant v1 = QVariant(), QVariant v2 = QVariant(), QVariant v3 = QVariant(),
|
||||
QVariant v4 = QVariant(), QVariant v5 = QVariant(), QVariant v6 = QVariant(),
|
||||
QVariant v7 = QVariant(), QVariant v8 = QVariant(), QVariant v9 = QVariant());
|
||||
|
||||
Query<T> *orderBy(QString fieldName, QString type);
|
||||
|
||||
private:
|
||||
static QHash<QString, QString> _compiledCommands;
|
||||
QString compileCommand(QString command);
|
||||
QString queryText();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
QHash<QString, QString> Query<T>::_compiledCommands;
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet) : QueryBase(database), _database(database), _tableSet(tableSet),
|
||||
_joinClassName(QString::null)
|
||||
{
|
||||
_tableName = _database->tableName(T::staticMetaObject.className());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
|
||||
{
|
||||
QList<T*> result;
|
||||
_select = "*";
|
||||
qDebug()<<queryText();
|
||||
QSqlQuery q = _database->exec(queryText());
|
||||
|
||||
QString pk =_database->model().scheema(_tableName)->primaryKey();
|
||||
QVariant lastPkValue = QVariant();
|
||||
int childTypeId = 0;
|
||||
T *lastRow = 0;
|
||||
TableSetBase *childTableSet;
|
||||
QStringList masterFields = _database->model().scheema(_tableName)->fieldsNames();
|
||||
QStringList childFields;
|
||||
if(!_joinClassName.isNull()){
|
||||
childFields = _database->model().scheemaByClass(_joinClassName)->fieldsNames();
|
||||
QString joinTableName = _database->tableName(_joinClassName);
|
||||
childTypeId = _database->model().scheema(joinTableName)->typeId();
|
||||
}
|
||||
|
||||
while (q.next()) {
|
||||
if(lastPkValue != q.value(pk)){
|
||||
T *t = new T();
|
||||
|
||||
foreach (QString field, masterFields)
|
||||
t->setProperty(field.toLatin1().data(), q.value(field));
|
||||
|
||||
t->setTableSet(_tableSet);
|
||||
t->setStatus(Table::FeatchedFromDB);
|
||||
t->setParent(this);
|
||||
|
||||
result.append(t);
|
||||
lastRow = t;
|
||||
|
||||
if(childTypeId){
|
||||
QSet<TableSetBase*> tableSets = t->tableSets;
|
||||
foreach (TableSetBase *ts, tableSets)
|
||||
if(ts->childClassName() == _joinClassName)
|
||||
childTableSet = ts;
|
||||
}
|
||||
}
|
||||
|
||||
if(childTypeId){
|
||||
const QMetaObject *childMetaObject = QMetaType::metaObjectForType(childTypeId);
|
||||
Table *childTable = qobject_cast<Table*>(childMetaObject->newInstance());
|
||||
|
||||
foreach (QString field, childFields)
|
||||
childTable->setProperty(field.toLatin1().data(), q.value(field));
|
||||
|
||||
childTable->setParent(this);
|
||||
childTable->setParentTable(lastRow);
|
||||
childTable->setStatus(Table::FeatchedFromDB);
|
||||
childTable->setTableSet(childTableSet);
|
||||
childTableSet->add(childTable);
|
||||
}
|
||||
lastPkValue = q.value(pk);
|
||||
|
||||
if(!--count)
|
||||
break;
|
||||
}
|
||||
|
||||
deleteLater();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE T *Query<T>::first()
|
||||
{
|
||||
QList<T *> list = toList(1);
|
||||
|
||||
if(list.count())
|
||||
return list.first();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE int Query<T>::count()
|
||||
{
|
||||
_select = "COUNT(*)";
|
||||
QSqlQuery q = _database->exec(queryText());
|
||||
if(q.next())
|
||||
return q.value(0).toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
|
||||
{
|
||||
QString sql = _database->sqlGenertor()->deleteTableRows(_tableName, _where);
|
||||
sql = compileCommand(sql);
|
||||
QSqlQuery q = _database->exec(sql);
|
||||
return q.numRowsAffected();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &tableName)
|
||||
{
|
||||
_joinClassName = tableName;
|
||||
return this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(const QString &where)
|
||||
{
|
||||
_where = where;
|
||||
return this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void Query<T>::bind(QVariant v)
|
||||
{
|
||||
_where = _where.arg(v.toString());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void Query<T>::bind(QString name, QVariant v)
|
||||
{
|
||||
if(!name.startsWith(":"))
|
||||
name.prepend(":");
|
||||
_where = _where.replace(name, v.toString());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::bindValues(QVariant v1, QVariant v2, QVariant v3, QVariant v4, QVariant v5, QVariant v6, QVariant v7, QVariant v8, QVariant v9)
|
||||
{
|
||||
if(v1 != QVariant()) _where = _where.arg(v1.toString());
|
||||
if(v2 != QVariant()) _where = _where.arg(v2.toString());
|
||||
if(v3 != QVariant()) _where = _where.arg(v3.toString());
|
||||
if(v4 != QVariant()) _where = _where.arg(v4.toString());
|
||||
if(v5 != QVariant()) _where = _where.arg(v5.toString());
|
||||
if(v6 != QVariant()) _where = _where.arg(v6.toString());
|
||||
if(v7 != QVariant()) _where = _where.arg(v7.toString());
|
||||
if(v8 != QVariant()) _where = _where.arg(v8.toString());
|
||||
if(v9 != QVariant()) _where = _where.arg(v9.toString());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(QString fieldName, QString type)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE QString Query<T>::compileCommand(QString command)
|
||||
{
|
||||
if(!_compiledCommands.contains(command)){
|
||||
QString q = command
|
||||
.replace("::", ".")
|
||||
.replace("()", "")
|
||||
.replace("==", "=")
|
||||
.replace("!=", "<>");
|
||||
|
||||
QRegularExpression r("(\\w+)\\.(\\w+)");
|
||||
QRegularExpressionMatchIterator i = r.globalMatch(command);
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
QString tableName = match.captured(1);
|
||||
QString fieldName = match.captured(2);
|
||||
tableName = _database->tableName(tableName);
|
||||
q = command.replace(match.captured(), tableName + "." + fieldName);
|
||||
}
|
||||
_compiledCommands.insert(command, q);
|
||||
}
|
||||
|
||||
return _compiledCommands[command];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE QString Query<T>::queryText()
|
||||
{
|
||||
QString orderby = "";
|
||||
QString q = compileCommand(_where);
|
||||
|
||||
QString t = _tableName;
|
||||
if(!_joinClassName.isNull()){
|
||||
QString joinTableName = _database->tableName(_joinClassName);
|
||||
Relation *rel = _database->model().relationByTableNames(_tableName, joinTableName);
|
||||
if(rel){
|
||||
QString pk = _database->model().scheema(_tableName)->primaryKey();
|
||||
t = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)")
|
||||
.arg(_tableName)
|
||||
.arg(joinTableName)
|
||||
.arg(pk)
|
||||
.arg(rel->localColumn);
|
||||
orderby = " ORDER BY " + _tableName + "." + pk;
|
||||
}else{
|
||||
qWarning(QString("Relation between table %1 and class %2 (%3) not exists!")
|
||||
.arg(_tableName)
|
||||
.arg(_joinClassName)
|
||||
.arg(joinTableName.isNull() ? "NULL" : joinTableName)
|
||||
.toLatin1().data());
|
||||
_joinClassName = QString::null;
|
||||
}
|
||||
}
|
||||
|
||||
return QString("SELECT %1 FROM %2 %3%4")
|
||||
.arg(_select)
|
||||
.arg(t)
|
||||
.arg(q.isEmpty() ? "" : "WHERE " + q)
|
||||
.arg(orderby);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QUERY_H
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#include "querybase_p.h"
|
||||
|
||||
QueryBase::QueryBase(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef QUERYBASE_H
|
||||
#define QUERYBASE_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
class QueryBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QueryBase(QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // QUERYBASE_H
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#include "databasemodel.h"
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
#include "table.h"
|
||||
#include "tablescheema.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
SqlGeneratorBase::SqlGeneratorBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SqlGeneratorBase::~SqlGeneratorBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::saveSql(Table *t, QString tableName)
|
||||
{
|
||||
switch(t->status()){
|
||||
case Table::Added:
|
||||
return insertCommand(t, tableName);
|
||||
|
||||
case Table::Deleted:
|
||||
return deleteCommand(t, tableName);
|
||||
|
||||
case Table::Modified:
|
||||
return updateCommand(t, tableName);
|
||||
|
||||
case Table::NewCreated:
|
||||
case Table::FeatchedFromDB:
|
||||
// disable compiler warning
|
||||
return "***";
|
||||
}
|
||||
}
|
||||
|
||||
QStringList SqlGeneratorBase::getDiff(DatabaseModel lastModel, DatabaseModel newModel)
|
||||
{
|
||||
QStringList ret;
|
||||
|
||||
QSet<QString> tableNames;
|
||||
foreach (TableScheema *table, lastModel)
|
||||
tableNames.insert(table->name());
|
||||
|
||||
foreach (TableScheema *table, newModel)
|
||||
tableNames.insert(table->name());
|
||||
|
||||
|
||||
foreach (QString tableName, tableNames) {
|
||||
TableScheema *oldTable = lastModel.scheema(tableName);
|
||||
TableScheema *newTable = newModel.scheema(tableName);
|
||||
ret << getDiff(oldTable, newTable);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::getDiff(Field *oldField, Field *newField)
|
||||
{
|
||||
QString sql = "";
|
||||
if(oldField && newField)
|
||||
if(*oldField == *newField)
|
||||
return QString::null;
|
||||
|
||||
if(!newField){
|
||||
sql = "DROP COLUMN " + oldField->name;
|
||||
}else{
|
||||
if(oldField)
|
||||
sql = "ALTER COLUMN ";
|
||||
else
|
||||
sql = "ADD COLUMN ";
|
||||
sql.append(getColumnDef(newField));
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::getDiff(TableScheema *oldTable, TableScheema *newTable)
|
||||
{
|
||||
if(oldTable && newTable)
|
||||
if(*oldTable == *newTable)
|
||||
return "";
|
||||
|
||||
if(!newTable)
|
||||
return "DROP TABLE " + oldTable->name();
|
||||
|
||||
QSet<QString> fieldNames;
|
||||
|
||||
if(oldTable)
|
||||
foreach (Field *f, oldTable->fields())
|
||||
fieldNames.insert(f->name);
|
||||
|
||||
foreach (Field *f, newTable->fields())
|
||||
fieldNames.insert(f->name);
|
||||
|
||||
QStringList columnSql;
|
||||
foreach (QString fieldName, fieldNames) {
|
||||
Field *newField = newTable->field(fieldName);
|
||||
if(oldTable){
|
||||
Field *oldField = oldTable->field(fieldName);
|
||||
|
||||
QString buffer = getDiff(oldField, newField);
|
||||
if(!buffer.isNull())
|
||||
columnSql << buffer;
|
||||
}else{
|
||||
columnSql << getColumnDef(newField);
|
||||
}
|
||||
}
|
||||
QString sql;
|
||||
if(oldTable){
|
||||
sql = QString("ALTER TABLE %1 \n%2")
|
||||
.arg(newTable->name())
|
||||
.arg(columnSql.join(",\n"));
|
||||
}else{
|
||||
if(!newTable->primaryKey().isNull())
|
||||
columnSql << QString("CONSTRAINT pk_%1 PRIMARY KEY (%2)")
|
||||
.arg(newTable->name())
|
||||
.arg(newTable->primaryKey());
|
||||
|
||||
sql = QString("CREATE TABLE %1 \n(%2)")
|
||||
.arg(newTable->name())
|
||||
.arg(columnSql.join(",\n"));
|
||||
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::insertCommand(Table *t, QString tableName)
|
||||
{
|
||||
QString sql = "";
|
||||
QString key = t->primaryKey();
|
||||
QStringList values;
|
||||
|
||||
foreach (QString f, t->changedProperties())
|
||||
if(f != key)
|
||||
values.append("'" + t->property(f.toLatin1().data()).toString() + "'");
|
||||
|
||||
sql = QString("INSERT INTO %1 (%2) VALUES (%3)")
|
||||
.arg(tableName)
|
||||
.arg(t->changedProperties().toList().join(", "))
|
||||
.arg(values.join(", "));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::updateCommand(Table *t, QString tableName)
|
||||
{
|
||||
QString sql = "";
|
||||
QString key = t->primaryKey();
|
||||
QStringList values;
|
||||
|
||||
foreach (QString f, t->changedProperties())
|
||||
if(f != key)
|
||||
values.append(f + "='" + t->property(f.toLatin1().data()).toString() + "'");
|
||||
sql = QString("UPDATE %1 SET %2 WHERE %3=%4")
|
||||
.arg(tableName)
|
||||
.arg(values.join(", "))
|
||||
.arg(key)
|
||||
.arg(t->primaryValue().toString());
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::deleteCommand(Table *t, QString tableName)
|
||||
{
|
||||
return QString("DELETE FROM %1 WHERE %2='%3'")
|
||||
.arg(tableName)
|
||||
.arg(t->primaryKey())
|
||||
.arg(t->primaryValue().toString());
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::deleteTableRows(QString tableName, QString where)
|
||||
{
|
||||
QString sql = "";
|
||||
if(where.isEmpty() || where.isNull())
|
||||
sql = "DELETE FROM " + tableName;
|
||||
else
|
||||
sql = "DELETE FROM " + tableName + " WHERE " + where;
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef SQLGENERATORBASE_H
|
||||
#define SQLGENERATORBASE_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Table;
|
||||
class Field;
|
||||
class DatabaseModel;
|
||||
class TableScheema;
|
||||
class SqlGeneratorBase
|
||||
{
|
||||
public:
|
||||
SqlGeneratorBase();
|
||||
virtual ~SqlGeneratorBase();
|
||||
|
||||
virtual QString saveSql(Table *t, QString tableName);
|
||||
virtual QString getColumnDef(Field *field) = 0;
|
||||
virtual QStringList getDiff(DatabaseModel lastModel, DatabaseModel newModel);
|
||||
virtual QString getDiff(Field *oldField, Field *newField);
|
||||
virtual QString getDiff(TableScheema *oldTable, TableScheema *newTable);
|
||||
|
||||
|
||||
virtual QString insertCommand(Table *t, QString tableName);
|
||||
virtual QString updateCommand(Table *t, QString tableName);
|
||||
virtual QString deleteCommand(Table *t, QString tableName);
|
||||
|
||||
virtual QString deleteTableRows(QString tableName, QString where);
|
||||
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // SQLGENERATORBASE_H
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include "sqlitegenerator.h"
|
||||
#include "table.h"
|
||||
#include "tablescheema.h"
|
||||
|
||||
SqliteGenerator::SqliteGenerator() : SqlGeneratorBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString SqliteGenerator::getColumnDef(Field *field)
|
||||
{
|
||||
QString ret = field->name + " ";
|
||||
QString dbType;
|
||||
|
||||
switch (field->type) {
|
||||
case QVariant::Bool:
|
||||
dbType = "int";
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
dbType = "blob";
|
||||
break;
|
||||
case QVariant::Date:
|
||||
dbType = "date";
|
||||
break;
|
||||
case QVariant::DateTime:
|
||||
dbType = "datetime";
|
||||
break;
|
||||
case QVariant::Double:
|
||||
dbType = "real";
|
||||
break;
|
||||
case QVariant::Int:
|
||||
// if(field->isAutoIncrement)
|
||||
// dbType = "INTEGER PRIMARY KEY";
|
||||
// else
|
||||
dbType = "integer";
|
||||
break;
|
||||
case QVariant::String:
|
||||
if(field->length)
|
||||
dbType = QString("varchar(%1)").arg(field->length);
|
||||
else
|
||||
dbType = "text";
|
||||
break;
|
||||
case QVariant::Time:
|
||||
dbType = "time";
|
||||
break;
|
||||
default:
|
||||
dbType = "";
|
||||
}
|
||||
ret.append(dbType);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef SQLITEGENERATOR_H
|
||||
#define SQLITEGENERATOR_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
|
||||
class SqliteGenerator : public SqlGeneratorBase
|
||||
{
|
||||
public:
|
||||
SqliteGenerator();
|
||||
|
||||
QString getColumnDef(Field *field);
|
||||
};
|
||||
|
||||
#endif // SQLITEGENERATOR_H
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <QMetaMethod>
|
||||
#include <QVariant>
|
||||
#include "table.h"
|
||||
#include "database.h"
|
||||
#include "sqlgeneratorbase_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Table::Table(QObject *parent) : QObject(parent)
|
||||
{
|
||||
setStatus(NewCreated);
|
||||
}
|
||||
|
||||
void Table::add(TableSetBase *t)
|
||||
{
|
||||
this->tableSets.insert(t);
|
||||
}
|
||||
|
||||
|
||||
QString Table::primaryKey() const
|
||||
{
|
||||
static QString ret = QString::null;
|
||||
|
||||
if(ret == QString::null){
|
||||
for(int i = 0; i < metaObject()->classInfoCount(); i++){
|
||||
QMetaClassInfo ci = metaObject()->classInfo(i);
|
||||
QString ciName = ci.name();
|
||||
|
||||
if(ciName.startsWith(__nut_NAME_PERFIX))
|
||||
ciName.remove(__nut_NAME_PERFIX);
|
||||
|
||||
if(ciName.contains(" ")){
|
||||
QStringList parts = ciName.split(" ");
|
||||
QString propName = parts.at(1);
|
||||
if(propName == __nut_PRIMARY_KEY)
|
||||
ret = parts.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == QString::null)
|
||||
ret = "";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString Table::autoIncrementField() const
|
||||
{
|
||||
static QString ret = QString::null;
|
||||
|
||||
if(ret == QString::null){
|
||||
for(int i = 0; i < metaObject()->classInfoCount(); i++){
|
||||
QMetaClassInfo ci = metaObject()->classInfo(i);
|
||||
QString ciName = ci.name();
|
||||
|
||||
if(ciName.startsWith(__nut_NAME_PERFIX))
|
||||
ciName.remove(__nut_NAME_PERFIX);
|
||||
|
||||
if(ciName.contains(" ")){
|
||||
QStringList parts = ciName.split(" ");
|
||||
QString propName = parts.at(1);
|
||||
if(propName == __nut_AUTO_INCREMENT)
|
||||
ret = parts.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == QString::null)
|
||||
ret = "";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariant Table::primaryValue() const
|
||||
{
|
||||
return property(primaryKey().toLatin1().data());
|
||||
}
|
||||
|
||||
void Table::propertyChanged(QString propName)
|
||||
{
|
||||
if(propName == primaryKey())
|
||||
return;
|
||||
|
||||
// qDebug() << "Table::propertyChanged" << metaObject()->className() << propName;
|
||||
_changedProperties.insert(propName);
|
||||
if(_status == FeatchedFromDB)
|
||||
_status = Modified;
|
||||
|
||||
if(_status == NewCreated)
|
||||
_status = Added;
|
||||
}
|
||||
|
||||
QSet<QString> Table::changedProperties() const
|
||||
{
|
||||
return _changedProperties;
|
||||
}
|
||||
|
||||
bool Table::setParentTable(Table *master)
|
||||
{
|
||||
QString masterClassName = master->metaObject()->className();
|
||||
TableScheema *myModel = TableScheema::findByClassName(metaObject()->className());
|
||||
|
||||
foreach (Relation *r, myModel->foregionKeys())
|
||||
if(r->className == masterClassName)
|
||||
{
|
||||
setProperty(QString(r->localColumn).toLatin1().data(), master->primaryValue());
|
||||
_changedProperties.insert(r->localColumn);
|
||||
}
|
||||
}
|
||||
|
||||
TableSetBase *Table::tableSet() const
|
||||
{
|
||||
return _tableSet;
|
||||
}
|
||||
|
||||
void Table::setTableSet(TableSetBase *parent)
|
||||
{
|
||||
_tableSet = parent;
|
||||
_tableSet->add(this);
|
||||
}
|
||||
|
||||
void Table::save(Database *db)
|
||||
{
|
||||
QSqlQuery q = db->exec(db->sqlGenertor()->saveSql(this, db->tableName(metaObject()->className())));
|
||||
//if(q.next())
|
||||
// setProperty(primaryKey().toLatin1().data(), q.value(0));
|
||||
|
||||
if(status() == Added)
|
||||
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
|
||||
|
||||
foreach(TableSetBase *ts, tableSets)
|
||||
ts->save(db);
|
||||
setStatus(FeatchedFromDB);
|
||||
}
|
||||
|
||||
Table::Status Table::status() const
|
||||
{
|
||||
return _status;
|
||||
}
|
||||
|
||||
void Table::setStatus(const Status &status)
|
||||
{
|
||||
_status = status;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TABLE_H
|
||||
#define TABLE_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QSet>
|
||||
|
||||
#include "tablescheema.h"
|
||||
#include "defines.h"
|
||||
//#include "tableset.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Database;
|
||||
class TableSetBase;
|
||||
class NUT_EXPORT Table : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Table(QObject *tableSet = 0);
|
||||
|
||||
enum Status{
|
||||
NewCreated,
|
||||
FeatchedFromDB,
|
||||
Added,
|
||||
Modified,
|
||||
Deleted
|
||||
};
|
||||
|
||||
void add(TableSetBase *);
|
||||
void save(Database *db);
|
||||
|
||||
QString primaryKey() const;
|
||||
QString autoIncrementField() const;
|
||||
QVariant primaryValue() const;
|
||||
Status status() const;
|
||||
void setStatus(const Status &status);
|
||||
|
||||
TableSetBase *tableSet() const;
|
||||
void setTableSet(TableSetBase *tableSet);
|
||||
|
||||
QSet<QString> changedProperties() const;
|
||||
|
||||
bool setParentTable(Table *master);
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
protected:
|
||||
void propertyChanged(QString propName);
|
||||
|
||||
private:
|
||||
Status _status;
|
||||
QSet<QString> _changedProperties;
|
||||
TableSetBase *_tableSet;
|
||||
|
||||
QSet<TableSetBase*> tableSets;
|
||||
|
||||
// template<class T>
|
||||
// friend class TableSet;
|
||||
template<class T>
|
||||
friend class Query;
|
||||
// friend class Database;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "tableset.cpp"
|
||||
#endif // TABLE_H
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QMetaProperty>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "tablescheema.h"
|
||||
#include "defines_p.h"
|
||||
|
||||
|
||||
QSet<TableScheema*> TableScheema::_allModels;
|
||||
//QMap<int, TableScheema*> TableScheema::scheemas;
|
||||
|
||||
QString TableScheema::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void TableScheema::setName(const QString &name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
QString TableScheema::className() const
|
||||
{
|
||||
return _className;
|
||||
}
|
||||
|
||||
void TableScheema::setClassName(const QString &className)
|
||||
{
|
||||
_className = className;
|
||||
}
|
||||
|
||||
int TableScheema::typeId() const
|
||||
{
|
||||
return _typeId;
|
||||
}
|
||||
|
||||
void TableScheema::setTypeId(const int &typeId)
|
||||
{
|
||||
_typeId = typeId;
|
||||
}
|
||||
|
||||
Field *TableScheema::field(QString name) const
|
||||
{
|
||||
foreach (Field *f, _fields)
|
||||
if(f->name == name)
|
||||
return f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<Field *> TableScheema::fields() const
|
||||
{
|
||||
return _fields;
|
||||
}
|
||||
|
||||
QList<Relation *> TableScheema::foregionKeys() const
|
||||
{
|
||||
return _foregionKeys;
|
||||
}
|
||||
|
||||
QStringList TableScheema::fieldsNames() const
|
||||
{
|
||||
QStringList ret;
|
||||
foreach (Field *f, _fields)
|
||||
ret.append(f->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TableScheema *TableScheema::findByTypeId(int typeId)
|
||||
{
|
||||
foreach (TableScheema *model, _allModels)
|
||||
if(model->typeId() == typeId)
|
||||
return model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TableScheema *TableScheema::findByName(QString name)
|
||||
{
|
||||
foreach (TableScheema *model, _allModels)
|
||||
if(model->name() == name)
|
||||
return model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TableScheema *TableScheema::findByClassName(QString className)
|
||||
{
|
||||
foreach (TableScheema *model, _allModels)
|
||||
if(model->className() == className)
|
||||
return model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TableScheema::operator ==(const TableScheema &t) const{
|
||||
if(_name != t.name())
|
||||
return false;
|
||||
|
||||
foreach (Field *f, _fields) {
|
||||
Field *tf = t.field(f->name);
|
||||
if(!tf)
|
||||
return false;
|
||||
|
||||
if(*f != *tf)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TableScheema::operator !=(const TableScheema &t) const
|
||||
{
|
||||
return !(*this == t);
|
||||
}
|
||||
|
||||
TableScheema::TableScheema(int typeId, QString tableName)
|
||||
{
|
||||
const QMetaObject *tableMetaObject = QMetaType::metaObjectForType(typeId);
|
||||
|
||||
_typeId = typeId;
|
||||
_name = tableName;
|
||||
_className = tableMetaObject->className();
|
||||
|
||||
// get fields names
|
||||
for(int j = 0; j < tableMetaObject->classInfoCount(); j++){
|
||||
QString name = tableMetaObject->classInfo(j).name();
|
||||
|
||||
name = name.remove(__nut_NAME_PERFIX);
|
||||
|
||||
if(name.contains(" ")){
|
||||
QStringList parts = name.split(" ");
|
||||
QString propName = parts.at(1);
|
||||
|
||||
if(propName == __nut_FIELD){
|
||||
Field *f = new Field;
|
||||
f->name = parts.at(0);
|
||||
_fields.append(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Browse all fields
|
||||
for(int j = 1; j < tableMetaObject->propertyCount(); j++){
|
||||
QMetaProperty fieldProperty = tableMetaObject->property(j);
|
||||
|
||||
Field *f = field(fieldProperty.name());
|
||||
if(!f)
|
||||
continue;
|
||||
|
||||
f->type = fieldProperty.type();
|
||||
|
||||
_fields.append(f);
|
||||
}
|
||||
|
||||
// Browse class infos
|
||||
for(int j = 0; j < tableMetaObject->classInfoCount(); j++){
|
||||
QString name = tableMetaObject->classInfo(j).name();
|
||||
QString value = tableMetaObject->classInfo(j).value();
|
||||
|
||||
name = name.remove(__nut_NAME_PERFIX);
|
||||
|
||||
|
||||
if(name.contains(" ")){
|
||||
QStringList parts = name.split(" ");
|
||||
QString propName = parts.at(1);
|
||||
|
||||
if(propName == __nut_FOREGION_KEY){
|
||||
Relation *fk = new Relation;
|
||||
fk->localColumn = parts.at(0);
|
||||
fk->foregionColumn = value;
|
||||
fk->className = value;
|
||||
_foregionKeys.append(fk);
|
||||
}
|
||||
|
||||
if(propName == __nut_FIELD){
|
||||
|
||||
}
|
||||
|
||||
|
||||
Field *f = field(parts.at(0));
|
||||
if(!f)
|
||||
continue;
|
||||
|
||||
if(propName == __nut_LEN)
|
||||
f->length = value.toInt();
|
||||
else if(propName == __nut_NOT_NULL)
|
||||
f->notNull = false;
|
||||
else if(propName == __nut_DEFAULT_VALUE)
|
||||
f->defaultValue = value;
|
||||
else if(propName == __nut_PRIMARY_KEY)
|
||||
f->isPrimaryKey = true;
|
||||
else if(propName == __nut_AUTO_INCREMENT)
|
||||
f->isAutoIncrement = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_allModels.insert(this);
|
||||
}
|
||||
|
||||
/*
|
||||
"comment": {
|
||||
"auto_increment": "id",
|
||||
"fields": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "int"
|
||||
},
|
||||
"userId": {
|
||||
"name": "userId",
|
||||
"type": "int"
|
||||
}
|
||||
},
|
||||
"primary_key": "id"
|
||||
},
|
||||
*/
|
||||
TableScheema::TableScheema(QJsonObject json, QString tableName)
|
||||
{
|
||||
_name = tableName;
|
||||
|
||||
QJsonObject fields = json.value(__FIELDS).toObject();
|
||||
foreach (QString key, fields.keys()) {
|
||||
QJsonObject fieldObject = fields.value(key).toObject();
|
||||
Field *f = new Field;
|
||||
f->name = fieldObject.value(__NAME).toString();
|
||||
f->type = QVariant::nameToType(fieldObject.value(__TYPE).toString().toLatin1().data());
|
||||
|
||||
if(fieldObject.contains(__nut_NOT_NULL))
|
||||
f->notNull = fieldObject.value(__nut_NOT_NULL).toBool();
|
||||
|
||||
if(fieldObject.contains(__nut_LEN))
|
||||
f->length = fieldObject.value(__nut_LEN).toInt();
|
||||
|
||||
if(fieldObject.contains(__nut_DEFAULT_VALUE))
|
||||
f->defaultValue = fieldObject.value(__nut_DEFAULT_VALUE).toString();
|
||||
_fields.append(f);
|
||||
}
|
||||
|
||||
if(json.keys().contains(__nut_AUTO_INCREMENT))
|
||||
field(json.value(__nut_AUTO_INCREMENT).toString())->isAutoIncrement = true;
|
||||
|
||||
if(json.keys().contains(__nut_PRIMARY_KEY))
|
||||
field(json.value(__nut_PRIMARY_KEY).toString())->isAutoIncrement = true;
|
||||
|
||||
}
|
||||
|
||||
QJsonObject TableScheema::toJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
QJsonObject fieldsObj;
|
||||
|
||||
foreach (Field *f, _fields) {
|
||||
QJsonObject fieldObj;
|
||||
fieldObj.insert(__NAME, f->name);
|
||||
fieldObj.insert(__TYPE, QVariant::typeToName(f->type));
|
||||
|
||||
if(f->length)
|
||||
fieldObj.insert(__nut_LEN, f->length);
|
||||
|
||||
if(f->notNull)
|
||||
fieldObj.insert(__nut_NOT_NULL, f->notNull);
|
||||
|
||||
if(!f->defaultValue.isNull())
|
||||
fieldObj.insert(__nut_DEFAULT_VALUE, f->defaultValue);
|
||||
|
||||
fieldsObj.insert(f->name, fieldObj);
|
||||
|
||||
if(f->isAutoIncrement)
|
||||
obj.insert(__nut_PRIMARY_KEY, f->name);
|
||||
|
||||
if(f->isPrimaryKey)
|
||||
obj.insert(__nut_AUTO_INCREMENT, f->name);
|
||||
}
|
||||
obj.insert(__FIELDS, fieldsObj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
//TableScheema *TableScheema::registerTable(int typeId, QString tableName)
|
||||
//{
|
||||
// TableScheema *scheema = new TableScheema(typeId, tableName);
|
||||
// scheemas.insert(typeId, scheema);
|
||||
// return scheema;
|
||||
//}
|
||||
|
||||
//void TableScheema::createForegionKeys()
|
||||
//{
|
||||
// foreach (TableScheema *sch, scheemas) {
|
||||
// foreach (ForegionKey *fk, sch->_foregionKeys) {
|
||||
// fk->table = scheema(fk->tableName);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//TableScheema *TableScheema::scheema(QString className)
|
||||
//{
|
||||
// foreach (TableScheema *s, scheemas)
|
||||
// if(s->_className == className)
|
||||
// return s;
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
Relation *TableScheema::foregionKey(QString otherTable) const
|
||||
{
|
||||
foreach (Relation *fk, _foregionKeys)
|
||||
if(fk->className == otherTable)
|
||||
return fk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString TableScheema::toString() const
|
||||
{
|
||||
QStringList sl;
|
||||
foreach (Field *f, _fields)
|
||||
sl.append(f->name + " " + QVariant::typeToName(f->type));
|
||||
|
||||
QString ret = QString("%1 (%2)")
|
||||
.arg(_name)
|
||||
.arg(sl.join(", "));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString TableScheema::primaryKey() const
|
||||
{
|
||||
foreach (Field *f, _fields)
|
||||
if(f->isPrimaryKey)
|
||||
return f->name;
|
||||
return QString::null;
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TABLESCHEEMA_H
|
||||
#define TABLESCHEEMA_H
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QDebug>
|
||||
class QJsonObject;
|
||||
class TableScheema;
|
||||
|
||||
struct Field{
|
||||
Field() : name(QString::null), length(0), defaultValue(QString::null),
|
||||
notNull(false), isPrimaryKey(false), isAutoIncrement(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString name;
|
||||
QVariant::Type type;
|
||||
int length;
|
||||
QString defaultValue;
|
||||
bool notNull;
|
||||
bool isPrimaryKey;
|
||||
bool isAutoIncrement;
|
||||
|
||||
bool operator ==(const Field &f) const{
|
||||
|
||||
bool b = name == f.name
|
||||
&& type == f.type
|
||||
&& length == f.length
|
||||
&& defaultValue == f.defaultValue
|
||||
&& notNull == f.notNull;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool operator !=(const Field &f) const{
|
||||
return !(*this == f);
|
||||
}
|
||||
};
|
||||
|
||||
struct Relation{
|
||||
QString className;
|
||||
QString localColumn;
|
||||
TableScheema *table;
|
||||
QString foregionColumn;
|
||||
};
|
||||
class TableScheema
|
||||
{
|
||||
public:
|
||||
|
||||
TableScheema(int typeId, QString tableName);
|
||||
TableScheema(QJsonObject json, QString tableName);
|
||||
|
||||
QJsonObject toJson() const;
|
||||
|
||||
// static TableScheema *registerTable(int typeId, QString tableName);
|
||||
// static void createForegionKeys();
|
||||
// static TableScheema* scheema(QString className);
|
||||
|
||||
Field *field(QString name) const;
|
||||
Relation *foregionKey(QString otherTable) const;
|
||||
|
||||
QString toString() const;
|
||||
|
||||
QString primaryKey() const;
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
QString className() const;
|
||||
void setClassName(const QString &className);
|
||||
|
||||
int typeId() const;
|
||||
void setTypeId(const int &typeId);
|
||||
QList<Field *> fields() const;
|
||||
QList<Relation *> foregionKeys() const;
|
||||
QStringList fieldsNames() const;
|
||||
|
||||
static TableScheema *findByTypeId(int typeId);
|
||||
static TableScheema *findByName(QString name);
|
||||
static TableScheema *findByClassName(QString className);
|
||||
|
||||
bool operator ==(const TableScheema &t) const;
|
||||
bool operator !=(const TableScheema &t) const;
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QString _className;
|
||||
int _typeId;
|
||||
QList<Field*> _fields;
|
||||
QList<Relation*> _foregionKeys;
|
||||
static QSet<TableScheema*>_allModels;
|
||||
};
|
||||
|
||||
#endif // TABLESCHEEMA_H
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
///**************************************************************************
|
||||
//**
|
||||
//** This file is part of Nut project.
|
||||
//** https://github.com/HamedMasafi/Nut
|
||||
//**
|
||||
//** Nut is free software: you can redistribute it and/or modify
|
||||
//** it under the terms of the GNU Lesser General Public License as published by
|
||||
//** the Free Software Foundation, either version 3 of the License, or
|
||||
//** (at your option) any later version.
|
||||
//**
|
||||
//** Nut is distributed in the hope that it will be useful,
|
||||
//** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
//** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
//** GNU Lesser General Public License for more details.
|
||||
//**
|
||||
//** You should have received a copy of the GNU Lesser General Public License
|
||||
//** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
//**
|
||||
//**************************************************************************/
|
||||
|
||||
#include "tableset.h"
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TABLESET_H
|
||||
#define TABLESET_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QMetaMethod>
|
||||
#include <QtSql/QSqlQuery>
|
||||
|
||||
#include "tablesetbase_p.h"
|
||||
#include "database.h"
|
||||
#include "table.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
template<class T>
|
||||
class Query;
|
||||
|
||||
template<class T>
|
||||
class NUT_EXPORT TableSet : public TableSetBase
|
||||
{
|
||||
public:
|
||||
TableSet(Database *parent);
|
||||
TableSet(Table *parent);
|
||||
|
||||
void append(T *t);
|
||||
void append(QList<T*> t);
|
||||
void remove(T *t);
|
||||
void remove(QList<T*> t);
|
||||
|
||||
int length() const;
|
||||
T *at(int i) const;
|
||||
const T &operator[](int i) const;
|
||||
Query<T> *createQuery();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE TableSet<T>::TableSet(Database *parent) : TableSetBase(parent)
|
||||
{
|
||||
_childClassName = T::staticMetaObject.className();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE TableSet<T>::TableSet(Table *parent) : TableSetBase(parent)
|
||||
{
|
||||
_childClassName = T::staticMetaObject.className();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE Query<T> *TableSet<T>::createQuery()
|
||||
{
|
||||
Query<T> *q = new Query<T>(_database, this);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE int TableSet<T>::length() const
|
||||
{
|
||||
return _tables.count();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE T *TableSet<T>::at(int i) const
|
||||
{
|
||||
return (T*)_tables.values().at(i);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE const T &TableSet<T>::operator[](int i) const
|
||||
{
|
||||
return _tables.values()[i];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(T *t)
|
||||
{
|
||||
_tables.insert(t);
|
||||
// rows.append(t);
|
||||
t->setTableSet(this);
|
||||
if(t->status() != Table::FeatchedFromDB)
|
||||
t->setStatus(Table::Added);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(QList<T *> t)
|
||||
{
|
||||
foreach (T* i, t)
|
||||
append(i);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(T *t)
|
||||
{
|
||||
_tables.remove(t);
|
||||
t->setStatus(Table::Deleted);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(QList<T *> t)
|
||||
{
|
||||
foreach (T* i, t)
|
||||
remove(i);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // TABLESET_H
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "table.h"
|
||||
#include "database.h"
|
||||
#include "tablesetbase_p.h"
|
||||
#include "databasemodel.h"
|
||||
|
||||
TableSetBase::TableSetBase(Database *parent) : QObject(parent), _database(parent), _table(0)
|
||||
{
|
||||
parent->add(this);
|
||||
}
|
||||
|
||||
TableSetBase::TableSetBase(Table *parent) : QObject(parent), _database(0), _table(parent)
|
||||
{
|
||||
parent->add(this);
|
||||
}
|
||||
|
||||
void TableSetBase::save(Database *db)
|
||||
{
|
||||
foreach (Table *t, _tables) {
|
||||
if(_table)
|
||||
t->setParentTable(_table);
|
||||
|
||||
if(t->status() == Table::Added
|
||||
|| t->status() == Table::Modified
|
||||
|| t->status() == Table::Deleted){
|
||||
t->save(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSetBase::add(Table *t)
|
||||
{
|
||||
_tables.insert(t);
|
||||
}
|
||||
|
||||
QString TableSetBase::childClassName() const
|
||||
{
|
||||
return _childClassName;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Nut project.
|
||||
** https://github.com/HamedMasafi/Nut
|
||||
**
|
||||
** Nut is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Nut is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TABLESETBASE_H
|
||||
#define TABLESETBASE_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QSet>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
class Table;
|
||||
class Database;
|
||||
class TableSetBase : public QObject
|
||||
{
|
||||
|
||||
public:
|
||||
TableSetBase(Database *parent);
|
||||
TableSetBase(Table *parent);
|
||||
|
||||
virtual void save(Database *db);
|
||||
void add(Table* t);
|
||||
QString childClassName() const;
|
||||
|
||||
protected:
|
||||
QSet<Table*> _tables;
|
||||
QString _tableName;
|
||||
Database *_database;
|
||||
Table *_table;
|
||||
QString _childClassName;
|
||||
};
|
||||
|
||||
#endif // TABLESETBASE_H
|
||||
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
#include "comment.h"
|
||||
|
||||
Comment::Comment(QObject *parent) : Table(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef COMMENT_H
|
||||
#define COMMENT_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QDateTime>
|
||||
#include "table.h"
|
||||
|
||||
class Post;
|
||||
class Comment : public Table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
NUT_DECLARE_FIELD(QString, message, message, setMessage)
|
||||
NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate)
|
||||
|
||||
NUT_FOREGION_KEY(Post, int, post, post, setPost)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE explicit Comment(QObject *tableSet = 0);
|
||||
};
|
||||
|
||||
#endif // COMMENT_H
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
#include <QtTest>
|
||||
#include <QJsonDocument>
|
||||
#include <QSqlError>
|
||||
|
||||
#include "maintest.h"
|
||||
#include "query.h"
|
||||
#include "tableset.h"
|
||||
#include "tablescheema.h"
|
||||
#include "databasemodel.h"
|
||||
|
||||
#include "post.h"
|
||||
#include "comment.h"
|
||||
|
||||
MainTest::MainTest(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MainTest::initTestCase()
|
||||
{
|
||||
qDebug() << "Table type id:" << qRegisterMetaType<Table*>();
|
||||
qDebug() << "User type id:" << qRegisterMetaType<Post*>();
|
||||
qDebug() << "Comment type id:" << qRegisterMetaType<Comment*>();
|
||||
qDebug() << "DB type id:" << qRegisterMetaType<WeblogDatabase*>();
|
||||
|
||||
db.setDriver("QSQLITE");
|
||||
db.setHostName("127.0.0.1");
|
||||
db.setDatabaseName("nutdb");
|
||||
// db.setUserName("postgres");
|
||||
// db.setPassword("856856");
|
||||
// db.setUserName("root");
|
||||
// db.setPassword("onlyonlyi");
|
||||
bool ok = db.open();
|
||||
|
||||
QTEST_ASSERT(ok);
|
||||
}
|
||||
|
||||
void MainTest::dataScheema()
|
||||
{
|
||||
auto json = db.model().toJson();
|
||||
auto model = DatabaseModel::fromJson(json);
|
||||
|
||||
// qDebug() << model.toJson();
|
||||
// qDebug() << db.model().toJson();
|
||||
QTEST_ASSERT(model == db.model());
|
||||
}
|
||||
|
||||
void MainTest::createPost()
|
||||
{
|
||||
Post *newPost = new Post;
|
||||
newPost->setTitle("post title");
|
||||
|
||||
db.posts()->append(newPost);
|
||||
|
||||
for(int i = 0 ; i < 3; i++){
|
||||
Comment *comment = new Comment;
|
||||
comment->setMessage("comment #" + QString::number(i));
|
||||
|
||||
newPost->comments()->append(comment);
|
||||
}
|
||||
db.saveChanges();
|
||||
|
||||
postId = newPost->id();
|
||||
|
||||
QTEST_ASSERT(newPost->id() != 0);
|
||||
qDebug() << "New post inserted with id:" << newPost->id();
|
||||
}
|
||||
|
||||
void MainTest::selectPosts()
|
||||
{
|
||||
auto q = FROM(db.posts())
|
||||
JOIN(Comment)
|
||||
WHERE(Post::id() == %1)
|
||||
BIND(postId);
|
||||
auto posts = q->toList();
|
||||
|
||||
QTEST_ASSERT(posts.length() == 1);
|
||||
QTEST_ASSERT(posts.at(0)->comments()->length() == 3);
|
||||
QTEST_ASSERT(posts.at(0)->title() == "post title");
|
||||
|
||||
qDebug()<<posts.at(0)->comments()->at(0)->message();
|
||||
QTEST_ASSERT(posts.at(0)->comments()->at(0)->message() == "comment #0");
|
||||
QTEST_ASSERT(posts.at(0)->comments()->at(1)->message() == "comment #1");
|
||||
QTEST_ASSERT(posts.at(0)->comments()->at(2)->message() == "comment #2");
|
||||
}
|
||||
|
||||
void MainTest::selectWithInvalidRelation()
|
||||
{
|
||||
auto q = FROM(db.posts())
|
||||
JOIN(Invalid_Class_Name)
|
||||
SELECT();
|
||||
}
|
||||
|
||||
void MainTest::modifyPost()
|
||||
{
|
||||
auto q = FROM(db.posts())
|
||||
WHERE(Post::id() == %1)
|
||||
BIND(postId);
|
||||
|
||||
Post *post = q->first();
|
||||
|
||||
QTEST_ASSERT(post != 0);
|
||||
|
||||
post->setTitle("new name");
|
||||
db.saveChanges();
|
||||
|
||||
q = FROM(db.posts())
|
||||
WHERE(Post::id() == %1)
|
||||
BIND(postId);
|
||||
post = q->first();
|
||||
QTEST_ASSERT(post->title() == "new name");
|
||||
}
|
||||
|
||||
void MainTest::deletePost()
|
||||
{
|
||||
auto count = FROM(db.posts())
|
||||
WHERE(Post::id() == %1)
|
||||
BIND(postId)
|
||||
DELETE();
|
||||
|
||||
QTEST_ASSERT(count == 1);
|
||||
|
||||
count = FROM(db.posts())
|
||||
WHERE(Post::id() == %1)
|
||||
BIND(postId)
|
||||
COUNT();
|
||||
|
||||
QTEST_ASSERT(count == 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(MainTest)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef MAINTEST_H
|
||||
#define MAINTEST_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include "weblogdatabase.h"
|
||||
class MainTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
WeblogDatabase db;
|
||||
int postId;
|
||||
|
||||
public:
|
||||
explicit MainTest(QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
||||
void dataScheema();
|
||||
void createPost();
|
||||
void selectPosts();
|
||||
void selectWithInvalidRelation();
|
||||
void modifyPost();
|
||||
void deletePost();
|
||||
};
|
||||
|
||||
#endif // MAINTEST_H
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include "comment.h"
|
||||
#include "tableset.h"
|
||||
#include "post.h"
|
||||
|
||||
Post::Post(QObject *parent) : Table(parent),
|
||||
m_comments(new TableSet<Comment>(this)), m_id(0), m_title("")
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef USER_H
|
||||
#define USER_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include "table.h"
|
||||
#include "database.h"
|
||||
#include "comment.h"
|
||||
#include "databasemodel.h"
|
||||
|
||||
class Post : public Table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
|
||||
NUT_NOT_NULL(title)
|
||||
NUT_LEN(title, 50)
|
||||
NUT_DECLARE_FIELD(QString, title, title, setTitle)
|
||||
|
||||
NUT_DECLARE_FIELD(QString, body, body, setBody)
|
||||
|
||||
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
||||
|
||||
public:
|
||||
explicit Post(QObject *tableSet = 0);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
//Q_DECLARE_METATYPE(User*)
|
||||
#endif // USER_H
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
QT += qml quick testlib sql
|
||||
|
||||
QT -= gui
|
||||
|
||||
TARGET = tst_nut
|
||||
CONFIG += warn_on qmltestcase c++11
|
||||
INCLUDEPATH += $$PWD/../src
|
||||
include(../nut.pri)
|
||||
TEMPLATE = app
|
||||
IMPORTPATH += $$OUT_PWD/../src/imports
|
||||
SOURCES += \
|
||||
maintest.cpp \
|
||||
comment.cpp \
|
||||
post.cpp \
|
||||
weblogdatabase.cpp
|
||||
|
||||
HEADERS += \
|
||||
maintest.h \
|
||||
comment.h \
|
||||
post.h \
|
||||
weblogdatabase.h
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include "post.h"
|
||||
#include "comment.h"
|
||||
#include "weblogdatabase.h"
|
||||
|
||||
WeblogDatabase::WeblogDatabase() : Database(), m_posts(new TableSet<Post>(this)), m_comments(new TableSet<Comment>(this))
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef TDATABASE_H
|
||||
#define TDATABASE_H
|
||||
|
||||
#include "database.h"
|
||||
|
||||
class Post;
|
||||
class Comment;
|
||||
class WeblogDatabase : public Database
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_DB_VERSION(1, 0)
|
||||
|
||||
NUT_DECLARE_TABLE(Post, post)
|
||||
|
||||
NUT_DECLARE_TABLE(Comment, comment)
|
||||
|
||||
public:
|
||||
WeblogDatabase();
|
||||
};
|
||||
|
||||
|
||||
#endif // TDATABASE_H
|
||||
Loading…
Reference in New Issue