From 3cee4dae4f7a6a308f3ce3e450ae387937e81586 Mon Sep 17 00:00:00 2001 From: Hamed Masafi Date: Sun, 7 Jul 2019 12:20:49 +0430 Subject: [PATCH] sqlite passed tst_datetime --- src/generators/sqlgeneratorbase.cpp | 24 +++++-- src/generators/sqlitegenerator.cpp | 61 ++++++++++++++-- src/generators/sqlitegenerator.h | 3 + src/phrases/datephrase.h | 13 ++++ src/phrases/phrasedata.h | 8 +++ test/tst_datetime/tst_datetime.cpp | 104 +++++++++++++++++++++++++--- test/tst_datetime/tst_datetime.h | 4 +- 7 files changed, 195 insertions(+), 22 deletions(-) diff --git a/src/generators/sqlgeneratorbase.cpp b/src/generators/sqlgeneratorbase.cpp index a5ff052..74afe17 100644 --- a/src/generators/sqlgeneratorbase.cpp +++ b/src/generators/sqlgeneratorbase.cpp @@ -788,12 +788,24 @@ void SqlGeneratorBase::removeTableNames(QString &command) 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"; + case PhraseData::AddYears: + case PhraseData::AddYearsDateTime: + return "YEAR"; + case PhraseData::AddMonths: + case PhraseData::AddMonthsDateTime: + return "MONTH"; + case PhraseData::AddDays: + case PhraseData::AddDaysDateTime: + return "DAY"; + case PhraseData::AddHours: + case PhraseData::AddHoursDateTime: + return "HOUR"; + case PhraseData::AddMinutes: + case PhraseData::AddMinutesDateTime: + return "MINUTE"; + case PhraseData::AddSeconds: + case PhraseData::AddSecondsDateTime: + return "SECOND"; } return QString(); } diff --git a/src/generators/sqlitegenerator.cpp b/src/generators/sqlitegenerator.cpp index 4ea91e7..4ed07a7 100644 --- a/src/generators/sqlitegenerator.cpp +++ b/src/generators/sqlitegenerator.cpp @@ -219,22 +219,73 @@ QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const 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: + case PhraseData::AddDays: { int i = d->operand.toInt(); return QString("DATE(%1,'%2 %3')") .arg(createConditionalPhrase(d->left), - (i < 0 ? "-" : "+") + QString::number(i), + (i < 0 ? "" : "+") + QString::number(i), dateTimePartName(op)); + break; + } + case PhraseData::AddHours: + case PhraseData::AddMinutes: + case PhraseData::AddSeconds: { + int i = d->operand.toInt(); + return QString("TIME(%1,'%2 %3')") + .arg(createConditionalPhrase(d->left), + (i < 0 ? "" : "+") + QString::number(i), + dateTimePartName(op)); + break; + } + case PhraseData::AddYearsDateTime: + case PhraseData::AddMonthsDateTime: + case PhraseData::AddDaysDateTime: + case PhraseData::AddHoursDateTime: + case PhraseData::AddMinutesDateTime: + case PhraseData::AddSecondsDateTime: { + int i = d->operand.toInt(); + return QString("DATETIME(%1,'%2 %3')") + .arg(createConditionalPhrase(d->left), + (i < 0 ? "" : "+") + QString::number(i), + dateTimePartName(op)); + break; + } } } return SqlGeneratorBase::createConditionalPhrase(d); } +QString SqliteGenerator::escapeValue(const QVariant &v) const +{ + 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") + "'"; + + return SqlGeneratorBase::escapeValue(v); +} + +QVariant SqliteGenerator::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(); + + return SqlGeneratorBase::unescapeValue(type, dbValue); +} + NUT_END_NAMESPACE diff --git a/src/generators/sqlitegenerator.h b/src/generators/sqlitegenerator.h index 5576bae..b0f2f0e 100644 --- a/src/generators/sqlitegenerator.h +++ b/src/generators/sqlitegenerator.h @@ -42,6 +42,9 @@ public: QStringList diff(TableModel *oldTable, TableModel *newTable) override; QString createConditionalPhrase(const PhraseData *d) const override; + + QString escapeValue(const QVariant &v) const override; + QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override; }; NUT_END_NAMESPACE diff --git a/src/phrases/datephrase.h b/src/phrases/datephrase.h index 5db2186..ab79d9c 100644 --- a/src/phrases/datephrase.h +++ b/src/phrases/datephrase.h @@ -102,32 +102,45 @@ public: ConditionalPhrase addYears(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddYearsDateTime, val); + return ConditionalPhrase(this, PhraseData::AddYears, val); } ConditionalPhrase addMonths(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddMonthsDateTime, val); return ConditionalPhrase(this, PhraseData::AddMonths, val); } ConditionalPhrase addDays(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddDaysDateTime, val); return ConditionalPhrase(this, PhraseData::AddDays, val); } ConditionalPhrase addHours(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddHoursDateTime, val); return ConditionalPhrase(this, PhraseData::AddHours, val); } ConditionalPhrase addMinutes(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddMinutesDateTime, val); return ConditionalPhrase(this, PhraseData::AddMinutes, val); } ConditionalPhrase addSeconds(int val) { if (!is_valid_template()) return ConditionalPhrase(); + if (std::is_same::value) + return ConditionalPhrase(this, PhraseData::AddSecondsDateTime, val); return ConditionalPhrase(this, PhraseData::AddSeconds, val); } diff --git a/src/phrases/phrasedata.h b/src/phrases/phrasedata.h index d1ae6f0..a773cb6 100644 --- a/src/phrases/phrasedata.h +++ b/src/phrases/phrasedata.h @@ -64,6 +64,14 @@ public: AddMinutes, AddSeconds, + // sqlite need to know works with qdate, qtime or qdatetime + AddYearsDateTime, + AddMonthsDateTime, + AddDaysDateTime, + AddHoursDateTime, + AddMinutesDateTime, + AddSecondsDateTime, + DatePartYear, DatePartMonth, DatePartDay, diff --git a/test/tst_datetime/tst_datetime.cpp b/test/tst_datetime/tst_datetime.cpp index 9b11845..eb5119f 100644 --- a/test/tst_datetime/tst_datetime.cpp +++ b/test/tst_datetime/tst_datetime.cpp @@ -35,19 +35,103 @@ void DateTimeTest::initTestCase() db.sampleTables()->query()->remove(); } -void DateTimeTest::date() +#define TEST_DATE(date, command, n) \ +do { \ + auto s = Nut::create(); \ + s->setD(date); \ + db.sampleTables()->append(s); \ + db.saveChanges(); \ + auto count = db.sampleTables()->query() \ + ->where(SampleTable::dField().command(n) == date.command(n)) \ + ->count(); \ + QTEST_ASSERT(count); \ +} while (false) + +#define TEST_TIME(time, command, n, num) \ +do { \ + auto s = Nut::create(); \ + s->setT(time); \ + db.sampleTables()->append(s); \ + db.saveChanges(); \ + auto count = db.sampleTables()->query() \ + ->where(SampleTable::tField().command(n) == time.addSecs(num)) \ + ->count(); \ + QTEST_ASSERT(count); \ +} while (false) + +#define TEST_DATE2(datetime, command, n) \ +do { \ + auto s = Nut::create(); \ + s->setDT(datetime); \ + db.sampleTables()->append(s); \ + db.saveChanges(); \ + auto count = db.sampleTables()->query() \ + ->where(SampleTable::dtField().command(n) == datetime.command(n)); \ + ->count(); \ + QTEST_ASSERT(count); \ +} while (false) + +#define TEST_TIME2(datetime, command, n, num) \ +do { \ + auto s = Nut::create(); \ + s->setDT(datetime); \ + db.sampleTables()->append(s); \ + db.saveChanges(); \ + auto count = db.sampleTables()->query() \ + ->where(SampleTable::dtField().command(n) == datetime.addSecs(num)); \ + ->count(); \ + QTEST_ASSERT(count); \ +} while (false) + +#define MINUTE(m) m * 60 +#define HOUR(h) MINUTE(h) * 60 + +void DateTimeTest::dateAdd() { - auto s = Nut::create(); - s->setD(_baseDateTime.addDays(10).date()); - db.sampleTables()->append(s); - db.saveChanges(); + QDate d = QDate::currentDate(); - auto q = db.sampleTables()->query() - ->where(SampleTable::dField().addDays(9) < QDate::currentDate().addDays(10)); + TEST_DATE(d, addYears, 10); + TEST_DATE(d, addMonths, 10); + TEST_DATE(d, addDays, 10); - auto count = q->count(); - qDebug() << q->sqlCommand(); - QTEST_ASSERT(count); + TEST_DATE(d, addYears, -10); + TEST_DATE(d, addMonths, -10); + TEST_DATE(d, addDays, -10); +} + +void DateTimeTest::timeAdd() +{ + QTime t = QTime::currentTime(); + + TEST_TIME(t, addHours, 10, HOUR(10)); + TEST_TIME(t, addMinutes, 10, MINUTE(10)); + TEST_TIME(t, addSeconds, 10, 10); + + TEST_TIME(t, addHours, -10, HOUR(-10)); + TEST_TIME(t, addMinutes, -10, MINUTE(-10)); + TEST_TIME(t, addSeconds, -10, -10); +} + +void DateTimeTest::dateTimeAdd() +{ + QDateTime dt = QDateTime::currentDateTime(); + + TEST_DATE2(dt, addYears, 10); + TEST_DATE2(dt, addMonths, 10); + TEST_DATE2(dt, addDays, 10); + + TEST_DATE2(dt, addYears, -10); + TEST_DATE2(dt, addMonths, -10); + TEST_DATE2(dt, addDays, -10); + + + TEST_TIME2(dt, addHours, 10, HOUR(10)); + TEST_TIME2(dt, addMinutes, 10, MINUTE(10)); + TEST_TIME2(dt, addSeconds, 10, 10); + + TEST_TIME2(dt, addHours, -10, HOUR(-10)); + TEST_TIME2(dt, addMinutes, -10, MINUTE(-10)); + TEST_TIME2(dt, addSeconds, -10, -10); } void DateTimeTest::cleanupTestCase() diff --git a/test/tst_datetime/tst_datetime.h b/test/tst_datetime/tst_datetime.h index 830a2a0..960a47f 100644 --- a/test/tst_datetime/tst_datetime.h +++ b/test/tst_datetime/tst_datetime.h @@ -30,7 +30,9 @@ signals: private slots: void initTestCase(); - void date(); + void dateAdd(); + void timeAdd(); + void dateTimeAdd(); void cleanupTestCase(); };