Merge pull request #43 from HamedMasafi/dev

Finally _dev_ merged into _master_ !!!
This commit is contained in:
Hamed Masafi 2019-06-19 11:38:24 +04:30 committed by GitHub
commit 404c1c3198
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
148 changed files with 5546 additions and 2101 deletions

2
.gitignore vendored
View File

@ -32,3 +32,5 @@ Makefile*
#QtCtreator Qml
*.qmlproject.user
*.qmlproject.user.*
build

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "3rdparty/serializer"]
path = 3rdparty/serializer
url = https://github.com/HamedMasafi/Serializer.git

View File

@ -13,29 +13,23 @@ compiler:
env:
matrix:
- QT=5 BREW=
- QT=5 BREW=ex PPA=ubuntu-sdk-team/ppa
- QT=51 BREW=ex PPA=beineri/opt-qt511-trusty
- QT=52 BREW=ex PPA=beineri/opt-qt521-trusty
- QT=53 BREW=ex PPA=beineri/opt-qt532-trusty
- QT=54 BREW=ex PPA=beineri/opt-qt542-trusty
- QT=55 BREW=@5.5 PPA=beineri/opt-qt551-trusty
- QT=56 BREW=ex PPA=beineri/opt-qt562-trusty
- QT=56 BREW=ex PPA=beineri/opt-qt563-trusty
- QT=57 BREW=@5.7 PPA=beineri/opt-qt571-trusty
- QT=58 BREW=ex PPA=beineri/opt-qt58-trusty
- QT=59 BREW=@5.9 PPA=beineri/opt-qt591-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt591-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt592-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt593-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt594-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt595-trusty
- QT=59 BREW=ex PPA=beineri/opt-qt596-trusty
- QT=510 BREW=ex PPA=beineri/opt-qt-5.10.1-trusty
matrix:
exclude:
- { os: osx, env: QT=5 BREW=ex PPA=ubuntu-sdk-team/ppa }
- { os: osx, env: QT=51 BREW=ex PPA=beineri/opt-qt511-trusty }
- { os: osx, env: QT=52 BREW=ex PPA=beineri/opt-qt521-trusty }
- { os: osx, env: QT=53 BREW=ex PPA=beineri/opt-qt532-trusty }
- { os: osx, env: QT=54 BREW=ex PPA=beineri/opt-qt542-trusty }
- { os: osx, env: QT=56 BREW=ex PPA=beineri/opt-qt562-trusty }
- { os: osx, env: QT=56 BREW=ex PPA=beineri/opt-qt563-trusty }
- { os: osx, env: QT=58 BREW=ex PPA=beineri/opt-qt58-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt591-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt592-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt593-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt594-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt595-trusty }
- { os: osx, env: QT=59 BREW=ex PPA=beineri/opt-qt596-trusty }
- { os: osx, env: QT=510 BREW=ex PPA=beineri/opt-qt-5.10.1-trusty }
addons:
coverity_scan:
@ -72,7 +66,8 @@ before_script:
- '[[ "$TRAVIS_OS_NAME" != linux || "$PPA" != */opt-* ]] || . /opt/qt$QT/bin/qt$QT-env.sh'
- '[[ "$TRAVIS_OS_NAME" != linux || "$PPA" == */opt-* ]] || export QT_SELECT=qt5'
- mkdir -p "$TRAVIS_BUILD_DIR-build"
- qmake -o "$TRAVIS_BUILD_DIR-build" -r -Wall -Wlogic -Wparser CONFIG+=debug_and_release "$TRAVIS_BUILD_DIR"
- cd "$TRAVIS_BUILD_DIR-build"
- qmake -r -Wall -Wlogic -Wparser CONFIG+=debug_and_release "$TRAVIS_BUILD_DIR/nut.pro"
script:
- make -C "$TRAVIS_BUILD_DIR-build" all

1
3rdparty/serializer vendored Submodule

@ -0,0 +1 @@
Subproject commit f9d81fcc6244271b3926891b0c86554e1e6b967e

View File

