Merge pull request #43 from HamedMasafi/dev
Finally _dev_ merged into _master_ !!!
This commit is contained in:
commit
404c1c3198
|
|
@ -32,3 +32,5 @@ Makefile*
|
|||
#QtCtreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
|
||||
build
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "3rdparty/serializer"]
|
||||
path = 3rdparty/serializer
|
||||
url = https://github.com/HamedMasafi/Serializer.git
|
||||
39
.travis.yml
39
.travis.yml
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f9d81fcc6244271b3926891b0c86554e1e6b967e
|
||||
54
README.md
54
README.md
|
|
@ -1,11 +1,17 @@
|
|||
|
||||
|
||||
# Nut
|
||||
|
||||
## Build result
|
||||
| Brancc name | Icon |
|
||||
| Branch | Status |
|
||||
| ------------- |:-------------:|
|
||||
| master | [](https://travis-ci.org/HamedMasafi/Nut) |
|
||||
| dev | [](https://travis-ci.org/HamedMasafi/Nut) |
|
||||
|
||||
[](https://gitlicense.com/license/hamedmasafi/nut)
|
||||
|
||||
[](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:
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
#QT -= gui
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/sqlmodel.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/tablemodel.h"
|
||||
|
|
@ -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<&-
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/sqlmodel.h"
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include "../src/tablemodel.h"
|
||||
|
|
@ -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
30
nut.pri
|
|
@ -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
55
nut.pro
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
150
src/database.cpp
150
src/database.cpp
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
186
src/defines.h
186
src/defines.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
534
src/phrase.cpp
534
src/phrase.cpp
|
|
@ -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)
|
||||
//{
|
||||
|
|
|
|||
446
src/phrase.h
446
src/phrase.h
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#include "numericphrase.h"
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
160
src/query.h
160
src/query.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,2 @@
|
|||
#include "serializableobject.h"
|
||||
|
||||
SerializableObject::SerializableObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
class SerializableObject
|
||||
{
|
||||
public:
|
||||
SerializableObject();
|
||||
SerializableObject() = default;
|
||||
|
||||
virtual void load(const QVariant &value) = 0;
|
||||
virtual QVariant save() = 0;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
154
src/table.cpp
154
src/table.cpp
|
|
@ -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
|
||||
|
|
|
|||
33
src/table.h
33
src/table.h
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#include "tuple.h"
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
Loading…
Reference in New Issue