diff --git a/src/generators/mysqlgenerator.cpp b/src/generators/mysqlgenerator.cpp index c33af38..ea50b15 100644 --- a/src/generators/mysqlgenerator.cpp +++ b/src/generators/mysqlgenerator.cpp @@ -290,4 +290,41 @@ bool MySqlGenerator::readInsideParentese(QString &text, QString &out) // return command; //} +QString MySqlGenerator::createConditionalPhrase(const PhraseData *d) const +{ + if (!d) + return QString(); + + PhraseData::Condition op = d->operatorCond; + //apply not (!) + if (d->isNot) { + if (op < 20) + op = static_cast((op + 10) % 20); + } + + if (d->type == PhraseData::WithVariant) { + if (op == PhraseData::AddYears) + return QString("DATE_ADD(%2, INTERVAL %1 YEAR)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMonths) + return QString("DATE_ADD(%2, INTERVAL %1 MONTH)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddDays) + return QString("DATE_ADD(%2, INTERVAL %1 DAY)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddHours) + return QString("DATE_ADD(%2, INTERVAL %1 HOUR)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMinutes) + return QString("DATE_ADD(%2, INTERVAL %1 MINUTE)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddSeconds) + return QString("DATE_ADD(%2, INTERVAL %1 SECOND)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + + } + + return SqlGeneratorBase::createConditionalPhrase(d); +} + NUT_END_NAMESPACE diff --git a/src/generators/mysqlgenerator.h b/src/generators/mysqlgenerator.h index 847b653..1609c81 100644 --- a/src/generators/mysqlgenerator.h +++ b/src/generators/mysqlgenerator.h @@ -31,11 +31,12 @@ class MySqlGenerator : public SqlGeneratorBase public: explicit MySqlGenerator(Database *parent = 0); - QString fieldType(FieldModel *field); - QString escapeValue(const QVariant &v) const; - QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue); + QString fieldType(FieldModel *field) override; + QString escapeValue(const QVariant &v) const override; + QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override; // QString phrase(const PhraseData *d) const; // QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList &wheres, QList &orders, QList joins, int skip, int take); + QString createConditionalPhrase(const PhraseData *d) const override; private: bool readInsideParentese(QString &text, QString &out); }; diff --git a/src/generators/postgresqlgenerator.cpp b/src/generators/postgresqlgenerator.cpp index e1da1c2..83bc2c9 100644 --- a/src/generators/postgresqlgenerator.cpp +++ b/src/generators/postgresqlgenerator.cpp @@ -328,12 +328,38 @@ QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const if (!d) return QString(); + PhraseData::Condition op = d->operatorCond; + //apply not (!) + if (d->isNot) { + if (op < 20) + op = static_cast((op + 10) % 20); + } + 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)); } + if (op == PhraseData::AddYears) + return QString("DATEADD(year, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMonths) + return QString("DATEADD(month, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddDays) + return QString("DATEADD(day, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddHours) + return QString("DATEADD(hour, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMinutes) + return QString("DATEADD(minute, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + else if (op == PhraseData::AddSeconds) + return QString("DATEADD(second, %1, %2)") + .arg(d->operand.toString(), createConditionalPhrase(d->left)); + } return SqlGeneratorBase::createConditionalPhrase(d); diff --git a/src/generators/sqlgeneratorbase.cpp b/src/generators/sqlgeneratorbase.cpp index 53dd741..a5ff052 100644 --- a/src/generators/sqlgeneratorbase.cpp +++ b/src/generators/sqlgeneratorbase.cpp @@ -785,6 +785,19 @@ void SqlGeneratorBase::removeTableNames(QString &command) command = command.replace("[" + m->className() + "].", ""); } +QString SqlGeneratorBase::dateTimePartName(const PhraseData::Condition &op) const +{ + switch (op) { + case PhraseData::AddYears: return "YEAR"; + case PhraseData::AddMonths: return "MONTH"; + case PhraseData::AddDays: return "DAY"; + case PhraseData::AddHours: return "HOUR"; + case PhraseData::AddMinutes: return "MINUTE"; + case PhraseData::AddSeconds: return "SECOND"; + } + return QString(); +} + //QString SqlGeneratorBase::deleteCommand(QList &wheres, // QString tableName) //{ @@ -973,7 +986,7 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const break; case PhraseData::WithVariant: - if (op == PhraseData::AddYears) + /* if (op == PhraseData::AddYears) ret = QString("DATEADD(year, %1, %2)") .arg(d->operand.toString(), createConditionalPhrase(d->left)); else if (op == PhraseData::AddMonths) @@ -991,7 +1004,7 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const else if (op == PhraseData::AddSeconds) ret = QString("DATEADD(second, %1, %2)") .arg(d->operand.toString(), createConditionalPhrase(d->left)); - else if (op == PhraseData::Between) { + else */if (op == PhraseData::Between) { QVariantList list = d->operand.toList(); ret = QString("%1 BETWEEN %2 AND %3") .arg(createConditionalPhrase(d->left), escapeValue(list.at(0)), escapeValue(list.at(1))); diff --git a/src/generators/sqlgeneratorbase_p.h b/src/generators/sqlgeneratorbase_p.h index e6acf73..a25d3ee 100644 --- a/src/generators/sqlgeneratorbase_p.h +++ b/src/generators/sqlgeneratorbase_p.h @@ -162,6 +162,7 @@ protected: void replaceTableNames(QString &command); void removeTableNames(QString &command); + QString dateTimePartName(const PhraseData::Condition &op) const; }; NUT_END_NAMESPACE diff --git a/src/generators/sqlitegenerator.cpp b/src/generators/sqlitegenerator.cpp index e45168f..4ea91e7 100644 --- a/src/generators/sqlitegenerator.cpp +++ b/src/generators/sqlitegenerator.cpp @@ -205,4 +205,36 @@ QString SqliteGenerator::primaryKeyConstraint(const TableModel *table) const // return sql; } +QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const +{ + if (!d) + return QString(); + + PhraseData::Condition op = d->operatorCond; + //apply not (!) + if (d->isNot) { + if (op < 20) + op = static_cast((op + 10) % 20); + } + + if (d->type == PhraseData::WithVariant) { + QString part; + switch (op) { + case PhraseData::AddYears: + case PhraseData::AddMonths: + case PhraseData::AddDays: + case PhraseData::AddHours: + case PhraseData::AddMinutes: + case PhraseData::AddSeconds: + int i = d->operand.toInt(); + return QString("DATE(%1,'%2 %3')") + .arg(createConditionalPhrase(d->left), + (i < 0 ? "-" : "+") + QString::number(i), + dateTimePartName(op)); + } + } + + return SqlGeneratorBase::createConditionalPhrase(d); +} + NUT_END_NAMESPACE diff --git a/src/generators/sqlitegenerator.h b/src/generators/sqlitegenerator.h index 402ae41..5576bae 100644 --- a/src/generators/sqlitegenerator.h +++ b/src/generators/sqlitegenerator.h @@ -41,6 +41,7 @@ public: QString primaryKeyConstraint(const TableModel *table) const override; QStringList diff(TableModel *oldTable, TableModel *newTable) override; + QString createConditionalPhrase(const PhraseData *d) const override; }; NUT_END_NAMESPACE diff --git a/src/tablesetbase.cpp b/src/tablesetbase.cpp index 6546650..97bcefc 100644 --- a/src/tablesetbase.cpp +++ b/src/tablesetbase.cpp @@ -61,9 +61,11 @@ int TableSetBase::save(Database *db, bool cleanUp) || t->status() == Table::Modified || t->status() == Table::Deleted){ rowsAffected += t->save(db); -#ifndef NUT_SHARED_POINTER if(cleanUp) +#ifndef NUT_SHARED_POINTER t->deleteLater(); +#else + remove(t); #endif } } diff --git a/test/test.pro b/test/test.pro index 6fad6dd..1a7a38e 100644 --- a/test/test.pro +++ b/test/test.pro @@ -8,5 +8,6 @@ SUBDIRS += \ tst_quuid \ tst_generators \ tst_upgrades \ - tst_json + tst_json \ + tst_datetime diff --git a/test/tst_datetime/db.cpp b/test/tst_datetime/db.cpp new file mode 100644 index 0000000..e570806 --- /dev/null +++ b/test/tst_datetime/db.cpp @@ -0,0 +1,9 @@ +#include "db.h" + +#include "sampletable.h" + +DB::DB() : Nut::Database (), + m_sampleTables(new Nut::TableSet(this)) +{ + +} diff --git a/test/tst_datetime/db.h b/test/tst_datetime/db.h new file mode 100644 index 0000000..401ac8c --- /dev/null +++ b/test/tst_datetime/db.h @@ -0,0 +1,21 @@ +#ifndef DB_H +#define DB_H + +#include "database.h" + +class SampleTable; +class DB : public Nut::Database +{ + Q_OBJECT + + NUT_DB_VERSION(1) + + NUT_DECLARE_TABLE(SampleTable, sampleTables) + +public: + DB(); +}; + +Q_DECLARE_METATYPE(DB*) + +#endif // DB_H diff --git a/test/tst_datetime/sampletable.cpp b/test/tst_datetime/sampletable.cpp new file mode 100644 index 0000000..68a9c9d --- /dev/null +++ b/test/tst_datetime/sampletable.cpp @@ -0,0 +1,6 @@ +#include "sampletable.h" + +SampleTable::SampleTable(QObject *parent) : Nut::Table (parent) +{ + +} diff --git a/test/tst_datetime/sampletable.h b/test/tst_datetime/sampletable.h new file mode 100644 index 0000000..2587bac --- /dev/null +++ b/test/tst_datetime/sampletable.h @@ -0,0 +1,27 @@ +#ifndef SAMPLETABLE_H +#define SAMPLETABLE_H + +#include +#include +#include + +#include "table.h" + +class SampleTable : public Nut::Table +{ + Q_OBJECT + + NUT_PRIMARY_AUTO_INCREMENT(id) + NUT_DECLARE_FIELD(int, id, id, setId) + + NUT_DECLARE_FIELD(QDate, d, d, setD) + NUT_DECLARE_FIELD(QTime, t, t, setT) + NUT_DECLARE_FIELD(QDateTime, dt, dt, setDT) + +public: + Q_INVOKABLE SampleTable(QObject *parent = Q_NULLPTR); +}; + +Q_DECLARE_METATYPE(SampleTable*) + +#endif // SAMPLETABLE_H diff --git a/test/tst_datetime/tst_datetime.cpp b/test/tst_datetime/tst_datetime.cpp new file mode 100644 index 0000000..9b11845 --- /dev/null +++ b/test/tst_datetime/tst_datetime.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include "consts.h" + +#include "tst_datetime.h" +#include "query.h" +#include "tableset.h" +#include "tablemodel.h" +#include "databasemodel.h" + +#include "sampletable.h" + +DateTimeTest::DateTimeTest(QObject *parent) : QObject(parent) +{ + _baseDateTime = QDateTime::currentDateTime(); +} + +void DateTimeTest::initTestCase() +{ + //register all entities with Qt-MetaType mechanism + REGISTER(SampleTable); + REGISTER(DB); + + db.setDriver(DRIVER); + db.setHostName(HOST); + db.setDatabaseName(DATABASE); + db.setUserName(USERNAME); + db.setPassword(PASSWORD); + + QTEST_ASSERT(db.open()); + + db.sampleTables()->query()->remove(); +} + +void DateTimeTest::date() +{ + auto s = Nut::create(); + s->setD(_baseDateTime.addDays(10).date()); + db.sampleTables()->append(s); + db.saveChanges(); + + auto q = db.sampleTables()->query() + ->where(SampleTable::dField().addDays(9) < QDate::currentDate().addDays(10)); + + auto count = q->count(); + qDebug() << q->sqlCommand(); + QTEST_ASSERT(count); +} + +void DateTimeTest::cleanupTestCase() +{ + db.sampleTables()->query()->remove(); + db.close(); +} + +QTEST_MAIN(DateTimeTest) diff --git a/test/tst_datetime/tst_datetime.h b/test/tst_datetime/tst_datetime.h new file mode 100644 index 0000000..830a2a0 --- /dev/null +++ b/test/tst_datetime/tst_datetime.h @@ -0,0 +1,37 @@ +#ifndef MAINTEST_H +#define MAINTEST_H + +#include +#include + +#include +#include +#include +#include +#ifdef QT_GUI_LIB +#include +#include +#endif +#include +#include + +#include "db.h" +class DateTimeTest : public QObject +{ + Q_OBJECT + DB db; + + QDateTime _baseDateTime; + +public: + explicit DateTimeTest(QObject *parent = nullptr); + +signals: + +private slots: + void initTestCase(); + void date(); + void cleanupTestCase(); +}; + +#endif // MAINTEST_H diff --git a/test/tst_datetime/tst_datetime.pro b/test/tst_datetime/tst_datetime.pro new file mode 100644 index 0000000..7a9a327 --- /dev/null +++ b/test/tst_datetime/tst_datetime.pro @@ -0,0 +1,20 @@ +QT += testlib sql gui + +TARGET = tst_datetime +TEMPLATE = app + +CONFIG += warn_on c++11 + +include(../common/nut-lib.pri) + +SOURCES += \ + db.cpp \ + sampletable.cpp \ + tst_datetime.cpp + +HEADERS += \ + db.h \ + sampletable.h \ + tst_datetime.h + +include($$PWD/../../ci-test-init.pri)