@ -1,11 +1,17 @@
# Nut
## Build result
| Brancc name | Icon |
| Branch | Status |
| ------------- |:-------------:|
| master | [![Build Status](https://travis-ci.org/HamedMasafi/Nut.svg?branch=master)](https://travis-ci.org/HamedMasafi/Nut) |
| dev | [![Build Status](https://travis-ci.org/HamedMasafi/Nut.svg?branch=dev)](https://travis-ci.org/HamedMasafi/Nut) |
[![GitLicense](https://gitlicense.com/badge/hamedmasafi/nut)](https://gitlicense.com/license/hamedmasafi/nut)
[![Codacy
Badge](https://api.codacy.com/project/badge/Grade/f3802610beb946068f6cd2c2b6608a8b)](https://www.codacy.com/app/HamedMasafi/Nut?utm_source=github.com&utm_medium=referral&utm_content=HamedMasafi/Nut&utm_campaign=Badge_Grade)
## Advanced, Powerful and easy to use ORM for Qt5
@ -17,6 +23,52 @@
- Automatically create and update database
- IDE auto complete support, No hard-code nedded
- Table join detect
- Supported types:
| Type | Sqlite | MySql | Postgresql| Ms Sql server |
|--------|--------|--------|--------|--------|
| QBitArray | BLOB | VARBINARY | BYTEA | VARBINARY (MAX) |
| QByteArray | BLOB | BLOB | BYTEA | VARBINARY (MAX) |
| QChar | NCHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) |
| QColor | TEXT | TEXT | TEXT | TEXT |
| QDate | DATE | DATE | DATE | DATE |
| QDateTime | DATETIME | DATETIME | TIMESTAMP | DATETIME |
| QJsonArray | TEXT | TEXT | JSON | TEXT |
| QJsonDocument | TEXT | TEXT | JSON | TEXT |
| QJsonObject | TEXT | TEXT | JSON | TEXT |
| QJsonValue | TEXT | TEXT | JSON | TEXT |
| QLine | TEXT | TEXT | LINE | TEXT |
| QLineF | TEXT | TEXT | LINE | TEXT |
| QPoint | TEXT | POINT | POINT | GEOMETRY |
| QPointF | TEXT | POINT | POINT | GEOMETRY |
| QPolygon | TEXT | POLYGON | POLYGON | TEXT |
| QPolygonF | TEXT | POLYGON | POLYGON | TEXT |
| QRect | TEXT | TEXT | BOX | TEXT |
| QRectF | TEXT | TEXT | BOX | TEXT |
| QSize | TEXT | TEXT | TEXT | TEXT |
| QSizeF | TEXT | TEXT | TEXT | TEXT |
| QString | TEXT | TEXT | TEXT | NVARCHAR(MAX) |
| QStringList | TEXT[^*] | TEXT | TEXT[] | TEXT |
| QTime | TIME | TIME | TIME | TIME |
| QUrl | TEXT | TEXT | TEXT | TEXT |
| QUuid | TEXT | VARCHAR(64) | UUID | UNIQUEIDENTIFIER |
| bool | BOOLEAN | BOOLEAN | BOOLEAN | BIT |
| char | TINYINT | CHAR(1) | CHAR(1) | CHAR(1) |
| double | DOUBLE | REAL | REAL | REAL |
| float | FLOAT | FLOAT | FLOAT | FLOAT(24) |
| int | INT | INT | INTEGER | INT |
| long | MEDIUMINT | BIGINT | BIGINT | BIGINT |
| qlonglong | BIGINT | BIGINT | BIGINT | BIGINT |
| qulonglong | BIGINT UNSIGNED | BIGINT | BIGINT | BIGINT |
| short | SMALLINT | SMALLINT | SMALLINT | SMALLINT |
| signed char | TINYINT | TINYINT | SMALLINT | TINYINT |
| uchar | TINYINT UNSIGNED | TINYINT | SMALLINT | TINYINT |
| uint | INT UNSIGNED | INT | INTEGER | INT |
| ulong | MEDIUMINT UNSIGNED | BIGINT | BIGINT | BIGINT |
| ushort | SMALLINT UNSIGNED | SMALLINT | SMALLINT | SMALLINT |
[^*]: Using internal store/restore serialization
## Sample Codes
### Read data from database:

1
ci-test-init.pri Normal file
View File

@ -0,0 +1 @@
#QT -= gui

View File

@ -1,5 +1,7 @@
#include "../src/table.h"
#include "../src/database.h"
#include "../src/sqlmodel.h"
#include "../src/tableset.h"
#include "../src/tablemodel.h"
#include "../src/query.h"

1
include/SqlModel Normal file
View File

@ -0,0 +1 @@
#include "../src/sqlmodel.h"

1
include/TableModel Normal file
View File

@ -0,0 +1 @@
#include "../src/tablemodel.h"

6
include/header_copier Normal file → Executable file
View File

@ -3,11 +3,10 @@
src_dir="src"
namespace_name="nut"
ns=$(echo $namespace_name|awk '{print tolower($0)}')
#ns=$(echo $namespace_name|awk '{print tolower($0)}')
Ns="Nut"
NS=$(echo $namespace_name|awk '{print toupper($0)}')
echo $NS
exit
create_sub_folder=true
@ -38,5 +37,6 @@ while read line; do
echo "#include \"../$src_dir/$header.h\"" >> "$Ns"
echo "#include \"../$src_dir/$header.h\"" >> "$ns.h"
fi
echo $Ns
done <&3
exec 3<&-

View File

@ -1,6 +1,7 @@
#include "../src/table.h"
#include "../src/database.h"
#include "../src/sqlmodel.h"
#include "../src/tableset.h"
#include "../src/dbgeography.h"
#include "../src/tablemodel.h"
#include "../src/query.h"

1
include/sqlmodel.h Normal file
View File

@ -0,0 +1 @@
#include "../src/sqlmodel.h"

1
include/tablemodel.h Normal file
View File

@ -0,0 +1 @@
#include "../src/tablemodel.h"

10
nut-dynamic.pro Normal file
View File

@ -0,0 +1,10 @@
QT += sql gui
TARGET = nut
TEMPLATE = lib
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS NUT_COMPILE_STATIC
include($$PWD/src/src.pri)
include($$PWD/3rdparty/serializer/src/src.pri)

30
nut.pri
View File

@ -3,6 +3,8 @@ QT += core sql
CONFIG += c++11
INCLUDEPATH += $$PWD/include
DEFINES += NUT_SHARED_POINTER
include(3rdparty/serializer/src/src.pri)
HEADERS += \
$$PWD/src/generators/sqlgeneratorbase_p.h \
@ -27,7 +29,19 @@ HEADERS += \
$$PWD/src/serializableobject.h \
$$PWD/src/sqlmodel.h \
$$PWD/src/sqlmodel_p.h \
$$PWD/src/phrase.h
$$PWD/src/phrase.h \
$$PWD/src/tuple.h \
$$PWD/src/phrases/conditionalphrase.h \
$$PWD/src/phrases/abstractfieldphrase.h \
$$PWD/src/phrases/fieldphrase.h \
$$PWD/src/phrases/phraselist.h \
$$PWD/src/phrases/assignmentphraselist.h \
$$PWD/src/phrases/phrasedatalist.h \
$$PWD/src/phrases/phrasedata.h \
$$PWD/src/phrases/assignmentphrase.h \
$$PWD/src/phrases/numericphrase.h \
$$PWD/src/phrases/datephrase.h \
$$PWD/src/bulkinserter.h
SOURCES += \
$$PWD/src/generators/sqlgeneratorbase.cpp \
@ -47,4 +61,16 @@ SOURCES += \
$$PWD/src/database.cpp \
$$PWD/src/serializableobject.cpp \
$$PWD/src/sqlmodel.cpp \
$$PWD/src/phrase.cpp
$$PWD/src/phrase.cpp \
$$PWD/src/tuple.cpp \
$$PWD/src/phrases/conditionalphrase.cpp \
$$PWD/src/phrases/abstractfieldphrase.cpp \
$$PWD/src/phrases/fieldphrase.cpp \
$$PWD/src/phrases/phraselist.cpp \
$$PWD/src/phrases/assignmentphraselist.cpp \
$$PWD/src/phrases/phrasedatalist.cpp \
$$PWD/src/phrases/phrasedata.cpp \
$$PWD/src/phrases/assignmentphrase.cpp \
$$PWD/src/phrases/numericphrase.cpp \
$$PWD/src/phrases/datephrase.cpp \
$$PWD/src/bulkinserter.cpp

55
nut.pro
View File

@ -1,53 +1,6 @@
QT += sql
QT -= gui
TEMPLATE = subdirs
TARGET = nut
TEMPLATE = lib
CONFIG += c++11
SUBDIRS += \
src \
test
DEFINES += QT_DEPRECATED_WARNINGS
HEADERS += \
$$PWD/src/generators/sqlgeneratorbase_p.h \
$$PWD/src/generators/postgresqlgenerator.h \
$$PWD/src/generators/mysqlgenerator.h \
$$PWD/src/generators/sqlitegenerator.h \
$$PWD/src/generators/sqlservergenerator.h \
$$PWD/src/types/dbgeography.h \
$$PWD/src/tableset.h \
$$PWD/src/defines_p.h \
$$PWD/src/defines.h \
$$PWD/src/query.h \
$$PWD/src/databasemodel.h \
$$PWD/src/changelogtable.h \
$$PWD/src/tablesetbase_p.h \
$$PWD/src/querybase_p.h \
$$PWD/src/tablemodel.h \
$$PWD/src/query_p.h \
$$PWD/src/table.h \
$$PWD/src/database.h \
$$PWD/src/database_p.h \
$$PWD/src/serializableobject.h \
$$PWD/src/sqlmodel.h \
$$PWD/src/sqlmodel_p.h \
$$PWD/src/phrase.h
SOURCES += \
$$PWD/src/generators/sqlgeneratorbase.cpp \
$$PWD/src/generators/postgresqlgenerator.cpp \
$$PWD/src/generators/mysqlgenerator.cpp \
$$PWD/src/generators/sqlitegenerator.cpp \
$$PWD/src/generators/sqlservergenerator.cpp \
$$PWD/src/types/dbgeography.cpp \
$$PWD/src/tableset.cpp \
$$PWD/src/query.cpp \
$$PWD/src/databasemodel.cpp \
$$PWD/src/tablesetbase.cpp \
$$PWD/src/changelogtable.cpp \
$$PWD/src/querybase.cpp \
$$PWD/src/tablemodel.cpp \
$$PWD/src/table.cpp \
$$PWD/src/database.cpp \
$$PWD/src/serializableobject.cpp \
$$PWD/src/sqlmodel.cpp \
$$PWD/src/phrase.cpp

43
src/bulkinserter.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "bulkinserter.h"
#include "phrases/phraselist.h"
#include "database.h"
#include "generators/sqlgeneratorbase_p.h"
#include "databasemodel.h"
#include <QDebug>
Nut::BulkInserter::BulkInserter(Nut::Database *db, QString &className)
: _database(db), _fieldCount(0)
{
foreach (TableModel *m, db->model())
if (m->className() == className)
_className = m->name();
}
void Nut::BulkInserter::setFields(const Nut::PhraseList &ph)
{
_fields = ph;
_fieldCount = static_cast<size_t>(ph.data.count());
}
void Nut::BulkInserter::insert(std::initializer_list<QVariant> vars)
{
if (vars.size() != _fieldCount) {
qInfo("Number of rows mistake");
return;
}
QVariantList list;
std::initializer_list<QVariant>::iterator it;
for (it = vars.begin(); it != vars.end(); ++it)
list.append(*it);
variants.append(list);
}
int Nut::BulkInserter::apply()
{
auto sql = _database->sqlGenertor()->insertBulk(_className, _fields, variants);
QSqlQuery q = _database->exec(sql);
return q.numRowsAffected();
}

36
src/bulkinserter.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef BULKINSERTER_H
#define BULKINSERTER_H
#include <initializer_list>
#include <QDebug>
#include "defines.h"
#include "phrases/phraselist.h"
#include "phrases/fieldphrase.h"
NUT_BEGIN_NAMESPACE
class PhraseList;
class Database;
class BulkInserter
{
Database *_database;
QString _className;
Nut::PhraseList _fields;
QList<QVariantList> variants;
size_t _fieldCount;
public:
BulkInserter(Database *db, QString &className);
void setFields(const PhraseList &ph);
void insert(std::initializer_list<QVariant> vars);
template<typename... Args>
void insert(Args... args) {
insert({args...});
}
int apply();
};
NUT_END_NAMESPACE
#endif // BULKINSERTER_H

View File

@ -35,7 +35,7 @@ class ChangeLogTable : public Table
NUT_DECLARE_FIELD(QString, data, data, setData)
NUT_DECLARE_FIELD(QString, version, version, setVersion)
NUT_DECLARE_FIELD(int, version, version, setVersion)
public:
explicit ChangeLogTable(QObject *parentTableSet = Q_NULLPTR);

View File

@ -45,7 +45,9 @@
#include <iostream>
#include <cstdarg>
#define __CHANGE_LOG_TABLE_NAME "__change_logs"
#ifndef __CHANGE_LOG_TABLE_NAME
# define __CHANGE_LOG_TABLE_NAME "__change_logs"
#endif
NUT_BEGIN_NAMESPACE
@ -53,7 +55,7 @@ qulonglong DatabasePrivate::lastId = 0;
QMap<QString, DatabaseModel> DatabasePrivate::allTableMaps;
DatabasePrivate::DatabasePrivate(Database *parent) : q_ptr(parent),
port(0), sqlGenertor(0), changeLogs(0),
port(0), sqlGenertor(nullptr), changeLogs(nullptr),
isDatabaseNew(false)
{
}
@ -69,12 +71,13 @@ bool DatabasePrivate::open(bool update)
db = QSqlDatabase::addDatabase(driver, connectionName);
db.setHostName(hostName);
db.setPort(port);
if (port)
db.setPort(port);
db.setDatabaseName(databaseName);
db.setUserName(userName);
db.setPassword(password);
if (driver.toLower().startsWith("qsqlite")
if (driver.startsWith("qsqlite", Qt::CaseInsensitive)
&& !QFile::exists(databaseName)) {
//Force to execute update database
isDatabaseNew = true;
@ -108,18 +111,18 @@ bool DatabasePrivate::open(bool update)
isDatabaseNew = true;
return open(update);
} else {
qWarning("Unknown error detecting change logs, %s",
db.lastError().text().toLatin1().data());
}
qWarning("Unknown error detecting change logs, %s",
db.lastError().text().toLatin1().data());
}
return false;
}
if(update)
// if(update)
return updateDatabase();
else
return true;
// else
// return true;
}
bool DatabasePrivate::updateDatabase()
@ -134,24 +137,39 @@ bool DatabasePrivate::updateDatabase()
if (last == current) {
qDebug("Databse is up-to-date");
//TODO: crash without this and I don't know why!
changeLogs->clearChilds();
return true;
}
foreach (TableModel *tm, current) {
foreach (FieldModel *fm, tm->fields()) {
if (sqlGenertor->fieldType(fm).isEmpty()) {
qWarning("The type (%s) is not supported for field %s::%s",
QMetaType::typeName(fm->type),
qPrintable(tm->className()),
qPrintable(fm->name));
return false;
}
}
}
if (!last.count())
qDebug("Databse is new");
else
qDebug("Databse is changed");
QStringList sql = sqlGenertor->diff(last, current);
qDebug()<<"database Sql =\n"<<sql;
db.transaction();
foreach (QString s, sql) {
db.exec(s);
if (db.lastError().type() != QSqlError::NoError)
if (db.lastError().type() != QSqlError::NoError) {
qWarning("Error executing sql command `%s`, %s",
qPrintable(s),
db.lastError().text().toLatin1().data());
return false;
}
}
putModelToDatabase();
bool ok = db.commit();
@ -159,15 +177,9 @@ qDebug()<<"database Sql =\n"<<sql;
if (db.lastError().type() == QSqlError::NoError) {
q->databaseUpdated(last.version(), current.version());
if (!last.count())
q->databaseCreated();
for (int i = 0; i < q->metaObject()->methodCount(); i++) {
QMetaMethod m = q->metaObject()->method(i);
if (m.name() == "update" + current.version()) {
m.invoke(q, Qt::DirectConnection,
Q_ARG(QString, current.version()));
break;
}
}
} else {
qWarning("Unable update database, error = %s",
db.lastError().text().toLatin1().data());
@ -186,6 +198,7 @@ bool DatabasePrivate::getCurrectScheema()
return false;
}
QMap<QString, QString> tables;
tables.clear();
// TODO: change logs must not be in model
@ -205,7 +218,9 @@ bool DatabasePrivate::getCurrectScheema()
if (!nutClassInfoString(q->metaObject()->classInfo(i),
type, name, value)) {
qDebug() << "No valid table in" << q->metaObject()->classInfo(i).value();
errorMessage = QString("No valid table in %1")
.arg(q->metaObject()->classInfo(i).value());
continue;
}
if (type == __nut_TABLE) {
@ -222,23 +237,13 @@ bool DatabasePrivate::getCurrectScheema()
currentModel.append(sch);
}
if (type == __nut_DB_VERSION)
currentModel.setVersion(name);
/* TODO: remove
QStringList version
= QString(ci.value()).replace("\"", "").split('.');
bool ok = false;
if (version.length() == 1) {
currentModel.setVersion(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 (type == __nut_DB_VERSION) {
bool ok;
int version = value.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");*/
qFatal("NUT_DB_VERSION macro accept version in format 'x'");
currentModel.setVersion(version);
}
}
for (int i = 1; i < q->metaObject()->propertyCount(); i++) {
@ -252,42 +257,37 @@ bool DatabasePrivate::getCurrectScheema()
}
}
foreach (TableModel *table, currentModel)
foreach (TableModel *table, currentModel) {
foreach (FieldModel *f, table->fields()) {
if (f->isPrimaryKey && ! sqlGenertor->supportPrimaryKey(f->type))
qFatal("The field of type %s does not support as primary key",
qPrintable(f->typeName));
if (f->isAutoIncrement && ! sqlGenertor->supportAutoIncrement(f->type))
qFatal("The field of type %s does not support as auto increment",
qPrintable(f->typeName));
}
foreach (RelationModel *fk, table->foregionKeys())
fk->masterTable = currentModel.tableByClassName(fk->masterClassName);
}
allTableMaps.insert(q->metaObject()->className(), currentModel);
return true;
}
//bool DatabasePrivate::checkClassInfo(const QMetaClassInfo &classInfo, QString &type, QString &name, QString &value)
//{
// if (!QString(classInfo.name()).startsWith(__nut_NAME_PERFIX)) {
// return false;
// } else {
// QStringList parts = QString(classInfo.value()).split("\n");
// if (parts.count() != 3)
// return false;
// type = parts[0];
// name = parts[1];
// value = parts[2];
// return true;
// }
//}
DatabaseModel DatabasePrivate::getLastScheema()
{
ChangeLogTable *u = changeLogs->query()
Row<ChangeLogTable> u = changeLogs->query()
->orderBy(!ChangeLogTable::idField())
->first();
// DatabaseModel ret(q->metaObject()->className());
if (u) {
QJsonParseError e;
QJsonObject json
= QJsonDocument::fromJson(
QByteArray(u->data().toLocal8Bit().data())).object();
= QJsonDocument::fromJson(u->data().replace("\\\"", "\"").toUtf8(), &e).object();
DatabaseModel ret = json;
return ret;
@ -321,11 +321,11 @@ bool DatabasePrivate::putModelToDatabase()
DatabaseModel current = currentModel;
/*current.remove(__CHANGE_LOG_TABLE_NAME)*/;
ChangeLogTable *changeLog = new ChangeLogTable();
changeLog->setData(QJsonDocument(current.toJson()).toJson());
auto changeLog = create<ChangeLogTable>();
changeLog->setData(QJsonDocument(current.toJson()).toJson(QJsonDocument::Compact));
changeLog->setVersion(current.version());
changeLogs->append(changeLog);
q->saveChanges();
q->saveChanges(true);
changeLog->deleteLater();
return true;
@ -344,9 +344,10 @@ bool DatabasePrivate::putModelToDatabase()
void DatabasePrivate::createChangeLogs()
{
// currentModel.model("change_log")
QString diff = sqlGenertor->diff(0, currentModel.tableByName("__change_log"));
QStringList diff = sqlGenertor->diff(nullptr, currentModel.tableByName("__change_log"));
db.exec(diff);
foreach (QString s, diff)
db.exec(s);
}
/*!
@ -357,6 +358,7 @@ void DatabasePrivate::createChangeLogs()
Database::Database(QObject *parent)
: QObject(parent), d_ptr(new DatabasePrivate(this))
{
// _d = new QSharedDataPointer<DatabasePrivate>(new DatabasePrivate(this));
DatabasePrivate::lastId++;
}
@ -364,6 +366,7 @@ Database::Database(const Database &other)
: QObject(other.parent()), d_ptr(new DatabasePrivate(this))
{
DatabasePrivate::lastId++;
// _d = other._d;
setDriver(other.driver());
setHostName(other.hostName());
@ -393,8 +396,7 @@ Database::~Database()
if (d->db.isOpen())
d->db.close();
if (d_ptr)
delete d_ptr;
delete d_ptr;
}
QString Database::databaseName() const
@ -516,7 +518,12 @@ QSqlDatabase Database::database()
return d->db;
}
void Database::databaseUpdated(QString oldVersion, QString newVersion)
void Database::databaseCreated()
{
}
void Database::databaseUpdated(int oldVersion, int newVersion)
{
Q_UNUSED(oldVersion);
Q_UNUSED(newVersion);
@ -559,10 +566,9 @@ bool Database::open(bool updateDatabase)
if (!d->sqlGenertor) {
qFatal("Sql generator for driver %s not found",
driver().toLatin1().constData());
return false;
} else {
return d->open(updateDatabase);
}
return d->open(updateDatabase);
}
void Database::close()
@ -571,7 +577,7 @@ void Database::close()
d->db.close();
}
QSqlQuery Database::exec(QString sql)
QSqlQuery Database::exec(const QString &sql)
{
Q_D(Database);
@ -592,6 +598,12 @@ void Database::add(TableSetBase *t)
int Database::saveChanges(bool cleanUp)
{
Q_D(Database);
if (!d->db.isOpen()) {
qWarning("Database is not open");
return 0;
}
int rowsAffected = 0;
foreach (TableSetBase *ts, d->tableSets)
rowsAffected += ts->save(this, cleanUp);

View File

@ -24,6 +24,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/QList>
#include <QtSql/QSqlDatabase>
#include <QSharedDataPointer>
#include "defines.h"
#include "tableset.h"
@ -39,11 +40,12 @@ class NUT_EXPORT Database : public QObject
{
Q_OBJECT
// QSharedDataPointer<DatabasePrivate> *_d;
DatabasePrivate *d_ptr;
Q_DECLARE_PRIVATE(Database)
public:
explicit Database(QObject *parent = 0);
explicit Database(QObject *parent = nullptr);
explicit Database(const Database &other);
explicit Database(const QSqlDatabase &other);
~Database();
@ -52,7 +54,7 @@ public:
bool open(bool updateDatabase);
void close();
QSqlQuery exec(QString sql);
QSqlQuery exec(const QString& sql);
int saveChanges(bool cleanUp = false);
void cleanUp();
@ -73,7 +75,8 @@ public:
protected:
//remove minor version
virtual void databaseUpdated(QString oldVersion, QString newVersion);
virtual void databaseCreated();
virtual void databaseUpdated(int oldVersion, int newVersion);
public slots:
void setDatabaseName(QString databaseName);

View File

@ -25,11 +25,12 @@
#include "databasemodel.h"
#include <QDebug>
#include <QSharedData>
NUT_BEGIN_NAMESPACE
class ChangeLogTable;
class DatabasePrivate
class DatabasePrivate //: public QSharedData
{
Database *q_ptr;
Q_DECLARE_PUBLIC(Database)
@ -45,8 +46,6 @@ public:
DatabaseModel getLastScheema();
bool getCurrectScheema();
// bool checkClassInfo(const QMetaClassInfo &classInfo,
// QString &type, QString &name, QString &value);
QSqlDatabase db;
QString hostName;
@ -62,14 +61,14 @@ public:
TableSet<ChangeLogTable> *changeLogs;
QT_DEPRECATED
QMap<QString, QString> tables;
static QMap<QString, DatabaseModel> allTableMaps;
static qulonglong lastId;
QSet<TableSetBase *> tableSets;
bool isDatabaseNew;
QString errorMessage;
};
NUT_END_NAMESPACE

View File

@ -31,13 +31,13 @@ QMap<QString, DatabaseModel*> DatabaseModel::_models;
#define NODE_VERSION "version"
#define NODE_TABLES "tables"
DatabaseModel::DatabaseModel(const QString &name) :
QList<TableModel*>(), _databaseClassName(name), _version(QString())
QList<TableModel*>(), _databaseClassName(name), _version(0)
{
_models.insert(name, this);
}
DatabaseModel::DatabaseModel(const DatabaseModel &other) :
QList<TableModel*>(other), _version(QString())
QList<TableModel*>(other), _version(0)
{
}
@ -45,7 +45,7 @@ DatabaseModel::DatabaseModel(const DatabaseModel &other) :
DatabaseModel::DatabaseModel(const QJsonObject &json) :
QList<TableModel*>()
{
setVersion(json.value(NODE_VERSION).toString());
setVersion(json.value(NODE_VERSION).toInt());
QJsonObject tables = json.value(NODE_TABLES).toObject();
foreach (QString key, tables.keys()) {
@ -57,11 +57,7 @@ DatabaseModel::DatabaseModel(const QJsonObject &json) :
}
}
DatabaseModel::~DatabaseModel()
{
}
TableModel *DatabaseModel::tableByName(QString tableName) const
TableModel *DatabaseModel::tableByName(const QString &tableName) const
{
for(int i = 0; i < size(); i++){
TableModel *s = at(i);
@ -72,7 +68,7 @@ TableModel *DatabaseModel::tableByName(QString tableName) const
// qWarning("Table with name '%s' not found in model",
// qUtf8Printable(tableName));
return 0;
return nullptr;
}
TableModel *DatabaseModel::tableByClassName(QString className) const
@ -86,7 +82,7 @@ TableModel *DatabaseModel::tableByClassName(QString className) const
return s;
}
return 0;
return nullptr;
}
bool DatabaseModel::operator ==(const DatabaseModel &other) const
@ -108,19 +104,19 @@ bool DatabaseModel::operator ==(const DatabaseModel &other) const
return true;
}
DatabaseModel DatabaseModel::operator +(const DatabaseModel &other)
{
DatabaseModel model;
DatabaseModel::const_iterator i;
//DatabaseModel DatabaseModel::operator +(const DatabaseModel &other)
//{
// DatabaseModel model;
// DatabaseModel::const_iterator i;
for (i = constBegin(); i != constEnd(); ++i)
model.append(*i);
// for (i = constBegin(); i != constEnd(); ++i)
// model.append(*i);
for (i = other.constBegin(); i != other.constEnd(); ++i)
model.append(*i);
// for (i = other.constBegin(); i != other.constEnd(); ++i)
// model.append(*i);
return model;
}
// return model;
//}
QJsonObject DatabaseModel::toJson() const
{
@ -148,13 +144,13 @@ RelationModel *DatabaseModel::relationByClassNames(const QString &masterClassNam
TableModel *childTable = tableByClassName(childClassName);
if(!childTable)
return 0;
return nullptr;
foreach (RelationModel *rel, childTable->foregionKeys())
if(rel->masterClassName == masterClassName)
return rel;
return 0;
return nullptr;
}
RelationModel *DatabaseModel::relationByTableNames(const QString &masterTableName, const QString &childTableName)
@ -162,20 +158,20 @@ RelationModel *DatabaseModel::relationByTableNames(const QString &masterTableNam
TableModel *childTable = tableByName(childTableName);
if(!childTable)
return 0;
return nullptr;
foreach (RelationModel *rel, childTable->foregionKeys())
if(rel->masterTable->name() == masterTableName)
return rel;
return 0;
return nullptr;
}
DatabaseModel DatabaseModel::fromJson(QJsonObject &json)
{
DatabaseModel model;
model.setVersion(json.value(NODE_VERSION).toString());
model.setVersion(json.value(NODE_VERSION).toInt());
QJsonObject tables = json.value(NODE_TABLES).toObject();
foreach (QString key, tables.keys()) {
@ -188,12 +184,12 @@ DatabaseModel DatabaseModel::fromJson(QJsonObject &json)
return model;
}
QString DatabaseModel::version() const
int DatabaseModel::version() const
{
return _version;
}
void DatabaseModel::setVersion(QString version)
void DatabaseModel::setVersion(int version)
{
_version = version;
}
@ -236,7 +232,44 @@ void DatabaseModel::deleteAllModels()
// qDeleteAll(i.value());
}
// qDeleteAll(_models.values());
_models.clear();
_models.clear();
}
DatabaseModel operator +(const DatabaseModel &l, const DatabaseModel &r)
{
DatabaseModel model;
DatabaseModel::const_iterator i;
for (i = r.constBegin(); i != r.constEnd(); ++i)
model.append(*i);
for (i = l.constBegin(); i != l.constEnd(); ++i)
model.append(*i);
return model;
}
DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r)
{
DatabaseModel ret;
DatabaseModel::const_iterator i;
QSet<QString> tables;
for (i = r.constBegin(); i != r.constEnd(); ++i) {
if (tables.contains((*i)->name()))
continue;
ret.append(*i);
tables.insert((*i)->name());
}
for (i = l.constBegin(); i != l.constEnd(); ++i) {
if (tables.contains((*i)->name()))
continue;
ret.append(*i);
tables.insert((*i)->name());
}
return ret;
}
NUT_END_NAMESPACE

View File

@ -36,16 +36,16 @@ struct RelationModel;
class DatabaseModel : public QList<TableModel *>
{
QString _databaseClassName;
QString _version;
int _version;
static QMap<QString, DatabaseModel *> _models;
public:
DatabaseModel(const QString &name = QString());
DatabaseModel(const DatabaseModel &other);
DatabaseModel(const QJsonObject &json);
~DatabaseModel();
~DatabaseModel() = default;
TableModel *tableByName(QString tableName) const;
TableModel *tableByName(const QString &tableName) const;
TableModel *tableByClassName(QString className) const;
RelationModel *relationByClassNames(const QString &masterClassName,
@ -54,15 +54,15 @@ public:
const QString &childClassName);
bool operator==(const DatabaseModel &other) const;
DatabaseModel operator +(const DatabaseModel &other);
// DatabaseModel operator +(const DatabaseModel &other);
Q_DECL_DEPRECATED
static DatabaseModel fromJson(QJsonObject &json);
QJsonObject toJson() const;
operator QJsonObject();
QString version() const;
void setVersion(QString version);
int version() const;
void setVersion(int version);
bool remove(const QString &tableName);
@ -73,6 +73,9 @@ public:
static void deleteAllModels();
};
DatabaseModel operator +(const DatabaseModel &l, const DatabaseModel &r);
DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r);
NUT_END_NAMESPACE
#endif // DATABASEMODEL_H

View File

@ -45,6 +45,83 @@
Q_CLASSINFO(__nut_NAME_PERFIX type #name #value, \
type "\n" #name "\n" value)
#define NUT_FIELD_PERFIX
#define NUT_FIELD_POSTFIX Field
// Database
#define NUT_DB_VERSION(version) \
NUT_INFO(__nut_DB_VERSION, version, 0)
#define NUT_DECLARE_TABLE(type, name) \
NUT_INFO(__nut_TABLE, type, name) \
Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name READ name) \
NUT_WRAP_NAMESPACE(TableSet<type>) *m_##name; \
public: \
static const type *_##name; \
NUT_WRAP_NAMESPACE(TableSet<type>) *name() const \
{ return m_##name; } \
private:
//Table
#define NUT_DECLARE_FIELD(type, name, read, write) \
Q_PROPERTY(type name READ read WRITE write) \
NUT_INFO(__nut_FIELD, name, 0) \
type m_##name; \
public: \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>)& name ## Field(){ \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = \
NUT_WRAP_NAMESPACE(FieldPhrase<type>) \
(staticMetaObject.className(), #name); \
return f; \
} \
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(Nut::Row<type> name READ read WRITE write) \
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
NUT_INFO(__nut_FOREGION_KEY, name, type) \
Nut::Row<type> m_##name; \
public: \
Nut::Row<type> read() const { return m_##name ; } \
void write(Nut::Row<type> name){ \
m_##name = name; \
}
#define NUT_DECLARE_CHILD_TABLE(type, n) \
private: \
NUT_WRAP_NAMESPACE(TableSet)<type> *m_##n; \
public: \
static type *n##Table(); \
NUT_WRAP_NAMESPACE(TableSet)<type> *n();
#define NUT_IMPLEMENT_CHILD_TABLE(class, type, n) \
type *class::n##Table(){ \
static auto f = new type(); \
return f; \
} \
NUT_WRAP_NAMESPACE(TableSet)<type> *class::n(){ \
return m_##n; \
}
#define NUT_FIELD(name) NUT_INFO(__nut_FIELD, name, 0)
#define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0)
#define NUT_AUTO_INCREMENT(x) NUT_INFO(__nut_AUTO_INCREMENT, x, 0)
#define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_INFO(__nut_PRIMARY_KEY_AI, x, 0)
#define NUT_DISPLAY_NAME(field, name) NUT_INFO(__nut_DISPLAY, field, name)
#define NUT_UNIQUE(x) NUT_INFO(__nut_UNIQUE, x, 0)
#define NUT_LEN(field, len) NUT_INFO(__nut_LEN, field, len)
#define NUT_DEFAULT_VALUE(x, n) NUT_INFO(__nut_DEFAULT_VALUE, x, n)
#define NUT_NOT_NULL(x) NUT_INFO(__nut_NOT_NULL, x, 1)
#define NUT_INDEX(name, field, order)
NUT_BEGIN_NAMESPACE
inline bool nutClassInfo(const QMetaClassInfo &classInfo,
QString &type, QString &name, QVariant &value)
{
@ -117,76 +194,57 @@ inline bool nutClassInfoInt(const QMetaClassInfo &classInfo,
}
}
#ifdef NUT_SHARED_POINTER
template <class T>
using RowList = QList<QSharedPointer<T>>;
// Database
#define NUT_DB_VERSION(version) \
NUT_INFO(__nut_DB_VERSION, version, 0)
template <class T>
using RowSet = QSet<QSharedPointer<T>>;
#define NUT_DECLARE_TABLE(type, name) \
NUT_INFO(__nut_TABLE, type, name) \
Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name READ name) \
NUT_WRAP_NAMESPACE(TableSet<type>) *m_##name; \
public: \
static const type *_##name; \
NUT_WRAP_NAMESPACE(TableSet<type>) *name() const \
{ return m_##name; } \
private:
template <typename T>
using Row = QSharedPointer<T>;
//Table
#define NUT_DECLARE_FIELD(type, name, read, write) \
Q_PROPERTY(type name READ read WRITE write) \
NUT_INFO(__nut_FIELD, name, 0) \
type m_##name; \
public: \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>)& name ## Field(){ \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = \
NUT_WRAP_NAMESPACE(FieldPhrase<type>) \
(staticMetaObject.className(), #name); \
return f; \
} \
type read() const{ \
return m_##name; \
} \
void write(type name){ \
m_##name = name; \
propertyChanged(#name); \
}
template<class T>
inline Row<T> create() {
return QSharedPointer<T>(new T);
}
#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) \
NUT_INFO(__nut_FOREGION_KEY, name, type) \
type *m_##name; \
public: \
type *read() const { return m_##name ; } \
void write(type *name){ \
m_##name = name; \
}
template<class T>
inline T *get(T *row) {
return row;
}
template<class T>
inline T *get(const QSharedPointer<T> row) {
return row.data();
}
#define NUT_DECLARE_CHILD_TABLE(type, n) \
private: \
NUT_WRAP_NAMESPACE(TableSet)<type> *m_##n; \
public: \
static type *n##Table(); \
NUT_WRAP_NAMESPACE(TableSet)<type> *n();
#else
template <typename T>
using RowList = QList<T*>;
#define NUT_IMPLEMENT_CHILD_TABLE(class, type, n) \
type *class::n##Table(){ \
static type *f = new type(); \
return f; \
} \
NUT_WRAP_NAMESPACE(TableSet)<type> *class::n(){ \
return m_##n; \
}
template <typename T>
using RowSet = QSet<T*>;
#define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0)
#define NUT_AUTO_INCREMENT(x) NUT_INFO(__nut_AUTO_INCREMENT, x, 0)
#define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_INFO(__nut_PRIMARY_KEY_AI, x, 0)
#define NUT_DISPLAY_NAME(field, name) NUT_INFO(__nut_DISPLAY, field, name)
#define NUT_UNIQUE(x) NUT_INFO(__nut_UNIQUE, x, 0)
#define NUT_LEN(field, len) NUT_INFO(__nut_LEN, field, len)
#define NUT_DEFAULT_VALUE(x, n) NUT_INFO(__nut_DEFAULT_VALUE, x, n)
#define NUT_NOT_NULL(x) NUT_INFO(__nut_NOT_NULL, x, 1)
#define NUT_INDEX(name, field, order)
template <typename T>
using Row = T*;
template<class T>
inline Row<T> create() {
return new T;
}
template<class T>
inline T *get(const Row<T> row) {
return row;
}
template<class T>
inline T *get(const QSharedPointer<T> row) {
return row.data();
}
#endif
NUT_END_NAMESPACE
#endif // SYNTAX_DEFINES_H

View File

@ -23,6 +23,15 @@
#include <QPoint>
#include <QPointF>
#include <QTime>
#include <QDate>
#include <QDateTime>
#ifdef QT_GUI_LIB
#include <QPolygon>
#include <QPolygonF>
#endif
#include "sqlserializer.h"
NUT_BEGIN_NAMESPACE
@ -36,52 +45,71 @@ QString MySqlGenerator::fieldType(FieldModel *field)
QString dbType;
switch (field->type) {
case QVariant::Bool:
dbType = "BOOLEAN";
break;
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;
case QVariant::Int:
dbType = "INT(4)";
case QMetaType::Bool: return "BOOLEAN";
case QMetaType::Char:
case QMetaType::QChar: return "CHAR(1)";
case QMetaType::SChar:
case QMetaType::UChar: return "TINYINT";
case QMetaType::Short:
case QMetaType::UShort: return "SMALLINT";
case QMetaType::UInt:
case QMetaType::Int:
dbType = "INT";
if(field->isAutoIncrement)
dbType += " AUTO_INCREMENT";
break;
case QVariant::String:
case QMetaType::Long:
case QMetaType::ULong:
case QMetaType::LongLong:
case QMetaType::ULongLong:
return "BIGINT";
case QMetaType::Float:
return "FLOAT";
case QMetaType::Double:
return "REAL";
case QMetaType::QBitArray: return "VARBINARY";
case QMetaType::QByteArray: return "BLOB";
case QMetaType::QDate: return "DATE";
case QMetaType::QTime: return "TIME";
case QMetaType::QDateTime: return "DATETIME";
case QMetaType::QString:
if(field->length)
dbType = QString("VARCHAR(%1)").arg(field->length);
else
dbType = "TEXT";
break;
case QVariant::Point:
case QVariant::PointF:
dbType = "POINT";
break;
case QVariant::Polygon:
case QVariant::PolygonF:
dbType = "POLYGON";
break;
case QMetaType::QPolygon:
case QMetaType::QPolygonF:
// dbType = "POLYGON";
// break;
case QVariant::Uuid:
dbType = "VARCHAR(64)";
break;
case QMetaType::QUuid:
// dbType = "VARCHAR(64)";
// break;
case QMetaType::QPoint:
case QMetaType::QPointF:
// dbType = "POINT";
// break;
case QMetaType::QSize:
case QMetaType::QSizeF:
case QMetaType::QRect:
case QMetaType::QRectF:
case QMetaType::QLine:
case QMetaType::QLineF:
case QMetaType::QColor:
case QMetaType::QUrl:
case QMetaType::QJsonArray:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonDocument:
case QMetaType::QStringList: return "TEXT";
default:
qWarning("Type %s::%s(%d) is not supported",
@ -91,38 +119,146 @@ QString MySqlGenerator::fieldType(FieldModel *field)
dbType = QString();
}
if(field->typeName == QStringLiteral("Nut::DbGeography"))
dbType = "GEOMETRY";
// if(field->typeName == QStringLiteral("Nut::DbGeography"))
// dbType = "GEOMETRY";
return dbType;
}
QString MySqlGenerator::escapeValue(const QVariant &v) const
{
switch (v.type()) {
case QVariant::Point: {
QPoint pt = v.toPoint();
return QString("GeomFromText('POINT(%1 %2)',0)").arg(pt.x()).arg(pt.y());
}
if (v.type() == QVariant::Bool)
return v.toBool() ? "1" : "0";
case QVariant::PointF: {
QPointF pt = v.toPointF();
return QString("GeomFromText('POINT(%1 %2)',0)").arg(pt.x()).arg(pt.y());
}
if (v.type() == QVariant::Time)
return "'" + v.toTime().toString("HH:mm:ss") + "'";
default:
if (v.type() == QVariant::Date)
return "'" + v.toDate().toString("yyyy-MM-dd") + "'";
if (v.type() == QVariant::DateTime)
return "'" + v.toDateTime().toString("yyyy-MM-dd HH:mm:ss") + "'";
//#ifdef QT_GUI_LIB
// if (v.type() == QVariant::Polygon) {
// QString ret;
// QPoint pt;
// QPolygon pol = v.value<QPolygon>();
// for (int i = 0; i < pol.size(); ++i) {
// pt = pol.at(i);
// if (!ret.isEmpty())
// ret.append(", ");
// ret.append(QString::number(pt.x()) + " " + QString::number(pt.y()));
// }
// return "GeomFromText('POLYGON(" + ret + "))')";
// }
// if (v.type() == QVariant::PolygonF) {
// QString ret;
// QPointF pt;
// QPolygonF pol = v.value<QPolygonF>();
// for (int i = 0; i < pol.size(); ++i) {
// pt = pol.at(i);
// if (!ret.isEmpty())
// ret.append("),(");
// ret.append(QString::number(pt.x()) + " " + QString::number(pt.y()));
// }
// return "GeomFromText('POLYGON(" + ret + "))')";
// }
//#endif
// switch (v.type()) {
// case QMetaType::QPoint: {
// QPoint pt = v.toPoint();
// return QString("GeomFromText('POINT(%1 %2)',0)").arg(pt.x()).arg(pt.y());
// }
// case QMetaType::QPointF: {
// QPointF pt = v.toPointF();
// return QString("GeomFromText('POINT(%1 %2)',0)").arg(pt.x()).arg(pt.y());
// }
// default:
return SqlGeneratorBase::escapeValue(v);
}
// }
}
QVariant MySqlGenerator::readValue(const QVariant::Type &type, const QVariant &dbValue)
QVariant MySqlGenerator::unescapeValue(const QMetaType::Type &type, const QVariant &dbValue)
{
if (type == QVariant::PointF) {
qDebug() << "QVariant::PointF" << dbValue;
}
return SqlGeneratorBase::readValue(type, dbValue);
//#ifdef QT_GUI_LIB
// if (type == QMetaType::QPolygon) {
// qDebug() << "p=" << dbValue;
// QString p;
// QString ref = dbValue.toString();
// QPolygon pol;
// if (!readInsideParentese(ref, p))
// return pol;
// QStringList parts = p.split(",");
// foreach (QString v, parts) {
// QList<int> l = _serializer->toListInt(p.trimmed(), " ");
// if (l.count() != 2)
// return QPolygon();
// pol.append(QPoint(l.at(0), l.at(1)));
// }
// return pol;
// }
// if (type == QMetaType::QPolygonF) {
// QString p;
// QString ref = dbValue.toString();
// QPolygonF pol;
// if (!readInsideParentese(ref, p))
// return pol;
// QStringList parts = p.split(",");
// foreach (QString v, parts) {
// QList<qreal> l = _serializer->toListReal(p.trimmed(), " ");
// if (l.count() != 2)
// return QPolygonF();
// pol.append(QPointF(l.at(0), l.at(1)));
// }
// return pol;
// }
//#endif
if (type == QMetaType::QDateTime)
return dbValue.toDateTime();
if (type == QMetaType::QTime)
return dbValue.toTime();
if (type == QMetaType::QDate)
return dbValue.toDate();
return SqlGeneratorBase::unescapeValue(type, dbValue);
}
bool MySqlGenerator::readInsideParentese(QString &text, QString &out)
{
int start = -1;
int end = -1;
int pc = 0;
for (int i = 0; i < text.length(); ++i) {
QChar ch = text.at(i);
if (ch == '(') {
if (start == -1)
start = i;
pc++;
}
if (ch == ')') {
pc--;
if (!pc && end == -1)
end = i;
}
if (start != -1 && end != -1){
out = text.mid(start + 1, end - start - 1);
text = text.mid(end + 1);
return true;
}
}
return false;
}
//QString MySqlGenerator::phrase(const PhraseData *d) const
//{
// if (d->operatorCond == PhraseData::Distance) {

View File

@ -33,9 +33,11 @@ public:
QString fieldType(FieldModel *field);
QString escapeValue(const QVariant &v) const;
QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue);
// QString phrase(const PhraseData *d) const;
// QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QList<RelationModel *> joins, int skip, int take);
// QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QList<RelationModel *> joins, int skip, int take);
private:
bool readInsideParentese(QString &text, QString &out);
};
NUT_END_NAMESPACE

View File

@ -18,12 +18,60 @@
**
**************************************************************************/
#include <QDateTime>
#include <QPoint>
#ifdef QT_GUI_LIB
#include <QPolygon>
#include <QPolygonF>
#endif
#include <QVariant>
#include <QJsonDocument>
#include "postgresqlgenerator.h"
#include "../table.h"
#include "../tablemodel.h"
#include "sqlserializer.h"
NUT_BEGIN_NAMESPACE
bool PostgreSqlGenerator::readInsideParentese(QString &text, QString &out)
{
int start = -1;
int end = -1;
int pc = 0;
for (int i = 0; i < text.length(); ++i) {
QChar ch = text.at(i);
if (ch == '(') {
if (start == -1)
start = i;
pc++;
}
if (ch == ')') {
pc--;
if (!pc && end == -1)
end = i;
}
if (start != -1 && end != -1){
out = text.mid(start + 1, end - start - 1);
text = text.mid(end + 1);
return true;
}
}
return false;
}
bool PostgreSqlGenerator::isPostGisType(const QVariant::Type &t) const
{
return t == QVariant::Point
|| t == QVariant::PointF
|| t == QVariant::Rect
|| t == QVariant::RectF
|| t == QVariant::Polygon
|| t == QVariant::PolygonF;
}
PostgreSqlGenerator::PostgreSqlGenerator(Database *parent) : SqlGeneratorBase (parent)
{
@ -34,70 +82,109 @@ QString PostgreSqlGenerator::fieldType(FieldModel *field)
QString dbType;
switch (field->type) {
case QVariant::Bool:
case QMetaType::Bool:
dbType = "BOOLEAN";
break;
case QVariant::ByteArray:
case QMetaType::QBitArray:
case QMetaType::QByteArray:
dbType = "BYTEA";
break;
case QVariant::Date:
case QMetaType::QDate:
dbType = "DATE";
break;
case QVariant::DateTime:
case QMetaType::QDateTime:
dbType = "TIMESTAMP";
break;
case QVariant::Time:
case QMetaType::QTime:
dbType = "TIME";
break;
case QVariant::Int:
case QVariant::UInt:
case QMetaType::SChar:
case QMetaType::UChar:
case QMetaType::Short:
case QMetaType::UShort:
dbType = "SMALLINT";
break;
case QMetaType::Float:
dbType = "FLOAT";
break;
case QMetaType::Double:
dbType = "REAL";
break;
case QMetaType::Int:
case QMetaType::UInt:
if(field->isAutoIncrement)
dbType = "SERIAL";
else
dbType = "INTEGER";
break;
case QVariant::ULongLong:
case QVariant::LongLong:
case QMetaType::Long:
case QMetaType::ULong:
case QMetaType::LongLong:
case QMetaType::ULongLong:
if(field->isAutoIncrement)
dbType = "BIGSERIAL";
else
dbType = "BIGINT";
break;
case QVariant::Double:
dbType = "REAL";
break;
case QVariant::String:
case QMetaType::Char:
case QMetaType::QChar:
return "CHAR(1)";
case QMetaType::QString:
if(field->length)
dbType = QString("VARCHAR(%1)").arg(field->length);
else
dbType = "TEXT";
break;
case QVariant::Point:
case QVariant::PointF:
case QMetaType::QPoint:
case QMetaType::QPointF:
dbType="POINT";
break;
case QVariant::Uuid:
case QMetaType::QUuid:
dbType = "UUID";
break;
case QVariant::Polygon:
case QVariant::PolygonF:
case QMetaType::QPolygon:
case QMetaType::QPolygonF:
dbType = "POLYGON";
break;
case QMetaType::QLine:
case QMetaType::QLineF:
return "LINE";
case QMetaType::QRect:
case QMetaType::QRectF:
return "BOX";
case QMetaType::QJsonArray:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonDocument:
return "JSON";
case QMetaType::QStringList:
return "TEXT[]";
case QMetaType::QSize:
case QMetaType::QSizeF:
case QMetaType::QUrl:
case QMetaType::QColor:
return "TEXT";
default:
qDebug() << "Type for " << (int)field->type << field->type << "(" << QMetaType::typeName(field->type) << ")" << "nut supported";
dbType = QString();
}
if(field->type == (unsigned)QMetaType::type("Nut::DbGeography"))
dbType = "GEOGRAPHY";
return dbType;
}
@ -122,11 +209,134 @@ QString PostgreSqlGenerator::diff(FieldModel *oldField, FieldModel *newField)
return sql;
}
void PostgreSqlGenerator::replaceTableNames(QString &command)
QString PostgreSqlGenerator::escapeValue(const QVariant &v) const
{
foreach (TableModel *m, TableModel::allModels())
command = command
.replace("[" + m->className() + "]", m->name() );
if (v.type() == QVariant::Time)
return "'" + v.toTime().toString("HH:mm:ss") + "'";
if (v.type() == QVariant::Date)
return "'" + v.toDate().toString("yyyy-MM-dd") + "'";
if (v.type() == QVariant::DateTime)
return "'" + v.toDateTime().toString("yyyy-MM-dd HH:mm:ss") + "'";
if (v.type() == QVariant::StringList)
return "'{" + v.toStringList().join(",") + "}'";
if (v.type() == QVariant::Point) {
QPoint pt = v.toPoint();
return QString("point(%1, %2)").arg(pt.x()).arg(pt.y());
}
if (v.type() == QVariant::PointF) {
QPointF pt = v.toPointF();
return QString("point(%1, %2)").arg(pt.x()).arg(pt.y());
}
if (v.userType() == QMetaType::QJsonDocument) {
return "'" + QString(v.toJsonDocument().toJson(QJsonDocument::Compact)) + "'";
}
#ifdef QT_GUI_LIB
if (v.type() == QVariant::Polygon) {
QString ret;
QPoint pt;
QPolygon pol = v.value<QPolygon>();
for (int i = 0; i < pol.size(); ++i) {
pt = pol.at(i);
if (!ret.isEmpty())
ret.append("),(");
ret.append(QString::number(pt.x()) + ", " + QString::number(pt.y()));
}
return "'((" + ret + "))'";
}
if (v.type() == QVariant::PolygonF) {
QString ret;
QPointF pt;
QPolygonF pol = v.value<QPolygonF>();
for (int i = 0; i < pol.size(); ++i) {
pt = pol.at(i);
if (!ret.isEmpty())
ret.append("),(");
ret.append(QString::number(pt.x()) + ", " + QString::number(pt.y()));
}
return "'((" + ret + "))'";
}
#endif
return SqlGeneratorBase::escapeValue(v);
}
QVariant PostgreSqlGenerator::unescapeValue(const QMetaType::Type &type, const QVariant &dbValue)
{
if (type == QMetaType::QDateTime)
return dbValue.toDateTime();
if (type == QMetaType::QTime)
return dbValue.toTime();
if (type == QMetaType::QDate)
return dbValue.toDate();
if (type == QMetaType::QPoint)
return SqlGeneratorBase::unescapeValue(QMetaType::QPoint, dbValue.toString()
.replace("(", "").replace(")", ""));
if (type == QMetaType::QPointF)
return SqlGeneratorBase::unescapeValue(QMetaType::QPointF, dbValue.toString()
.replace("(", "").replace(")", ""));
if (type == QMetaType::QStringList)
return dbValue.toString().replace("{", "").replace("}", "")
.split(",");
#ifdef QT_GUI_LIB
if (type == QMetaType::QPolygon) {
QString p;
QString ref = dbValue.toString();
QPolygon pol;
if (!readInsideParentese(ref, p))
return pol;
ref = p;
while (readInsideParentese(ref, p)) {
QList<int> l = _serializer->toListInt(p);
if (l.count() != 2)
return QPolygon();
pol.append(QPoint(l.at(0), l.at(1)));
}
return pol;
}
if (type == QMetaType::QPolygonF) {
QString p;
QString ref = dbValue.toString();
QPolygonF pol;
if (!readInsideParentese(ref, p))
return pol;
ref = p;
while (readInsideParentese(ref, p)) {
QList<qreal> l = _serializer->toListReal(p);
if (l.count() != 2)
return QPolygonF();
pol.append(QPointF(l.at(0), l.at(1)));
}
return pol;
}
#endif
return SqlGeneratorBase::unescapeValue(type, dbValue);
}
QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const
{
if (!d)
return QString();
if (d->type == PhraseData::WithVariant) {
if (isPostGisType(d->operand.type()) && d->operatorCond == PhraseData::Equal) {
return QString("%1 ~= %2")
.arg(SqlGeneratorBase::createConditionalPhrase(d->left),
escapeValue(d->operand));
}
}
return SqlGeneratorBase::createConditionalPhrase(d);
}
NUT_END_NAMESPACE

View File

@ -28,14 +28,24 @@ NUT_BEGIN_NAMESPACE
class PostgreSqlGenerator : public SqlGeneratorBase
{
private:
bool readInsideParentese(QString &ref, QString &out);
bool isPostGisType(const QVariant::Type &t) const;
public:
explicit PostgreSqlGenerator(Database *parent);
explicit PostgreSqlGenerator(Database *parent = nullptr);
QString fieldType(FieldModel *field);
QString fieldType(FieldModel *field) override;
QString diff(FieldModel *oldField, FieldModel *newField);
QString diff(FieldModel *oldField, FieldModel *newField) override;
void replaceTableNames(QString &command);
// SqlGeneratorBase interface
public:
QString escapeValue(const QVariant &v) const override;
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override;
// SqlGeneratorBase interface
protected:
QString createConditionalPhrase(const PhraseData *d) const override;
};
NUT_END_NAMESPACE

View File

@ -31,6 +31,7 @@
#include "../table.h"
#include "../databasemodel.h"
#include "../tablemodel.h"
#include "sqlserializer.h"
NUT_BEGIN_NAMESPACE
@ -51,15 +52,28 @@ NUT_BEGIN_NAMESPACE
* INNER JOIN dbo.GiftCards ON dbo.GiftTypes.GiftTypeID = dbo.GiftCards.GiftTypeID
* INNER JOIN dbo.Entities ON dbo.GiftCards.GiftCardID = dbo.Entities.GiftCardID
*/
bool SqlGeneratorBase::isNumeric(const QMetaType::Type &type)
{
return type == QMetaType::SChar
|| type == QMetaType::Char
|| type == QMetaType::UChar
|| type == QMetaType::Short
|| type == QMetaType::UShort
|| type == QMetaType::Int
|| type == QMetaType::UInt
|| type == QMetaType::Long
|| type == QMetaType::ULong
|| type == QMetaType::LongLong
|| type == QMetaType::ULongLong;
}
SqlGeneratorBase::SqlGeneratorBase(Database *parent)
: QObject((QObject *)parent)
: QObject(parent)
{
if (parent)
_database = parent;
}
SqlGeneratorBase::~SqlGeneratorBase()
{
_serializer = new SqlSerializer;
}
QString SqlGeneratorBase::masterDatabaseName(QString databaseName)
@ -104,36 +118,65 @@ QString SqlGeneratorBase::recordsPhrase(TableModel *table)
foreach (FieldModel *f, table->fields()) {
if (!ret.isEmpty())
ret.append(", ");
ret.append(QString("%1.%2 AS [%1.%2]").arg(table->name()).arg(f->name));
ret.append(QString("%1.%2 AS \"%1.%2\"").arg(table->name(), f->name));
}
return ret;
}
QString SqlGeneratorBase::insertBulk(const QString &tableName, const PhraseList &ph, const QList<QVariantList> &vars)
{
QString sql;
foreach (QVariantList list, vars) {
QStringList values;
foreach (QVariant v, list)
values.append(escapeValue(v));
if (!sql.isEmpty())
sql.append(", ");
sql.append("(" + values.join(", ") + ")");
}
sql = "INSERT INTO " + tableName + "(" + createFieldPhrase(ph)
+ ") VALUES" + sql;
removeTableNames(sql);
return sql;
}
QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
{
return field->name + " " + fieldType(field) + (field->notNull ? " NOT NULL" : "");
QString type = fieldType(field);
if (type.isEmpty())
return type;
return field->name + " " + type + (field->notNull ? " NOT NULL" : "");
}
QStringList SqlGeneratorBase::constraints(TableModel *table)
{
Q_UNUSED(table);
return QStringList();
}
QString SqlGeneratorBase::relationDeclare(const RelationModel *relation)
{
return QString("FOREIGN KEY (FK_%1) REFERENCES %2(%1)")
.arg(relation->localColumn)
.arg(relation->slaveTable->name());
.arg(relation->localColumn, relation->slaveTable->name());
}
QStringList SqlGeneratorBase::diff(DatabaseModel lastModel,
DatabaseModel newModel)
QStringList SqlGeneratorBase::diff(const DatabaseModel &lastModel,
const DatabaseModel &newModel)
{
QStringList ret;
DatabaseModel unionModel = lastModel + newModel;
DatabaseModel unionModel = lastModel | newModel;
DatabaseModel::iterator i;
foreach (TableModel *table, unionModel) {
TableModel *oldTable = lastModel.tableByName(table->name());
TableModel *newTable = newModel.tableByName(table->name());
QString sql = diff(oldTable, newTable);
for (i = unionModel.begin(); i != unionModel.end(); ++i) {
TableModel *oldTable = lastModel.tableByName((*i)->name());
TableModel *newTable = newModel.tableByName((*i)->name());
QStringList sql = diff(oldTable, newTable);
if (!sql.isEmpty())
ret << sql;
// QString sqlRel = diffRelation(oldTable, newTable);
// if (!sqlRel.isEmpty())
// ret << sqlRel;
@ -147,7 +190,7 @@ QString SqlGeneratorBase::diff(FieldModel *oldField, FieldModel *newField)
QString sql = QString();
if (oldField && newField)
if (*oldField == *newField)
return QString();
return sql;
if (!newField) {
sql = "DROP COLUMN " + oldField->name;
@ -161,14 +204,17 @@ QString SqlGeneratorBase::diff(FieldModel *oldField, FieldModel *newField)
return sql;
}
QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
QStringList SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
{
if (!newTable && !oldTable)
return QStringList();
if (oldTable && newTable)
if (*oldTable == *newTable)
return QString();
return QStringList();
if (!newTable)
return "DROP TABLE " + oldTable->name();
return QStringList() << ("DROP TABLE " + oldTable->name());
QList<QString> fieldNames;
QList<QString> relations;
@ -196,10 +242,13 @@ QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
FieldModel *oldField = oldTable->field(fieldName);
QString buffer = diff(oldField, newField);
if (!buffer.isNull())
if (!buffer.isEmpty())
columnSql << buffer;
} else {
columnSql << fieldDeclare(newField);
QString declare = fieldDeclare(newField);
if (declare.isEmpty())
return QStringList() << declare;
columnSql << declare;
}
}
// foreach (QString fieldName, relations) {
@ -217,25 +266,27 @@ QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
QString sql;
if (oldTable) {
sql = QString("ALTER TABLE %1 \n%2")
.arg(newTable->name())
.arg(columnSql.join(",\n"));
.arg(newTable->name(), columnSql.join(",\n"));
} else {
if (!newTable->primaryKey().isNull())
columnSql << QString("CONSTRAINT pk_%1 PRIMARY KEY (%2)")
.arg(newTable->name())
.arg(newTable->primaryKey());
if (!newTable->primaryKey().isNull()) {
QString pkCon = primaryKeyConstraint(newTable);
if (!pkCon.isEmpty())
columnSql << pkCon;
columnSql << constraints(newTable);
}
sql = QString("CREATE TABLE %1 \n(%2)")
.arg(newTable->name())
.arg(columnSql.join(",\n"));
.arg(newTable->name(), columnSql.join(",\n"));
}
return sql;
return QStringList() << sql;
}
QString SqlGeneratorBase::diffRelation(TableModel *oldTable, TableModel *newTable)
QStringList SqlGeneratorBase::diffRelation(TableModel *oldTable, TableModel *newTable)
{
QStringList ret;
if (!newTable)
return QString();
return ret;
QList<QString> relations;
@ -251,25 +302,25 @@ QString SqlGeneratorBase::diffRelation(TableModel *oldTable, TableModel *newTabl
QStringList columnSql;
foreach (QString fieldName, relations) {
RelationModel *newRelation = newTable->foregionKeyByField(fieldName);
RelationModel *oldRelation = 0;
RelationModel *oldRelation = nullptr;
if (oldTable)
oldRelation = oldTable->foregionKeyByField(fieldName);
QString buffer = diff(oldRelation, newRelation);
if (!buffer.isNull())
columnSql << buffer;
QStringList buffer = diff(oldRelation, newRelation);
if (!buffer.isEmpty())
columnSql << buffer.at(0);
}
if (columnSql.count())
return "ALTER TABLE " + newTable->name() + "\n"
+ columnSql.join(",\n");
else
return QString();
ret.append("ALTER TABLE " + newTable->name() + "\n"
+ columnSql.join(",\n"));
return ret;
}
QString SqlGeneratorBase::diff(RelationModel *oldRel, RelationModel *newRel)
QStringList SqlGeneratorBase::diff(RelationModel *oldRel, RelationModel *newRel)
{
QStringList ret;
/*
CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID)
REFERENCES Persons(PersonID)
@ -283,25 +334,23 @@ QString SqlGeneratorBase::diff(RelationModel *oldRel, RelationModel *newRel)
.arg(newRelation->foreignColumn);
*/
if (!oldRel)
return QString("ADD CONSTRAINT FK_%1 FOREIGN KEY (%1) "
ret.append(QString("ADD CONSTRAINT FK_%1 FOREIGN KEY (%1) "
"REFERENCES %2(%3)")
.arg(newRel->localColumn)
.arg(newRel->masterTable->name())
.arg(newRel->foreignColumn);
.arg(newRel->localColumn, newRel->masterTable->name(),
newRel->foreignColumn));
if (!newRel)
return QString("ADD CONSTRAINT FK_%1 FOREIGN KEY (%1) "
ret.append(QString("ADD CONSTRAINT FK_%1 FOREIGN KEY (%1) "
"REFERENCES %2(%3)")
.arg(oldRel->localColumn)
.arg(oldRel->masterTable->name())
.arg(oldRel->foreignColumn);
.arg(oldRel->localColumn, oldRel->masterTable->name(),
oldRel->foreignColumn));
// if (*oldRel == *newRel)
return QString();
return ret;
}
QString SqlGeneratorBase::join(const QString &mainTable,
const QList<RelationModel*> list,
const QList<RelationModel*> &list,
QStringList *order)
{
QString ret = mainTable;
@ -309,19 +358,19 @@ QString SqlGeneratorBase::join(const QString &mainTable,
for (i = list.begin(); i != list.end(); ++i) {
if ((*i)->masterTable->name() == mainTable) {
ret.append(QString(" INNER JOIN %3 ON %1.%2 = %3.%4")
.arg((*i)->masterTable->name())
.arg((*i)->masterTable->primaryKey())
.arg((*i)->slaveTable->name())
.arg((*i)->localColumn));
.arg((*i)->masterTable->name(),
(*i)->masterTable->primaryKey(),
(*i)->slaveTable->name(),
(*i)->localColumn));
if (order != Q_NULLPTR)
order->append((*i)->slaveTable->name() + "." + (*i)->slaveTable->primaryKey());
} else {
ret.append(QString(" INNER JOIN %3 ON %1.%2 = %3.%4")
.arg(mainTable)
.arg((*i)->localColumn)
.arg((*i)->masterTable->name())
.arg((*i)->masterTable->primaryKey()));
.arg(mainTable,
(*i)->localColumn,
(*i)->masterTable->name(),
(*i)->masterTable->primaryKey()));
if (order != Q_NULLPTR)
order->append((*i)->masterTable->name() + "." + (*i)->masterTable->primaryKey());
@ -359,10 +408,8 @@ QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
if (rel) {
//mainTable is master of table
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
.arg(table)
.arg(rel->masterTable->primaryKey())
.arg(rel->localColumn)
.arg(mainTable));
.arg(table, rel->masterTable->primaryKey(),
rel->localColumn, mainTable));
if (order != Q_NULLPTR)
order->append(mainTable + "." + rel->masterTable->primaryKey());
@ -372,10 +419,8 @@ QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
if (rel) {
// table is master of mainTable
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
.arg(table)
.arg(rel->localColumn)
.arg(rel->masterTable->primaryKey())
.arg(mainTable));
.arg(table, rel->localColumn,
rel->masterTable->primaryKey(), mainTable));
if (order != Q_NULLPTR)
order->append(mainTable + "." + rel->localColumn);
@ -395,7 +440,9 @@ QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
{
QString sql = QString();
QString key = t->isPrimaryKeyAutoIncrement() ? t->primaryKey() : QString();
auto model = _database->model().tableByName(tableName);
QString key = model->isPrimaryKeyAutoIncrement() ? model->primaryKey() : QString();
QStringList values;
@ -411,9 +458,7 @@ QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
changedPropertiesText.append(s);
}
sql = QString("INSERT INTO %1 (%2) VALUES (%3)")
.arg(tableName)
.arg(changedPropertiesText)
.arg(values.join(", "));
.arg(tableName, changedPropertiesText, values.join(", "));
removeTableNames(sql);
@ -423,7 +468,8 @@ QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
QString SqlGeneratorBase::updateRecord(Table *t, QString tableName)
{
QString sql = QString();
QString key = t->primaryKey();
auto model = _database->model().tableByName(tableName);
QString key = model->primaryKey();
QStringList values;
foreach (QString f, t->changedProperties())
@ -431,10 +477,8 @@ QString SqlGeneratorBase::updateRecord(Table *t, QString tableName)
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());
.arg(tableName, values.join(", "),
key, t->property(key.toUtf8().data()).toString());
removeTableNames(sql);
@ -443,10 +487,10 @@ QString SqlGeneratorBase::updateRecord(Table *t, QString tableName)
QString SqlGeneratorBase::deleteRecord(Table *t, QString tableName)
{
auto model = _database->model().tableByName(tableName);
QString key = model->primaryKey();
QString sql = QString("DELETE FROM %1 WHERE %2='%3'")
.arg(tableName)
.arg(t->primaryKey())
.arg(t->primaryValue().toString());
.arg(tableName, key, t->property(key.toUtf8().data()).toString());
replaceTableNames(sql);
return sql;
}
@ -457,27 +501,20 @@ QString SqlGeneratorBase::agregateText(const AgregateType &t,
switch (t) {
case Min:
return "MIN(" + arg + ")";
break;
case Max:
return "MAX(" + arg + ")";
break;
case Average:
return "AVERAGE(" + arg + ")";
break;
return "AVG(" + arg + ")";
case Count:
return "COUNT(" + arg + ")";
break;
case SignleField:
return arg;
break;
default:
return QString();
}
return QString(); // never reach
}
QString SqlGeneratorBase::fromTableText(const QString &tableName,
@ -492,10 +529,8 @@ QString SqlGeneratorBase::fromTableText(const QString &tableName,
if (rel) {
QString pk = _database->model().tableByName(tableName)->primaryKey();
tableNameText = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)")
.arg(tableName)
.arg(joinTableName)
.arg(pk)
.arg(rel->localColumn);
.arg(tableName, joinTableName,
pk, rel->localColumn);
orderBy = tableName + "." + pk;
} else {
qWarning("Relation between table %s and class %s (%s) not exists!",
@ -509,7 +544,7 @@ QString SqlGeneratorBase::fromTableText(const QString &tableName,
return tableNameText;
}
QString SqlGeneratorBase::deleteRecords(QString tableName, QString where)
QString SqlGeneratorBase::deleteRecords(const QString &tableName, const QString &where)
{
QString sql = QString();
if (where.isEmpty() || where.isNull())
@ -526,7 +561,7 @@ QString SqlGeneratorBase::selectCommand(const QString &tableName,
const PhraseList &fields,
const ConditionalPhrase &where,
const PhraseList &order,
const QList<RelationModel*> joins,
const QList<RelationModel*> &joins,
const int skip,
const int take)
{
@ -563,9 +598,9 @@ QString SqlGeneratorBase::selectCommand(const QString &tableName,
if (orderText != "")
sql.append(" ORDER BY " + orderText);
for (int i = 0; i < _database->model().count(); i++)
sql = sql.replace(_database->model().at(i)->className() + ".",
_database->model().at(i)->name() + ".");
// for (int i = 0; i < _database->model().count(); i++)
// sql = sql.replace(_database->model().at(i)->className() + ".",
// _database->model().at(i)->name() + ".");
appendSkipTake(sql, skip, take);
replaceTableNames(sql);
@ -664,9 +699,7 @@ QString SqlGeneratorBase::insertCommand(const QString &tableName, const Assignme
values.append(escapeValue(d->operand));
}
return QString("INSERT INTO %1 (%2) VALUES (%3);")
.arg(tableName)
.arg(fieldNames)
.arg(values);
.arg(tableName, fieldNames, values);
}
//QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
@ -740,14 +773,14 @@ QString SqlGeneratorBase::insertCommand(const QString &tableName, const Assignme
void SqlGeneratorBase::replaceTableNames(QString &command)
{
foreach (TableModel *m, TableModel::allModels())
foreach (TableModel *m, _database->model())
command = command
.replace("[" + m->className() + "]", "`" + m->name() + "`");
.replace("[" + m->className() + "]", m->name());
}
void SqlGeneratorBase::removeTableNames(QString &command)
{
foreach (TableModel *m, TableModel::allModels())
foreach (TableModel *m, _database->model())
command = command.replace("[" + m->className() + "].", "");
}
@ -792,65 +825,25 @@ void SqlGeneratorBase::removeTableNames(QString &command)
QString SqlGeneratorBase::escapeValue(const QVariant &v) const
{
switch (v.type()) {
case QVariant::Bool:
return v.toBool() ? "1" : "0";
break;
if (v.type() == QVariant::String && v.toString().isEmpty())
return "''";
case QVariant::Int:
case QVariant::UInt:
case QVariant::ULongLong:
case QVariant::LongLong:
case QVariant::Double:
return v.toString();
break;
case QVariant::Uuid:
return "'" + v.toUuid().toString() + "'";
break;
case QVariant::Char:
case QVariant::String:
return "'" + v.toString() + "'";
case QVariant::DateTime:
return "'" + v.toDateTime().toString(Qt::ISODate) + "'";
case QVariant::Date:
return "'" + v.toDate().toString(Qt::ISODate) + "'";
case QVariant::Time:
return "'" + v.toTime().toString(Qt::ISODate) + "'";
case QVariant::StringList:
case QVariant::List:
return "('" + v.toStringList().join("', '") + "')";
case QVariant::Point: {
QPoint pt = v.toPoint();
return QString("POINT(%1 %2)").arg(pt.x()).arg(pt.y());
QString serialized = _serializer->serialize(v);
if (serialized.isEmpty()) {
qWarning("No field escape rule for: %s", v.typeName());
return QString();
}
case QVariant::PointF: {
QPointF pt = v.toPointF();
return QString("POINT(%1 %2)").arg(pt.x()).arg(pt.y());
}
if (v.type() == QVariant::List)
return serialized;
case QVariant::Invalid:
qFatal("Invalud field value");
return "<FAIL>";
default:
Q_UNREACHABLE();
return QString();
}
return "'" + serialized + "'";
}
QVariant SqlGeneratorBase::readValue(const QVariant::Type &type,
QVariant SqlGeneratorBase::unescapeValue(const QMetaType::Type &type,
const QVariant &dbValue)
{
Q_UNUSED(type);
return dbValue;
return _serializer->deserialize(dbValue.toString(), type);
}
QString SqlGeneratorBase::phrase(const PhraseData *d) const
@ -875,9 +868,6 @@ QString SqlGeneratorBase::phrase(const PhraseData *d) const
case PhraseData::WithoutOperand:
ret = phrase(d->left) + " " + operatorString(d->operatorCond);
break;
default:
ret = "<FAIL>";
}
if (d->operatorCond == PhraseData::And || d->operatorCond == PhraseData::Or)
@ -957,6 +947,12 @@ void SqlGeneratorBase::appendSkipTake(QString &sql, int skip, int take)
Q_UNUSED(take);
}
QString SqlGeneratorBase::primaryKeyConstraint(const TableModel *table) const
{
return QString("CONSTRAINT pk_%1 PRIMARY KEY (%2)")
.arg(table->name(), table->primaryKey());
}
QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
{
if (!d)
@ -968,7 +964,7 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
//apply not (!)
if (d->isNot) {
if (op < 20)
op = (PhraseData::Condition)((op + 10) % 20);
op = static_cast<PhraseData::Condition>((op + 10) % 20);
}
switch (d->type) {
case PhraseData::Field:
@ -978,22 +974,40 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
case PhraseData::WithVariant:
if (op == PhraseData::AddYears)
ret = QString("DATEADD(year, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::AddMonths)
ret = QString("DATEADD(month, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::AddDays)
ret = QString("DATEADD(day, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::AddHours)
ret = QString("DATEADD(hour, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::AddMinutes)
ret = QString("DATEADD(minute, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::AddSeconds)
ret = QString("DATEADD(second, %1, %2)")
.arg(d->operand.toString()).arg(createConditionalPhrase(d->left));
.arg(d->operand.toString(), createConditionalPhrase(d->left));
else if (op == PhraseData::DatePartYear)
ret = QString("DATEPART(year, %1)")
.arg(d->operand.toString());
else if (op == PhraseData::DatePartMonth)
ret = QString("DATEPART(month, %1)")
.arg(d->operand.toString());
else if (op == PhraseData::DatePartDay)
ret = QString("DATEPART(day, %1)")
.arg(d->operand.toString());
else if (op == PhraseData::DatePartHour)
ret = QString("DATEPART(hour, %1)")
.arg(d->operand.toString());
else if (op == PhraseData::DatePartMinute)
ret = QString("DATEPART(minute, %1)")
.arg(d->operand.toString());
else if (op == PhraseData::DatePartMilisecond)
ret = QString("DATEPART(milisecond, %1)")
.arg(d->operand.toString());
else
ret = createConditionalPhrase(d->left) + " " + operatorString(op) + " "
+ escapeValue(d->operand);
@ -1007,9 +1021,6 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
case PhraseData::WithoutOperand:
ret = createConditionalPhrase(d->left) + " " + operatorString(op);
break;
default:
ret = "<FAIL phrase>";
}
if (d->operatorCond == PhraseData::And || d->operatorCond == PhraseData::Or)
@ -1069,7 +1080,6 @@ void SqlGeneratorBase::createInsertPhrase(const AssignmentPhraseList &ph, QStrin
case PhraseData::Field:
case PhraseData::WithoutOperand:
default:
qFatal("Invalid insert command");
}
}

View File

@ -27,6 +27,8 @@
#include "../phrase.h"
//#include "../wherephrase.h"
class SqlSerializer;
NUT_BEGIN_NAMESPACE
class Table;
@ -40,6 +42,11 @@ class SqlGeneratorBase : public QObject
// Q_OBJECT
Database *_database;
protected:
SqlSerializer *_serializer;
bool isNumeric(const QMetaType::Type &type);
public:
//TODO: remove this enum
enum CommandType{
@ -58,24 +65,38 @@ public:
};
explicit SqlGeneratorBase(Database *parent);
virtual ~SqlGeneratorBase();
virtual ~SqlGeneratorBase() = default;
virtual bool supportPrimaryKey(const QMetaType::Type &type) {
Q_UNUSED(type);
return true;
}
virtual bool supportAutoIncrement(const QMetaType::Type &type) {
Q_UNUSED(type);
return true;
}
//fields
virtual QString fieldType(FieldModel *field) = 0;
virtual QString fieldDeclare(FieldModel *field);
virtual QStringList constraints(TableModel *table);
virtual QString escapeValue(const QVariant &v) const;
virtual QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue);
virtual QString masterDatabaseName(QString databaseName);
virtual QString createTable(TableModel *table);
virtual QString fieldType(FieldModel *field) = 0;
virtual QString fieldDeclare(FieldModel *field);
virtual QString relationDeclare(const RelationModel *relation);
virtual QStringList diff(DatabaseModel lastModel, DatabaseModel newModel);
virtual QStringList diff(const DatabaseModel &lastModel, const DatabaseModel &newModel);
virtual QString diff(FieldModel *oldField, FieldModel *newField);
virtual QString diff(TableModel *oldTable, TableModel *newTable);
virtual QString diffRelation(TableModel *oldTable, TableModel *newTable);
virtual QString diff(RelationModel *oldRel, RelationModel *newRel);
virtual QStringList diff(TableModel *oldTable, TableModel *newTable);
virtual QStringList diffRelation(TableModel *oldTable, TableModel *newTable);
virtual QStringList diff(RelationModel *oldRel, RelationModel *newRel);
virtual QString join(const QString &mainTable,
const QList<RelationModel*> list,
const QList<RelationModel*> &list,
QStringList *order = Q_NULLPTR);
virtual QString join(const QStringList &list, QStringList *order = Q_NULLPTR);
@ -83,16 +104,17 @@ public:
virtual QString recordsPhrase(TableModel *table);
virtual QString insertBulk(const QString &tableName, const PhraseList &ph, const QList<QVariantList> &vars);
virtual QString insertRecord(Table *t, QString tableName);
virtual QString updateRecord(Table *t, QString tableName);
virtual QString deleteRecord(Table *t, QString tableName);
virtual QString deleteRecords(QString tableName, QString where);
virtual QString deleteRecords(const QString &tableName, const QString &where);
virtual QString selectCommand(const QString &tableName,
const PhraseList &fields,
const ConditionalPhrase &where,
const PhraseList &order,
const QList<RelationModel*> joins,
const QList<RelationModel *> &joins,
const int skip = -1,
const int take = -1);
@ -123,18 +145,13 @@ public:
// virtual QString updateCommand(WherePhrase &phrase, QList<WherePhrase> &wheres, QString tableName);
virtual QString escapeValue(const QVariant &v) const;
virtual QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
virtual QString phrase(const PhraseData *d) const;
virtual QString operatorString(const PhraseData::Condition &cond) const;
virtual void appendSkipTake(QString &sql, int skip = -1, int take = -1);
virtual void replaceTableNames(QString &command);
virtual void removeTableNames(QString &command);
virtual QString primaryKeyConstraint(const TableModel *table) const;
protected:
QString createConditionalPhrase(const PhraseData *d) const;
virtual QString createConditionalPhrase(const PhraseData *d) const;
QString createFieldPhrase(const PhraseList &ph);
QString createOrderPhrase(const PhraseList &ph);
void createInsertPhrase(const AssignmentPhraseList &ph, QString &fields, QString &values);

View File

@ -31,55 +31,178 @@ SqliteGenerator::SqliteGenerator(Database *parent) : SqlGeneratorBase(parent)
QString SqliteGenerator::fieldType(FieldModel *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::Time:
dbType = "time";
break;
case QVariant::Double:
dbType = "real";
break;
case QVariant::Int:
dbType = "integer";
case QMetaType::Bool: return "BOOLEAN";
case QMetaType::QBitArray:
case QMetaType::QByteArray: return "BLOB";
case QMetaType::QDate: return "DATE";
case QMetaType::QDateTime: return "DATETIME";
case QMetaType::QTime: return "TIME";
case QMetaType::Double: return "DOUBLE";
case QMetaType::Float: return "FLOAT";
case QMetaType::SChar:
case QMetaType::Char: return "TINYINT";
case QMetaType::UChar: return "TINYINT UNSIGNED";
case QMetaType::Short: return "SMALLINT";
case QMetaType::UShort: return "SMALLINT UNSIGNED";
case QMetaType::Int: return "INT";
case QMetaType::UInt: return "INT UNSIGNED";
case QMetaType::Long: return "MEDIUMINT";
case QMetaType::ULong: return "MEDIUMINT UNSIGNED";
case QMetaType::LongLong: return "BIGINT";
case QMetaType::ULongLong: return "BIGINT UNSIGNED";
case QMetaType::QChar: return "NCHAR(1)";
case QMetaType::QUrl:
case QMetaType::QJsonArray:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonDocument:
case QMetaType::QPoint:
case QMetaType::QPointF:
case QMetaType::QSize:
case QMetaType::QSizeF:
case QMetaType::QLine:
case QMetaType::QLineF:
case QMetaType::QRect:
case QMetaType::QRectF:
case QMetaType::QPolygon:
case QMetaType::QPolygonF:
case QMetaType::QStringList:
case QMetaType::QColor:
case QMetaType::QUuid: return "TEXT";
// if (field->isAutoIncrement)
// dbType.append(" PRIMARY KEY AUTOINCREMENT");
break;
case QVariant::String:
if(field->length)
dbType = QString("varchar(%1)").arg(field->length);
else
dbType = "text";
break;
case QVariant::Uuid:
dbType = "text";
break;
default:
dbType = QString();
}
return dbType;
case QMetaType::QString:
if(field->length)
return QString("VARCHAR(%1)").arg(field->length);
else
return "TEXT";
default:
// qWarning("The type (%s) does not supported",
// QMetaType::typeName(field->type));
return QString();
}
}
QString SqliteGenerator::fieldDeclare(FieldModel *field)
{
QString type = fieldType(field);
if (type.isEmpty())
return type;
if (isNumeric(field->type) && field->isPrimaryKey) {
type = "INTEGER PRIMARY KEY";
if (field->isAutoIncrement)
type.append(" AUTOINCREMENT");
}
if (field->notNull)
type.append(" NOT NULL");
return field->name + " " + type;
}
bool SqliteGenerator::supportAutoIncrement(const QMetaType::Type &type)
{
return isNumeric(type);
}
QStringList SqliteGenerator::diff(TableModel *oldTable, TableModel *newTable)
{
QStringList ret;
if (oldTable && newTable)
if (*oldTable == *newTable)
return ret;
QStringList newTableSql = SqlGeneratorBase::diff(nullptr, newTable);
if (!newTable)
return QStringList() << "DROP TABLE " + oldTable->name();
if (!oldTable)
return newTableSql;
QList<QString> fieldNames;
QList<QString> relations;
foreach (FieldModel *f, oldTable->fields())
if (!fieldNames.contains(f->name))
fieldNames.append(f->name);
foreach (RelationModel *r, oldTable->foregionKeys())
if (!relations.contains(r->localColumn))
relations.append(r->localColumn);
foreach (FieldModel *f, newTable->fields())
if (!fieldNames.contains(f->name))
fieldNames.append(f->name);
foreach (RelationModel *r, newTable->foregionKeys())
if (!relations.contains(r->localColumn))
relations.append(r->localColumn);
QString columns;
foreach (FieldModel *f, oldTable->fields()) {
if (!newTable->field(f->name))
continue;
if (!columns.isEmpty())
columns.append(", ");
columns.append(f->name);
}
/*
ALTER TABLE sampleTable RENAME TO sqlitestudio_temp_table;
CREATE TABLE sampleTable (
id INTEGER PRIMARY KEY AUTOINCREMENT,
t BIGINT,
m CHAR
);
INSERT INTO sampleTable (
id,
t,
m
)
SELECT id,
t,
m
FROM sqlitestudio_temp_table;
DROP TABLE sqlitestudio_temp_table;
*/
ret.append("ALTER TABLE " + newTable->name() + " RENAME TO sqlitestudio_temp_table;");
ret.append(newTableSql);
ret.append(QString("INSERT INTO %1 ( %2 ) SELECT %2 FROM sqlitestudio_temp_table;")
.arg(newTable->name(), columns));
ret.append("DROP TABLE sqlitestudio_temp_table;");
return ret;
}
void SqliteGenerator::appendSkipTake(QString &sql, int skip, int take)
{
if (take != -1 && skip != -1)
sql.append(QString(" LIMIT %1 OFFSET %2")
.arg(take)
.arg(skip));
.arg(skip));
}
QString SqliteGenerator::primaryKeyConstraint(const TableModel *table) const
{
Q_UNUSED(table);
return QString();
// QString sql = QString("CONSTRAINT pk_%1 PRIMARY KEY (%2)")
// .arg(table->name())
// .arg(table->primaryKey());
// if (table->field(table->primaryKey())->isAutoIncrement)
// sql += " AUTOINCREMENT";
// return sql;
}
NUT_END_NAMESPACE

View File

@ -29,11 +29,18 @@ NUT_BEGIN_NAMESPACE
class SqliteGenerator : public SqlGeneratorBase
{
public:
explicit SqliteGenerator(Database *parent = 0);
explicit SqliteGenerator(Database *parent = nullptr);
QString fieldType(FieldModel *field);
QString fieldType(FieldModel *field) override;
QString fieldDeclare(FieldModel *field) override;
bool supportAutoIncrement(const QMetaType::Type &type) override;
void appendSkipTake(QString &sql, int skip, int take) override;
QString primaryKeyConstraint(const TableModel *table) const override;
QStringList diff(TableModel *oldTable, TableModel *newTable) override;
void appendSkipTake(QString &sql, int skip, int take);
};
NUT_END_NAMESPACE

View File

@ -45,10 +45,44 @@ QString SqlServerGenerator::fieldType(FieldModel *field)
QString dbType;
switch (field->type) {
case QVariant::Bool:
case QMetaType::Bool:
dbType = "BIT";
break;
case QVariant::ByteArray:
case QMetaType::Char:
case QMetaType::QChar:
dbType = "CHAR(1)";
break;
case QMetaType::SChar:
case QMetaType::UChar:
return "tinyint";
case QMetaType::Short:
case QMetaType::UShort:
return "smallint";
case QMetaType::UInt:
case QMetaType::Int:
dbType = "INT";
if (field->isAutoIncrement)
dbType += " IDENTITY(1,1)";
break;
case QMetaType::Long:
case QMetaType::ULong:
case QMetaType::LongLong:
case QMetaType::ULongLong:
return "bigint";
case QMetaType::Float:
return "FLOAT(24)";
case QMetaType::Double:
return "REAL";
case QMetaType::QBitArray:
case QMetaType::QByteArray:
dbType = "VARBINARY";
if (field->length)
@ -56,42 +90,51 @@ QString SqlServerGenerator::fieldType(FieldModel *field)
else
dbType.append(" (MAX)");
break;
case QVariant::Date:
case QMetaType::QDate:
dbType = "DATE";
break;
case QVariant::DateTime:
case QMetaType::QDateTime:
dbType = "DATETIME";
break;
case QVariant::Time:
case QMetaType::QTime:
dbType = "TIME";
break;
case QVariant::Double:
dbType = "REAL";
break;
case QVariant::Int:
dbType = "INT";
if (field->isAutoIncrement)
dbType += " IDENTITY(1,1)";
break;
case QVariant::Point:
case QVariant::PointF:
case QMetaType::QPoint:
case QMetaType::QPointF:
dbType = "GEOMETRY";
break;
case QVariant::String:
case QMetaType::QString:
if (field->length)
dbType = QString("NVARCHAR(%1)").arg(field->length);
else
dbType = "NVARCHAR(MAX)";
break;
case QVariant::Uuid:
case QMetaType::QUuid:
dbType = "UNIQUEIDENTIFIER";
break;
case QMetaType::QPolygon:
case QMetaType::QPolygonF:
case QMetaType::QSize:
case QMetaType::QSizeF:
case QMetaType::QRect:
case QMetaType::QRectF:
case QMetaType::QLine:
case QMetaType::QLineF:
case QMetaType::QColor:
case QMetaType::QStringList:
case QMetaType::QJsonArray:
case QMetaType::QJsonValue:
case QMetaType::QJsonObject:
case QMetaType::QJsonDocument:
case QMetaType::QUrl:
return "TEXT";
default:
Q_UNREACHABLE();
// Q_UNREACHABLE();
dbType = QString();
}
@ -103,7 +146,7 @@ QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField)
QString sql = QString();
if (oldField && newField)
if (*oldField == *newField)
return QString();
return sql;
if (!newField) {
sql = "DROP COLUMN " + oldField->name;
@ -120,13 +163,15 @@ QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField)
QString SqlServerGenerator::escapeValue(const QVariant &v) const
{
if (v.type() == QVariant::String || v.type() == QVariant::Char)
auto mid = static_cast<QMetaType::Type>(v.userType());
if (mid == QMetaType::QString || mid == QMetaType::QChar)
return "N'" + v.toString() + "'";
else if (v.type() == QVariant::Point) {
else if (mid == QMetaType::QPoint) {
QPoint pt = v.toPoint();
return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg(
pt.y());
} else if (v.type() == QVariant::PointF) {
} else if (mid == QMetaType::QPointF) {
QPointF pt = v.toPointF();
return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg(
pt.y());

View File

@ -29,7 +29,7 @@ NUT_BEGIN_NAMESPACE
class SqlServerGenerator : public SqlGeneratorBase
{
public:
explicit SqlServerGenerator(Database *parent = 0);
explicit SqlServerGenerator(Database *parent = nullptr);
QString masterDatabaseName(QString databaseName);

View File

@ -24,275 +24,9 @@
NUT_BEGIN_NAMESPACE
PhraseData::PhraseData() :
className(""), fieldName(""),
type(Field), operatorCond(NotAssign),
left(0), right(0), operand(QVariant::Invalid), isNot(false), parents(1)
{ }
PhraseData::PhraseData(const char *className, const char *fieldName) :
className(className), fieldName(fieldName),
type(Field), operatorCond(NotAssign),
left(0), right(0), operand(QVariant::Invalid), isNot(false), parents(1)
{ }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o)
: className(0), fieldName(0),
type(WithoutOperand), operatorCond(o), left(l), right(0),
isNot(false), parents(1)
{
l->parents++;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o,
PhraseData *r)
: className(0), fieldName(0),
type(WithOther), operatorCond(o),
left(l), right(r),
isNot(false), parents(1)
{
l->parents++;
r->parents++;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r)
: className(0), fieldName(0),
type(WithVariant), operatorCond(o), left(l),
right(0), operand(r), isNot(false), parents(1)
{ }
PhraseData *PhraseData::operator =(PhraseData *other)
{
other->parents++;
return other;
}
PhraseData &PhraseData::operator =(PhraseData &other)
{
other.parents++;
return other;
}
QString PhraseData::toString() const
{
return QString("[%1].%2").arg(className).arg(fieldName);
}
PhraseData::~PhraseData()
{
}
void PhraseData::cleanUp()
{
}
void PhraseData::cleanUp(PhraseData *d)
{
if (d->left)
cleanUp(d->left);
if (d->right)
cleanUp(d->right);
}
AbstractFieldPhrase::AbstractFieldPhrase(PhraseData *d) : data(d)
{ }
AbstractFieldPhrase::AbstractFieldPhrase(const char *className,
const char *fieldName)
:data(new PhraseData(className, fieldName))
{
qDebug() <<"AbstractFieldPhrase created"<<className<<fieldName;
}
AbstractFieldPhrase::AbstractFieldPhrase(const AbstractFieldPhrase &other)
{
data = other.data;
data->parents++;
qDebug() <<"Copy ctor"<<other.data->toString()<<other.data->parents;
}
AbstractFieldPhrase::AbstractFieldPhrase(AbstractFieldPhrase &&other)
{
data = other.data;
data->parents++;
other.data = 0;
}
AbstractFieldPhrase::~AbstractFieldPhrase()
{
if (data) {
--data->parents;
if (data->parents <= 0)
delete data;
}
}
PhraseList AbstractFieldPhrase::operator |(const AbstractFieldPhrase &other)
{
return PhraseList(this, other);
}
ConditionalPhrase AbstractFieldPhrase::isNull()
{
return ConditionalPhrase(this, PhraseData::Null);
}
ConditionalPhrase AbstractFieldPhrase::operator ==(const ConditionalPhrase
&other)
{
return ConditionalPhrase(this, PhraseData::Equal,
const_cast<ConditionalPhrase&>(other));
}
#define AbstractFieldPhraseOperatorVariant(class, op, cond) \
ConditionalPhrase class::operator op(const QVariant &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
AbstractFieldPhraseOperatorVariant(AbstractFieldPhrase, ==, PhraseData::Equal)
AbstractFieldPhraseOperatorVariant(AbstractFieldPhrase, !=, PhraseData::NotEqual)
#define AbstractFieldPhraseOperatorField(op, cond) \
ConditionalPhrase AbstractFieldPhrase::operator op(const AbstractFieldPhrase &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
AbstractFieldPhraseOperatorField(==, PhraseData::Equal)
AbstractFieldPhraseOperatorField(!=, PhraseData::NotEqual)
AbstractFieldPhraseOperatorField(< , PhraseData::Less)
AbstractFieldPhraseOperatorField(<=, PhraseData::LessEqual)
AbstractFieldPhraseOperatorField(> , PhraseData::Greater)
AbstractFieldPhraseOperatorField(>=, PhraseData::GreaterEqual)
AbstractFieldPhrase AbstractFieldPhrase::operator !()
{
AbstractFieldPhrase f(data->className, data->fieldName);
f.data->isNot = !data->isNot;
return f;
}
AssignmentPhrase AbstractFieldPhrase::operator =(const QVariant &other)
{
return AssignmentPhrase(this, other);
}
AssignmentPhrase AbstractFieldPhrase::operator <<(const QVariant &other)
{
return AssignmentPhrase(this, other);
}
PhraseList::PhraseList() : isValid(false)
{
}
PhraseList::PhraseList(const PhraseList &other) : isValid(true)
{
data = qMove(other.data);
const_cast<PhraseList&>(other).data.clear();
}
PhraseList::PhraseList(PhraseList &&other)
{
data = other.data;
}
PhraseList::PhraseList(const AbstractFieldPhrase &other) : isValid(true)
{
data.append(other.data);
incAllDataParents();
}
PhraseList::PhraseList(const AbstractFieldPhrase *left,
const AbstractFieldPhrase &right)
: isValid(true)
{
data.append(left->data);
data.append(right.data);
incAllDataParents();
}
PhraseList::PhraseList(PhraseList *left, PhraseList *right) : isValid(true)
{
// data = qMove(left->data + right->data);
data.append(left->data);
data.append(right->data);
// left->data.clear();
// right->data.clear();
}
PhraseList::PhraseList(PhraseList *left, const AbstractFieldPhrase *right)
: isValid(true)
{
data.append(left->data);
data.append(right->data);
incAllDataParents();
}
PhraseList::~PhraseList()
{
}
PhraseList &PhraseList::operator =(const PhraseList &other)
{
data.append(const_cast<PhraseList&>(other).data);
return *this;
}
PhraseList PhraseList::operator |(const AbstractFieldPhrase &other) {
return PhraseList(this, &other);
}
void PhraseList::incAllDataParents()
{
// foreach (PhraseData *d, data)
// d->parents++;
}
PhraseList PhraseList::operator |(PhraseList &other) {
return PhraseList(this, &other);
}
AssignmentPhrase::AssignmentPhrase(PhraseData *d) : data(d)
{
d->parents++;
}
AssignmentPhrase::AssignmentPhrase(AbstractFieldPhrase *l, const QVariant r)
{
data = new PhraseData(l->data, PhraseData::Equal, r);
// l->data = 0;
}
AssignmentPhrase::AssignmentPhrase(AbstractFieldPhrase *l,
const AssignmentPhrase *r)
{
data = new PhraseData(l->data, PhraseData::Equal, r->data);
// l->data = 0;
}
AssignmentPhrase::AssignmentPhrase(AssignmentPhrase *ph, const QVariant &v)
{
data = new PhraseData(ph->data, PhraseData::Equal, v);
}
//AssignmentPhrase::AssignmentPhrase(AssignmentPhrase &other)
//{
// data = other.data;
// other.data = 0;
//}
AssignmentPhrase::~AssignmentPhrase()
{
if (data)
if (!--data->parents)
delete data;
}
//AssignmentPhrase::AssignmentPhrase(AssignmentPhrase *l, const AssignmentPhrase *r)
//{
@ -300,278 +34,10 @@ AssignmentPhrase::~AssignmentPhrase()
// qFatal("SS");
//}
AssignmentPhraseList AssignmentPhrase::operator &(const AssignmentPhrase &other)
{
return AssignmentPhraseList(this, &other);
}
AssignmentPhraseList::AssignmentPhraseList()
{
}
AssignmentPhraseList::AssignmentPhraseList(const AssignmentPhrase &l)
{
data.append(l.data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(AssignmentPhraseList *l,
const AssignmentPhrase *r)
{
data.append(l->data);
data.append(r->data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(AssignmentPhrase *l,
const AssignmentPhrase *r)
{
data.append(l->data);
data.append(r->data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(const AssignmentPhrase &r,
const AssignmentPhrase &l)
{
data.append(l.data);
data.append(r.data);
incAllDataParents();
}
AssignmentPhraseList AssignmentPhraseList::operator &(const AssignmentPhrase
&ph)
{
return AssignmentPhraseList(this, &ph);
}
AssignmentPhraseList::~AssignmentPhraseList()
{
foreach (PhraseData *d, data)
if (!--d->parents)
delete d;
// qDeleteAll(data);
// data.clear();
}
void AssignmentPhraseList::incAllDataParents()
{
foreach (PhraseData *d, data)
d->parents++;
}
ConditionalPhrase::ConditionalPhrase() : data(0)
{ }
ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &other)
{
qDebug() << "************* ctor called:";
data = other.data;
data->parents++;
// const_cast<ConditionalPhrase&>(other).data = 0;
}
#ifdef Q_COMPILER_RVALUE_REFS
ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &&other)
{
qDebug() << "************* ctor called:";
this->data = qMove(other.data);
}
#endif
ConditionalPhrase::ConditionalPhrase(const PhraseData *data)
{
this->data = const_cast<PhraseData*>(data);
this->data->parents++;
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond)
{
data = new PhraseData(l->data, cond);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
const QVariant &v)
{
data = new PhraseData(l->data, cond, v);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
const AbstractFieldPhrase &other)
{
data = new PhraseData(l->data, cond, other.data);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
ConditionalPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
r.data = 0;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
const AbstractFieldPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
l->data = 0;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
const QVariant &r)
{
data = new PhraseData(l->data, cond, r);
l->data = 0;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
ConditionalPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
l->data = 0;
r.data = 0;
}
ConditionalPhrase::~ConditionalPhrase()
{
if (data) {
data->cleanUp();
if (!--data->parents)
delete data;
}
}
ConditionalPhrase &ConditionalPhrase::operator =(const ConditionalPhrase &other)
{
data = other.data;
data->parents++;
return *this;
}
ConditionalPhrase ConditionalPhrase::operator ==(const QVariant &other)
{
return ConditionalPhrase(this, PhraseData::Equal, other);
}
//ConditionalPhrase ConditionalPhrase::operator ==(const AbstractFieldPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::Equal, other);
//}
//ConditionalPhrase ConditionalPhrase::operator &&(const ConditionalPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::And,
// const_cast<ConditionalPhrase&>(other));
//}
//ConditionalPhrase ConditionalPhrase::operator ||(const ConditionalPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::Or,
// const_cast<ConditionalPhrase&>(other));
//}
#define DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(op, cond) \
ConditionalPhrase operator op(const ConditionalPhrase &l, \
const ConditionalPhrase &r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(const ConditionalPhrase &l, \
ConditionalPhrase &&r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(ConditionalPhrase &&l, \
const ConditionalPhrase &r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(ConditionalPhrase &&l, ConditionalPhrase &&r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
}
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(==, PhraseData::Equal)
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(||, PhraseData::Or)
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(&&, PhraseData::And)
ConditionalPhrase ConditionalPhrase::operator !()
{
ConditionalPhrase f(data);
f.data->isNot = !data->isNot;
return f;
}
PhraseDataList::PhraseDataList() : QList<PhraseData*>()
{
}
PhraseDataList::PhraseDataList(const PhraseDataList &other) : QList<PhraseData*>()
{
PhraseDataList &o = const_cast<PhraseDataList&>(other);
PhraseDataList::iterator i;
for (i = o.begin(); i != o.end(); ++i)
append(*i);
}
void PhraseDataList::append(PhraseData *d)
{
d->parents++;
QList<PhraseData*>::append(d);
}
void PhraseDataList::append(QList<PhraseData *> &dl)
{
foreach (PhraseData *d, dl)
d->parents++;
QList<PhraseData*>::append(dl);
}
PhraseDataList::~PhraseDataList()
{
QList<PhraseData*>::iterator i;
for (i = begin(); i != end(); ++i) {
(*i)->cleanUp();
if (!--(*i)->parents)
delete *i;
}
}
//AssignmentPhraseList operator &(const AssignmentPhrase &l, const AssignmentPhrase &r)
//{

View File

@ -21,15 +21,16 @@
#ifndef PHRASE_H
#define PHRASE_H
#include <QSharedPointer>
#include <QString>
#include <QVariant>
#include <QtGlobal>
#ifdef Q_COMPILER_INITIALIZER_LISTS
# include <initializer_list>
#endif
#include "defines.h"
#include "phrases/conditionalphrase.h"
#include "phrases/abstractfieldphrase.h"
#include "phrases/fieldphrase.h"
#include "phrases/phraselist.h"
#include "phrases/assignmentphraselist.h"
#include "phrases/phrasedatalist.h"
#include "phrases/phrasedata.h"
#include "phrases/assignmentphrase.h"
#include "phrases/numericphrase.h"
#include "phrases/datephrase.h"
NUT_BEGIN_NAMESPACE
@ -43,426 +44,29 @@ class AbstractFieldPhrase;
class AssignmentPhrase;
class PhraseList;
class PhraseData
{
public:
enum Condition {
NotAssign = 0,
Equal,
Less,
LessEqual,
Null,
In,
Like,
Not = 10,
NotEqual,
GreaterEqual,
Greater,
NotNull,
NotIn,
NotLike,
And = 20,
Or,
Add,
Minus,
Multiple,
Divide,
Mod,
Between,
//date and time
AddYears,
AddMonths,
AddDays,
AddHours,
AddMinutes,
AddSeconds
// // special types
// Distance
};
enum Type { Field, WithVariant, WithOther, WithoutOperand };
const char *className;
const char *fieldName;
Type type;
PhraseData *left;
PhraseData *right;
QVariant operand;
Condition operatorCond;
bool isNot;
quint16 parents;
PhraseData();
PhraseData(const char *className, const char *fieldName);
PhraseData(PhraseData *l, Condition o);
PhraseData(PhraseData *l, Condition o, PhraseData *r);
PhraseData(PhraseData *l, Condition o, QVariant r);
// explicit PhraseData(const PhraseData &other);
// explicit PhraseData(const PhraseData *other);
PhraseData *operator =(PhraseData *other);
PhraseData &operator =(PhraseData &other);
QString toString() const;
~PhraseData();
void cleanUp();
private:
void cleanUp(PhraseData *d);
};
class PhraseDataList : public QList<PhraseData*>
{
public:
PhraseDataList();
PhraseDataList(const PhraseDataList &other);
void append(PhraseData *d);
void append(QList<PhraseData*> &dl);
virtual ~PhraseDataList();
};
class AssignmentPhraseList
{
public:
QList<PhraseData*> data;
explicit AssignmentPhraseList();
AssignmentPhraseList(const AssignmentPhrase &l);
AssignmentPhraseList(AssignmentPhraseList *l, const AssignmentPhrase *r);
AssignmentPhraseList(AssignmentPhrase *l, const AssignmentPhrase *r);
AssignmentPhraseList(const AssignmentPhrase &r, const AssignmentPhrase &l);
AssignmentPhraseList operator &(const AssignmentPhrase &ph);
~AssignmentPhraseList();
private:
void incAllDataParents();
};
class AssignmentPhrase
{
public:
PhraseData *data;
explicit AssignmentPhrase(PhraseData *d);
explicit AssignmentPhrase(AbstractFieldPhrase *l, const QVariant r);
explicit AssignmentPhrase(AbstractFieldPhrase *l, const AssignmentPhrase *r);
explicit AssignmentPhrase(AssignmentPhrase *ph, const QVariant &v);
// explicit AssignmentPhrase(AssignmentPhrase &other);
~AssignmentPhrase();
// AssignmentPhrase(AssignmentPhrase *l, const AssignmentPhrase *r);
AssignmentPhraseList operator &(const AssignmentPhrase &other);
};
//AssignmentPhraseList operator &(const AssignmentPhrase &l, const AssignmentPhrase &r);
//AssignmentPhraseList operator &(const AssignmentPhrase &l, AssignmentPhrase &&r);
//AssignmentPhraseList operator &(AssignmentPhrase &&l, const AssignmentPhrase &r);
//AssignmentPhraseList operator &(AssignmentPhrase &&l, AssignmentPhrase &&r);
class PhraseList{
public:
bool isValid;
PhraseDataList data;
explicit PhraseList();
PhraseList(const PhraseList &other);
PhraseList(PhraseList &&other);
PhraseList(const AbstractFieldPhrase &other);
PhraseList(const AbstractFieldPhrase *left, const AbstractFieldPhrase &right);
PhraseList(PhraseList *left, PhraseList *right);
PhraseList(PhraseList *left, const AbstractFieldPhrase *right);
virtual ~PhraseList();
PhraseList &operator =(const PhraseList &other);
PhraseList operator |(PhraseList &other);
PhraseList operator |(const AbstractFieldPhrase &other);
//ConditionalPhrase operator <(AbstractFieldPhrase &l, ConditionalPhrase &&other)
//{
// return ConditionalPhrase(&l, PhraseData::Less, other);
//}
private:
void incAllDataParents();
};
//template<typename T>
//class FieldPhrase : public AbstractFieldPhrase
//{
//public:
// FieldPhrase(const char *className, const char *s) :
// AbstractFieldPhrase(className, s)
// {}
class ConditionalPhrase
{
public:
PhraseData *data;
// QSharedPointer<PhraseData> leftDataPointer;
// QSharedPointer<PhraseData> rightDataPointer;
ConditionalPhrase();
ConditionalPhrase(const ConditionalPhrase &other);
#ifdef Q_COMPILER_RVALUE_REFS
ConditionalPhrase(const ConditionalPhrase &&other);
#endif
ConditionalPhrase(const PhraseData *data);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition, const QVariant &v);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition, const AbstractFieldPhrase &v);
ConditionalPhrase(AbstractFieldPhrase *l, PhraseData::Condition cond, ConditionalPhrase &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, const AbstractFieldPhrase &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, const QVariant &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, ConditionalPhrase &r);
virtual ~ConditionalPhrase();
ConditionalPhrase &operator =(const ConditionalPhrase &other);
ConditionalPhrase operator ==(const QVariant &other);
// ConditionalPhrase operator ==(const AbstractFieldPhrase &other);
// ConditionalPhrase operator &&(const ConditionalPhrase &other);
// ConditionalPhrase operator ||(const ConditionalPhrase &other);
ConditionalPhrase operator !();
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
};
#define DECLARE_CONDITIONALPHRASE_OPERATORS(op) \
ConditionalPhrase operator op(const ConditionalPhrase &l, const ConditionalPhrase &r); \
ConditionalPhrase operator op(const ConditionalPhrase &l, ConditionalPhrase &&r); \
ConditionalPhrase operator op(ConditionalPhrase &&l, const ConditionalPhrase &r); \
ConditionalPhrase operator op(ConditionalPhrase &&l, ConditionalPhrase &&r);
DECLARE_CONDITIONALPHRASE_OPERATORS(==)
DECLARE_CONDITIONALPHRASE_OPERATORS(&&)
DECLARE_CONDITIONALPHRASE_OPERATORS(||)
class AbstractFieldPhrase
{
public:
PhraseData *data;
explicit AbstractFieldPhrase(PhraseData *d);
AbstractFieldPhrase(const char *className, const char *fieldName);
AbstractFieldPhrase(const AbstractFieldPhrase &other);
AbstractFieldPhrase(AbstractFieldPhrase &&other);
virtual ~AbstractFieldPhrase();
PhraseList operator |(const AbstractFieldPhrase &other);
template<typename T>
ConditionalPhrase in(QList<T> list)
{
QVariantList vlist;
foreach (T t, list)
vlist.append(QVariant::fromValue(t));
return ConditionalPhrase(this, PhraseData::In, vlist);
}
#ifdef Q_COMPILER_INITIALIZER_LISTS
ConditionalPhrase in(std::initializer_list<int> list) {
QVariantList vlist;
std::initializer_list<int>::iterator it;
for (it = list.begin(); it != list.end(); ++it)
vlist.append(*it);
return ConditionalPhrase(this, PhraseData::In, vlist);
}
#endif
ConditionalPhrase isNull();
ConditionalPhrase operator ==(const QVariant &other);
ConditionalPhrase operator ==(const ConditionalPhrase &other);
ConditionalPhrase operator !=(const QVariant &other);
ConditionalPhrase operator ==(const AbstractFieldPhrase &other);
ConditionalPhrase operator !=(const AbstractFieldPhrase &other);
ConditionalPhrase operator <(const AbstractFieldPhrase &other);
ConditionalPhrase operator >(const AbstractFieldPhrase &other);
ConditionalPhrase operator <=(const AbstractFieldPhrase &other);
ConditionalPhrase operator >=(const AbstractFieldPhrase &other);
AbstractFieldPhrase operator !();
AssignmentPhrase operator =(const QVariant &other);
AssignmentPhrase operator <<(const QVariant &other);
};
template<typename T>
class FieldPhrase : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const QVariant &other) {
return AssignmentPhrase(this, other);
}
};
template<>
class FieldPhrase<QString> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
ConditionalPhrase like(const QString &term) {
return ConditionalPhrase(this, PhraseData::Like, term);
}
AssignmentPhrase operator =(const QVariant &v) {
return AssignmentPhrase(this, v);
}
};
#define SPECIALIZATION_NUMERIC(type) \
template<> \
class FieldPhrase<type> : public AbstractFieldPhrase \
{ \
public: \
FieldPhrase(const char *className, const char *s) : \
AbstractFieldPhrase(className, s) \
{} \
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less) \
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual) \
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater) \
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual) \
SPECIALIZATION_NUMERIC_MEMBER(type, %, PhraseData::Mod) \
\
SPECIALIZATION_NUMERIC_MEMBER(type, +, PhraseData::Add) \
SPECIALIZATION_NUMERIC_MEMBER(type, -, PhraseData::Minus) \
SPECIALIZATION_NUMERIC_MEMBER(type, *, PhraseData::Multiple) \
SPECIALIZATION_NUMERIC_MEMBER(type, /, PhraseData::Divide) \
AssignmentPhrase operator =(const QVariant &other) { \
return AssignmentPhrase(this, other); \
} \
ConditionalPhrase between(const QVariant &min, const QVariant &max) \
{ \
return ConditionalPhrase(this, PhraseData::Between, \
QVariantList() << min << max); \
} \
};
SPECIALIZATION_NUMERIC(qint8)
SPECIALIZATION_NUMERIC(qint16)
SPECIALIZATION_NUMERIC(qint32)
SPECIALIZATION_NUMERIC(qint64)
SPECIALIZATION_NUMERIC(quint8)
SPECIALIZATION_NUMERIC(quint16)
SPECIALIZATION_NUMERIC(quint32)
SPECIALIZATION_NUMERIC(quint64)
SPECIALIZATION_NUMERIC(qreal)
//Date and time
#define CONDITIONAL_VARIANT_METHOD(name, cond) \
ConditionalPhrase name(int val) \
{ \
return ConditionalPhrase(this, cond, val); \
}
template<>
class FieldPhrase<bool> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const bool &other) {
return AssignmentPhrase(this, other);
}
FieldPhrase<bool> operator !()
{
FieldPhrase<bool> f(data->className, data->fieldName);
// f.data = new PhraseData(data);
f.data->isNot = !data->isNot;
return f;
}
operator ConditionalPhrase()
{
return ConditionalPhrase(this, PhraseData::Equal, !data->isNot);
}
};
template<>
class FieldPhrase<QDate> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
AssignmentPhrase operator =(const QDate &other) {
return AssignmentPhrase(this, other);
}
ConditionalPhrase between(const QDate &min, const QDate &max)
{
return ConditionalPhrase(this, PhraseData::Between,
QVariantList() << min << max);
}
CONDITIONAL_VARIANT_METHOD(addYears, PhraseData::AddYears)
CONDITIONAL_VARIANT_METHOD(addMonths, PhraseData::AddMonths)
CONDITIONAL_VARIANT_METHOD(addDays, PhraseData::AddDays)
};
template<>
class FieldPhrase<QTime> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
AssignmentPhrase operator =(const QTime &other) {
return AssignmentPhrase(this, other);
}
ConditionalPhrase between(const QTime &min, const QTime &max)
{
return ConditionalPhrase(this, PhraseData::Between,
QVariantList() << min << max);
}
CONDITIONAL_VARIANT_METHOD(addHours, PhraseData::AddHours)
CONDITIONAL_VARIANT_METHOD(addMinutes, PhraseData::AddMinutes)
CONDITIONAL_VARIANT_METHOD(addSeconds, PhraseData::AddSeconds)
};
template<>
class FieldPhrase<QDateTime> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
AssignmentPhrase operator =(const QDateTime &other) {
return AssignmentPhrase(this, other);
}
ConditionalPhrase between(const QDateTime &min, const QDateTime &max)
{
return ConditionalPhrase(this, PhraseData::Between,
QVariantList() << min << max);
}
CONDITIONAL_VARIANT_METHOD(addYears, PhraseData::AddYears)
CONDITIONAL_VARIANT_METHOD(addMonths, PhraseData::AddMonths)
CONDITIONAL_VARIANT_METHOD(addDays, PhraseData::AddDays)
CONDITIONAL_VARIANT_METHOD(addHours, PhraseData::AddHours)
CONDITIONAL_VARIANT_METHOD(addMinutes, PhraseData::AddMinutes)
CONDITIONAL_VARIANT_METHOD(addSeconds, PhraseData::AddSeconds)
};
// AssignmentPhrase operator =(const QVariant &other) {
// return AssignmentPhrase(this, other);
// }
//};
NUT_END_NAMESPACE

View File

@ -0,0 +1,126 @@
/**************************************************************************
**
** 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 "abstractfieldphrase.h"
NUT_BEGIN_NAMESPACE
AbstractFieldPhrase::AbstractFieldPhrase(PhraseData *d) : data(d)
{ }
AbstractFieldPhrase::AbstractFieldPhrase(const char *className,
const char *fieldName)
:data(new PhraseData(className, fieldName))
{
}
AbstractFieldPhrase::AbstractFieldPhrase(const AbstractFieldPhrase &other)
{
data = other.data;
data->parents++;
}
AbstractFieldPhrase::AbstractFieldPhrase(AbstractFieldPhrase &&other)
{
data = other.data;
data->parents++;
other.data = nullptr;
}
AbstractFieldPhrase::~AbstractFieldPhrase()
{
if (data) {
--data->parents;
if (data->parents <= 0)
delete data;
}
}
PhraseList AbstractFieldPhrase::operator |(const AbstractFieldPhrase &other)
{
return PhraseList(this, other);
}
ConditionalPhrase AbstractFieldPhrase::isNull()
{
return ConditionalPhrase(this, PhraseData::Null);
}
ConditionalPhrase AbstractFieldPhrase::operator ==(const ConditionalPhrase
&other)
{
return ConditionalPhrase(this, PhraseData::Equal,
const_cast<ConditionalPhrase&>(other));
}
AssignmentPhrase AbstractFieldPhrase::operator =(const QVariant &other)
{
return AssignmentPhrase(this, other);
}
AssignmentPhrase AbstractFieldPhrase::operator =(const ConditionalPhrase &other)
{
return AssignmentPhrase(new PhraseData(data, PhraseData::Equal, other.data));
}
AssignmentPhrase AbstractFieldPhrase::operator <<(const QVariant &other)
{
return AssignmentPhrase(this, other);
}
#define AbstractFieldPhraseOperatorVariant(class, op, cond) \
ConditionalPhrase class::operator op(const QVariant &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
AbstractFieldPhraseOperatorVariant(AbstractFieldPhrase, ==, PhraseData::Equal)
AbstractFieldPhraseOperatorVariant(AbstractFieldPhrase, !=, PhraseData::NotEqual)
#define AbstractFieldPhraseOperatorField(op, cond) \
ConditionalPhrase AbstractFieldPhrase::operator op(const AbstractFieldPhrase &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
AbstractFieldPhraseOperatorField(==, PhraseData::Equal)
AbstractFieldPhraseOperatorField(!=, PhraseData::NotEqual)
AbstractFieldPhraseOperatorField(< , PhraseData::Less)
AbstractFieldPhraseOperatorField(<=, PhraseData::LessEqual)
AbstractFieldPhraseOperatorField(> , PhraseData::Greater)
AbstractFieldPhraseOperatorField(>=, PhraseData::GreaterEqual)
AbstractFieldPhrase AbstractFieldPhrase::operator ~()
{
AbstractFieldPhrase f(data->className, data->fieldName);
f.data->isNot = !data->isNot;
return f;
}
AbstractFieldPhrase AbstractFieldPhrase::operator !()
{
AbstractFieldPhrase f(data->className, data->fieldName);
f.data->isNot = !data->isNot;
return f;
}
NUT_END_NAMESPACE

View File

@ -0,0 +1,88 @@
/**************************************************************************
**
** 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 ABSTRACTFIELDPHRASE_H
#define ABSTRACTFIELDPHRASE_H
#include "../defines.h"
#include "assignmentphrase.h"
#include "conditionalphrase.h"
#include "phraselist.h"
NUT_BEGIN_NAMESPACE
class PhraseData;
class NUT_EXPORT AbstractFieldPhrase
{
public:
PhraseData *data;
explicit AbstractFieldPhrase(PhraseData *d);
AbstractFieldPhrase(const char *className, const char *fieldName);
AbstractFieldPhrase(const AbstractFieldPhrase &other);
AbstractFieldPhrase(AbstractFieldPhrase &&other);
virtual ~AbstractFieldPhrase();
PhraseList operator |(const AbstractFieldPhrase &other);
template<typename T>
ConditionalPhrase in(QList<T> list)
{
QVariantList vlist;
foreach (T t, list)
vlist.append(QVariant::fromValue(t));
return ConditionalPhrase(this, PhraseData::In, vlist);
}
#ifdef Q_COMPILER_INITIALIZER_LISTS
ConditionalPhrase in(std::initializer_list<int> list) {
QVariantList vlist;
std::initializer_list<int>::iterator it;
for (it = list.begin(); it != list.end(); ++it)
vlist.append(*it);
return ConditionalPhrase(this, PhraseData::In, vlist);
}
#endif
ConditionalPhrase isNull();
ConditionalPhrase operator ==(const QVariant &other);
ConditionalPhrase operator ==(const ConditionalPhrase &other);
//why?
ConditionalPhrase operator !=(const QVariant &other);
ConditionalPhrase operator ==(const AbstractFieldPhrase &other);
ConditionalPhrase operator !=(const AbstractFieldPhrase &other);
ConditionalPhrase operator <(const AbstractFieldPhrase &other);
ConditionalPhrase operator >(const AbstractFieldPhrase &other);
ConditionalPhrase operator <=(const AbstractFieldPhrase &other);
ConditionalPhrase operator >=(const AbstractFieldPhrase &other);
AbstractFieldPhrase operator ~();
AbstractFieldPhrase operator !();
AssignmentPhrase operator =(const QVariant &other);
AssignmentPhrase operator =(const ConditionalPhrase &other);
AssignmentPhrase operator <<(const QVariant &other);
};
NUT_END_NAMESPACE
#endif // ABSTRACTFIELDPHRASE_H

View File

@ -0,0 +1,64 @@
/**************************************************************************
**
** 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 "abstractfieldphrase.h"
#include "assignmentphrase.h"
#include "phrasedata.h"
NUT_BEGIN_NAMESPACE
AssignmentPhrase::AssignmentPhrase(PhraseData *d) : data(d)
{
d->parents++;
}
AssignmentPhrase::AssignmentPhrase(AbstractFieldPhrase *l, const QVariant r)
{
data = new PhraseData(l->data, PhraseData::Equal, r);
// l->data = 0;
}
AssignmentPhrase::AssignmentPhrase(AbstractFieldPhrase *l,
const AssignmentPhrase *r)
{
data = new PhraseData(l->data, PhraseData::Equal, r->data);
// l->data = 0;
}
AssignmentPhrase::AssignmentPhrase(AssignmentPhrase *ph, const QVariant &v)
{
data = new PhraseData(ph->data, PhraseData::Equal, v);
}
//AssignmentPhrase::AssignmentPhrase(AssignmentPhrase &other)
//{
// data = other.data;
// other.data = 0;
//}
AssignmentPhrase::~AssignmentPhrase()
{
if (data)
if (!--data->parents)
delete data;
}
NUT_END_NAMESPACE

View File

@ -0,0 +1,50 @@
/**************************************************************************
**
** 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 ASSIGNMENTPHRASE_H
#define ASSIGNMENTPHRASE_H
#include "../defines.h"
#include "assignmentphraselist.h"
NUT_BEGIN_NAMESPACE
class PhraseData;
class AbstractFieldPhrase;
class NUT_EXPORT AssignmentPhrase
{
public:
PhraseData *data;
explicit AssignmentPhrase(PhraseData *d);
explicit AssignmentPhrase(AbstractFieldPhrase *l, const QVariant r);
explicit AssignmentPhrase(AbstractFieldPhrase *l, const AssignmentPhrase *r);
explicit AssignmentPhrase(AssignmentPhrase *ph, const QVariant &v);
// explicit AssignmentPhrase(AssignmentPhrase &other);
~AssignmentPhrase();
// AssignmentPhrase(AssignmentPhrase *l, const AssignmentPhrase *r);
AssignmentPhraseList operator &(const AssignmentPhrase &other);
};
NUT_END_NAMESPACE
#endif // ASSIGNMENTPHRASE_H

View File

@ -0,0 +1,85 @@
/**************************************************************************
**
** 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 "assignmentphraselist.h"
#include "phrasedata.h"
#include "assignmentphrase.h"
NUT_BEGIN_NAMESPACE
AssignmentPhraseList AssignmentPhrase::operator &(const AssignmentPhrase &other)
{
return AssignmentPhraseList(this, &other);
}
AssignmentPhraseList::AssignmentPhraseList(const AssignmentPhrase &l)
{
data.append(l.data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(AssignmentPhraseList *l,
const AssignmentPhrase *r)
{
data.append(l->data);
data.append(r->data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(AssignmentPhrase *l,
const AssignmentPhrase *r)
{
data.append(l->data);
data.append(r->data);
incAllDataParents();
}
AssignmentPhraseList::AssignmentPhraseList(const AssignmentPhrase &r,
const AssignmentPhrase &l)
{
data.append(l.data);
data.append(r.data);
incAllDataParents();
}
AssignmentPhraseList AssignmentPhraseList::operator &(const AssignmentPhrase
&ph)
{
return AssignmentPhraseList(this, &ph);
}
AssignmentPhraseList::~AssignmentPhraseList()
{
foreach (PhraseData *d, data)
if (!--d->parents)
delete d;
// qDeleteAll(data);
// data.clear();
}
void AssignmentPhraseList::incAllDataParents()
{
foreach (PhraseData *d, data)
d->parents++;
}
NUT_END_NAMESPACE

View File

@ -0,0 +1,50 @@
/**************************************************************************
**
** 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 ASSIGNMENTPHRASELIST_H
#define ASSIGNMENTPHRASELIST_H
#include "../defines.h"
NUT_BEGIN_NAMESPACE
class PhraseData;
class AssignmentPhrase;
class NUT_EXPORT AssignmentPhraseList
{
public:
QList<PhraseData*> data;
explicit AssignmentPhraseList() = default;
AssignmentPhraseList(const AssignmentPhrase &l);
AssignmentPhraseList(AssignmentPhraseList *l, const AssignmentPhrase *r);
AssignmentPhraseList(AssignmentPhrase *l, const AssignmentPhrase *r);
AssignmentPhraseList(const AssignmentPhrase &r, const AssignmentPhrase &l);
AssignmentPhraseList operator &(const AssignmentPhrase &ph);
~AssignmentPhraseList();
private:
void incAllDataParents();
};
NUT_END_NAMESPACE
#endif // ASSIGNMENTPHRASELIST_H

View File

@ -0,0 +1,245 @@
/**************************************************************************
**
** 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 "abstractfieldphrase.h"
#include "conditionalphrase.h"
#include "phrasedata.h"
NUT_BEGIN_NAMESPACE
ConditionalPhrase::ConditionalPhrase() : data(nullptr)
{ }
ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &other)
{
data = other.data;
data->parents++;
// const_cast<ConditionalPhrase&>(other).data = 0;
}
#ifdef Q_COMPILER_RVALUE_REFS
ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &&other)
{
this->data = qMove(other.data);
}
#endif
ConditionalPhrase::ConditionalPhrase(const PhraseData *data)
{
this->data = const_cast<PhraseData*>(data);
this->data->parents++;
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond)
{
data = new PhraseData(l->data, cond);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
const QVariant &v)
{
data = new PhraseData(l->data, cond, v);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
const AbstractFieldPhrase &other)
{
data = new PhraseData(l->data, cond, other.data);
}
ConditionalPhrase::ConditionalPhrase(AbstractFieldPhrase *l,
PhraseData::Condition cond,
ConditionalPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
r.data = nullptr;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
const AbstractFieldPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
l->data = nullptr;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
const QVariant &r)
{
data = new PhraseData(l->data, cond, r);
l->data = nullptr;
}
ConditionalPhrase::ConditionalPhrase(ConditionalPhrase *l,
PhraseData::Condition cond,
ConditionalPhrase &r)
{
data = new PhraseData(l->data, cond, r.data);
l->data = nullptr;
r.data = nullptr;
}
ConditionalPhrase::~ConditionalPhrase()
{
if (data) {
data->cleanUp();
if (!--data->parents)
delete data;
}
}
ConditionalPhrase &ConditionalPhrase::operator =(const ConditionalPhrase &other)
{
data = other.data;
data->parents++;
return *this;
}
ConditionalPhrase ConditionalPhrase::operator ==(const QVariant &other)
{
return ConditionalPhrase(this, PhraseData::Equal, other);
}
//ConditionalPhrase ConditionalPhrase::operator ==(const AbstractFieldPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::Equal, other);
//}
//ConditionalPhrase ConditionalPhrase::operator &&(const ConditionalPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::And,
// const_cast<ConditionalPhrase&>(other));
//}
//ConditionalPhrase ConditionalPhrase::operator ||(const ConditionalPhrase &other)
//{
// return ConditionalPhrase(this, PhraseData::Or,
// const_cast<ConditionalPhrase&>(other));
//}
#define DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(op, cond) \
ConditionalPhrase operator op(const ConditionalPhrase &l, \
const ConditionalPhrase &r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->type = PhraseData::WithOther; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(const ConditionalPhrase &l, \
ConditionalPhrase &&r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->type = PhraseData::WithOther; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(ConditionalPhrase &&l, \
const ConditionalPhrase &r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->type = PhraseData::WithOther; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
} \
ConditionalPhrase operator op(ConditionalPhrase &&l, ConditionalPhrase &&r) \
{ \
ConditionalPhrase p; \
p.data = new PhraseData; \
p.data->type = PhraseData::WithOther; \
p.data->operatorCond = cond; \
p.data->left = l.data; \
p.data->right = r.data; \
l.data->parents++; \
r.data->parents++; \
return p; \
}
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(==, PhraseData::Equal)
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(||, PhraseData::Or)
DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(&&, PhraseData::And)
ConditionalPhrase ConditionalPhrase::operator !()
{
ConditionalPhrase f(data);
f.data->isNot = !data->isNot;
return f;
}
ConditionalPhrase operator <(AbstractFieldPhrase &l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::Less, r);
}
ConditionalPhrase operator <=(AbstractFieldPhrase &l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::LessEqual, r);
}
ConditionalPhrase operator >(AbstractFieldPhrase &l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::Greater, r);
}
ConditionalPhrase operator >=(AbstractFieldPhrase &l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::GreaterEqual, r);
}
ConditionalPhrase operator <(ConditionalPhrase &&l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::Less, r);
}
ConditionalPhrase operator <=(ConditionalPhrase &&l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::LessEqual, r);
}
ConditionalPhrase operator >(ConditionalPhrase &&l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::Greater, r);
}
ConditionalPhrase operator >=(ConditionalPhrase &&l, ConditionalPhrase &&r)
{
return ConditionalPhrase(&l, PhraseData::GreaterEqual, r);
}
NUT_END_NAMESPACE

View File

@ -0,0 +1,94 @@
/**************************************************************************
**
** 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 CONDITIONALPHRASE_H
#define CONDITIONALPHRASE_H
#include "phrasedata.h"
NUT_BEGIN_NAMESPACE
class PhraseData;
class AbstractFieldPhrase;
#define SPECIALIZATION_NUMERIC_MEMBER(type, op, cond) \
ConditionalPhrase operator op(const QVariant &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
class NUT_EXPORT ConditionalPhrase
{
public:
PhraseData *data;
// QSharedPointer<PhraseData> leftDataPointer;
// QSharedPointer<PhraseData> rightDataPointer;
ConditionalPhrase();
ConditionalPhrase(const ConditionalPhrase &other);
#ifdef Q_COMPILER_RVALUE_REFS
ConditionalPhrase(const ConditionalPhrase &&other);
#endif
explicit ConditionalPhrase(const PhraseData *data);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition, const QVariant &v);
ConditionalPhrase(AbstractFieldPhrase *, PhraseData::Condition, const AbstractFieldPhrase &v);
ConditionalPhrase(AbstractFieldPhrase *l, PhraseData::Condition cond, ConditionalPhrase &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, const AbstractFieldPhrase &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, const QVariant &r);
ConditionalPhrase(ConditionalPhrase *l, PhraseData::Condition cond, ConditionalPhrase &r);
virtual ~ConditionalPhrase();
ConditionalPhrase &operator =(const ConditionalPhrase &other);
ConditionalPhrase operator ==(const QVariant &other);
// ConditionalPhrase operator ==(const AbstractFieldPhrase &other);
// ConditionalPhrase operator &&(const ConditionalPhrase &other);
// ConditionalPhrase operator ||(const ConditionalPhrase &other);
ConditionalPhrase operator !();
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
};
#define DECLARE_CONDITIONALPHRASE_OPERATORS(op) \
ConditionalPhrase operator op(const ConditionalPhrase &l, const ConditionalPhrase &r); \
ConditionalPhrase operator op(const ConditionalPhrase &l, ConditionalPhrase &&r); \
ConditionalPhrase operator op(ConditionalPhrase &&l, const ConditionalPhrase &r); \
ConditionalPhrase operator op(ConditionalPhrase &&l, ConditionalPhrase &&r);
DECLARE_CONDITIONALPHRASE_OPERATORS(==)
DECLARE_CONDITIONALPHRASE_OPERATORS(&&)
DECLARE_CONDITIONALPHRASE_OPERATORS(||)
ConditionalPhrase operator <(AbstractFieldPhrase &l, ConditionalPhrase &&r);
ConditionalPhrase operator <=(AbstractFieldPhrase &l, ConditionalPhrase &&r);
ConditionalPhrase operator >(AbstractFieldPhrase &l, ConditionalPhrase &&r);
ConditionalPhrase operator >=(AbstractFieldPhrase &l, ConditionalPhrase &&r);
ConditionalPhrase operator <(ConditionalPhrase &&l, ConditionalPhrase &&r);
ConditionalPhrase operator <=(ConditionalPhrase &&l, ConditionalPhrase &&r);
ConditionalPhrase operator >(ConditionalPhrase &&l, ConditionalPhrase &&r);
ConditionalPhrase operator >=(ConditionalPhrase &&l, ConditionalPhrase &&r);
NUT_END_NAMESPACE
#endif // CONDITIONALPHRASE_H

View File

@ -0,0 +1,22 @@
/**************************************************************************
**
** 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 "datephrase.h"

173
src/phrases/datephrase.h Normal file
View File

@ -0,0 +1,173 @@
/**************************************************************************
**
** 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 DATEPHRASE_H
#define DATEPHRASE_H
#include "fieldphrase.h"
#include <QDateTime>
#include <type_traits>
NUT_BEGIN_NAMESPACE
template<typename>
struct __is_date_helper
: public std::false_type { };
template<>
struct __is_date_helper<QTime>
: public std::true_type { };
template<>
struct __is_date_helper<QDate>
: public std::true_type { };
template<>
struct __is_date_helper<QDateTime>
: public std::true_type { };
template<typename _Tp>
struct is_date
: public __is_date_helper<typename std::remove_cv<_Tp>::type>::type
{ };
template <class T, class P>
inline bool is_valid_template() {return false;}
template <>
inline bool is_valid_template<QDateTime, QTime>() {return true;}
template <>
inline bool is_valid_template<QDateTime, QDate>() {return true;}
template <>
inline bool is_valid_template<QDate, QDate>() {return true;}
template <>
inline bool is_valid_template<QTime, QTime>() {return true;}
template <typename T>
class NUT_EXPORT FieldPhrase<T, typename std::enable_if<is_date<T>::value>::type>
: public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const T &other) {
return AssignmentPhrase(this, other);
}
ConditionalPhrase operator <(const QVariant &other) {
return ConditionalPhrase(this, PhraseData::Less, other);
}
ConditionalPhrase operator <=(const QVariant &other) {
return ConditionalPhrase(this, PhraseData::LessEqual, other);
}
ConditionalPhrase operator >(const QVariant &other) {
return ConditionalPhrase(this, PhraseData::Greater, other);
}
ConditionalPhrase operator >=(const QVariant &other) {
return ConditionalPhrase(this, PhraseData::GreaterEqual, other);
}
ConditionalPhrase between(const QVariant &min, const QVariant &max)
{
return ConditionalPhrase(this, PhraseData::Between,
QVariantList() << min << max);
}
// template<class P = T,
// class std::enable_if<std::is_same<P, QDateTime>::value, int>::type = 0>
ConditionalPhrase addYears(int val) {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddYears, val);
}
ConditionalPhrase addMonths(int val) {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddMonths, val);
}
ConditionalPhrase addDays(int val) {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddDays, val);
}
ConditionalPhrase addHours(int val) {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddHours, val);
}
ConditionalPhrase addMinutes(int val) {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddMinutes, val);
}
ConditionalPhrase addSeconds(int val) {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::AddSeconds, val);
}
ConditionalPhrase year() {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartYear);
}
ConditionalPhrase month() {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartMonth);
}
ConditionalPhrase day() {
if (!is_valid_template<T, QDate>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartDay);
}
ConditionalPhrase hour() {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartHour);
}
ConditionalPhrase minute() {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartMinute);
}
ConditionalPhrase second() {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartSecond);
}
ConditionalPhrase msec() {
if (!is_valid_template<T, QTime>())
return ConditionalPhrase();
return ConditionalPhrase(this, PhraseData::DatePartMilisecond);
}
};
NUT_END_NAMESPACE
#endif // DATEPHRASE_H

View File

@ -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 "fieldphrase.h"

105
src/phrases/fieldphrase.h Normal file
View File

@ -0,0 +1,105 @@
/**************************************************************************
**
** 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 FIELDPHRASE_H
#define FIELDPHRASE_H
#include "../defines.h"
#include "abstractfieldphrase.h"
NUT_BEGIN_NAMESPACE
template<typename T, typename enable = void>
class NUT_EXPORT FieldPhrase : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const QVariant &other) {
return AssignmentPhrase(this, other);
}
ConditionalPhrase operator ==(const QVariant &other) {
return ConditionalPhrase(this, PhraseData::Equal, other);
}
};
template<>
class NUT_EXPORT FieldPhrase<QString> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
ConditionalPhrase like(const QString &term) {
return ConditionalPhrase(this, PhraseData::Like, term);
}
ConditionalPhrase contains(const QString &term) {
return ConditionalPhrase(this, PhraseData::Like, "%" + term + "%");
}
AssignmentPhrase operator =(const QVariant &v) {
return AssignmentPhrase(this, v);
}
};
//Date and time
#define CONDITIONAL_VARIANT_METHOD(name, cond) \
ConditionalPhrase name(int val) \
{ \
return ConditionalPhrase(this, cond, val); \
}
template<>
class NUT_EXPORT FieldPhrase<bool> : public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const bool &other) {
return AssignmentPhrase(this, other);
}
FieldPhrase<bool> operator !()
{
FieldPhrase<bool> f(data->className, data->fieldName);
// f.data = new PhraseData(data);
f.data->isNot = !data->isNot;
return f;
}
operator ConditionalPhrase()
{
return ConditionalPhrase(this, PhraseData::Equal, !data->isNot);
}
};
NUT_END_NAMESPACE
#endif // FIELDPHRASE_H

View File

@ -0,0 +1,2 @@
#include "numericphrase.h"

View File

@ -0,0 +1,90 @@
#ifndef NUMERICPHRASE_H
#define NUMERICPHRASE_H
#include "fieldphrase.h"
#include <type_traits>
NUT_BEGIN_NAMESPACE
#define SPECIALIZATION_NUMERIC_MEMBER(type, op, cond) \
ConditionalPhrase operator op(const QVariant &other) \
{ \
return ConditionalPhrase(this, cond, other); \
}
template <typename T>
class FieldPhrase<T, typename std::enable_if<
std::is_floating_point<T>::value || std::is_integral<T>::value
>::type>
: public AbstractFieldPhrase
{
public:
FieldPhrase(const char *className, const char *s) :
AbstractFieldPhrase(className, s)
{}
AssignmentPhrase operator =(const QVariant &other) {
return AssignmentPhrase(this, other);
}
AssignmentPhrase operator =(ConditionalPhrase &&other) {
return AssignmentPhrase(new PhraseData(data, PhraseData::Equal, other.data));
}
ConditionalPhrase between(const QVariant &min, const QVariant &max)
{
return ConditionalPhrase(this, PhraseData::Between,
QVariantList() << min << max);
}
ConditionalPhrase operator ++()
{
return ConditionalPhrase(this, PhraseData::Add, 1);
}
ConditionalPhrase operator --()
{
return ConditionalPhrase(this, PhraseData::Minus, 1);
}
ConditionalPhrase operator ++(int)
{
return ConditionalPhrase(this, PhraseData::Add, 1);
}
ConditionalPhrase operator --(int)
{
return ConditionalPhrase(this, PhraseData::Minus, 1);
}
SPECIALIZATION_NUMERIC_MEMBER(type, <, PhraseData::Less)
SPECIALIZATION_NUMERIC_MEMBER(type, <=, PhraseData::LessEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, >, PhraseData::Greater)
SPECIALIZATION_NUMERIC_MEMBER(type, >=, PhraseData::GreaterEqual)
SPECIALIZATION_NUMERIC_MEMBER(type, %, PhraseData::Mod)
SPECIALIZATION_NUMERIC_MEMBER(type, +, PhraseData::Add)
SPECIALIZATION_NUMERIC_MEMBER(type, -, PhraseData::Minus)
SPECIALIZATION_NUMERIC_MEMBER(type, *, PhraseData::Multiple)
SPECIALIZATION_NUMERIC_MEMBER(type, /, PhraseData::Divide)
};
#define SPECIALIZATION_NUMERIC_TYPE(type) \
template<> \
class FieldPhrase<type> : public NumericPhrase \
{ \
public: \
FieldPhrase(const char *className, const char *s) : \
NumericPhrase(className, s) \
{} \
};
//SPECIALIZATION_NUMERIC_TYPE(qint8)
//SPECIALIZATION_NUMERIC_TYPE(qint16)
//SPECIALIZATION_NUMERIC_TYPE(qint32)
//SPECIALIZATION_NUMERIC_TYPE(qint64)
//SPECIALIZATION_NUMERIC_TYPE(quint8)
//SPECIALIZATION_NUMERIC_TYPE(quint16)
//SPECIALIZATION_NUMERIC_TYPE(quint32)
//SPECIALIZATION_NUMERIC_TYPE(quint64)
//SPECIALIZATION_NUMERIC_TYPE(qreal)
NUT_END_NAMESPACE
#endif // NUMERICPHRASE_H

View File

@ -0,0 +1,91 @@
/**************************************************************************
**
** 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 "phrasedata.h"
NUT_BEGIN_NAMESPACE
PhraseData::PhraseData() :
className(""), fieldName(""),
type(Field), operatorCond(NotAssign),
left(nullptr), right(nullptr), operand(QVariant::Invalid), isNot(false), parents(1)
{ }
PhraseData::PhraseData(const char *className, const char *fieldName) :
className(className), fieldName(fieldName),
type(Field), operatorCond(NotAssign),
left(nullptr), right(nullptr), operand(QVariant::Invalid), isNot(false), parents(1)
{ }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o)
: className(nullptr), fieldName(nullptr),
type(WithoutOperand), operatorCond(o), left(l), right(nullptr),
isNot(false), parents(1)
{
l->parents++;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o,
PhraseData *r)
: className(nullptr), fieldName(nullptr),
type(WithOther), operatorCond(o),
left(l), right(r),
isNot(false), parents(1)
{
l->parents++;
r->parents++;
}
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r)
: className(nullptr), fieldName(nullptr),
type(WithVariant), operatorCond(o), left(l),
right(nullptr), operand(r), isNot(false), parents(1)
{ }
PhraseData *PhraseData::operator =(PhraseData *other)
{
other->parents++;
return other;
}
PhraseData &PhraseData::operator =(PhraseData &other)
{
other.parents++;
return other;
}
QString PhraseData::toString() const
{
return QString("[%1].%2").arg(className, fieldName);
}
void PhraseData::cleanUp()
{
}
void PhraseData::cleanUp(PhraseData *d)
{
if (d->left)
cleanUp(d->left);
if (d->right)
cleanUp(d->right);
}
NUT_END_NAMESPACE

116
src/phrases/phrasedata.h Normal file
View File

@ -0,0 +1,116 @@
/**************************************************************************
**
** 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 PHRASEDATA_H
#define PHRASEDATA_H
#include "../defines.h"
NUT_BEGIN_NAMESPACE
class NUT_EXPORT PhraseData
{
public:
enum Condition {
NotAssign = 0,
Equal,
Less,
LessEqual,
Null,
In,
Like,
Not = 10,
NotEqual,
GreaterEqual,
Greater,
NotNull,
NotIn,
NotLike,
And = 20,
Or,
Add,
Minus,
Multiple,
Divide,
Mod,
Between,
//date and time
AddYears,
AddMonths,
AddDays,
AddHours,
AddMinutes,
AddSeconds,
DatePartYear,
DatePartMonth,
DatePartDay,
DatePartHour,
DatePartMinute,
DatePartSecond,
DatePartMilisecond
// // special types
// Distance
};
enum Type { Field, WithVariant, WithOther, WithoutOperand };
const char *className;
const char *fieldName;
Type type;
Condition operatorCond;
PhraseData *left;
PhraseData *right;
QVariant operand;
bool isNot;
quint16 parents;
PhraseData();
PhraseData(const char *className, const char *fieldName);
PhraseData(PhraseData *l, Condition o);
PhraseData(PhraseData *l, Condition o, PhraseData *r);
PhraseData(PhraseData *l, Condition o, QVariant r);
// explicit PhraseData(const PhraseData &other);
// explicit PhraseData(const PhraseData *other);
PhraseData *operator =(PhraseData *other);
PhraseData &operator =(PhraseData &other);
QString toString() const;
~PhraseData() = default;
void cleanUp();
private:
void cleanUp(PhraseData *d);
};
NUT_END_NAMESPACE
#endif // PHRASEDATA_H

View File

@ -0,0 +1,61 @@
/**************************************************************************
**
** 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 "phrasedatalist.h"
NUT_BEGIN_NAMESPACE
PhraseDataList::PhraseDataList() : QList<PhraseData*>()
{
}
PhraseDataList::PhraseDataList(const PhraseDataList &other) : QList<PhraseData*>()
{
// auto &o = const_cast<PhraseDataList&>(other);
PhraseDataList::const_iterator i;
for (i = other.constBegin(); i != other.constEnd(); ++i)
append(*i);
}
void PhraseDataList::append(PhraseData *d)
{
d->parents++;
QList<PhraseData*>::append(d);
}
void PhraseDataList::append(QList<PhraseData *> &dl)
{
foreach (PhraseData *d, dl)
d->parents++;
QList<PhraseData*>::append(dl);
}
PhraseDataList::~PhraseDataList()
{
QList<PhraseData*>::iterator i;
for (i = begin(); i != end(); ++i) {
(*i)->cleanUp();
if (!--(*i)->parents)
delete *i;
}
}
NUT_END_NAMESPACE

View File

@ -0,0 +1,40 @@
/**************************************************************************
**
** 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 PHRASEDATALIST_H
#define PHRASEDATALIST_H
#include "phrasedata.h"
NUT_BEGIN_NAMESPACE
class NUT_EXPORT PhraseDataList : public QList<PhraseData*>
{
public:
PhraseDataList();
PhraseDataList(const PhraseDataList &other);
void append(PhraseData *d);
void append(QList<PhraseData*> &dl);
virtual ~PhraseDataList();
};
NUT_END_NAMESPACE
#endif // PHRASEDATALIST_H

View File

@ -0,0 +1,94 @@
/**************************************************************************
**
** 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 "abstractfieldphrase.h"
#include "phraselist.h"
NUT_BEGIN_NAMESPACE
PhraseList::PhraseList() : isValid(false)
{
}
PhraseList::PhraseList(const PhraseList &other) : isValid(true)
{
data = qMove(other.data);
const_cast<PhraseList&>(other).data.clear();
}
PhraseList::PhraseList(PhraseList &&other)
{
data = other.data;
}
PhraseList::PhraseList(const AbstractFieldPhrase &other) : isValid(true)
{
data.append(other.data);
incAllDataParents();
}
PhraseList::PhraseList(const AbstractFieldPhrase *left,
const AbstractFieldPhrase &right)
: isValid(true)
{
data.append(left->data);
data.append(right.data);
incAllDataParents();
}
PhraseList::PhraseList(PhraseList *left, PhraseList *right) : isValid(true)
{
// data = qMove(left->data + right->data);
data.append(left->data);
data.append(right->data);
// left->data.clear();
// right->data.clear();
}
PhraseList::PhraseList(PhraseList *left, const AbstractFieldPhrase *right)
: isValid(true)
{
data.append(left->data);
data.append(right->data);
incAllDataParents();
}
PhraseList &PhraseList::operator =(const PhraseList &other)
{
data.append(const_cast<PhraseList&>(other).data);
return *this;
}
PhraseList PhraseList::operator |(const AbstractFieldPhrase &other) {
return PhraseList(this, &other);
}
void PhraseList::incAllDataParents()
{
// foreach (PhraseData *d, data)
// d->parents++;
}
PhraseList PhraseList::operator |(PhraseList &other) {
return PhraseList(this, &other);
}
NUT_END_NAMESPACE

55
src/phrases/phraselist.h Normal file
View File

@ -0,0 +1,55 @@
/**************************************************************************
**
** 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 PHRASELIST_H
#define PHRASELIST_H
#include "../defines.h"
#include "phrasedatalist.h"
NUT_BEGIN_NAMESPACE
class AbstractFieldPhrase;
class NUT_EXPORT PhraseList
{
public:
bool isValid;
PhraseDataList data;
explicit PhraseList();
PhraseList(const PhraseList &other);
PhraseList(PhraseList &&other);
PhraseList(const AbstractFieldPhrase &other);
PhraseList(const AbstractFieldPhrase *left, const AbstractFieldPhrase &right);
PhraseList(PhraseList *left, PhraseList *right);
PhraseList(PhraseList *left, const AbstractFieldPhrase *right);
virtual ~PhraseList() = default;
PhraseList &operator =(const PhraseList &other);
PhraseList operator |(PhraseList &other);
PhraseList operator |(const AbstractFieldPhrase &other);
private:
void incAllDataParents();
};
NUT_END_NAMESPACE
#endif // PHRASELIST_H

View File

@ -23,15 +23,11 @@
NUT_BEGIN_NAMESPACE
QueryPrivate::QueryPrivate(QueryBase *parent) : q_ptr(parent),
database(0), tableSet(0), skip(-1), take(-1)
database(nullptr), tableSet(nullptr), skip(-1), take(-1)
{
}
QueryPrivate::~QueryPrivate()
{
}
/*!
* \class Query
* \brief This class hold a query. A query can be used for getting database rows, editing or deleting without row fetching.

View File

@ -29,7 +29,13 @@
#include <QtSql/QSqlResult>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQueryModel>
#include <QtSql/QSqlQuery>
#ifdef NUT_SHARED_POINTER
#include <QtCore/QSharedPointer>
#endif
#include "table.h"
#include "query_p.h"
#include "database.h"
#include "databasemodel.h"
@ -38,6 +44,7 @@
#include "querybase_p.h"
#include "phrase.h"
#include "tablemodel.h"
#include "sqlmodel.h"
NUT_BEGIN_NAMESPACE
@ -50,6 +57,14 @@ template <class T>
bool m_autoDelete;
public:
//#ifdef NUT_SHARED_POINTER
// typedef QList<QSharedPointer<T>> RowList;
// typedef QSharedPointer<T> Row;
//#else
// typedef QList<T*> RowList;
// typedef T* Row;
//#endif
explicit Query(Database *database, TableSetBase *tableSet, bool autoDelete);
~Query();
@ -74,16 +89,20 @@ public:
Query<T> *setWhere(const ConditionalPhrase &ph);
//data selecting
T *first();
QList<T*> toList(int count = -1);
Row<T> first();
RowList<T> toList(int count = -1);
template <typename F>
QList<F> select(const FieldPhrase<F> f);
template<typename O>
QList<O> select(const std::function<O(const QSqlQuery &q)> allocator);
int count();
QVariant max(const FieldPhrase<int> &f);
QVariant min(const FieldPhrase<int> &f);
QVariant average(const FieldPhrase<int> &f);
QVariant insert(AssignmentPhraseList p);
QVariant insert(const AssignmentPhraseList &p);
//data mailpulation
int update(const AssignmentPhraseList &ph);
@ -91,17 +110,46 @@ public:
int remove();
QSqlQueryModel *toModel();
void toModel(QSqlQueryModel *model);
void toModel(SqlModel *model);
//debug purpose
QString sqlCommand() const;
};
template <typename T>
inline Query<T> *createQuery(TableSet<T> *tableSet)
template<typename T>
template<typename O>
Q_OUTOFLINE_TEMPLATE QList<O> Query<T>::select(const std::function<O (const QSqlQuery &)> allocator)
{
return tableSet->query();
Q_D(Query);
QList<O> ret;
d->joins.prepend(d->tableName);
d->sql = d->database->sqlGenertor()->selectCommand(
d->tableName,
SqlGeneratorBase::SignleField, "*",
d->wherePhrase,
d->relations,
d->skip, d->take);
QSqlQuery q = d->database->exec(d->sql);
while (q.next()) {
O obj = allocator(q);
ret.append(obj);
}
if (m_autoDelete)
deleteLater();
return ret;
}
//template <typename T>
//inline Query<T> *createQuery(TableSet<T> *tableSet)
//{
// return tableSet->query();
//}
template <class T>
Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet,
bool autoDelete)
@ -115,7 +163,7 @@ Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet,
d->className = T::staticMetaObject.className();
d->tableName =
d->database->model()
.tableByClassName(T::staticMetaObject.className())
.tableByClassName(d->className)
->name();
}
@ -127,17 +175,17 @@ Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
}
template <class T>
Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
{
Q_UNUSED(count);
Q_D(Query);
QList<T*> returnList;
RowList<T> returnList;
d->select = "*";
d->sql = d->database->sqlGenertor()->selectCommand(
d->tableName, d->fieldPhrase, d->wherePhrase, d->orderPhrase,
d->relations, d->skip, d->take);
qDebug()<<d->sql;
QSqlQuery q = d->database->exec(d->sql);
if (q.lastError().isValid()) {
qDebug() << q.lastError().text();
@ -217,7 +265,6 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
int p = levels.count();
int n = -1;
int lastP = p;
while (p) {
// Q_ASSERT(p != lastP);
@ -252,24 +299,29 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
Table *table;
if (data.table->className() == d->className) {
table = new T();
table->setParentTableSet(d->tableSet);
#ifdef NUT_SHARED_POINTER
auto shp = QSharedPointer<T>(qobject_cast<T*>(table));
returnList.append(shp);
#else
returnList.append(dynamic_cast<T*>(table));
#endif
table->setParentTableSet(d->tableSet);
} else {
const QMetaObject *childMetaObject
= QMetaType::metaObjectForType(data.table->typeId());
table = qobject_cast<Table *>(childMetaObject->newInstance());
if (!table)
qFatal("Could not create instance of %s",
qPrintable(data.table->name()));
qDebug() << data.table->name() << "created";
}
QStringList childFields = data.table->fieldsNames();
foreach (QString field, childFields)
table->setProperty(field.toLatin1().data(),
q.value(data.table->name() + "." + field));
QList<FieldModel*> childFields = data.table->fields();
foreach (FieldModel *field, childFields)
table->setProperty(field->name.toLatin1().data(),
d->database->sqlGenertor()->unescapeValue(
field->type,
q.value(data.table->name() + "." + field->name)));
for (int i = 0; i < data.masters.count(); ++i) {
int master = data.masters[i];
@ -287,13 +339,13 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
//set last created row
data.lastRow = table;
lastP = p;
} //while
} // while
#ifndef NUT_SHARED_POINTER
if (m_autoDelete)
deleteLater();
#endif
return returnList;
}
@ -325,11 +377,11 @@ Q_OUTOFLINE_TEMPLATE QList<F> Query<T>::select(const FieldPhrase<F> f)
}
template <class T>
Q_OUTOFLINE_TEMPLATE T *Query<T>::first()
Q_OUTOFLINE_TEMPLATE Row<T> Query<T>::first()
{
skip(0);
take(1);
QList<T*> list = toList(1);
RowList<T> list = toList(1);
if (list.count())
return list.first();
@ -412,7 +464,7 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(const FieldPhrase<int> &f)
}
template<class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(AssignmentPhraseList p)
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(const AssignmentPhraseList &p)
{
Q_D(Query);
d->sql = d->database->sqlGenertor()
@ -520,6 +572,7 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::update(const AssignmentPhraseList &ph)
d->tableName,
ph,
d->wherePhrase);
QSqlQuery q = d->database->exec(d->sql);
if (m_autoDelete)
@ -543,6 +596,14 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
template <class T>
Q_OUTOFLINE_TEMPLATE QSqlQueryModel *Query<T>::toModel()
{
QSqlQueryModel *model = new QSqlQueryModel;
toModel(model);
return model;
}
template <class T>
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(QSqlQueryModel *model)
{
Q_D(Query);
@ -551,9 +612,8 @@ Q_OUTOFLINE_TEMPLATE QSqlQueryModel *Query<T>::toModel()
d->fieldPhrase,
d->wherePhrase, d->orderPhrase, d->relations,
d->skip, d->take);
qDebug() << d->sql;
DatabaseModel dbModel = d->database->model();
QSqlQueryModel *model = new QSqlQueryModel;
model->setQuery(d->sql, d->database->database());
int fieldIndex = 0;
@ -563,8 +623,6 @@ qDebug() << d->sql;
QString displayName = dbModel.tableByClassName(pd->className)
->field(pd->fieldName)->displayName;
qDebug() << "Display name for"<<pd->className<<pd->fieldName
<<"="<<displayName;
model->setHeaderData(fieldIndex++,
Qt::Horizontal,
displayName);
@ -577,8 +635,43 @@ qDebug() << d->sql;
f->displayName);
}
}
}
return model;
template<class T>
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(SqlModel *model)
{
Q_D(Query);
d->sql = d->database->sqlGenertor()->selectCommand(
d->tableName,
d->fieldPhrase,
d->wherePhrase, d->orderPhrase, d->relations,
d->skip, d->take);
model->setTable(toList());
/*
DatabaseModel dbModel = d->database->model();
model->setQuery(d->sql, d->database->database());
int fieldIndex = 0;
if (d->fieldPhrase.data.count()) {
foreach (const PhraseData *pd, d->fieldPhrase.data) {
QString displayName = dbModel.tableByClassName(pd->className)
->field(pd->fieldName)->displayName;
model->setHeaderData(fieldIndex++,
Qt::Horizontal,
displayName);
}
} else {
TableModel *tbl = d->database->model().tableByName(d->tableName);
foreach (FieldModel *f, tbl->fields()) {
model->setHeaderData(fieldIndex++,
Qt::Horizontal,
f->displayName);
}
}*/
}
template <class T>
@ -588,6 +681,15 @@ Q_OUTOFLINE_TEMPLATE QString Query<T>::sqlCommand() const
return d->sql;
}
//TODO: complete this class later
//class RawQuery : public Query<void>
//{
//public:
// void setRawCommand(const QString &sql) {
// }
//};
NUT_END_NAMESPACE
#endif // QUERY_H

View File

@ -23,8 +23,9 @@
#include "phrase.h"
#include <QList>
#include <QString>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QSharedData>
NUT_BEGIN_NAMESPACE
@ -32,13 +33,13 @@ class Database;
class TableSetBase;
class QueryBase;
struct RelationModel;
class QueryPrivate{
class QueryPrivate : public QSharedData {
QueryBase *q_ptr;
Q_DECLARE_PUBLIC(QueryBase)
public:
explicit QueryPrivate(QueryBase *parent);
~QueryPrivate();
~QueryPrivate() = default;
QString sql;
QString className;

View File

@ -11,9 +11,9 @@ QueryBase::QueryBase(QObject *parent) : QObject(parent)
}
void QueryBase::addTableToSet(TableSetBase *set, Table *table)
{
set->add(table);
}
//void QueryBase::addTableToSet(TableSetBase *set, Table *table)
//{
// set->add(table);
//}
NUT_END_NAMESPACE

View File

@ -23,7 +23,10 @@
#include <QtCore/QObject>
#include <QtCore/qglobal.h>
#include <QtCore/QExplicitlySharedDataPointer>
#include "defines.h"
#include "query_p.h"
NUT_BEGIN_NAMESPACE
@ -33,11 +36,15 @@ class TableSetBase;
class QueryBase : public QObject
{
Q_OBJECT
protected:
QExplicitlySharedDataPointer<QueryPrivate> d;
public:
explicit QueryBase(QObject *parent = 0);
protected:
void addTableToSet(TableSetBase *set, Table *table);
// void addTableToSet(TableSetBase *set, Table *table);
public slots:
};

View File

@ -1,6 +1,2 @@
#include "serializableobject.h"
SerializableObject::SerializableObject()
{
}

View File

@ -6,7 +6,7 @@
class SerializableObject
{
public:
SerializableObject();
SerializableObject() = default;
virtual void load(const QVariant &value) = 0;
virtual QVariant save() = 0;

View File

@ -21,20 +21,33 @@
#include "database.h"
#include "tablesetbase_p.h"
#include "databasemodel.h"
#include "tablemodel.h"
#include "table.h"
#include "sqlmodel_p.h"
#include "sqlmodel.h"
#include "query.h"
NUT_BEGIN_NAMESPACE
//SqlModel::SqlModel(Query *q) : QAbstractItemModel(q.)
//{
//}
void SqlModel::setRenderer(const std::function<QVariant (int, QVariant)> &renderer)
{
_renderer = renderer;
}
SqlModel::SqlModel(Database *database, TableSetBase *tableSet, QObject *parent) :
QAbstractTableModel(parent)
QAbstractTableModel(parent), d_ptr(new SqlModelPrivate(this)), _renderer(nullptr)
{
Q_D(SqlModel);
d->model = database->model()
.tableByClassName(tableSet->childClassName());
d->tableName = d->model->name();
// setQuery("SELECT * FROM " + d->tableName, database->databaseName());
}
@ -62,8 +75,12 @@ QVariant SqlModel::data(const QModelIndex &index, int role) const
return QVariant("-");
if (role == Qt::DisplayRole) {
Table *t = d->rows.at(index.row());
return t->property(d->model->field(index.column())->name.toLocal8Bit().data());
Row<Table> t = d->rows.at(index.row());
QVariant v = t->property(d->model->field(index.column())->name.toLocal8Bit().data());
// emit beforeShowText(index.column(), v);
if (_renderer != nullptr)
v = _renderer(index.column(), v);
return v;
// LogData *d = dataList.at(index.row());
// switch (index.column()) {
@ -85,9 +102,49 @@ QVariant SqlModel::data(const QModelIndex &index, int role) const
return QVariant();
}
SqlModelPrivate::SqlModelPrivate()
void SqlModel::setRows(RowList<Table> rows)
{
Q_D(SqlModel);
beginRemoveRows(QModelIndex(), 0, d->rows.count());
d->rows.clear();
endRemoveRows();
beginInsertRows(QModelIndex(), 0, rows.count());
d->rows = rows;
endInsertRows();
}
void SqlModel::append(Row<Table> table)
{
Q_D(SqlModel);
beginInsertRows(QModelIndex(), d->rows.count(), d->rows.count());
d->rows.append(table);
endInsertRows();
}
//void SqlModel::append(Table *table)
//{
// append(TableType<Table>::Row(table));
//}
QVariant SqlModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Q_D(const SqlModel);
return d->model->field(section)->displayName;
}
return QAbstractItemModel::headerData(section, orientation, role);
}
Row<Table> SqlModel::at(const int &i) const
{
Q_D(const SqlModel);
return d->rows.at(i);
}
SqlModelPrivate::SqlModelPrivate(SqlModel *parent) : q_ptr(parent)
{
}
NUT_END_NAMESPACE

View File

@ -23,6 +23,8 @@
#include <QtCore/QAbstractTableModel>
#include "defines.h"
#include <QList>
#include <functional>
NUT_BEGIN_NAMESPACE
@ -31,22 +33,52 @@ class TableSetBase;
class SqlModelPrivate;
class Table;
class TableModel;
class SqlModel : public QAbstractTableModel
class NUT_EXPORT SqlModel : public QAbstractTableModel
{
Q_OBJECT
std::function <QVariant(int, QVariant)> _renderer;
public:
// explicit SqlModel(Query *q);
explicit SqlModel(Database *database, TableSetBase *tableSet, QObject *parent = Q_NULLPTR);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
template<class T>
void setTable(RowList<T> rows);
void setRows(RowList<Table> rows);
void append(Row<Table> table);
// void append(Table *table);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Row<Nut::Table> at(const int &i) const;
void setRenderer(const std::function<QVariant (int, QVariant)> &renderer);
private:
SqlModelPrivate *d_ptr;
Q_DECLARE_PRIVATE(SqlModel)
signals:
void beforeShowText(int col, QVariant &value);
};
template<class T>
Q_OUTOFLINE_TEMPLATE void SqlModel::setTable(RowList<T> rows)
{
Q_D(SqlModel);
RowList<Table> tab;
foreach (auto t, rows)
tab.append(t);
setRows(tab);
}
NUT_END_NAMESPACE
#endif // SQLMODEL_H

View File

@ -1,6 +1,7 @@
#ifndef SQLMODEL_P_H
#define SQLMODEL_P_H
#include <QSharedPointer>
#include <QString>
#include "defines.h"
@ -13,11 +14,11 @@ class SqlModelPrivate {
SqlModel *q_ptr;
Q_DECLARE_PUBLIC(SqlModel)
public:
explicit SqlModelPrivate();
explicit SqlModelPrivate(SqlModel *parent);
QString tableName;
QList<Table*> rows;
RowList<Table> rows;
TableModel *model;
};

69
src/src.pri Normal file
View File

@ -0,0 +1,69 @@
DEFINES += NUT_SHARED_POINTER
HEADERS += \
$$PWD/generators/sqlgeneratorbase_p.h \
$$PWD/generators/postgresqlgenerator.h \
$$PWD/generators/mysqlgenerator.h \
$$PWD/generators/sqlitegenerator.h \
$$PWD/generators/sqlservergenerator.h \
$$PWD/tablesetbasedata.h \
$$PWD/types/dbgeography.h \
$$PWD/tableset.h \
$$PWD/defines_p.h \
$$PWD/defines.h \
$$PWD/query.h \
$$PWD/databasemodel.h \
$$PWD/changelogtable.h \
$$PWD/tablesetbase_p.h \
$$PWD/querybase_p.h \
$$PWD/tablemodel.h \
$$PWD/query_p.h \
$$PWD/table.h \
$$PWD/database.h \
$$PWD/database_p.h \
$$PWD/serializableobject.h \
$$PWD/sqlmodel.h \
$$PWD/sqlmodel_p.h \
$$PWD/phrase.h \
$$PWD/phrases/abstractfieldphrase.h \
$$PWD/phrases/assignmentphrase.h \
$$PWD/phrases/assignmentphraselist.h \
$$PWD/phrases/conditionalphrase.h \
$$PWD/phrases/fieldphrase.h \
$$PWD/phrases/phrasedata.h \
$$PWD/phrases/phrasedatalist.h \
$$PWD/phrases/phraselist.h \
$$PWD/phrases/datephrase.h \
$$PWD/table_p.h
SOURCES += \
$$PWD/generators/sqlgeneratorbase.cpp \
$$PWD/generators/postgresqlgenerator.cpp \
$$PWD/generators/mysqlgenerator.cpp \
$$PWD/generators/sqlitegenerator.cpp \
$$PWD/generators/sqlservergenerator.cpp \
$$PWD/types/dbgeography.cpp \
$$PWD/tableset.cpp \
$$PWD/query.cpp \
$$PWD/databasemodel.cpp \
$$PWD/tablesetbase.cpp \
$$PWD/changelogtable.cpp \
$$PWD/querybase.cpp \
$$PWD/tablemodel.cpp \
$$PWD/table.cpp \
$$PWD/database.cpp \
$$PWD/serializableobject.cpp \
$$PWD/sqlmodel.cpp \
$$PWD/phrase.cpp \
$$PWD/phrases/abstractfieldphrase.cpp \
$$PWD/phrases/assignmentphrase.cpp \
$$PWD/phrases/assignmentphraselist.cpp \
$$PWD/phrases/conditionalphrase.cpp \
$$PWD/phrases/fieldphrase.cpp \
$$PWD/phrases/phrasedata.cpp \
$$PWD/phrases/phrasedatalist.cpp \
$$PWD/phrases/phraselist.cpp \
$$PWD/phrases/datephrase.cpp
include($$PWD/../3rdparty/serializer/src/src.pri)

11
src/src.pro Normal file
View File

@ -0,0 +1,11 @@
QT += sql gui
TARGET = nut
TEMPLATE = lib
CONFIG += c++11
CONFIG += staticlib
DEFINES += QT_DEPRECATED_WARNINGS NUT_COMPILE_STATIC
include($$PWD/src.pri)
include($$PWD/../ci-test-init.pri)

View File

@ -20,10 +20,14 @@
#include <QMetaMethod>
#include <QVariant>
#include <QSqlQuery>
#include "table.h"
#include "table_p.h"
#include "database.h"
#include "databasemodel.h"
#include "generators/sqlgeneratorbase_p.h"
#include "tablesetbase_p.h"
NUT_BEGIN_NAMESPACE
@ -39,73 +43,100 @@ NUT_BEGIN_NAMESPACE
* This should be fixed to v1.2
*/
Table::Table(QObject *parent) : QObject(parent), myModel(0), _parentTableSet(0)
Table::Table(QObject *parent) : QObject(parent),
d_ptr(new TablePrivate(this))
{ }
Table::~Table()
{
setStatus(NewCreated);
Q_D(Table);
if (d->parentTableSet)
d->parentTableSet->remove(this);
}
void Table::add(TableSetBase *t)
{
this->childTableSets.insert(t);
Q_D(Table);
d->childTableSets.insert(t);
}
//QString Table::primaryKey() const
//{
// Q_D(const Table);
// return d->model->primaryKey();
//}
QString Table::primaryKey() const
//bool Table::isPrimaryKeyAutoIncrement() const
//{
// Q_D(const Table);
// FieldModel *pk = d->model->field(d->model->primaryKey());
// if (!pk)
// return false;
// return pk->isAutoIncrement;
//}
//QVariant Table::primaryValue() const
//{
// return property(primaryKey().toLatin1().data());
//}
void Table::propertyChanged(const QString &propName)
{
return myModel->primaryKey();
Q_D(Table);
// if (!d->model)
// d->model = TableModel::findByClassName(metaObject()->className());
// if (!d->model)
// qFatal ("model for class '%s' not found", qPrintable(metaObject()->className()));
// foreach (FieldModel *f, d->model->fields())
// if(f->isPrimaryKey && propName == f->name && f->isAutoIncrement)
// return;
d->changedProperties.insert(propName);
if (d->status == FeatchedFromDB)
d->status = Modified;
if (d->status == NewCreated)
d->status = Added;
}
bool Table::isPrimaryKeyAutoIncrement() const
void Table::setModel(TableModel *model)
{
return myModel->field(myModel->primaryKey())->isAutoIncrement;
}
QVariant Table::primaryValue() const
{
return property(primaryKey().toLatin1().data());
}
void Table::propertyChanged(QString propName)
{
if (!myModel)
myModel = TableModel::findByClassName(metaObject()->className());
if (!myModel)
qFatal ("model for this class not found");
foreach (FieldModel *f, myModel->fields())
if(f->isPrimaryKey && propName == f->name && f->isAutoIncrement)
return;
_changedProperties.insert(propName);
if (_status == FeatchedFromDB)
_status = Modified;
if (_status == NewCreated)
_status = Added;
Q_D(Table);
d->model = model;
}
void Table::clear()
{
_changedProperties.clear();
Q_D(Table);
d->changedProperties.clear();
}
QSet<QString> Table::changedProperties() const
{
return _changedProperties;
Q_D(const Table);
return d->changedProperties;
}
bool Table::setParentTable(Table *master)
bool Table::setParentTable(Table *master, TableModel *masterModel, TableModel *model)
{
QString masterClassName = master->metaObject()->className();
Q_D(Table);
foreach (RelationModel *r, myModel->foregionKeys())
QString masterClassName = master->metaObject()->className();
d->refreshModel();
// if (!d->model)
// d->model = TableModel::findByClassName(metaObject()->className());
foreach (RelationModel *r, model->foregionKeys())
if(r->masterClassName == masterClassName)
{
setProperty(QString(r->localColumn).toLatin1().data(),
master->primaryValue());
_changedProperties.insert(r->localColumn);
master->property(masterModel->primaryKey().toUtf8().data()));
d->changedProperties.insert(r->localColumn);
return true;
}
@ -114,18 +145,23 @@ bool Table::setParentTable(Table *master)
TableSetBase *Table::parentTableSet() const
{
return _parentTableSet;
Q_D(const Table);
return d->parentTableSet;
}
void Table::setParentTableSet(TableSetBase *parent)
{
_parentTableSet = parent;
_parentTableSet->add(this);
Q_D(Table);
d->parentTableSet = parent;
if (parent)
d->parentTableSet->add(this);
}
TableSetBase *Table::childTableSet(const QString &name) const
{
foreach (TableSetBase *t, childTableSets)
Q_D(const Table);
foreach (TableSetBase *t, d->childTableSets)
if (t->childClassName() == name)
return t;
return Q_NULLPTR;
@ -133,12 +169,15 @@ TableSetBase *Table::childTableSet(const QString &name) const
int Table::save(Database *db)
{
Q_D(Table);
QSqlQuery q = db->exec(db->sqlGenertor()->saveRecord(this, db->tableName(metaObject()->className())));
if(status() == Added && isPrimaryKeyAutoIncrement())
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
auto model = db->model().tableByClassName(metaObject()->className());
if(status() == Added && model->isPrimaryKeyAutoIncrement())
setProperty(model->primaryKey().toLatin1().data(), q.lastInsertId());
foreach(TableSetBase *ts, childTableSets)
foreach(TableSetBase *ts, d->childTableSets)
ts->save(db);
setStatus(FeatchedFromDB);
@ -147,12 +186,29 @@ int Table::save(Database *db)
Table::Status Table::status() const
{
return _status;
Q_D(const Table);
return static_cast<Status>(d->status);
}
void Table::setStatus(const Status &status)
{
_status = status;
Q_D(Table);
d->status = status;
}
TablePrivate::TablePrivate(Table *parent) : q_ptr(parent),
model(nullptr), status(Table::NewCreated), parentTableSet(nullptr)
{
}
void TablePrivate::refreshModel()
{
Q_Q(Table);
// if (!model)
// model = TableModel::findByClassName(q->metaObject()->className());
}
NUT_END_NAMESPACE

View File

@ -34,12 +34,16 @@ NUT_BEGIN_NAMESPACE
class Database;
class TableSetBase;
class TableModel;
class TablePrivate;
class NUT_EXPORT Table : public QObject
{
Q_OBJECT
TablePrivate *d_ptr;
Q_DECLARE_PRIVATE(Table)
public:
explicit Table(QObject *parentTableSet = nullptr);
virtual ~Table();
enum Status{
NewCreated,
@ -51,9 +55,15 @@ public:
int save(Database *db);
QString primaryKey() const;
bool isPrimaryKeyAutoIncrement() const;
QVariant primaryValue() const;
// Q_DECL_DEPRECATED
// QString primaryKey() const;
// Q_DECL_DEPRECATED
// bool isPrimaryKeyAutoIncrement() const;
// Q_DECL_DEPRECATED
// QVariant primaryValue() const;
Status status() const;
void setStatus(const Status &status);
@ -64,28 +74,31 @@ public:
QSet<QString> changedProperties() const;
bool setParentTable(Table *master);
bool setParentTable(Table *master, TableModel *masterModel, TableModel *model);
signals:
public slots:
protected:
void propertyChanged(QString propName);
void propertyChanged(const QString &propName);
private:
TableModel *myModel;
Status _status;
QSet<QString> _changedProperties;
void setModel(TableModel *model);
// TableModel *myModel;
// Status _status;
// QSet<QString> _changedProperties;
//TODO: is this removable?
TableSetBase *_parentTableSet;
// TableSetBase *_parentTableSet;
QSet<TableSetBase*> childTableSets;
// QSet<TableSetBase*> childTableSets;
void clear();
void add(TableSetBase *);
template<class T>
friend class Query;
template<class T>
friend class TableSet;
friend class TableSetBase;
};

32
src/table_p.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef TABLEPRIVATE_H
#define TABLEPRIVATE_H
#include "defines.h"
#include <QtCore/QSet>
NUT_BEGIN_NAMESPACE
class TableModel;
class Table;
class TableSetBase;
class TablePrivate {
Table *q_ptr;
Q_DECLARE_PUBLIC(Table)
public:
TablePrivate(Table *parent);
TableModel *model;
int status;
QSet<QString> changedProperties;
TableSetBase *parentTableSet;
QSet<TableSetBase*> childTableSets;
void refreshModel();
};
NUT_END_NAMESPACE
#endif // TABLEPRIVATE_H

View File

@ -1,4 +1,4 @@
/**************************************************************************
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
@ -69,18 +69,18 @@ void TableModel::setTypeId(const int &typeId)
FieldModel *TableModel::field(int n) const
{
if (n < 0 || n >= _fields.count())
return 0;
return nullptr;
return _fields.at(n);
}
FieldModel *TableModel::field(QString name) const
FieldModel *TableModel::field(const QString &name) const
{
foreach (FieldModel *f, _fields)
if(f->name == name)
return f;
return 0;
return nullptr;
}
QList<FieldModel *> TableModel::fields() const
@ -101,37 +101,6 @@ QStringList TableModel::fieldsNames() const
return ret;
}
QSet<TableModel *> TableModel::allModels()
{
return _allModels;
}
/*
* This is not used anywhere
*/
TableModel *TableModel::findByTypeId(int typeId)
{
foreach (TableModel *model, _allModels)
if(model->typeId() == typeId)
return model;
return 0;
}
/**
* @brief TableModel::findByClassName
* Find a table model by class name
* @param className
* @return
*/
TableModel *TableModel::findByClassName(QString className)
{
foreach (TableModel *model, _allModels)
if(model->className() == className)
return model;
return 0;
}
bool TableModel::operator ==(const TableModel &t) const{
if(_name != t.name())
return false;
@ -156,24 +125,7 @@ bool TableModel::operator !=(const TableModel &t) const
return !(*this == t);
}
//bool TableModel::checkClassInfo(const QMetaClassInfo &classInfo,
// QString &type, QString &name, QString &value)
//{
// if (!QString(classInfo.name()).startsWith(__nut_NAME_PERFIX)) {
// return false;
// } else {
// QStringList parts = QString(classInfo.value()).split("\n");
// if (parts.count() != 3)
// return false;
// type = parts[0];
// name = parts[1];
// value = parts[2];
// return true;
// }
//}
TableModel::TableModel(int typeId, QString tableName)
TableModel::TableModel(int typeId, const QString &tableName)
{
//TODO: check that
// if (findByTypeId(typeId))
@ -202,7 +154,7 @@ TableModel::TableModel(int typeId, QString tableName)
}
if(type == __nut_FIELD){
FieldModel *f = new FieldModel;
auto *f = new FieldModel;
f->name = f->displayName = name;
_fields.append(f);
}
@ -217,7 +169,7 @@ TableModel::TableModel(int typeId, QString tableName)
f = fieldObj;
if(!fieldObj)
continue;
fieldObj->type = fieldProperty.type();
fieldObj->type = static_cast<QMetaType::Type>(fieldProperty.type());
fieldObj->typeName = QString(fieldProperty.typeName());
}
@ -233,7 +185,7 @@ TableModel::TableModel(int typeId, QString tableName)
}
if(type == __nut_FOREGION_KEY){
RelationModel *fk = new RelationModel;
auto *fk = new RelationModel;
fk->slaveTable = this;
fk->localColumn = name + "Id";
fk->localProperty = name;
@ -270,9 +222,6 @@ TableModel::TableModel(int typeId, QString tableName)
f->isAutoIncrement = true;
}
}
if(!findByTypeId(typeId) && !tableName.isNull())
_allModels.insert(this);
}
/*
@ -291,7 +240,7 @@ TableModel::TableModel(int typeId, QString tableName)
"primary_key": "id"
},
*/
TableModel::TableModel(QJsonObject json, QString tableName)
TableModel::TableModel(const QJsonObject &json, const QString &tableName) : _typeId(0)
{
_name = tableName;
@ -299,9 +248,11 @@ TableModel::TableModel(QJsonObject json, QString tableName)
QJsonObject relations = json.value(__FOREIGN_KEYS).toObject();
foreach (QString key, fields.keys()) {
QJsonObject fieldObject = fields.value(key).toObject();
FieldModel *f = new FieldModel;
//TODO: use FieldModel(QJsonObject) ctor
auto *f = new FieldModel;
f->name = fieldObject.value(__NAME).toString();
f->type = QVariant::nameToType(fieldObject.value(__TYPE).toString().toLatin1().data());
f->type = static_cast<QMetaType::Type>(QMetaType::type(fieldObject.value(__TYPE).toString().toLatin1().data()));
f->typeName = QMetaType::typeName(f->type);
if(fieldObject.contains(__nut_NOT_NULL))
f->notNull = fieldObject.value(__nut_NOT_NULL).toBool();
@ -377,7 +328,7 @@ RelationModel *TableModel::foregionKey(const QString &otherTable) const
if(fk->masterClassName == otherTable)
return fk;
return 0;
return nullptr;
}
RelationModel *TableModel::foregionKeyByField(const QString &fieldName) const
@ -386,7 +337,7 @@ RelationModel *TableModel::foregionKeyByField(const QString &fieldName) const
if(fk->localColumn == fieldName)
return fk;
return 0;
return nullptr;
}
QString TableModel::toString() const
@ -396,8 +347,7 @@ QString TableModel::toString() const
sl.append(f->name + " " + QVariant::typeToName(f->type));
QString ret = QString("%1 (%2)")
.arg(_name)
.arg(sl.join(", "));
.arg(_name, sl.join(", "));
return ret;
}
@ -409,10 +359,18 @@ QString TableModel::primaryKey() const
return QString();
}
bool TableModel::isPrimaryKeyAutoIncrement() const
{
FieldModel *pk = field(primaryKey());
if (!pk)
return false;
return pk->isAutoIncrement;
}
FieldModel::FieldModel(const QJsonObject &json)
{
name = json.value(__NAME).toString();
type = static_cast<QVariant::Type>(json.value(__TYPE).toInt());
type = static_cast<QMetaType::Type>(json.value(__TYPE).toInt());
length = json.value(__nut_LEN).toInt();
notNull = json.value(__nut_NOT_NULL).toBool();
isAutoIncrement = json.value(__nut_AUTO_INCREMENT).toBool();
@ -440,7 +398,7 @@ RelationModel::RelationModel(const QJsonObject &obj)
localProperty = obj.value("localProperty").toString();
masterClassName = obj.value("masterClassName").toString();
foreignColumn = obj.value("foreignColumn").toString();
slaveTable = masterTable = 0;
slaveTable = masterTable = nullptr;
}
QJsonObject RelationModel::toJson() const

View File

@ -40,8 +40,7 @@ struct FieldModel{
explicit FieldModel(const QJsonObject &json);
QString name;
//TODO: QMetaType::Type??
QVariant::Type type;
QMetaType::Type type;
QString typeName;
int length;
QString defaultValue;
@ -70,8 +69,9 @@ struct FieldModel{
};
struct RelationModel{
RelationModel() : localColumn(QString()), localProperty(QString()), slaveTable(0),
foreignColumn(QString()), masterTable(0), masterClassName(QString())
RelationModel() : localColumn(QString()), localProperty(QString()),
slaveTable(nullptr), foreignColumn(QString()), masterTable(nullptr),
masterClassName(QString())
{}
explicit RelationModel(const QJsonObject &obj);
@ -87,29 +87,28 @@ struct RelationModel{
QJsonObject toJson() const;
};
bool operator ==(const RelationModel &l, const RelationModel &r);
bool operator !=(const RelationModel &l, const RelationModel &r);
class TableModel
class NUT_EXPORT TableModel
{
public:
explicit TableModel(int typeId, QString tableName = QString());
explicit TableModel(QJsonObject json, QString tableName);
explicit TableModel(int typeId, const QString &tableName = QString());
explicit TableModel(const QJsonObject &json, const QString &tableName);
virtual ~TableModel();
QJsonObject toJson() const;
// static TableScheema *registerTable(int typeId, QString tableName);
// static void createForegionKeys();
// static TableModel* model(QString className);
FieldModel *field(int n) const;
FieldModel *field(QString name) const;
FieldModel *field(const QString &name) const;
RelationModel *foregionKey(const QString &otherTable) const;
RelationModel *foregionKeyByField(const QString &fieldName) const;
QString toString() const;
QString primaryKey() const;
bool isPrimaryKeyAutoIncrement() const;
QString name() const;
void setName(const QString &name);
@ -123,11 +122,6 @@ public:
QList<RelationModel *> foregionKeys() const;
QStringList fieldsNames() const;
static QSet<TableModel *> allModels();
static TableModel *findByTypeId(int typeId);
// static TableModel *findByName(QString name);
static TableModel *findByClassName(QString className);
bool operator ==(const TableModel &t) const;
bool operator !=(const TableModel &t) const;
@ -137,9 +131,9 @@ private:
int _typeId;
QList<FieldModel*> _fields;
QList<RelationModel*> _foreignKeys;
Q_DECL_DEPRECATED
static QSet<TableModel*>_allModels;
// bool checkClassInfo(const QMetaClassInfo &classInfo,
// QString &type, QString &name, QString &value);
};
NUT_END_NAMESPACE

View File

@ -29,102 +29,117 @@
#include "tablesetbase_p.h"
#include "table.h"
#include "bulkinserter.h"
#include "databasemodel.h"
#include "tablesetbasedata.h"
NUT_BEGIN_NAMESPACE
template<class T>
class Query;
class BulkInserter;
class Database;
template<class T>
class NUT_EXPORT TableSet : public TableSetBase
{
public:
typedef T value_type;
typedef T *pointer;
typedef T &reference;
explicit TableSet(Database *parent);
explicit TableSet(Table *parent);
void append(T *t);
void append(QList<T *> t);
void append(Row<T> t);
void append(RowList<T> t);
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;
Query<T> *query();
Query<T> *query(bool autoDelete);
Query<T> *query(bool autoDelete = true);
BulkInserter *bulkInserter();
};
template<class T>
Q_OUTOFLINE_TEMPLATE TableSet<T>::TableSet(Database *parent) : TableSetBase(parent)
{
_childClassName = T::staticMetaObject.className();
data->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>::query()
{
Query<T> *q = new Query<T>(_database, this, true);
return q;
data->childClassName = T::staticMetaObject.className();
}
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *TableSet<T>::query(bool autoDelete)
{
Query<T> *q = new Query<T>(_database, this, autoDelete);
Query<T> *q = new Query<T>(data->database, this, autoDelete);
return q;
}
template<class T>
Q_OUTOFLINE_TEMPLATE BulkInserter *TableSet<T>::bulkInserter()
{
BulkInserter *bi = new BulkInserter(data->database, data->childClassName);
return bi;
}
template<class T>
Q_OUTOFLINE_TEMPLATE int TableSet<T>::length() const
{
return _tables.count();
return data->tables.count();
}
template<class T>
Q_OUTOFLINE_TEMPLATE T *TableSet<T >::at(int i) const
{
return (T*)_tablesList.at(i);
//TODO: check
return reinterpret_cast<T*>(data->childRows.at(i));
}
template<class T>
Q_OUTOFLINE_TEMPLATE const T &TableSet<T>::operator[](int i) const
{
return _tablesList[i];
return data->childRows[i];
}
template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(T *t)
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(Row<T> t)
{
_tables.insert(t);
_tablesList.append(t);
// rows.append(t);
data.detach();
data->childs.append(t);
data->tables.insert(t.data());
data->childRows.append(t.data());
// if (_database)
// t->setModel(_database->model().tableByClassName(t->metaObject()->className()));
t->setParentTableSet(this);
if(t->status() != Table::FeatchedFromDB)
t->setStatus(Table::Added);
}
template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(QList<T *> t)
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(RowList<T> t)
{
foreach (T* i, t)
foreach (Row<T> i, t)
append(i);
}
template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(T *t)
{
_tables.remove(t);
data.detach();
data->childs.removeOne(t);
data->tables.remove(t);
t->setStatus(Table::Deleted);
}

View File

@ -22,27 +22,40 @@
#include "database.h"
#include "tablesetbase_p.h"
#include "databasemodel.h"
#include "tablesetbasedata.h"
NUT_BEGIN_NAMESPACE
TableSetBase::TableSetBase(Database *parent) : QObject(parent), _database(parent), _table(0),
_tableName(QString())
TableSetBase::TableSetBase(Database *parent) : QObject(parent),
data(new TableSetBaseData(parent))
{
parent->add(this);
}
TableSetBase::TableSetBase(Table *parent) : QObject(parent), _database(0), _table(parent),
_tableName(QString())
TableSetBase::TableSetBase(Table *parent) : QObject(parent),
data(new TableSetBaseData(parent))
{
parent->add(this);
}
TableSetBase::~TableSetBase()
{
foreach (Table *t, data->tables)
t->setParentTableSet(nullptr);
}
int TableSetBase::save(Database *db, bool cleanUp)
{
int rowsAffected = 0;
foreach (Table *t, _tablesList) {
if(_table)
t->setParentTable(_table);
TableModel *masterModel = nullptr;
if (data->table)
masterModel = db->model().tableByClassName(data->table->metaObject()->className());
foreach (Table *t, data->childRows) {
if(data->table)
t->setParentTable(data->table,
masterModel,
db->model().tableByClassName(t->metaObject()->className()));
if(t->status() == Table::Added
|| t->status() == Table::Modified
@ -55,39 +68,50 @@ int TableSetBase::save(Database *db, bool cleanUp)
}
if (cleanUp)
_tablesList.clear();
data->childRows.clear();
return rowsAffected;
}
void TableSetBase::clearChilds()
{
foreach (Table *t, _tablesList)
#ifndef NUT_SHARED_POINTER
foreach (Table *t, data->_childRows)
t->deleteLater();
_tablesList.clear();
#endif
data->childRows.clear();
}
void TableSetBase::add(Table *t)
{
if(!_tables.contains(t)){
_tables.insert(t);
_tablesList.append(t);
if(!data->tables.contains(get(t))){
data.detach();
data->tables.insert(get(t));
data->childRows.append(get(t));
}
}
void TableSetBase::remove(Table *t)
{
data.detach();
data->tables.remove(get(t));
data->childRows.removeOne(get(t));
}
QString TableSetBase::childClassName() const
{
return _childClassName;
return data->childClassName;
}
Database *TableSetBase::database() const
{
return _database;
return data->database;
}
void TableSetBase::setDatabase(Database *database)
{
_database = database;
data.detach();
data->database = database;
}
NUT_END_NAMESPACE

View File

@ -24,6 +24,7 @@
#include <QtCore/QObject>
#include <QtCore/qglobal.h>
#include <QtCore/QSet>
#include <QExplicitlySharedDataPointer>
#include "defines.h"
@ -31,12 +32,14 @@ NUT_BEGIN_NAMESPACE
class Table;
class Database;
class TableSetBaseData;
class TableSetBase : public QObject
{
public:
explicit TableSetBase(Database *parent);
explicit TableSetBase(Table *parent);
virtual ~TableSetBase();
virtual int save(Database *db, bool cleanUp = false);
void clearChilds();
@ -46,15 +49,17 @@ public:
void setDatabase(Database *database);
protected:
QSet<Table*> _tables;
QList<Table*> _tablesList;
QString _tableName;
Database *_database;
Table *_table;
QString _childClassName;
// QSet<Table*> _tables;
// RowList<Table> _childRows;
// Database *_database;
// Table *_table;
//// QString _tableName;
// QString _childClassName;
QExplicitlySharedDataPointer<TableSetBaseData> data;
private:
void add(Table* t);
void remove(Table *t);
friend class Table;
friend class QueryBase;

53
src/tablesetbasedata.h Normal file
View File

@ -0,0 +1,53 @@
/**************************************************************************
**
** 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 TABLESETBASEDATA_H
#define TABLESETBASEDATA_H
#include <QSharedData>
#include "defines.h"
NUT_BEGIN_NAMESPACE
class Table;
class Database;
class TableSetBaseData : public QSharedData
{
public:
TableSetBaseData(Database *parent) :
database(parent), table(nullptr)
{ }
TableSetBaseData(Table *parent) :
database(nullptr), table(parent)
{ }
QSet<Table*> tables;
QList<Table*> childRows;
RowList<Table> childs;
Database *database;
Table *table;
QString childClassName;
};
NUT_END_NAMESPACE
#endif // TABLESETBASEDATA_H

2
src/tuple.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "tuple.h"

18
src/tuple.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef TUPLE_H
#define TUPLE_H
#include <QObject>
//class AbstractTuple
//{
// Q_GADGET
//};
//template <typename T>
//class Tuple
//{
//public:
// T _1;
//};
#endif // TUPLE_H

View File

@ -1,21 +0,0 @@
QT += qml quick testlib sql
QT -= gui
TARGET = tst_nut
CONFIG += warn_on qmltestcase c++11
INCLUDEPATH += $$PWD/../../src $$PWD/../common
include(../../nut.pri)
TEMPLATE = app
IMPORTPATH += $$OUT_PWD/../src/imports
SOURCES += \
maintest.cpp \
../common/comment.cpp \
../common/post.cpp \
../common/weblogdatabase.cpp
HEADERS += \
maintest.h \
../common/comment.h \
../common/post.h \
../common/weblogdatabase.h

View File

@ -3,7 +3,6 @@
#include <QtCore/qglobal.h>
#include <QtCore/QDateTime>
#include <QtCore/QUuid>
#include "table.h"
#ifdef NUT_NAMESPACE
@ -16,14 +15,14 @@ class Comment : public Table
{
Q_OBJECT
NUT_PRIMARY_KEY(id)
NUT_DECLARE_FIELD(QUuid, id, id, setId)
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_DECLARE_FIELD(qreal, point, point, setPoint)
NUT_FOREGION_KEY(Post, int, post, post, setPost)
NUT_FOREGION_KEY(User, QUuid, author, author, setAuthor)
NUT_FOREGION_KEY(User, int, author, author, setAuthor)
public:
Q_INVOKABLE explicit Comment(QObject *parentTableSet = nullptr);

View File

@ -1,29 +1,21 @@
#ifndef CONSTS_H
#define CONSTS_H
#define PRINT(x) qDebug() << #x "=" << x;
#include <qsystemdetection.h>
#define REGISTER(x) qDebug() << (#x) << "type id:" << qMetaTypeId<x*>()
#define PRINT(x)
//qDebug() << (#x "=") << (x);
#define TIC() QElapsedTimer timer; timer.start()
#define TOC() qDebug() << QString("Elapsed time: %1ms for %2") \
.arg(timer.elapsed() / 1000.) \
.arg(__func__)
//#define DRIVER "QPSQL"
//#define HOST "127.0.0.1"
//#define DATABASE "nutdb2"
//#define USERNAME "postgres"
//#define PASSWORD "856856"
#define DRIVER "QSQLITE"
#define DATABASE QString("nut_test_%1_db").arg(metaObject()->className()).toLower()
#define HOST "127.0.0.1"
#define DATABASE "nutdb1"
#define USERNAME "root"
#define PASSWORD "onlyonlyi"
//#define DRIVER "QODBC"
//#define HOST "127.0.0.1"
//#define DATABASE "DRIVER={SQL Server};Server=.;Database=Nut2;Uid=sa;Port=1433;Pwd=qwe123!@#;WSID=."
//#define USERNAME "sa"
//#define PASSWORD "qwe123!@#"
#define USERNAME "postgres"
#define PASSWORD "856856"
#ifdef Q_OS_LINUX
# define OS "Linux"
@ -46,4 +38,5 @@
<< "\n\tTest:" << metaObject()->className() \
<< "\n****************************\n";
#endif // CONSTS_H

12
test/common/nut-lib.pri Normal file
View File

@ -0,0 +1,12 @@
win32 {
CONFIG(debug,debug|release): LIBDIR = $$absolute_path($$OUT_PWD/../../src/debug)
CONFIG(release,debug|release): LIBDIR = $$absolute_path($$OUT_PWD/../../src/release)
} else {
LIBDIR = $$absolute_path($$OUT_PWD/../../src)
}
LIBS += -L$$LIBDIR -lnut
INCLUDEPATH += $$PWD/../../src $$PWD/../common
#include(../../src/src.pri)
DEFINES += NUT_SHARED_POINTER

View File

@ -33,7 +33,7 @@ class Post : public Table
NUT_DECLARE_CHILD_TABLE(Score, scores)
public:
Q_INVOKABLE Post(QObject *parentTableSet = 0);
Q_INVOKABLE Post(QObject *parentTableSet = nullptr);
signals:

View File

@ -17,8 +17,8 @@ class User : public Nut::Table
{
Q_OBJECT
NUT_PRIMARY_KEY(id)
NUT_DECLARE_FIELD(QUuid, id, id, setId)
NUT_PRIMARY_AUTO_INCREMENT(id)
NUT_DECLARE_FIELD(int, id, id, setId)
NUT_NOT_NULL(username)
NUT_LEN(username, 50)

View File

@ -1,27 +0,0 @@
#include <QtTest>
#include <QDate>
#include "maintest.h"
#include "phrase.h"
using namespace Nut;
MainTest::MainTest(QObject *parent) : QObject(parent)
{
}
void MainTest::initTestCase()
{
}
void MainTest::no1()
{
FieldPhrase<int> id("main", "id");
FieldPhrase<QString> name("main", "name");
FieldPhrase<QString> last_name("main", "last_name");
FieldPhrase<QDate> date("main", "date");
auto w = (id == 4 && name == "hi");
}
QTEST_MAIN(MainTest)

View File

@ -1,23 +0,0 @@
#ifndef MAINTEST_H
#define MAINTEST_H
#include <QtCore/QObject>
#include <QtCore/qglobal.h>
class Post;
class User;
class MainTest : public QObject
{
Q_OBJECT
public:
explicit MainTest(QObject *parent = nullptr);
signals:
private slots:
void initTestCase();
void no1();
};
#endif // MAINTEST_H

View File

@ -1,15 +0,0 @@
QT += qml quick testlib sql
QT -= gui
TARGET = tst_phrases
TEMPLATE = app
CONFIG += warn_on qmltestcase c++11
INCLUDEPATH += $$PWD/../../src $$PWD/../common
include(../../nut.pri)
IMPORTPATH += $$OUT_PWD/../src/imports
SOURCES += \
maintest.cpp
HEADERS += \
maintest.h

View File

@ -1,63 +0,0 @@
#include <QtTest>
#include <QJsonDocument>
#include <QSqlError>
#include <QDebug>
#include <QElapsedTimer>
#include "consts.h"
#include "maintest.h"
#include "query.h"
#include "tableset.h"
#include "tablemodel.h"
#include "test.h"
MainTest::MainTest(QObject *parent) : QObject(parent)
{
}
void MainTest::initTestCase()
{
qDebug() << "Test type id:" << qRegisterMetaType<Test*>();
qDebug() << "DB type id:" << qRegisterMetaType<TestDatabase*>();
db.setDriver(DRIVER);
db.setHostName(HOST);
db.setDatabaseName("nut_tst_quuid");
db.setUserName(USERNAME);
db.setPassword(PASSWORD);
bool ok = db.open();
db.tests()->query()->remove();
QTEST_ASSERT(ok);
}
void MainTest::add()
{
TIC();
QUuid uuid = QUuid::createUuid();
Test t;
t.setId(uuid);
t.setUsername("test username");
db.tests()->append(&t);
db.saveChanges();
TOC();
Test *t2 = db.tests()->query()
->where(Test::idField() == uuid)
->first();
TOC();
QTEST_ASSERT(t2->id() == uuid);
}
void MainTest::cleanupTestCase()
{
qDeleteAll(Nut::TableModel::allModels());
// Nut::DatabaseModel::deleteAllModels();
}
QTEST_MAIN(MainTest)

View File

@ -1,20 +0,0 @@
QT += qml quick testlib sql
QT -= gui
TARGET = tst_nut
TEMPLATE = app
CONFIG += warn_on qmltestcase c++11
INCLUDEPATH += $$PWD/../../src $$PWD/../common
include(../../nut.pri)
IMPORTPATH += $$OUT_PWD/../src/imports
SOURCES += \
maintest.cpp \
testdatabase.cpp \
test.cpp
HEADERS += \
maintest.h \
../common/consts.h \
testdatabase.h \
test.h

14
test/test.pro Normal file
View File

@ -0,0 +1,14 @@
TEMPLATE = subdirs
SUBDIRS += \
tst_basic \
tst_benckmark \
# tst_commands \
tst_datatypes \
#tst_join \
tst_phrases \
tst_quuid \
tst_generators \
tst_upgrades \
tst_json

View File

@ -5,7 +5,7 @@
#include "consts.h"
#include "maintest.h"
#include "tst_basic.h"
#include "query.h"
#include "tableset.h"
#include "tablemodel.h"
@ -16,19 +16,11 @@
#include "comment.h"
#include "score.h"
#define PRINT(x) qDebug() << #x "=" << x;
#define TIC() QElapsedTimer timer; timer.start()
#define TOC() qDebug() << QString("Elapsed time: %1ms for %2") \
.arg(timer.elapsed() / 1000.) \
.arg(__func__)
#define REGISTER(x) qDebug() << #x << "type id:" << qRegisterMetaType<x*>()
MainTest::MainTest(QObject *parent) : QObject(parent)
BasicTest::BasicTest(QObject *parent) : QObject(parent)
{
}
void MainTest::initTestCase()
void BasicTest::initTestCase()
{
//register all entities with Qt-MetaType mechanism
REGISTER(User);
@ -39,7 +31,7 @@ void MainTest::initTestCase()
db.setDriver(DRIVER);
db.setHostName(HOST);
db.setDatabaseName("nut_tst_basic");
db.setDatabaseName(DATABASE);
db.setUserName(USERNAME);
db.setPassword(PASSWORD);
@ -52,7 +44,7 @@ void MainTest::initTestCase()
db.scores()->query()->remove();
}
void MainTest::dataScheema()
void BasicTest::dataScheema()
{
// auto json = db.model().toJson();
// auto model = DatabaseModel::fromJson(json);
@ -62,20 +54,19 @@ void MainTest::dataScheema()
// QTEST_ASSERT(model == db.model());
}
void MainTest::createUser()
void BasicTest::createUser()
{
user = new User;
user->setId(QUuid::createUuid());
user = Nut::create<User>();
user->setUsername("admin");
user->setPassword("123456");
db.users()->append(user);
db.saveChanges();
}
void MainTest::createPost()
void BasicTest::createPost()
{
TIC();
Post *newPost = new Post;
auto newPost = Nut::create<Post>();
newPost->setTitle("post title");
newPost->setSaveDate(QDateTime::currentDateTime());
newPost->setPublic(false);
@ -83,15 +74,14 @@ void MainTest::createPost()
db.posts()->append(newPost);
for(int i = 0 ; i < 3; i++){
Comment *comment = new Comment;
comment->setId(QUuid::createUuid());
auto comment = Nut::create<Comment>();
comment->setMessage("comment #" + QString::number(i));
comment->setSaveDate(QDateTime::currentDateTime());
comment->setAuthorId(user->id());
newPost->comments()->append(comment);
db.comments()->append(comment);
}
for (int i = 0; i < 10; ++i) {
Score *score = new Score;
auto score = Nut::create<Score>();
score->setScore(i % 5);
newPost->scores()->append(score);
}
@ -105,19 +95,18 @@ void MainTest::createPost()
qDebug() << "New post inserted with id:" << newPost->id();
}
void MainTest::createPost2()
void BasicTest::createPost2()
{
//create post on the fly
QVariant postIdVar = db.posts()->query()->insert(
(Post::titleField() = "This is a sample")
& (Post::isPublicField() = true));
QTEST_ASSERT(postIdVar.type() == QVariant::LongLong);
QTEST_ASSERT(postIdVar.type() == QVariant::LongLong || postIdVar.type() == QVariant::ULongLong);
int postId = postIdVar.toInt();
for(int i = 0 ; i < 3; i++){
Comment *comment = new Comment;
comment->setId(QUuid::createUuid());
auto comment = Nut::create<Comment>();
comment->setMessage("comment #" + QString::number(i + 2));
comment->setSaveDate(QDateTime::currentDateTime());
comment->setAuthor(user);
@ -130,7 +119,7 @@ void MainTest::createPost2()
QTEST_ASSERT(postId != 0);
}
void MainTest::updatePostOnTheFly()
void BasicTest::updatePostOnTheFly()
{
auto c = db.posts()->query()
->where(Post::idField() == postId)
@ -139,7 +128,7 @@ void MainTest::updatePostOnTheFly()
QTEST_ASSERT(c == 1);
}
void MainTest::selectPublicts()
void BasicTest::selectPublicts()
{
auto q = db.posts()->query()
->where(Post::isPublicField())
@ -153,7 +142,7 @@ void MainTest::selectPublicts()
QTEST_ASSERT(q2 == 1);
}
void MainTest::selectPosts()
void BasicTest::selectPosts()
{
auto q = db.posts()->query()
->join<Comment>()
@ -177,7 +166,7 @@ void MainTest::selectPosts()
db.cleanUp();
}
void MainTest::selectScoreAverage()
void BasicTest::selectScoreAverage()
{
auto a = db.scores()->query()
->join<Post>()
@ -186,7 +175,7 @@ void MainTest::selectScoreAverage()
qDebug() << a;
}
void MainTest::selectFirst()
void BasicTest::selectFirst()
{
auto posts = db.posts()->query()
->first();
@ -194,7 +183,7 @@ void MainTest::selectFirst()
QTEST_ASSERT(posts != Q_NULLPTR);
}
void MainTest::selectPostsWithoutTitle()
void BasicTest::selectPostsWithoutTitle()
{
auto q = db.posts()->query();
q->setWhere(Post::titleField().isNull());
@ -202,7 +191,7 @@ void MainTest::selectPostsWithoutTitle()
QTEST_ASSERT(count == 0);
}
void MainTest::selectPostIds()
void BasicTest::selectPostIds()
{
auto q = db.posts()->query();
auto ids = q->select(Post::idField());
@ -210,13 +199,13 @@ qDebug() << ids.count();
QTEST_ASSERT(ids.count() == 2);
}
void MainTest::testDate()
void BasicTest::testDate()
{
QDateTime d = QDateTime::currentDateTime();
QTime t = QTime(d.time().hour(), d.time().minute(), d.time().second());
d.setTime(t);
Post *newPost = new Post;
auto newPost = Nut::create<Post>();
newPost->setTitle("post title");
newPost->setSaveDate(d);
@ -228,38 +217,39 @@ void MainTest::testDate()
->setWhere(Post::idField() == newPost->id())
->first();
qDebug() << q->saveDate() << d;
QTEST_ASSERT(q->saveDate() == d);
}
void MainTest::join()
void BasicTest::join()
{
TIC();
auto q = db.comments()->query()
->join<User>()
->join<Post>();
// TIC();
// auto q = db.comments()->query()
// ->join<User>()
// ->join<Post>();
auto comments = q->toList();
// auto comments = q->toList();
TOC();
QTEST_ASSERT(comments.length());
QTEST_ASSERT(comments[0]->author());
QTEST_ASSERT(comments[0]->author()->username() == "admin");
// TOC();
// QTEST_ASSERT(comments.length());
// QTEST_ASSERT(comments[0]->author());
// QTEST_ASSERT(comments[0]->author()->username() == "admin");
}
void MainTest::selectWithInvalidRelation()
void BasicTest::selectWithInvalidRelation()
{
auto q = db.posts()->query();
q->join("Invalid_Class_Name");
q->toList();
}
void MainTest::modifyPost()
void BasicTest::modifyPost()
{
auto q = db.posts()->query();
q->setWhere(Post::idField() == postId);
Post *post = q->first();
Nut::Row<Post> post = q->first();
QTEST_ASSERT(post != nullptr);
@ -274,7 +264,7 @@ void MainTest::modifyPost()
QTEST_ASSERT(post->title() == "new name");
}
void MainTest::emptyDatabase()
void BasicTest::emptyDatabase()
{
// auto commentsCount = db.comments()->query()->remove();
// auto postsCount = db.posts()->query()->remove();
@ -282,15 +272,18 @@ void MainTest::emptyDatabase()
// QTEST_ASSERT(commentsCount == 6);
}
void MainTest::cleanupTestCase()
void BasicTest::cleanupTestCase()
{
post->deleteLater();
user->deleteLater();
// post->deleteLater();
// user->deleteLater();
//release models before exiting
qDeleteAll(TableModel::allModels());
// qDeleteAll(TableModel::allModels());
// if (QFile::remove("nut_tst_basic"))
// qDebug() << "database removed";
PRINT_FORM(db);
}
QTEST_MAIN(MainTest)
QTEST_MAIN(BasicTest)

View File

@ -7,16 +7,16 @@
#include "weblogdatabase.h"
class Post;
class User;
class MainTest : public QObject
class BasicTest : public QObject
{
Q_OBJECT
WeblogDatabase db;
int postId;
Post *post;
User *user;
Nut::Row<Post> post;
Nut::Row<User> user;
public:
explicit MainTest(QObject *parent = nullptr);
explicit BasicTest(QObject *parent = nullptr);
signals:

View File

@ -0,0 +1,27 @@
QT += testlib sql
TARGET = tst_basic
TEMPLATE = app
CONFIG += warn_on c++11
include(../common/nut-lib.pri)
SOURCES += \
../common/comment.cpp \
../common/post.cpp \
../common/user.cpp \
../common/weblogdatabase.cpp \
../common/score.cpp \
tst_basic.cpp
HEADERS += \
../common/consts.h \
../common/comment.h \
../common/post.h \
../common/user.h \
../common/weblogdatabase.h \
../common/score.h \
tst_basic.h
include($$PWD/../../ci-test-init.pri)

View File

@ -6,7 +6,7 @@
#include "weblogdatabase.h"
class Post;
class MainTest : public QObject
class BenchmarkTest : public QObject
{
Q_OBJECT
WeblogDatabase db;
@ -14,7 +14,7 @@ class MainTest : public QObject
Post *post;
Query<Post> *q;
public:
explicit MainTest(QObject *parent = nullptr);
explicit BenchmarkTest(QObject *parent = nullptr);
signals:

View File

@ -10,23 +10,27 @@
#include "tablemodel.h"
#include "databasemodel.h"
#include "user.h"
#include "post.h"
#include "comment.h"
#include "score.h"
MainTest::MainTest(QObject *parent) : QObject(parent)
BenchmarkTest::BenchmarkTest(QObject *parent) : QObject(parent)
{
}
void MainTest::initTestCase()
void BenchmarkTest::initTestCase()
{
qDebug() << "User type id:" << qRegisterMetaType<Post*>();
qDebug() << "Comment type id:" << qRegisterMetaType<Comment*>();
qDebug() << "DB type id:" << qRegisterMetaType<WeblogDatabase*>();
REGISTER(User);
REGISTER(Post);
REGISTER(Score);
REGISTER(Comment);
REGISTER(WeblogDatabase);
db.setDriver(DRIVER);
db.setHostName(HOST);
db.setDatabaseName(DATABASE);
db.setDatabaseName("tst_benchmark_db");
db.setUserName(USERNAME);
db.setPassword(PASSWORD);
@ -35,21 +39,21 @@ void MainTest::initTestCase()
QTEST_ASSERT(ok);
}
void MainTest::insert1kPost()
void BenchmarkTest::insert1kPost()
{
QTime t;
t.start();
for (int i = 0; i < 1000; ++i) {
Post *newPost = new Post;
for (int i = 0; i < 100; ++i) {
auto newPost = Nut::create<Post>();
newPost->setTitle("post title");
newPost->setSaveDate(QDateTime::currentDateTime());
db.posts()->append(newPost);
}
db.saveChanges();
qDebug("1k post inserted in %d ms", t.elapsed());
}
QTEST_MAIN(MainTest)
QTEST_MAIN(BenchmarkTest)

View File

@ -1,20 +1,19 @@
QT += qml quick testlib sql
QT -= gui
QT += testlib sql
TARGET = tst_nut
TARGET = tst_benchmark
TEMPLATE = app
CONFIG += warn_on qmltestcase c++11
INCLUDEPATH += $$PWD/../../src $$PWD/../common
include(../../nut.pri)
IMPORTPATH += $$OUT_PWD/../src/imports
CONFIG += warn_on c++11
include(../common/nut-lib.pri)
SOURCES += \
maintest.cpp \
../common/comment.cpp \
../common/post.cpp \
../common/user.cpp \
../common/weblogdatabase.cpp \
../common/score.cpp
../common/score.cpp \
tst_benchmark.cpp
HEADERS += \
maintest.h \
@ -24,3 +23,5 @@ HEADERS += \
../common/user.h \
../common/weblogdatabase.h \
../common/score.h
include($$PWD/../../ci-test-init.pri)

View File

@ -4,7 +4,7 @@
#include "consts.h"
#include "maintest.h"
#include "tst_commands.h"
#include "query.h"
#include "tableset.h"
#include "tablemodel.h"
@ -12,17 +12,19 @@
#include "post.h"
#include "comment.h"
#include "user.h"
#include "score.h"
MainTest::MainTest(QObject *parent) : QObject(parent)
CommandsTest::CommandsTest(QObject *parent) : QObject(parent)
{
}
void MainTest::initTestCase()
void CommandsTest::initTestCase()
{
qDebug() << "User type id:" << qRegisterMetaType<Post*>();
qDebug() << "Comment type id:" << qRegisterMetaType<Comment*>();
qDebug() << "DB type id:" << qRegisterMetaType<WeblogDatabase*>();
REGISTER(Post);
REGISTER(Comment);
REGISTER(WeblogDatabase);
db.setDriver(DRIVER);
db.setHostName(HOST);
@ -35,7 +37,7 @@ void MainTest::initTestCase()
QTEST_ASSERT(ok);
}
void MainTest::cmd1()
void CommandsTest::cmd1()
{
Query<Post> *q = db.posts()->query()
->setWhere(Post::titleField() == "test" && Post::idField() < 4 + 5);
@ -45,7 +47,7 @@ void MainTest::cmd1()
qDebug() << q->sqlCommand();
}
void MainTest::cmd2()
void CommandsTest::cmd2()
{
Query<Post> *q = db.posts()->query()
->setWhere(!Post::idField().in({1, 2, 3, 4}));
@ -56,7 +58,7 @@ void MainTest::cmd2()
qDebug() << q->sqlCommand();
}
void MainTest::join()
void CommandsTest::join()
{
auto q = db.posts()->query()
->join<User>()
@ -64,4 +66,4 @@ void MainTest::join()
}
QTEST_MAIN(MainTest)
QTEST_MAIN(CommandsTest)

View File

@ -6,7 +6,7 @@
#include "weblogdatabase.h"
class Post;
class MainTest : public QObject
class CommandsTest : public QObject
{
Q_OBJECT
WeblogDatabase db;
@ -14,7 +14,7 @@ class MainTest : public QObject
Post *post;
Query<Post> *q;
public:
explicit MainTest(QObject *parent = nullptr);
explicit CommandsTest(QObject *parent = nullptr);
signals:

Some files were not shown because too many files have changed in this diff Show More