Read me edited

This commit is contained in:
Hamed Masafi 2016-05-21 12:39:03 +04:30
parent 034203c7d0
commit f87923ff95
38 changed files with 1414 additions and 449 deletions

View File

@ -15,11 +15,13 @@
```cpp
autoq = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId);
WHERE(Post::idField() == postId);
auto posts = q->toList();
// now posts is a QList<Post*> contain all posts in
// database that has id equal to postId variable
auto post = q->first();
// post is first row in database that its id is equal to postId
```
### Adding to database:
@ -41,8 +43,7 @@ db.saveChanges();
### Modify database data:
```cpp
auto q = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId);
WHERE(Post::idField() == postId);
Post *post = q->first();

12
nut.pri
View File

@ -10,7 +10,6 @@ HEADERS += \
$$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 \
@ -18,14 +17,16 @@ HEADERS += \
$$PWD/src/tablesetbase_p.h \
$$PWD/src/querybase_p.h \
$$PWD/src/mysqlgenerator.h \
$$PWD/src/sqlitegenerator.h
$$PWD/src/sqlitegenerator.h \
$$PWD/src/tablemodel.h \
$$PWD/src/sqlservergenerator.h \
$$PWD/src/wherephrase.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 \
@ -33,4 +34,7 @@ SOURCES += \
$$PWD/src/changelogtable.cpp \
$$PWD/src/querybase.cpp \
$$PWD/src/mysqlgenerator.cpp \
$$PWD/src/sqlitegenerator.cpp
$$PWD/src/sqlitegenerator.cpp \
$$PWD/src/tablemodel.cpp \
$$PWD/src/sqlservergenerator.cpp \
$$PWD/src/wherephrase.cpp

BIN
src.tar.gz Normal file

Binary file not shown.

View File

@ -25,6 +25,7 @@ QT_BEGIN_NAMESPACE
ChangeLogTable::ChangeLogTable()
{
}
QT_END_NAMESPACE

View File

@ -33,7 +33,7 @@ class ChangeLogTable : public Table
NUT_PRIMARY_AUTO_INCREMENT(id)
NUT_DECLARE_FIELD(int, id, id, setId)
NUT_DECLARE_FIELD(QByteArray, data, data, setData)
NUT_DECLARE_FIELD(QString, data, data, setData)
NUT_DECLARE_FIELD(int, versionMajor, versionMajor, setVersionMajor)

View File

@ -33,10 +33,11 @@
#include "tableset.h"
#include "database_p.h"
#include "defines_p.h"
#include "tablescheema.h"
#include "tablemodel.h"
#include "postgresqlgenerator.h"
#include "mysqlgenerator.h"
#include "sqlitegenerator.h"
#include "sqlservergenerator.h"
#include "query.h"
#include <iostream>
@ -63,13 +64,18 @@ bool DatabasePrivate::open()
qWarning("Could not connect to database");
qWarning(db.lastError().text().toLocal8Bit().data());
if(db.lastError().text().contains("database \"" + databaseName + "\" does not exist")){
db.setDatabaseName("");
if(db.lastError().text().contains("database \"" + databaseName + "\" does not exist")
|| db.lastError().text().contains("Cannot open database")){
db.setDatabaseName(sqlGenertor->masterDatabaseName(databaseName));
ok = db.open();
qInfo("Creating database");
if(ok){
db.exec("CREATE DATABASE " + databaseName);
db.close();
if(db.lastError().type() != QSqlError::NoError)
qWarning(db.lastError().text().prepend("Creating database error: ").toLatin1().data());
return open();
}else{
qWarning(db.lastError().text().toLatin1().data());
@ -84,26 +90,25 @@ bool DatabasePrivate::open()
bool DatabasePrivate::updateDatabase()
{
DatabaseModel last = getLastScheema();
DatabaseModel current = currentModel;
if(last == currentModel){
if(last == current){
qInfo("Databse is up-to-date");
return true;
}
if(!last.size()){
if(!last.count())
qInfo("Databse is new");
createChangeLogs();
}else{
else
qInfo("Databse is changed");
}
QStringList sql = sqlGenertor->getDiff(last, currentModel);
QStringList sql = sqlGenertor->diff(last, current);
db.transaction();
foreach (QString s, sql){
qDebug() << "going to exec " << s;
db.exec(s);
if(db.lastError().type() != QSqlError::NoError)
if(!db.lastError().type() == QSqlError::NoError)
qWarning(db.lastError().text().toLatin1().data());
}
bool ok = db.commit();
@ -123,82 +128,94 @@ QVariantMap DatabasePrivate::getCurrectScheema()
Q_Q(Database);
tables.clear();
//TODO: change logs must not be in model
int changeLogTypeId = qRegisterMetaType<ChangeLogTable*>();
currentModel.append(new TableScheema(changeLogTypeId, "__change_logs"));
currentModel.append(new TableModel(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))
QString ciName = QString(ci.name()).replace(__nut_NAME_PERFIX, "");
if(ciName.startsWith(__nut_TABLE))
tables.insert(QString(ci.name()).replace(__nut_NAME_PERFIX, "").split(" ").at(1), ci.value());
if(ciName == __nut_DB_VERSION){
QStringList version = QString(ci.value()).split('.');
bool ok = false;
if(version.length() == 1){
currentModel.setVersionMajor(version.at(0).toInt(&ok));
} else if(version.length() == 2){
currentModel.setVersionMajor(version.at(0).toInt(&ok));
currentModel.setVersionMinor(version.at(1).toInt(&ok));
}
if(!ok)
qFatal("NUT_DB_VERSION macro accept version in format 'x' or 'x.y' only, and x[,y] must be integer values\n");
}
}
QVariantMap databaseVariant;
for(int i = 1; i < q->metaObject()->propertyCount(); i++){
QMetaProperty tableProperty = q->metaObject()->property(i);
int typeId = QMetaType::type(tableProperty.typeName());
uint typeId = QMetaType::type(tableProperty.typeName());
if(tables.values().contains(tableProperty.name()) && typeId >= QVariant::UserType){
TableScheema *sch = new TableScheema(typeId, tableProperty.name());
TableModel *sch = new TableModel(typeId, tableProperty.name());
currentModel.append(sch);
}
}
foreach (TableScheema *sch, currentModel)
foreach (Relation *fk, sch->foregionKeys())
fk->table = currentModel.scheemaByClass(fk->className);
foreach (TableModel *sch, currentModel)
foreach (RelationModel *fk, sch->foregionKeys())
fk->table = currentModel.modelByClass(fk->className);
return databaseVariant;
}
DatabaseModel DatabasePrivate::getLastScheema()
{
// ChangeLogTable *changeLog = FROM(_changeLogs)
// ORDERBY_DESC(id)
// FIRST();
ChangeLogTable *u = changeLogs->createQuery()->orderBy("id", "desc")->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();
QJsonObject json = QJsonDocument::fromJson(QByteArray(u->data().toLocal8Bit().data())).object();
foreach (QString key, json.keys()) {
TableScheema *sch = new TableScheema(json.value(key).toObject(), key);
TableModel *sch = new TableModel(json.value(key).toObject(), key);
ret.append(sch);
}
u->deleteLater();
}
return ret;
}
bool DatabasePrivate::storeScheemaInDB()
{
/*int changeLogTypeId = qRegisterMetaType<ChangeLogTable>();
TableScheema *changeLogModel = new TableScheema(changeLogTypeId, "__change_logs");
sqlGenertor->getDiff(0, changeLogModel);*/
/*Q_Q(Database);
Q_Q(Database);
ChangeLogTable *changeLog = new ChangeLogTable();
changeLog->setData(QJsonDocument(currentModel.toJson()).toJson());
q->saveChanges();*/
changeLog->setVersionMajor(currentModel.versionMajor());
changeLog->setVersionMinor(currentModel.versionMinor());
changeLogs->append(changeLog);
q->saveChanges();
changeLog->deleteLater();
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;
return true;
// 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(QString("storeScheemaInDB" + q.lastError().text()).toLatin1().data());
// return ret;
}
void DatabasePrivate::createChangeLogs()
{
Q_Q(Database);
QString diff = sqlGenertor->getDiff(0, currentModel.scheema("__change_logs"));
QString diff = sqlGenertor->diff(0, currentModel.model("__change_logs"));
db.exec(diff);
}
@ -315,12 +332,22 @@ bool Database::open()
{
Q_D(Database);
if(driver() == "QPSQL")
if(d->driver == "QPSQL" || d->driver == "QPSQL7")
d->sqlGenertor = new PostgreSqlGenerator;
else if (driver() == "QMYSQL")
else if (d->driver == "QMYSQL" || d->driver == "QMYSQL3")
d->sqlGenertor = new MySqlGenerator;
else if (driver() == "QSQLITE")
else if (d->driver == "QSQLITE" || d->driver == "QSQLITE3")
d->sqlGenertor = new SqliteGenerator;
else if(d->driver == "QODBC" || d->driver == "QODBC3"){
QString driverName = QString::null;
QStringList parts = d->databaseName.toLower().split(';');
foreach (QString p, parts)
if(p.trimmed().startsWith("driver="))
driverName = p.split('=').at(1);
if(driverName == "{sql server}")
d->sqlGenertor = new SqlServerGenerator;
}
if(!d->sqlGenertor){
qWarning(QString("Sql generator for driver " + driver() + " not found").toLatin1().data());
@ -330,23 +357,6 @@ bool Database::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);
@ -363,10 +373,14 @@ void Database::add(TableSetBase *t)
void Database::saveChanges()
{
Q_D(Database);
foreach(TableSetBase *ts, tableSets)
ts->save(this);
}
void Database::cleanUp()
{
foreach(TableSetBase *ts, tableSets)
ts->clearChilds();
}
QT_END_NAMESPACE

View File

@ -46,12 +46,11 @@ public:
bool open();
QString decodeQuery(QString sql);
QSqlQuery exec(QString sql);
void add(TableSetBase *);
void saveChanges();
void cleanUp();
QString databaseName() const;
QString hostName() const;

View File

@ -19,29 +19,31 @@
**************************************************************************/
#include "databasemodel.h"
#include "tablescheema.h"
#include "tablemodel.h"
#include <QJsonObject>
DatabaseModel::DatabaseModel() : QList<TableScheema*>()
QT_BEGIN_NAMESPACE
DatabaseModel::DatabaseModel() : QList<TableModel*>(), _versionMajor(0), _versionMinor(0)
{
}
TableScheema *DatabaseModel::scheema(QString tableName) const
TableModel *DatabaseModel::model(QString tableName) const
{
for(int i = 0; i < size(); i++){
TableScheema *s = at(i);
TableModel *s = at(i);
if(s->name() == tableName)
return s;
}
return 0;
}
TableScheema *DatabaseModel::scheemaByClass(QString className) const
TableModel *DatabaseModel::modelByClass(QString className) const
{
for(int i = 0; i < size(); i++){
TableScheema *s = at(i);
TableModel *s = at(i);
if(s->className() == className)
return s;
}
@ -54,8 +56,8 @@ bool DatabaseModel::operator ==(const DatabaseModel &other) const
return false;
for(int i = 0; i < size(); i++){
TableScheema *mine = at(i);
TableScheema *others = other.scheema(mine->name());
TableModel *mine = at(i);
TableModel *others = other.model(mine->name());
if(!others)
return false;
@ -71,36 +73,39 @@ QJsonObject DatabaseModel::toJson() const
{
QJsonObject obj;
// obj.insert(QT_STRINGIFY(versionMajor), QJsonValue(_versionMajor));
// obj.insert(QT_STRINGIFY(versionMinor), QJsonValue(_versionMinor));
for(int i = 0; i < size(); i++){
TableScheema *s = at(i);
TableModel *s = at(i);
obj.insert(s->name(), s->toJson());
}
return obj;
}
Relation *DatabaseModel::relationByClassNames(QString masterClassName, QString childClassName)
RelationModel *DatabaseModel::relationByClassNames(QString masterClassName, QString childClassName)
{
TableScheema *childTable = scheemaByClass(childClassName);
TableModel *childTable = modelByClass(childClassName);
if(!childTable)
return 0;
foreach (Relation *rel, childTable->foregionKeys())
foreach (RelationModel *rel, childTable->foregionKeys())
if(rel->className == masterClassName)
return rel;
return 0;
}
Relation *DatabaseModel::relationByTableNames(QString masterTableName, QString childTableName)
RelationModel *DatabaseModel::relationByTableNames(QString masterTableName, QString childTableName)
{
TableScheema *childTable = scheema(childTableName);
TableModel *childTable = model(childTableName);
if(!childTable)
return 0;
foreach (Relation *rel, childTable->foregionKeys())
foreach (RelationModel *rel, childTable->foregionKeys())
if(rel->table->name() == masterTableName)
return rel;
@ -110,9 +115,38 @@ Relation *DatabaseModel::relationByTableNames(QString masterTableName, QString c
DatabaseModel DatabaseModel::fromJson(QJsonObject &json)
{
DatabaseModel model;
// model.setVersionMajor(json.value(QT_STRINGIFY(versionMajor)).toInt());
// model.setVersionMinor(json.value(QT_STRINGIFY(versionMinor)).toInt());
foreach (QString key, json.keys()) {
TableScheema *sch = new TableScheema(json.value(key).toObject(), key);
if(!json.value(key).isObject())
continue;
TableModel *sch = new TableModel(json.value(key).toObject(), key);
model.append(sch);
}
return model;
}
int DatabaseModel::versionMajor() const
{
return _versionMajor;
}
void DatabaseModel::setVersionMajor(int versionMajor)
{
_versionMajor = versionMajor;
}
int DatabaseModel::versionMinor() const
{
return _versionMinor;
}
void DatabaseModel::setVersionMinor(int versionMinor)
{
_versionMinor = versionMinor;
}
QT_END_NAMESPACE

View File

@ -23,25 +23,35 @@
#include <QtCore/QList>
class TableScheema;
struct Relation;
QT_BEGIN_NAMESPACE
class TableModel;
struct RelationModel;
class QJsonObject;
class DatabaseModel : public QList<TableScheema*>
class DatabaseModel : public QList<TableModel*>
{
int _versionMajor, _versionMinor;
public:
DatabaseModel();
TableScheema *scheema(QString tableName) const;
TableScheema *scheemaByClass(QString className) const;
TableModel *model(QString tableName) const;
TableModel *modelByClass(QString className) const;
Relation *relationByClassNames(QString masterClassName, QString childClassName);
Relation *relationByTableNames(QString masterTableName, QString childTableName);
RelationModel *relationByClassNames(QString masterClassName, QString childClassName);
RelationModel *relationByTableNames(QString masterTableName, QString childTableName);
bool operator ==(const DatabaseModel &other) const;
static DatabaseModel fromJson(QJsonObject &json);
QJsonObject toJson() const;
int versionMajor() const;
void setVersionMajor(int versionMajor);
int versionMinor() const;
void setVersionMinor(int versionMinor);
};
QT_END_NAMESPACE
#endif // DATABASEMODEL_H

View File

@ -21,7 +21,7 @@
#ifndef SYNTAX_DEFINES_H
#define SYNTAX_DEFINES_H
#include "qglobal.h"
#include "defines_p.h"
#define QT_NAMESPACE Nut
@ -33,10 +33,10 @@
#endif
// Database
#define NUT_DB_VERSION(major, minor) Q_CLASSINFO(__nut_NAME_PERFIX " " __nut_DB_VERSION, #major "." #minor)
#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_CLASSINFO(__nut_NAME_PERFIX __nut_TABLE " " #type, #name) \
Q_PROPERTY(type* name READ name) \
Q_PROPERTY(TableSet<type> name##s READ name##s) \
type* m_##name; \
@ -52,7 +52,10 @@ public: \
Q_CLASSINFO(__nut_NAME_PERFIX #name " " __nut_FIELD, #name) \
type m_##name; \
public: \
static type type_##name; \
static FieldPhrase name##Field(){ \
static FieldPhrase f = FieldPhrase(staticMetaObject.className(), #name); \
return f; \
} \
type read() const{ \
return m_##name; \
} \
@ -61,10 +64,10 @@ public: \
propertyChanged(#name); \
}
#define NUT_FOREGION_KEY(type, keytype, name, read, write) \
#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) \
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 ; } \
@ -72,10 +75,14 @@ public: \
m_##name = name; \
}
#define NUT_DECLARE_CHILD_TABLE(type, n) \
#define NUT_DECLARE_CHILD_TABLE(type, n) \
private: \
TableSet<type> *m_##n; \
public: \
/*static type ## Field() const{ \
static type t; \
return t; \
}*/ \
TableSet<type> *n(){ \
return m_##n; \
}
@ -86,29 +93,22 @@ public: \
#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_UNIQUE(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_UNIQUE, #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 WHERE(x) ->setWhere(x)
# define JOIN(x) ->join(#x)
# define ORDERBY(x) ->orderBy(#x, "ASC");
# define ORDERBY_DESC(x) ->orderBy(#x, "DESC");
# 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

View File

@ -27,9 +27,10 @@
#define __nut_FIELD "field"
#define __nut_DB_VERSION "database_version"
#define __nut_NAME_PERFIX "nut_db_key:"
#define __nut_NAME_PERFIX "nut_db_key::"
#define __nut_PRIMARY_KEY "primary_key"
#define __nut_AUTO_INCREMENT "auto_increment"
#define __nut_UNIQUE "unique"
#define __nut_TABLE "table"
#define __nut_TABLE_NAME "table_name"

View File

@ -1,16 +1,35 @@
/**************************************************************************
**
** 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 "mysqlgenerator.h"
#include "tablescheema.h"
#include "tablemodel.h"
QT_BEGIN_NAMESPACE
MySqlGenerator::MySqlGenerator() : SqlGeneratorBase()
MySqlGenerator::MySqlGenerator(QObject *parent) : SqlGeneratorBase(parent)
{
}
QString MySqlGenerator::getColumnDef(Field *field)
QString MySqlGenerator::fieldType(FieldModel *field)
{
QString ret = field->name + " ";
QString dbType;
switch (field->type) {
@ -20,6 +39,17 @@ QString MySqlGenerator::getColumnDef(Field *field)
case QVariant::ByteArray:
dbType = "blob";
break;
case QVariant::DateTime:
dbType = "datetime";
break;
case QVariant::Date:
dbType = "date";
break;
case QVariant::Time:
dbType = "time";
break;
case QVariant::Double:
dbType = "real";
break;
@ -35,22 +65,11 @@ QString MySqlGenerator::getColumnDef(Field *field)
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;
return dbType;
}
QT_END_NAMESPACE

View File

@ -1,3 +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/>.
**
**************************************************************************/
#ifndef MYSQLGENERATOR_H
#define MYSQLGENERATOR_H
@ -9,9 +29,9 @@ QT_BEGIN_NAMESPACE
class MySqlGenerator : public SqlGeneratorBase
{
public:
MySqlGenerator();
MySqlGenerator(QObject *parent = 0);
QString getColumnDef(Field *field);
QString fieldType(FieldModel *field);
};

View File

@ -1,17 +1,36 @@
/**************************************************************************
**
** 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 "postgresqlgenerator.h"
#include "table.h"
#include "tablescheema.h"
#include "tablemodel.h"
QT_BEGIN_NAMESPACE
PostgreSqlGenerator::PostgreSqlGenerator() : SqlGeneratorBase ()
PostgreSqlGenerator::PostgreSqlGenerator(QObject *parent) : SqlGeneratorBase (parent)
{
}
QString PostgreSqlGenerator::getColumnDef(Field *field)
QString PostgreSqlGenerator::fieldType(FieldModel *field)
{
QString ret = field->name + " ";
QString dbType;
switch (field->type) {
@ -27,8 +46,8 @@ QString PostgreSqlGenerator::getColumnDef(Field *field)
case QVariant::DateTime:
dbType = "timestamp";
break;
case QVariant::Double:
dbType = "real";
case QVariant::Time:
dbType = "time";
break;
case QVariant::Int:
if(field->isAutoIncrement)
@ -36,36 +55,42 @@ QString PostgreSqlGenerator::getColumnDef(Field *field)
else
dbType = "integer";
break;
case QVariant::Double:
dbType = "real";
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;
return dbType;
}
//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)
QString PostgreSqlGenerator::diff(FieldModel *oldField, FieldModel *newField)
{
return SqlGeneratorBase::deleteTableRows(tableName, where) + " RETURNING *";
QString sql = "";
if(oldField && newField)
if(*oldField == *newField)
return QString::null;
if(!newField){
sql = "DROP COLUMN " + oldField->name;
}else{
if(oldField){
sql = "ALTER COLUMN ";
sql.append(newField->name + " TYPE " + fieldType(newField));
} else {
sql = "ADD COLUMN ";
sql.append(fieldDeclare(newField));
}
}
return sql;
}
QT_END_NAMESPACE

View File

@ -1,3 +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/>.
**
**************************************************************************/
#ifndef POSTGRESQLGENERATOR_H
#define POSTGRESQLGENERATOR_H
@ -6,16 +26,14 @@
QT_BEGIN_NAMESPACE
class Field;
class PostgreSqlGenerator : public SqlGeneratorBase
{
public:
PostgreSqlGenerator();
PostgreSqlGenerator(QObject *parent = 0);
QString getColumnDef(Field *field);
// QString saveSql(Table *t, QString tableName);
QString fieldType(FieldModel *field);
QString deleteTableRows(QString tableName, QString where);
QString diff(FieldModel *oldField, FieldModel *newField);
};
QT_END_NAMESPACE

View File

@ -31,6 +31,7 @@
#include "tablesetbase_p.h"
#include "sqlgeneratorbase_p.h"
#include "querybase_p.h"
#include "wherephrase.h"
QT_BEGIN_NAMESPACE
@ -39,41 +40,48 @@ class NUT_EXPORT Query : public QueryBase
{
QString _tableName;
QString _select;
QString _where;
QString _joinClassName;
// QString _where;
Database *_database;
TableSetBase *_tableSet;
QString _joinClassName;
QList<FieldPhrase> _wheres;
public:
Query(Database *database, TableSetBase *tableSet);
Query(TableSet<T> *tset){
_database = tset->database();
_tableName = _database->tableName(T::staticMetaObject.className());
}
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> *setWhere(FieldPhrase where);
// Query<T> *setWhere(const QString &where);
Query<T> *orderBy(QString fieldName, QString type);
private:
static QHash<QString, QString> _compiledCommands;
QString compileCommand(QString command);
QString queryText();
QHash<QString, QString> _orders;
};
//template <typename T>
//inline Query<T> createQuery(TableSet<T> *tset)
//{
// return Query<T>(tset);
//}
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)
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());
}
@ -86,17 +94,17 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
qDebug()<<queryText();
QSqlQuery q = _database->exec(queryText());
QString pk =_database->model().scheema(_tableName)->primaryKey();
QString pk =_database->model().model(_tableName)->primaryKey();
QVariant lastPkValue = QVariant();
int childTypeId = 0;
T *lastRow = 0;
TableSetBase *childTableSet;
QStringList masterFields = _database->model().scheema(_tableName)->fieldsNames();
QStringList masterFields = _database->model().model(_tableName)->fieldsNames();
QStringList childFields;
if(!_joinClassName.isNull()){
childFields = _database->model().scheemaByClass(_joinClassName)->fieldsNames();
childFields = _database->model().modelByClass(_joinClassName)->fieldsNames();
QString joinTableName = _database->tableName(_joinClassName);
childTypeId = _database->model().scheema(joinTableName)->typeId();
childTypeId = _database->model().model(joinTableName)->typeId();
}
while (q.next()) {
@ -168,8 +176,8 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::count()
template<class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
{
QString sql = _database->sqlGenertor()->deleteTableRows(_tableName, _where);
sql = compileCommand(sql);
QString sql = _database->sqlGenertor()->deleteRecords(_tableName, queryText());
// sql = compileCommand(sql);
QSqlQuery q = _database->exec(sql);
return q.numRowsAffected();
}
@ -182,45 +190,23 @@ Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &tableName)
}
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(const QString &where)
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(FieldPhrase where)
{
_where = where;
_wheres.append(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>::setWhere(const QString &where)
//{
// _where = where;
// return this;
//}
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(QString fieldName, QString type)
{
_orders.insert(fieldName, type);
return this;
}
@ -252,21 +238,26 @@ Q_OUTOFLINE_TEMPLATE QString Query<T>::compileCommand(QString command)
template<class T>
Q_OUTOFLINE_TEMPLATE QString Query<T>::queryText()
{
QString orderby = "";
QString q = compileCommand(_where);
QStringList orderby;
QString q = "";//compileCommand(_where);
foreach (FieldPhrase p, _wheres) {
if(q != "")
q.append(" AND ");
q.append(p.command(_database->sqlGenertor()));
}
QString t = _tableName;
if(!_joinClassName.isNull()){
QString joinTableName = _database->tableName(_joinClassName);
Relation *rel = _database->model().relationByTableNames(_tableName, joinTableName);
RelationModel *rel = _database->model().relationByTableNames(_tableName, joinTableName);
if(rel){
QString pk = _database->model().scheema(_tableName)->primaryKey();
QString pk = _database->model().model(_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;
orderby.append(_tableName + "." + pk);
}else{
qWarning(QString("Relation between table %1 and class %2 (%3) not exists!")
.arg(_tableName)
@ -277,11 +268,23 @@ Q_OUTOFLINE_TEMPLATE QString Query<T>::queryText()
}
}
return QString("SELECT %1 FROM %2 %3%4")
QString orderText = "";
if(_orders.count())
foreach (QString o, _orders.keys())
orderby.append(o + " " + _orders.value(o));
if(orderby.count())
orderText = " ORDER BY " + orderby.join(", ");
QString command = QString("SELECT %1 FROM %2 %3%4")
.arg(_select)
.arg(t)
.arg(q.isEmpty() ? "" : "WHERE " + q)
.arg(orderby);
.arg(orderText);
for(int i = 0; i < _database->model().count(); i++)
command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + ".");
return command;
}
QT_END_NAMESPACE

View File

@ -15,4 +15,4 @@ signals:
public slots:
};
#endif // QUERYBASE_H
#endif // QUERYBASE_H

View File

@ -1,11 +1,36 @@
/**************************************************************************
**
** 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 <QDate>
#include <QDateTime>
#include <QTime>
#include <QVariant>
#include "databasemodel.h"
#include "sqlgeneratorbase_p.h"
#include "table.h"
#include "tablescheema.h"
#include "tablemodel.h"
QT_BEGIN_NAMESPACE
SqlGeneratorBase::SqlGeneratorBase()
SqlGeneratorBase::SqlGeneratorBase(QObject *parent) : QObject(parent)
{
}
@ -15,47 +40,60 @@ SqlGeneratorBase::~SqlGeneratorBase()
}
QString SqlGeneratorBase::saveSql(Table *t, QString tableName)
QString SqlGeneratorBase::masterDatabaseName(QString databaseName)
{
Q_UNUSED(databaseName);
return "";
}
QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
{
switch(t->status()){
case Table::Added:
return insertCommand(t, tableName);
return insertRecord(t, tableName);
case Table::Deleted:
return deleteCommand(t, tableName);
return deleteRecord(t, tableName);
case Table::Modified:
return updateCommand(t, tableName);
return updateRecord(t, tableName);
case Table::NewCreated:
case Table::FeatchedFromDB:
// disable compiler warning
return "***";
return "";
}
return "";
}
QStringList SqlGeneratorBase::getDiff(DatabaseModel lastModel, DatabaseModel newModel)
QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
{
return field->name + " " + fieldType(field);
}
QStringList SqlGeneratorBase::diff(DatabaseModel lastModel, DatabaseModel newModel)
{
QStringList ret;
QSet<QString> tableNames;
foreach (TableScheema *table, lastModel)
foreach (TableModel *table, lastModel)
tableNames.insert(table->name());
foreach (TableScheema *table, newModel)
foreach (TableModel *table, newModel)
tableNames.insert(table->name());
foreach (QString tableName, tableNames) {
TableScheema *oldTable = lastModel.scheema(tableName);
TableScheema *newTable = newModel.scheema(tableName);
ret << getDiff(oldTable, newTable);
TableModel *oldTable = lastModel.model(tableName);
TableModel *newTable = newModel.model(tableName);
ret << diff(oldTable, newTable);
}
return ret;
}
QString SqlGeneratorBase::getDiff(Field *oldField, Field *newField)
QString SqlGeneratorBase::diff(FieldModel *oldField, FieldModel *newField)
{
QString sql = "";
if(oldField && newField)
@ -69,12 +107,12 @@ QString SqlGeneratorBase::getDiff(Field *oldField, Field *newField)
sql = "ALTER COLUMN ";
else
sql = "ADD COLUMN ";
sql.append(getColumnDef(newField));
sql.append(fieldDeclare(newField));
}
return sql;
}
QString SqlGeneratorBase::getDiff(TableScheema *oldTable, TableScheema *newTable)
QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
{
if(oldTable && newTable)
if(*oldTable == *newTable)
@ -86,23 +124,23 @@ QString SqlGeneratorBase::getDiff(TableScheema *oldTable, TableScheema *newTable
QSet<QString> fieldNames;
if(oldTable)
foreach (Field *f, oldTable->fields())
foreach (FieldModel *f, oldTable->fields())
fieldNames.insert(f->name);
foreach (Field *f, newTable->fields())
foreach (FieldModel *f, newTable->fields())
fieldNames.insert(f->name);
QStringList columnSql;
foreach (QString fieldName, fieldNames) {
Field *newField = newTable->field(fieldName);
FieldModel *newField = newTable->field(fieldName);
if(oldTable){
Field *oldField = oldTable->field(fieldName);
FieldModel *oldField = oldTable->field(fieldName);
QString buffer = getDiff(oldField, newField);
QString buffer = diff(oldField, newField);
if(!buffer.isNull())
columnSql << buffer;
}else{
columnSql << getColumnDef(newField);
columnSql << fieldDeclare(newField);
}
}
QString sql;
@ -124,7 +162,7 @@ QString SqlGeneratorBase::getDiff(TableScheema *oldTable, TableScheema *newTable
return sql;
}
QString SqlGeneratorBase::insertCommand(Table *t, QString tableName)
QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
{
QString sql = "";
QString key = t->primaryKey();
@ -142,7 +180,7 @@ QString SqlGeneratorBase::insertCommand(Table *t, QString tableName)
return sql;
}
QString SqlGeneratorBase::updateCommand(Table *t, QString tableName)
QString SqlGeneratorBase::updateRecord(Table *t, QString tableName)
{
QString sql = "";
QString key = t->primaryKey();
@ -160,7 +198,7 @@ QString SqlGeneratorBase::updateCommand(Table *t, QString tableName)
return sql;
}
QString SqlGeneratorBase::deleteCommand(Table *t, QString tableName)
QString SqlGeneratorBase::deleteRecord(Table *t, QString tableName)
{
return QString("DELETE FROM %1 WHERE %2='%3'")
.arg(tableName)
@ -168,7 +206,7 @@ QString SqlGeneratorBase::deleteCommand(Table *t, QString tableName)
.arg(t->primaryValue().toString());
}
QString SqlGeneratorBase::deleteTableRows(QString tableName, QString where)
QString SqlGeneratorBase::deleteRecords(QString tableName, QString where)
{
QString sql = "";
if(where.isEmpty() || where.isNull())
@ -178,5 +216,38 @@ QString SqlGeneratorBase::deleteTableRows(QString tableName, QString where)
return sql;
}
QString SqlGeneratorBase::escapeFieldValue(QVariant &field) const
{
switch (field.type()) {
case QVariant::Int:
case QVariant::Double:
return field.toString();
break;
case QVariant::String:
return "'" + field.toString() + "'";
case QVariant::DateTime:
return "'" + field.toDateTime().toString(Qt::ISODate) + "'";
case QVariant::Date:
return "'" + field.toDate().toString(Qt::ISODate) + "'";
case QVariant::Time:
return "'" + field.toTime().toString(Qt::ISODate) + "'";
case QVariant::StringList:
case QVariant::List:
return "['" + field.toStringList().join("', '") + "']";
case QVariant::Invalid:
qFatal("Invalud field value");
return "<Invalid>";
default:
return "";
}
}
QT_END_NAMESPACE

View File

@ -1,35 +1,60 @@
/**************************************************************************
**
** 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 SQLGENERATORBASE_H
#define SQLGENERATORBASE_H
#include <QtCore/qglobal.h>
#include <QStringList>
#include <QtCore/QObject>
#include <QtCore/QStringList>
QT_BEGIN_NAMESPACE
class Table;
class Field;
struct FieldModel;
class DatabaseModel;
class TableScheema;
class SqlGeneratorBase
class TableModel;
class SqlGeneratorBase : public QObject
{
public:
SqlGeneratorBase();
SqlGeneratorBase(QObject *parent = 0);
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 masterDatabaseName(QString databaseName);
virtual QString fieldType(FieldModel *field) = 0;
virtual QString fieldDeclare(FieldModel *field);
virtual QStringList diff(DatabaseModel lastModel, DatabaseModel newModel);
virtual QString diff(FieldModel *oldField, FieldModel *newField);
virtual QString diff(TableModel *oldTable, TableModel *newTable);
virtual QString insertCommand(Table *t, QString tableName);
virtual QString updateCommand(Table *t, QString tableName);
virtual QString deleteCommand(Table *t, QString tableName);
virtual QString saveRecord(Table *t, QString tableName);
virtual QString insertRecord(Table *t, QString tableName);
virtual QString updateRecord(Table *t, QString tableName);
virtual QString deleteRecord(Table *t, QString tableName);
virtual QString deleteTableRows(QString tableName, QString where);
virtual QString deleteRecords(QString tableName, QString where);
virtual QString escapeFieldValue(QVariant &field) const;
};
QT_END_NAMESPACE

View File

@ -1,13 +1,33 @@
/**************************************************************************
**
** 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 "sqlitegenerator.h"
#include "table.h"
#include "tablescheema.h"
#include "tablemodel.h"
SqliteGenerator::SqliteGenerator() : SqlGeneratorBase()
SqliteGenerator::SqliteGenerator(QObject *parent) : SqlGeneratorBase(parent)
{
}
QString SqliteGenerator::getColumnDef(Field *field)
QString SqliteGenerator::fieldType(FieldModel *field)
{
QString ret = field->name + " ";
QString dbType;
@ -25,13 +45,16 @@ QString SqliteGenerator::getColumnDef(Field *field)
case QVariant::DateTime:
dbType = "datetime";
break;
case QVariant::Time:
dbType = "time";
break;
case QVariant::Double:
dbType = "real";
break;
case QVariant::Int:
// if(field->isAutoIncrement)
// dbType = "INTEGER PRIMARY KEY";
// else
if(field->isPrimaryKey)
dbType = "INTEGER PRIMARY KEY";
else
dbType = "integer";
break;
case QVariant::String:
@ -40,12 +63,9 @@ QString SqliteGenerator::getColumnDef(Field *field)
else
dbType = "text";
break;
case QVariant::Time:
dbType = "time";
break;
default:
dbType = "";
}
ret.append(dbType);
return ret;
return dbType;
}

View File

@ -1,3 +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/>.
**
**************************************************************************/
#ifndef SQLITEGENERATOR_H
#define SQLITEGENERATOR_H
@ -7,9 +27,9 @@
class SqliteGenerator : public SqlGeneratorBase
{
public:
SqliteGenerator();
SqliteGenerator(QObject *parent = 0);
QString getColumnDef(Field *field);
QString fieldType(FieldModel *field);
};
#endif // SQLITEGENERATOR_H

View File

@ -1,6 +1,105 @@
#include "sqlservergenerator.h"
/**************************************************************************
**
** 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/>.
**
**************************************************************************/
SqlServerGenerator::SqlServerGenerator()
#include "sqlservergenerator.h"
#include "table.h"
#include "tablemodel.h"
#include <QRegularExpression>
QT_BEGIN_NAMESPACE
SqlServerGenerator::SqlServerGenerator(QObject *parent) : SqlGeneratorBase(parent)
{
}
QString SqlServerGenerator::masterDatabaseName(QString databaseName)
{
return databaseName.replace(QRegularExpression("DATABASE\\=(\\w+)", QRegularExpression::CaseInsensitiveOption), "DATABASE=");
}
QString SqlServerGenerator::fieldType(FieldModel *field)
{
QString dbType;
switch (field->type) {
case QVariant::Bool:
dbType = "bit";
break;
case QVariant::ByteArray:
dbType = "varbinary";
if(field->length)
dbType.append(" (" + QString::number(field->length) + ")");
else
dbType.append(" (MAX)");
break;
case QVariant::Date:
dbType = "date";
break;
case QVariant::DateTime:
dbType = "datetime";
break;
case QVariant::Time:
dbType = "time";
break;
case QVariant::Double:
dbType = "real";
break;
case QVariant::Int:
dbType = "int";
if(field->isAutoIncrement)
dbType += " identity(1,1)";
break;
case QVariant::String:
if(field->length)
dbType = QString("varchar(%1)").arg(field->length);
else
dbType = "text";
break;
default:
dbType = "";
}
return dbType;
}
QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField)
{
QString sql = "";
if(oldField && newField)
if(*oldField == *newField)
return QString::null;
if(!newField){
sql = "DROP COLUMN " + oldField->name;
}else{
if(oldField)
sql = "MODIFY COLUMN ";
else
sql = "ADD ";
sql.append(fieldDeclare(newField));
}
return sql;
}
QT_END_NAMESPACE

View File

@ -1,12 +1,42 @@
/**************************************************************************
**
** 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 SQLSERVERGENERATOR_H
#define SQLSERVERGENERATOR_H
#include <QtCore/qglobal.h>
#include "sqlgeneratorbase_p.h"
class SqlServerGenerator
QT_BEGIN_NAMESPACE
class SqlServerGenerator : public SqlGeneratorBase
{
public:
SqlServerGenerator();
SqlServerGenerator(QObject *parent = 0);
QString masterDatabaseName(QString databaseName);
QString fieldType(FieldModel *field);
QString diff(FieldModel *oldField, FieldModel *newField);
};
#endif // SQLSERVERGENERATOR_H
QT_END_NAMESPACE
#endif // SQLSERVERGENERATOR_H

View File

@ -39,58 +39,38 @@ void Table::add(TableSetBase *t)
QString Table::primaryKey() const
{
static QString ret = QString::null;
// 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(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.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(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 = "";
}
// if(ret == QString::null)
// ret = "";
// }
return ret;
// return ret;
return TableModel::model(metaObject()->className())->primaryKey();
}
QString Table::autoIncrementField() const
bool Table::isPrimaryKeyAutoIncrement() 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;
return TableModel::model(metaObject()->className())->field(primaryKey())->isAutoIncrement;
}
QVariant Table::primaryValue() const
{
return property(primaryKey().toLatin1().data());
@ -101,7 +81,6 @@ void Table::propertyChanged(QString propName)
if(propName == primaryKey())
return;
// qDebug() << "Table::propertyChanged" << metaObject()->className() << propName;
_changedProperties.insert(propName);
if(_status == FeatchedFromDB)
_status = Modified;
@ -118,14 +97,17 @@ QSet<QString> Table::changedProperties() const
bool Table::setParentTable(Table *master)
{
QString masterClassName = master->metaObject()->className();
TableScheema *myModel = TableScheema::findByClassName(metaObject()->className());
TableModel *myModel = TableModel::findByClassName(metaObject()->className());
foreach (Relation *r, myModel->foregionKeys())
foreach (RelationModel *r, myModel->foregionKeys())
if(r->className == masterClassName)
{
setProperty(QString(r->localColumn).toLatin1().data(), master->primaryValue());
_changedProperties.insert(r->localColumn);
return true;
}
return false;
}
TableSetBase *Table::tableSet() const
@ -141,11 +123,9 @@ void Table::setTableSet(TableSetBase *parent)
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));
QSqlQuery q = db->exec(db->sqlGenertor()->saveRecord(this, db->tableName(metaObject()->className())));
if(status() == Added)
if(status() == Added && isPrimaryKeyAutoIncrement())
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
foreach(TableSetBase *ts, tableSets)

View File

@ -25,9 +25,9 @@
#include <QtCore/qglobal.h>
#include <QtCore/QSet>
#include "tablescheema.h"
#include "tablemodel.h"
#include "defines.h"
//#include "tableset.h"
#include "wherephrase.h"
QT_BEGIN_NAMESPACE
@ -52,7 +52,7 @@ public:
void save(Database *db);
QString primaryKey() const;
QString autoIncrementField() const;
bool isPrimaryKeyAutoIncrement() const;
QVariant primaryValue() const;
Status status() const;
void setStatus(const Status &status);
@ -77,14 +77,10 @@ private:
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

View File

@ -25,100 +25,103 @@
#include <QJsonArray>
#include <QJsonObject>
#include "tablescheema.h"
#include "tablemodel.h"
#include "defines_p.h"
QSet<TableScheema*> TableScheema::_allModels;
QSet<TableModel*> TableModel::_allModels;
//QMap<int, TableScheema*> TableScheema::scheemas;
QString TableScheema::name() const
QString TableModel::name() const
{
return _name;
}
void TableScheema::setName(const QString &name)
void TableModel::setName(const QString &name)
{
_name = name;
}
QString TableScheema::className() const
QString TableModel::className() const
{
return _className;
}
void TableScheema::setClassName(const QString &className)
void TableModel::setClassName(const QString &className)
{
_className = className;
}
int TableScheema::typeId() const
int TableModel::typeId() const
{
return _typeId;
}
void TableScheema::setTypeId(const int &typeId)
void TableModel::setTypeId(const int &typeId)
{
_typeId = typeId;
}
Field *TableScheema::field(QString name) const
FieldModel *TableModel::field(QString name) const
{
foreach (Field *f, _fields)
foreach (FieldModel *f, _fields)
if(f->name == name)
return f;
return 0;
}
QList<Field *> TableScheema::fields() const
QList<FieldModel *> TableModel::fields() const
{
return _fields;
}
QList<Relation *> TableScheema::foregionKeys() const
QList<RelationModel *> TableModel::foregionKeys() const
{
return _foregionKeys;
}
QStringList TableScheema::fieldsNames() const
QStringList TableModel::fieldsNames() const
{
QStringList ret;
foreach (Field *f, _fields)
foreach (FieldModel *f, _fields)
ret.append(f->name);
return ret;
}
TableScheema *TableScheema::findByTypeId(int typeId)
TableModel *TableModel::findByTypeId(int typeId)
{
foreach (TableScheema *model, _allModels)
foreach (TableModel *model, _allModels)
if(model->typeId() == typeId)
return model;
return 0;
}
TableScheema *TableScheema::findByName(QString name)
TableModel *TableModel::findByName(QString name)
{
foreach (TableScheema *model, _allModels)
foreach (TableModel *model, _allModels)
if(model->name() == name)
return model;
return 0;
}
TableScheema *TableScheema::findByClassName(QString className)
TableModel *TableModel::findByClassName(QString className)
{
foreach (TableScheema *model, _allModels)
foreach (TableModel *model, _allModels)
if(model->className() == className)
return model;
return 0;
}
bool TableScheema::operator ==(const TableScheema &t) const{
bool TableModel::operator ==(const TableModel &t) const{
if(_name != t.name())
return false;
foreach (Field *f, _fields) {
Field *tf = t.field(f->name);
if(fields().count() != t.fields().count())
return false;
foreach (FieldModel *f, _fields) {
FieldModel *tf = t.field(f->name);
if(!tf)
return false;
@ -129,12 +132,12 @@ bool TableScheema::operator ==(const TableScheema &t) const{
return true;
}
bool TableScheema::operator !=(const TableScheema &t) const
bool TableModel::operator !=(const TableModel &t) const
{
return !(*this == t);
}
TableScheema::TableScheema(int typeId, QString tableName)
TableModel::TableModel(int typeId, QString tableName)
{
const QMetaObject *tableMetaObject = QMetaType::metaObjectForType(typeId);
@ -153,7 +156,7 @@ TableScheema::TableScheema(int typeId, QString tableName)
QString propName = parts.at(1);
if(propName == __nut_FIELD){
Field *f = new Field;
FieldModel *f = new FieldModel;
f->name = parts.at(0);
_fields.append(f);
}
@ -163,13 +166,14 @@ TableScheema::TableScheema(int typeId, QString tableName)
for(int j = 1; j < tableMetaObject->propertyCount(); j++){
QMetaProperty fieldProperty = tableMetaObject->property(j);
Field *f = field(fieldProperty.name());
if(!f)
FieldModel *fieldObj = field(fieldProperty.name());
foreach (FieldModel *f, _fields)
if(f->name == fieldProperty.name())
f = fieldObj;
if(!fieldObj)
continue;
f->type = fieldProperty.type();
_fields.append(f);
fieldObj->type = fieldProperty.type();
}
// Browse class infos
@ -185,7 +189,7 @@ TableScheema::TableScheema(int typeId, QString tableName)
QString propName = parts.at(1);
if(propName == __nut_FOREGION_KEY){
Relation *fk = new Relation;
RelationModel *fk = new RelationModel;
fk->localColumn = parts.at(0);
fk->foregionColumn = value;
fk->className = value;
@ -197,7 +201,7 @@ TableScheema::TableScheema(int typeId, QString tableName)
}
Field *f = field(parts.at(0));
FieldModel *f = field(parts.at(0));
if(!f)
continue;
@ -211,6 +215,8 @@ TableScheema::TableScheema(int typeId, QString tableName)
f->isPrimaryKey = true;
else if(propName == __nut_AUTO_INCREMENT)
f->isAutoIncrement = true;
else if(propName == __nut_UNIQUE)
f->isUnique = true;
}
}
@ -234,14 +240,14 @@ TableScheema::TableScheema(int typeId, QString tableName)
"primary_key": "id"
},
*/
TableScheema::TableScheema(QJsonObject json, QString tableName)
TableModel::TableModel(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;
FieldModel *f = new FieldModel;
f->name = fieldObject.value(__NAME).toString();
f->type = QVariant::nameToType(fieldObject.value(__TYPE).toString().toLatin1().data());
@ -264,12 +270,12 @@ TableScheema::TableScheema(QJsonObject json, QString tableName)
}
QJsonObject TableScheema::toJson() const
QJsonObject TableModel::toJson() const
{
QJsonObject obj;
QJsonObject fieldsObj;
foreach (Field *f, _fields) {
foreach (FieldModel *f, _fields) {
QJsonObject fieldObj;
fieldObj.insert(__NAME, f->name);
fieldObj.insert(__TYPE, QVariant::typeToName(f->type));
@ -312,27 +318,27 @@ QJsonObject TableScheema::toJson() const
// }
//}
//TableScheema *TableScheema::scheema(QString className)
//{
// foreach (TableScheema *s, scheemas)
// if(s->_className == className)
// return s;
// return 0;
//}
Relation *TableScheema::foregionKey(QString otherTable) const
TableModel *TableModel::model(QString className)
{
foreach (Relation *fk, _foregionKeys)
foreach (TableModel *s, _allModels)
if(s->_className == className)
return s;
return 0;
}
RelationModel *TableModel::foregionKey(QString otherTable) const
{
foreach (RelationModel *fk, _foregionKeys)
if(fk->className == otherTable)
return fk;
return 0;
}
QString TableScheema::toString() const
QString TableModel::toString() const
{
QStringList sl;
foreach (Field *f, _fields)
foreach (FieldModel *f, _fields)
sl.append(f->name + " " + QVariant::typeToName(f->type));
QString ret = QString("%1 (%2)")
@ -341,9 +347,9 @@ QString TableScheema::toString() const
return ret;
}
QString TableScheema::primaryKey() const
QString TableModel::primaryKey() const
{
foreach (Field *f, _fields)
foreach (FieldModel *f, _fields)
if(f->isPrimaryKey)
return f->name;
return QString::null;

View File

@ -24,11 +24,11 @@
#include <QtCore/QVariant>
#include <QDebug>
class QJsonObject;
class TableScheema;
class TableModel;
struct Field{
Field() : name(QString::null), length(0), defaultValue(QString::null),
notNull(false), isPrimaryKey(false), isAutoIncrement(false)
struct FieldModel{
FieldModel() : name(QString::null), length(0), defaultValue(QString::null),
notNull(false), isPrimaryKey(false), isAutoIncrement(false), isUnique(false)
{
}
@ -40,8 +40,9 @@ struct Field{
bool notNull;
bool isPrimaryKey;
bool isAutoIncrement;
bool isUnique;
bool operator ==(const Field &f) const{
bool operator ==(const FieldModel &f) const{
bool b = name == f.name
&& type == f.type
@ -52,32 +53,32 @@ struct Field{
return b;
}
bool operator !=(const Field &f) const{
bool operator !=(const FieldModel &f) const{
return !(*this == f);
}
};
struct Relation{
struct RelationModel{
QString className;
QString localColumn;
TableScheema *table;
TableModel *table;
QString foregionColumn;
};
class TableScheema
class TableModel
{
public:
TableScheema(int typeId, QString tableName);
TableScheema(QJsonObject json, QString tableName);
TableModel(int typeId, QString tableName);
TableModel(QJsonObject json, QString tableName);
QJsonObject toJson() const;
// static TableScheema *registerTable(int typeId, QString tableName);
// static void createForegionKeys();
// static TableScheema* scheema(QString className);
static TableModel* model(QString className);
Field *field(QString name) const;
Relation *foregionKey(QString otherTable) const;
FieldModel *field(QString name) const;
RelationModel *foregionKey(QString otherTable) const;
QString toString() const;
@ -91,24 +92,24 @@ public:
int typeId() const;
void setTypeId(const int &typeId);
QList<Field *> fields() const;
QList<Relation *> foregionKeys() const;
QList<FieldModel *> fields() const;
QList<RelationModel *> foregionKeys() const;
QStringList fieldsNames() const;
static TableScheema *findByTypeId(int typeId);
static TableScheema *findByName(QString name);
static TableScheema *findByClassName(QString className);
static TableModel *findByTypeId(int typeId);
static TableModel *findByName(QString name);
static TableModel *findByClassName(QString className);
bool operator ==(const TableScheema &t) const;
bool operator !=(const TableScheema &t) const;
bool operator ==(const TableModel &t) const;
bool operator !=(const TableModel &t) const;
private:
QString _name;
QString _className;
int _typeId;
QList<Field*> _fields;
QList<Relation*> _foregionKeys;
static QSet<TableScheema*>_allModels;
QList<FieldModel*> _fields;
QList<RelationModel*> _foregionKeys;
static QSet<TableModel*>_allModels;
};
#endif // TABLESCHEEMA_H

View File

@ -47,6 +47,8 @@ public:
void remove(T *t);
void remove(QList<T*> t);
inline T type() const {}
int length() const;
T *at(int i) const;
const T &operator[](int i) const;
@ -82,19 +84,20 @@ Q_OUTOFLINE_TEMPLATE int TableSet<T>::length() const
template<class T>
Q_OUTOFLINE_TEMPLATE T *TableSet<T>::at(int i) const
{
return (T*)_tables.values().at(i);
return (T*)_tablesList.at(i);
}
template<class T>
Q_OUTOFLINE_TEMPLATE const T &TableSet<T>::operator[](int i) const
{
return _tables.values()[i];
return _tablesList[i];
}
template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(T *t)
{
_tables.insert(t);
_tablesList.append(t);
// rows.append(t);
t->setTableSet(this);
if(t->status() != Table::FeatchedFromDB)

View File

@ -35,7 +35,7 @@ TableSetBase::TableSetBase(Table *parent) : QObject(parent), _database(0), _tabl
void TableSetBase::save(Database *db)
{
foreach (Table *t, _tables) {
foreach (Table *t, _tablesList) {
if(_table)
t->setParentTable(_table);
@ -47,12 +47,31 @@ void TableSetBase::save(Database *db)
}
}
void TableSetBase::clearChilds()
{
foreach (Table *t, _tablesList)
delete t;
}
void TableSetBase::add(Table *t)
{
_tables.insert(t);
if(!_tables.contains(t)){
_tables.insert(t);
_tablesList.append(t);
}
}
QString TableSetBase::childClassName() const
{
return _childClassName;
}
Database *TableSetBase::database() const
{
return _database;
}
void TableSetBase::setDatabase(Database *database)
{
_database = database;
}

View File

@ -37,11 +37,16 @@ public:
TableSetBase(Table *parent);
virtual void save(Database *db);
void clearChilds();
void add(Table* t);
QString childClassName() const;
Database *database() const;
void setDatabase(Database *database);
protected:
QSet<Table*> _tables;
QList<Table*> _tablesList;
QString _tableName;
Database *_database;
Table *_table;

View File

@ -1,6 +1,349 @@
/**************************************************************************
**
** 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 <QDataStream>
#include <QDebug>
#include "wherephrase.h"
WherePhrase::WherePhrase()
{
QT_BEGIN_NAMESPACE
PhraseData::PhraseData(const char *className, const char *s){
text = QString(className) + "." + s;
type = Field;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) : left(l){
operatorCond = o;
type = WithoutOperand;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, const PhraseData *r) : left(l), right(r){
operatorCond = o;
type = WithOther;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r) : left(l), operand(r){
operatorCond = o;
type = WithVariant;
}
PhraseData::~PhraseData(){
// if(type == WithOther){
// delete left;
// delete right;
// }
// if(type == WithVariant){
//// qDebug() << operator
// delete left;
}
QString PhraseData::operatorString() const
{
switch (operatorCond){
case PhraseData::Equal:
return "=";
case PhraseData::NotEqual:
return "<>";
case PhraseData::Less:
return "<";
case PhraseData::Greater:
return ">";
case PhraseData::LessEqual:
return "<=";
case PhraseData::GreaterEqual:
return ">=";
case PhraseData::Null:
return "IS NULL";
case PhraseData::NotNull:
return "IS NOT NULL";
case PhraseData::In:
return "IN";
case PhraseData::NotIn:
return "NOT IN";
case PhraseData::And:
return "AND";
case PhraseData::Or:
return "OR";
case PhraseData::Like:
return "LIKE";
case PhraseData::NotLike:
return "NOT LIKE";
case PhraseData::Add:
return "+";
case PhraseData::Minus:
return "-";
case PhraseData::Multiple:
return "*";
case PhraseData::Divide:
return "/";
case PhraseData::Set:
return "=";
case PhraseData::Append:
return ",";
}
return QString("<FAIL>");
}
QString PhraseData::escapeVariant() const
{
switch (operand.type()) {
case QVariant::Int:
case QVariant::Double:
return operand.toString();
break;
case QVariant::String:
return "'" + operand.toString() + "'";
case QVariant::DateTime:
return "'" + operand.toDateTime().toString() + "'";
case QVariant::Date:
return "'" + operand.toDate().toString() + "'";
case QVariant::Time:
return "'" + operand.toTime().toString() + "'";
case QVariant::StringList:
case QVariant::List:
return "['" + operand.toStringList().join("', '") + "']";
case QVariant::Invalid:
return "<FAIL>";
default:
return "";
}
}
QString PhraseData::command(SqlGeneratorBase *generator) const
{
QString ret = "";
switch(type){
case Field:
ret = text;
break;
case WithVariant:
ret = left->command(generator) + " " + operatorString() + " " + escapeVariant();
break;
case WithOther:
ret = left->command(generator) + " " + operatorString() + " " + right->command(generator);
break;
case WithoutOperand:
ret = left->command(generator) + " " + operatorString();
break;
}
if(operatorCond == PhraseData::And || operatorCond == PhraseData::Or)
ret = "(" + ret + ")";
return ret;
}
FieldPhrase::FieldPhrase(const char *className, const char *s) : willDeleteData(false)
{
data = new PhraseData(className, s);
text = QString(className) + "." + s;
}
FieldPhrase::FieldPhrase(PhraseData *l) : willDeleteData(false)
{
data = l;
}
FieldPhrase::FieldPhrase(PhraseData *l, PhraseData::Condition o) : willDeleteData(false)
{
data = new PhraseData(l, o);
}
FieldPhrase::FieldPhrase(PhraseData *l, PhraseData::Condition o, PhraseData *r) : willDeleteData(false)
{
data = new PhraseData(l, o, r);
}
FieldPhrase::FieldPhrase(PhraseData *l, PhraseData::Condition o, QVariant r) : willDeleteData(false)
{
data = new PhraseData(l, o, r);
}
FieldPhrase::~FieldPhrase()
{
// if(willDeleteData)
// delete data;
}
QString FieldPhrase::command(SqlGeneratorBase *generator)
{
willDeleteData = true;
return data->command(generator);
}
void FieldPhrase::deleteData(PhraseData *d)
{
deleteData(d);
if(d->type == PhraseData::WithOther){
delete d->left;
delete d->right;
}
if(d->type == PhraseData::WithVariant)
delete d->left;
}
FieldPhrase FieldPhrase::operator ==(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Equal, other.data);
}
FieldPhrase FieldPhrase::operator !=(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::NotEqual, other.data);
}
FieldPhrase FieldPhrase::operator <(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Less, other.data);
}
FieldPhrase FieldPhrase::operator >(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Greater, other.data);
}
FieldPhrase FieldPhrase::operator <=(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::LessEqual, other.data);
}
FieldPhrase FieldPhrase::operator >=(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::GreaterEqual, other.data);
}
FieldPhrase FieldPhrase::operator =(const FieldPhrase &other)
{
return FieldPhrase(this->data, PhraseData::Set, other.data);
}
FieldPhrase FieldPhrase::operator +(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Add, other.data);
}
FieldPhrase FieldPhrase::operator -(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Minus, other.data);
}
FieldPhrase FieldPhrase::operator *(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Multiple, other.data);
}
FieldPhrase FieldPhrase::operator /(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Divide, other.data);
}
FieldPhrase FieldPhrase::operator &&(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::And, other.data);
}
FieldPhrase FieldPhrase::operator ||(const FieldPhrase &other){
return FieldPhrase(this->data, PhraseData::Or, other.data);
}
FieldPhrase FieldPhrase::operator &(const FieldPhrase &other)
{
return FieldPhrase(this->data, PhraseData::Append, other.data);
}
FieldPhrase FieldPhrase::operator ,(const FieldPhrase &other)
{
return FieldPhrase(this->data, PhraseData::Append, other.data);
}
FieldPhrase FieldPhrase::operator !(){
if(data->operatorCond < 20)
data->operatorCond = (PhraseData::Condition)((data->operatorCond + 10) % 20);
else
qFatal("Operator ! can not aplied to non condition statements");
return FieldPhrase(data);
}
FieldPhrase FieldPhrase::operator ==(const QVariant &other){
return FieldPhrase(this->data, PhraseData::Equal, other);
}
FieldPhrase FieldPhrase::operator !=(const QVariant &other){
return FieldPhrase(this->data, PhraseData::NotEqual, other);
}
FieldPhrase FieldPhrase::operator <(const QVariant &other){
return FieldPhrase(this->data, PhraseData::Less, other);
}
FieldPhrase FieldPhrase::operator >(const QVariant &other){
qDebug() << "var";
return FieldPhrase(this->data, PhraseData::Greater, other);
}
FieldPhrase FieldPhrase::operator <=(const QVariant &other){
return FieldPhrase(this->data, PhraseData::LessEqual, other);
}
FieldPhrase FieldPhrase::operator >=(const QVariant &other){
return FieldPhrase(this->data, PhraseData::GreaterEqual, other);
}
FieldPhrase FieldPhrase::operator =(const QVariant &other)
{
return FieldPhrase(this->data, PhraseData::Set, other);
}
FieldPhrase FieldPhrase::isNull(){
return FieldPhrase(this->data, PhraseData::Null);
}
FieldPhrase FieldPhrase::in(QVariantList list)
{
return FieldPhrase(this->data, PhraseData::In, list);
}
FieldPhrase FieldPhrase::in(QStringList list)
{
return FieldPhrase(this->data, PhraseData::In, list);
}
FieldPhrase FieldPhrase::like(QString pattern)
{
return FieldPhrase(this->data, PhraseData::Like, pattern);
}
QT_END_NAMESPACE

View File

@ -1,12 +1,151 @@
#ifndef WHEREPHRASE_H
#define WHEREPHRASE_H
/**************************************************************************
**
** 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 PHRASE_H
#define PHRASE_H
#include <QtCore/qglobal.h>
class WherePhrase
{
public:
WherePhrase();
#include <QVariant>
#include <QDate>
#include <QDateTime>
#include <QTime>
QT_BEGIN_NAMESPACE
class SqlGeneratorBase;
struct PhraseData{
enum Condition
{
Equal = 0,
Less,
LessEqual,
Null,
In,
Like,
NotEqual = 10,
GreaterEqual,
Greater,
NotNull,
NotIn,
NotLike,
And = 20,
Or,
Append,
Set,
Add,
Minus,
Multiple,
Divide
};
enum Type{
Field,
WithVariant,
WithOther,
WithoutOperand
};
Type type;
Condition operatorCond;
QString text;
const PhraseData *left;
const PhraseData *right;
QVariant operand;
PhraseData(const char *className, const char* s);
PhraseData(PhraseData *l, Condition o);
PhraseData(PhraseData *l, Condition o, const PhraseData *r);
PhraseData(PhraseData *l, Condition o, QVariant r);
~PhraseData();
QString operatorString() const;
QString escapeVariant() const;
QString command(SqlGeneratorBase *generator) const;
};
#endif // WHEREPHRASE_H
class FieldPhrase{
PhraseData *data;
bool willDeleteData;
public:
QString text;
FieldPhrase(const char *className, const char* s);
FieldPhrase(PhraseData *l);
FieldPhrase(PhraseData *l, PhraseData::Condition o);
FieldPhrase(PhraseData *l, PhraseData::Condition o, PhraseData *r);
FieldPhrase(PhraseData *l, PhraseData::Condition o, QVariant r);
~FieldPhrase();
QString command(SqlGeneratorBase *generator);
void deleteData(PhraseData *d);
FieldPhrase operator ==(const FieldPhrase &other);
FieldPhrase operator !=(const FieldPhrase &other);
FieldPhrase operator <(const FieldPhrase &other);
FieldPhrase operator >(const FieldPhrase &other);
FieldPhrase operator <=(const FieldPhrase &other);
FieldPhrase operator >=(const FieldPhrase &other);
FieldPhrase operator =(const FieldPhrase &other);
FieldPhrase operator +(const FieldPhrase &other);
FieldPhrase operator -(const FieldPhrase &other);
FieldPhrase operator *(const FieldPhrase &other);
FieldPhrase operator /(const FieldPhrase &other);
FieldPhrase operator &&(const FieldPhrase &other);
FieldPhrase operator ||(const FieldPhrase &other);
FieldPhrase operator &(const FieldPhrase &other);
FieldPhrase operator ,(const FieldPhrase &other);
FieldPhrase operator !();
FieldPhrase operator ==(const QVariant &other);
FieldPhrase operator !=(const QVariant &other);
FieldPhrase operator <(const QVariant &other);
FieldPhrase operator >(const QVariant &other);
FieldPhrase operator <=(const QVariant &other);
FieldPhrase operator >=(const QVariant &other);
FieldPhrase operator =(const QVariant &other);
FieldPhrase isNull();
FieldPhrase in(QVariantList list);
FieldPhrase in(QStringList list);
FieldPhrase like(QString pattern);
};
QT_END_NAMESPACE
#endif // PHRASE_H

Binary file not shown.

View File

@ -14,6 +14,7 @@ class Comment : public Table
NUT_DECLARE_FIELD(int, id, id, setId)
NUT_DECLARE_FIELD(QString, message, message, setMessage)
NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate)
NUT_DECLARE_FIELD(qreal, point, point, setPoint)
NUT_FOREGION_KEY(Post, int, post, post, setPost)

View File

@ -5,7 +5,7 @@
#include "maintest.h"
#include "query.h"
#include "tableset.h"
#include "tablescheema.h"
#include "tablemodel.h"
#include "databasemodel.h"
#include "post.h"
@ -18,18 +18,47 @@ MainTest::MainTest(QObject *parent) : QObject(parent)
void MainTest::initTestCase()
{
qDebug() << "Table type id:" << qRegisterMetaType<Table*>();
// 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");
//sql server
// db.setDriver("QODBC");
// db.setHostName("127.0.0.1");
// db.setDatabaseName("DRIVER={SQL Server};Server=.;Database=Nut;Uid=sa;Port=1433;Pwd=qwe123!@#;WSID=.");
// db.setUserName("sa");
// db.setPassword("qwe123!@#");
QStringList list;
list << "one" << "two" << "three";
FieldPhrase q = (Post::idField() = 1)
& (Post::saveDateField() = QDateTime::currentDateTime())
& (Post::saveDateField() < QDateTime::currentDateTime()
// (/*(Post::saveDateField() > Post::idField())
// && */
// !Post::saveDateField().isNull()
// &&
// !Post::idField().in(list)
// || (Post::idField() == 4)
// && Post::saveDateField() >= QDateTime::currentDateTime()
/*|| Post::saveDateField().isNull()*/);
qDebug() << "Command="<< q.command(0);
QTEST_ASSERT(1==2);
// postgres
db.setDriver("QPSQL");
db.setHostName("127.0.0.1");
db.setDatabaseName("nutdb");
// db.setUserName("postgres");
// db.setPassword("856856");
db.setDatabaseName("nutdb3");
db.setUserName("postgres");
db.setPassword("856856");
// mysql
// db.setDriver("QMYSQL");
// db.setHostName("127.0.0.1");
// db.setDatabaseName("nutdb");
// db.setUserName("root");
// db.setPassword("onlyonlyi");
bool ok = db.open();
QTEST_ASSERT(ok);
@ -49,13 +78,14 @@ void MainTest::createPost()
{
Post *newPost = new Post;
newPost->setTitle("post title");
newPost->setSaveDate(QDateTime::currentDateTime());
db.posts()->append(newPost);
for(int i = 0 ; i < 3; i++){
Comment *comment = new Comment;
comment->setMessage("comment #" + QString::number(i));
comment->setSaveDate(QDateTime::currentDateTime());
newPost->comments()->append(comment);
}
db.saveChanges();
@ -68,22 +98,48 @@ void MainTest::createPost()
void MainTest::selectPosts()
{
auto q = FROM(db.posts())
JOIN(Comment)
WHERE(Post::id() == %1)
BIND(postId);
q = FROM(db.posts())
JOIN(Comment)
WHERE(Post::idField() == postId);
auto posts = q->toList();
post = posts.at(0);
post->setBody("");
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");
db.cleanUp();
}
void MainTest::testDate()
{
QDateTime d = QDateTime::currentDateTime();
QTime t = QTime(d.time().hour(), d.time().minute(), d.time().second());
d.setTime(t);
Post *newPost = new Post;
newPost->setTitle("post title");
newPost->setSaveDate(d);
db.posts()->append(newPost);
db.saveChanges();
auto q = FROM(db.posts())
WHERE(Post::idField() == newPost->id())
FIRST();
qDebug() << d << q->saveDate();
QTEST_ASSERT(q->saveDate() == d);
}
void MainTest::selectWithInvalidRelation()
{
auto q = FROM(db.posts())
@ -94,8 +150,7 @@ void MainTest::selectWithInvalidRelation()
void MainTest::modifyPost()
{
auto q = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId);
WHERE(Post::idField() == postId);
Post *post = q->first();
@ -105,8 +160,8 @@ void MainTest::modifyPost()
db.saveChanges();
q = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId);
WHERE(Post::idField() == postId);
post = q->first();
QTEST_ASSERT(post->title() == "new name");
}
@ -114,15 +169,13 @@ void MainTest::modifyPost()
void MainTest::deletePost()
{
auto count = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId)
WHERE(Post::idField() == postId)
DELETE();
QTEST_ASSERT(count == 1);
count = FROM(db.posts())
WHERE(Post::id() == %1)
BIND(postId)
WHERE(Post::idField() == postId)
COUNT();
QTEST_ASSERT(count == 0);

View File

@ -5,12 +5,14 @@
#include <QtCore/qglobal.h>
#include "weblogdatabase.h"
class Post;
class MainTest : public QObject
{
Q_OBJECT
WeblogDatabase db;
int postId;
Post *post;
Query<Post> *q;
public:
explicit MainTest(QObject *parent = 0);
@ -22,6 +24,7 @@ private slots:
void dataScheema();
void createPost();
void selectPosts();
void testDate();
void selectWithInvalidRelation();
void modifyPost();
void deletePost();

View File

@ -18,6 +18,8 @@ class Post : public Table
NUT_LEN(title, 50)
NUT_DECLARE_FIELD(QString, title, title, setTitle)
NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate)
NUT_DECLARE_FIELD(QString, body, body, setBody)
NUT_DECLARE_CHILD_TABLE(Comment, comments)

View File

@ -9,7 +9,7 @@ class WeblogDatabase : public Database
{
Q_OBJECT
NUT_DB_VERSION(1, 0)
NUT_DB_VERSION(1, 1)
NUT_DECLARE_TABLE(Post, post)