From 0762e647fbce54138fd8ff485eb4fd47897ecc2e Mon Sep 17 00:00:00 2001 From: Hamed Masafi Date: Sat, 17 Feb 2018 19:14:39 +0330 Subject: [PATCH] wip: phrases polish --- appveyor.yml | 6 + include/header_copier | 0 nut.pri | 8 +- src/database.cpp | 1 + src/generators/mysqlgenerator.cpp | 54 +-- src/generators/mysqlgenerator.h | 4 +- src/generators/sqlgeneratorbase.cpp | 461 ++++++++++++++++++-------- src/generators/sqlgeneratorbase_p.h | 50 ++- src/generators/sqlitegenerator.cpp | 36 +- src/generators/sqlitegenerator.h | 10 +- src/generators/sqlservergenerator.cpp | 34 +- src/generators/sqlservergenerator.h | 10 +- src/phrase.cpp | 367 ++++++++++++++++++++ src/phrase.h | 391 ++++++++++++++++++++++ src/query.h | 129 ++++--- src/query_p.h | 13 +- src/table.h | 2 +- src/wherephrase.cpp | 2 +- src/wherephrase.h | 88 ++--- test/basic/maintest.cpp | 43 +-- test/common/post.h | 1 + test/common/weblogdatabase.cpp | 8 +- test/phrases/maintest.cpp | 27 ++ test/phrases/maintest.h | 23 ++ test/phrases/tst_phrases.pro | 15 + 25 files changed, 1420 insertions(+), 363 deletions(-) create mode 100644 appveyor.yml mode change 100755 => 100644 include/header_copier create mode 100644 src/phrase.cpp create mode 100644 src/phrase.h create mode 100644 test/phrases/maintest.cpp create mode 100644 test/phrases/maintest.h create mode 100644 test/phrases/tst_phrases.pro diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..14029db --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,6 @@ +install: + - set QTDIR=C:\Qt\5.9.2\winrt_x64_msvc2017 + - set PATH=%PATH%;%QTDIR%\bin;C:\MinGW\bin +build_script: + - qmake + - mingw32-make diff --git a/include/header_copier b/include/header_copier old mode 100755 new mode 100644 diff --git a/nut.pri b/nut.pri index 169ecea..d479e7d 100644 --- a/nut.pri +++ b/nut.pri @@ -18,14 +18,14 @@ HEADERS += \ $$PWD/src/tablesetbase_p.h \ $$PWD/src/querybase_p.h \ $$PWD/src/tablemodel.h \ - $$PWD/src/wherephrase.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/sqlmodel_p.h \ + $$PWD/src/phrase.h SOURCES += \ $$PWD/src/generators/sqlgeneratorbase.cpp \ @@ -41,8 +41,8 @@ SOURCES += \ $$PWD/src/changelogtable.cpp \ $$PWD/src/querybase.cpp \ $$PWD/src/tablemodel.cpp \ - $$PWD/src/wherephrase.cpp \ $$PWD/src/table.cpp \ $$PWD/src/database.cpp \ $$PWD/src/serializableobject.cpp \ - $$PWD/src/sqlmodel.cpp + $$PWD/src/sqlmodel.cpp \ + $$PWD/src/phrase.cpp diff --git a/src/database.cpp b/src/database.cpp index 948c06d..749aa83 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include diff --git a/src/generators/mysqlgenerator.cpp b/src/generators/mysqlgenerator.cpp index 559e392..166e424 100644 --- a/src/generators/mysqlgenerator.cpp +++ b/src/generators/mysqlgenerator.cpp @@ -123,35 +123,35 @@ QVariant MySqlGenerator::readValue(const QVariant::Type &type, const QVariant &d return SqlGeneratorBase::readValue(type, dbValue); } -QString MySqlGenerator::phrase(const PhraseData *d) const -{ - if (d->operatorCond == PhraseData::Distance) { - return QString("ST_Distance(%1, %2)") - .arg(d->left->text) - .arg(escapeValue(d->operand.toPointF())); - } +//QString MySqlGenerator::phrase(const PhraseData *d) const +//{ +// if (d->operatorCond == PhraseData::Distance) { +// return QString("ST_Distance(%1, %2)") +// .arg(d->left->text) +// .arg(escapeValue(d->operand.toPointF())); +// } - return SqlGeneratorBase::phrase(d); -} +// return SqlGeneratorBase::phrase(d); +//} -QString MySqlGenerator::selectCommand(SqlGeneratorBase::AgregateType t, - QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, - int skip, int take) -{ - QString command = SqlGeneratorBase::selectCommand(t, agregateArg, - tableName, - wheres, orders, - joins, skip, take); +//QString MySqlGenerator::selectCommand(SqlGeneratorBase::AgregateType t, +// QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, +// int skip, int take) +//{ +// QString command = SqlGeneratorBase::selectCommand(t, agregateArg, +// tableName, +// wheres, orders, +// joins, skip, take); - if (take != -1 && skip != -1) - command.append(QString(" LIMIT %1 OFFSET %2") - .arg(take) - .arg(skip)); - return command; -} +// if (take != -1 && skip != -1) +// command.append(QString(" LIMIT %1 OFFSET %2") +// .arg(take) +// .arg(skip)); +// return command; +//} NUT_END_NAMESPACE diff --git a/src/generators/mysqlgenerator.h b/src/generators/mysqlgenerator.h index bf4ec6f..d2224f4 100644 --- a/src/generators/mysqlgenerator.h +++ b/src/generators/mysqlgenerator.h @@ -34,8 +34,8 @@ public: QString fieldType(FieldModel *field); QString escapeValue(const QVariant &v) const; QVariant readValue(const QVariant::Type &type, const QVariant &dbValue); - 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 phrase(const PhraseData *d) const; +// QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList &wheres, QList &orders, QList joins, int skip, int take); }; NUT_END_NAMESPACE diff --git a/src/generators/sqlgeneratorbase.cpp b/src/generators/sqlgeneratorbase.cpp index 3a7b88f..7cdbca8 100644 --- a/src/generators/sqlgeneratorbase.cpp +++ b/src/generators/sqlgeneratorbase.cpp @@ -31,7 +31,6 @@ #include "../table.h" #include "../databasemodel.h" #include "../tablemodel.h" -#include "../wherephrase.h" NUT_BEGIN_NAMESPACE @@ -355,10 +354,6 @@ QString SqlGeneratorBase::agregateText(const AgregateType &t, const QString &arg) const { switch (t) { - case SelectAll: - return "*"; - break; - case Min: return "MIN(" + arg + ")"; break; @@ -426,48 +421,43 @@ QString SqlGeneratorBase::deleteRecords(QString tableName, QString where) return sql; } -QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t, - QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, - int skip, int take) +QString SqlGeneratorBase::selectCommand(const QString &tableName, + const PhraseList &fields, + const ConditionalPhrase &where, + const PhraseList &order, + const QList joins, + const int skip, + const int take) { - Q_UNUSED(take); Q_UNUSED(skip); + Q_UNUSED(take); + QString selectText; - QStringList joinedOrders; - QString select = agregateText(t, agregateArg); - - //TODO: temporatory disabled - if (t == SelectAll) { + if (!fields.isValid) { QSet tables; tables.insert(_database->model().tableByName(tableName)); foreach (RelationModel *rel, joins) tables << rel->masterTable << rel->slaveTable; - select = ""; + selectText = ""; foreach (TableModel *t, tables) { - if (!select.isEmpty()) - select.append(", "); - select.append(recordsPhrase(t)); + if (!selectText.isEmpty()) + selectText.append(", "); + selectText.append(recordsPhrase(t)); } - } - QString from = join(tableName, joins, &joinedOrders); - QString where = createWhere(wheres); - QString orderText = joinedOrders.join(", "); - - foreach (WherePhrase p, orders) { - if (orderText != "") - orderText.append(", "); - orderText.append(phraseOrder(p.data())); + } else { + selectText = createFieldPhrase(fields); } - QString sql = "SELECT " + select + " FROM " + from; + QStringList joinedOrders; + QString orderText = createOrderPhrase(order); + QString whereText = createConditionalPhrase(where.data); + QString fromText = join(tableName, joins, &joinedOrders); - if (where != "") - sql.append(" WHERE " + where); + QString sql = "SELECT " + selectText + " FROM " + fromText; + + if (whereText != "") + sql.append(" WHERE " + whereText); if (orderText != "") sql.append(" ORDER BY " + orderText); @@ -481,20 +471,149 @@ QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t, return sql + " "; } -QString SqlGeneratorBase::createWhere(QList &wheres) +QString SqlGeneratorBase::selectCommand(const QString &tableName, + const SqlGeneratorBase::AgregateType &t, + const QString &agregateArg, + const ConditionalPhrase &where, + const QList &joins, + const int skip, + const int take) { - QString whereText = ""; + Q_UNUSED(skip); + Q_UNUSED(take); + QStringList joinedOrders; + QString selectText = agregateText(t, agregateArg); + QString whereText = createConditionalPhrase(where.data); + QString fromText = join(tableName, joins, &joinedOrders); - foreach (WherePhrase w, wheres) { - if (whereText != "") - whereText.append(" AND "); + QString sql = "SELECT " + selectText + " FROM " + fromText; - whereText.append(phrase(w.data())); - } + if (whereText != "") + sql.append(" WHERE " + whereText); - return whereText; + for (int i = 0; i < _database->model().count(); i++) + sql = sql.replace(_database->model().at(i)->className() + ".", + _database->model().at(i)->name() + "."); + + replaceTableNames(sql); + + return sql + " "; } +QString SqlGeneratorBase::deleteCommand(const QString &tableName, + const ConditionalPhrase &where) +{ + QString command = "DELETE FROM " + tableName; + QString whereText = createConditionalPhrase(where.data); + + if (whereText != "") + command.append(" WHERE " + whereText); + + for (int i = 0; i < _database->model().count(); i++) + command = command.replace(_database->model().at(i)->className() + ".", + _database->model().at(i)->name() + "."); + + replaceTableNames(command); + + return command; +} + +QString SqlGeneratorBase::updateCommand(const QString &tableName, + const AssignmentPhraseList &assigments, + const ConditionalPhrase &where) +{ + QString assigmentTexts = ""; + foreach (PhraseData *d, assigments.data) { + if (assigmentTexts != "") + assigmentTexts.append(", "); + + assigmentTexts.append(createConditionalPhrase(d)); + } + QString whereText = createConditionalPhrase(where.data); + + QString sql = "UPDATE " + tableName + " SET " + assigmentTexts; + + if (whereText != "") + sql.append(" WHERE " + whereText); + + for (int i = 0; i < _database->model().count(); i++) + sql = sql.replace(_database->model().at(i)->className() + ".", + _database->model().at(i)->name() + "."); + + removeTableNames(sql); + + return sql; +} + +//QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t, +// QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, +// int skip, int take) +//{ +// Q_UNUSED(take); +// Q_UNUSED(skip); + +// QStringList joinedOrders; +// QString select = agregateText(t, agregateArg); + +// //TODO: temporatory disabled +// if (t == SelectAll) { +// QSet tables; +// tables.insert(_database->model().tableByName(tableName)); +// foreach (RelationModel *rel, joins) +// tables << rel->masterTable << rel->slaveTable; + +// select = ""; +// foreach (TableModel *t, tables) { +// if (!select.isEmpty()) +// select.append(", "); +// select.append(recordsPhrase(t)); +// } +// } +// QString from = join(tableName, joins, &joinedOrders); +// QString where = createWhere(wheres); +// QString orderText = joinedOrders.join(", "); + +// foreach (WherePhrase p, orders) { +// if (orderText != "") +// orderText.append(", "); +// orderText.append(phraseOrder(p.data())); +// } + +// QString sql = "SELECT " + select + " FROM " + from; + +// if (where != "") +// sql.append(" WHERE " + where); + +// 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() + "."); + +// replaceTableNames(sql); + +// return sql + " "; +//} + +//QString SqlGeneratorBase::createWhere(QList &wheres) +//{ +// QString whereText = ""; + +// foreach (WherePhrase w, wheres) { +// if (whereText != "") +// whereText.append(" AND "); + +// whereText.append(phrase(w.data())); +// } + +// return whereText; +//} + void SqlGeneratorBase::replaceTableNames(QString &command) { foreach (TableModel *m, TableModel::allModels()) @@ -508,44 +627,44 @@ void SqlGeneratorBase::removeTableNames(QString &command) command = command.replace("[" + m->className() + "].", ""); } -QString SqlGeneratorBase::deleteCommand(QList &wheres, - QString tableName) -{ - QString command = "DELETE FROM " + tableName; - QString where = createWhere(wheres); +//QString SqlGeneratorBase::deleteCommand(QList &wheres, +// QString tableName) +//{ +// QString command = "DELETE FROM " + tableName; +// QString where = createWhere(wheres); - if (where != "") - command.append(" WHERE " + where); +// if (where != "") +// command.append(" WHERE " + where); - for (int i = 0; i < _database->model().count(); i++) - command = command.replace(_database->model().at(i)->className() + ".", - _database->model().at(i)->name() + "."); +// for (int i = 0; i < _database->model().count(); i++) +// command = command.replace(_database->model().at(i)->className() + ".", +// _database->model().at(i)->name() + "."); - replaceTableNames(command); +// replaceTableNames(command); - return command; -} +// return command; +//} -QString SqlGeneratorBase::updateCommand(WherePhrase &phrase, - QList &wheres, - QString tableName) -{ - QString p = this->phrase(phrase.data()); - QString where = createWhere(wheres); +//QString SqlGeneratorBase::updateCommand(WherePhrase &phrase, +// QList &wheres, +// QString tableName) +//{ +// QString p = this->phrase(phrase.data()); +// QString where = createWhere(wheres); - QString sql = "UPDATE " + tableName + " SET " + p; +// QString sql = "UPDATE " + tableName + " SET " + p; - if (where != "") - sql.append(" WHERE " + where); +// if (where != "") +// sql.append(" WHERE " + where); - 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() + "."); - removeTableNames(sql); +// removeTableNames(sql); - return sql; -} +// return sql; +//} QString SqlGeneratorBase::escapeValue(const QVariant &v) const { @@ -610,78 +729,13 @@ QVariant SqlGeneratorBase::readValue(const QVariant::Type &type, return dbValue; } -QString SqlGeneratorBase::phraseOrder(const PhraseData *d) const -{ - - QString ret = ""; - - switch (d->type) { - case PhraseData::Field: - if (d->operatorCond == PhraseData::Not) - ret = d->text + " DESC"; - else - ret = d->text; - break; - - case PhraseData::WithOther: - if (d->operatorCond != PhraseData::Append) - qFatal("Order phease can only have & operator"); - - ret = phraseOrder(d->left) + ", " + phraseOrder(d->right); - break; - - case PhraseData::WithoutOperand: - case PhraseData::WithVariant: - break; - } - - return ret; -} - QString SqlGeneratorBase::phrase(const PhraseData *d) const { QString ret = ""; switch (d->type) { case PhraseData::Field: - ret = d->text; - break; - - case PhraseData::WithVariant: - ret = phrase(d->left) + " " + operatorString(d->operatorCond) + " " - + escapeValue(d->operand); - break; - - case PhraseData::WithOther: - ret = phrase(d->left) + " " + operatorString(d->operatorCond) + " " - + phrase(d->right); - break; - - case PhraseData::WithoutOperand: - ret = phrase(d->left) + " " + operatorString(d->operatorCond); - break; - - default: - ret = ""; - } - - if (d->operatorCond == PhraseData::And || d->operatorCond == PhraseData::Or) - ret = "(" + ret + ")"; - - return ret; -} - -QString SqlGeneratorBase::phraseUpdate(const PhraseData *d) const -{ - QString ret = ""; - - if (d->operatorCond != PhraseData::And - && d->operatorCond != PhraseData::Equal) - qFatal("Update command does not accept any phrase else &, ="); - - switch (d->type) { - case PhraseData::Field: - ret = d->text; + ret = d->toString(); break; case PhraseData::WithVariant: @@ -755,14 +809,139 @@ SqlGeneratorBase::operatorString(const PhraseData::Condition &cond) const case PhraseData::Divide: return "/"; - case PhraseData::Set: - return "="; +// case PhraseData::Set: +// return "="; - case PhraseData::Append: - return ","; +// case PhraseData::Append: +// return ","; + + case PhraseData::Between: + return "BETWEEN"; + + case PhraseData::Mod: + return "MOD"; default: - return QString(""); + return QString(" %1").arg(cond); + } +} + + +QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const +{ + if (!d) + return ""; + + QString ret = ""; + + PhraseData::Condition op = d->operatorCond; + //apply not (!) + if (d->isNot) { + if (op < 20) + op = (PhraseData::Condition)((op + 10) % 20); + } + switch (d->type) { + case PhraseData::Field: + ret = d->toString(); + break; + + case PhraseData::WithVariant: + if (op == PhraseData::AddYears) + ret = QString("DATEADD(year, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMonths) + ret = QString("DATEADD(month, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else if (op == PhraseData::AddYears) + ret = QString("DATEADD(day, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else if (op == PhraseData::AddHours) + ret = QString("DATEADD(hour, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else if (op == PhraseData::AddMinutes) + ret = QString("DATEADD(minute, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else if (op == PhraseData::AddSeconds) + ret = QString("DATEADD(second, %1, %2)") + .arg(d->operand.toString()).arg(createConditionalPhrase(d->left)); + else + ret = createConditionalPhrase(d->left) + " " + operatorString(op) + " " + + escapeValue(d->operand); + break; + + case PhraseData::WithOther: + ret = createConditionalPhrase(d->left) + " " + operatorString(op) + " " + + createConditionalPhrase(d->right); + break; + + case PhraseData::WithoutOperand: + ret = createConditionalPhrase(d->left) + " " + operatorString(op); + break; + + default: + ret = ""; + } + + if (d->operatorCond == PhraseData::And || d->operatorCond == PhraseData::Or) + ret = "(" + ret + ")"; + + return ret; +} + +QString SqlGeneratorBase::createOrderPhrase(const PhraseList &ph) +{ + QString ret = ""; + foreach (const PhraseData *d, ph.data) { + if (ret != "") + ret.append(", "); + ret.append(d->toString()); + if (d->isNot) + ret.append(" DESC"); + } + + return ret; +} + +QString SqlGeneratorBase::createFieldPhrase(const PhraseList &ph) +{ + QString ret = ""; + foreach (const PhraseData *d, ph.data) { + if (ret != "") + ret.append(", "); + ret.append(d->toString()); + if (d->isNot) + qDebug() << "Operator ! is ignored in fields phrase"; + } + return ret; +} + +void SqlGeneratorBase::createInsertPhrase(const AssignmentPhraseList &ph, QString &fields, QString &values) +{ + foreach (PhraseData *d, ph.data) { + if (fields != "") + fields.append(", "); + + if (values != "") + values.append(", "); + + switch (d->type) { + case PhraseData::WithVariant: + fields.append(d->left->toString()); + values.append(escapeValue(d->operand)); +// ret = createConditionalPhrase(d->left->toString()) + " " + operatorString(d->operatorCond) + " " +// + escapeValue(d->operand); + break; + + case PhraseData::WithOther: + fields.append(d->left->toString()); + values.append(d->right->toString()); + break; + + case PhraseData::Field: + case PhraseData::WithoutOperand: + default: + qFatal("Invalid insert command"); + } } } diff --git a/src/generators/sqlgeneratorbase_p.h b/src/generators/sqlgeneratorbase_p.h index 74e2d6c..897d251 100644 --- a/src/generators/sqlgeneratorbase_p.h +++ b/src/generators/sqlgeneratorbase_p.h @@ -24,7 +24,8 @@ #include #include #include -#include "../wherephrase.h" +#include "../phrase.h" +//#include "../wherephrase.h" NUT_BEGIN_NAMESPACE @@ -47,7 +48,7 @@ public: Delete }; enum AgregateType{ - SelectAll, +// SelectAll, Count, Min, Max, @@ -83,28 +84,51 @@ public: virtual QString deleteRecord(Table *t, QString tableName); virtual QString deleteRecords(QString tableName, QString where); - virtual QString selectCommand(AgregateType t, - QString agregateArg, QString tableName, - QList &wheres, - QList &orders, - QList joins, - int skip = -1, int take = -1); + virtual QString selectCommand(const QString &tableName, + const PhraseList &fields, + const ConditionalPhrase &where, + const PhraseList &order, + const QList joins, + const int skip = -1, + const int take = -1); - virtual QString deleteCommand(QList &wheres, QString tableName); + virtual QString selectCommand(const QString &tableName, + const AgregateType &t, const QString &agregateArg, + const ConditionalPhrase &where, + const QList &joins, + const int skip = -1, + const int take = -1); - virtual QString updateCommand(WherePhrase &phrase, QList &wheres, QString tableName); + virtual QString deleteCommand(const QString &tableName, + const ConditionalPhrase &where); + virtual QString updateCommand(const QString &tableName, + const AssignmentPhraseList &assigments, + const ConditionalPhrase &where); +// virtual QString selectCommand(AgregateType t, +// QString agregateArg, QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, +// int skip = -1, int take = -1); + +// virtual QString deleteCommand(QList &wheres, QString tableName); + +// virtual QString updateCommand(WherePhrase &phrase, QList &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 phraseUpdate(const PhraseData *d) const; virtual QString operatorString(const PhraseData::Condition &cond) const; - QString phraseOrder(const PhraseData *d) const; private: + 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); + QString agregateText(const AgregateType &t, const QString &arg = QString::null) const; QString fromTableText(const QString &tableName, QString &joinClassName, QString &orderBy) const; - QString createWhere(QList &wheres); +// QString createWhere(QList &wheres); void replaceTableNames(QString &command); void removeTableNames(QString &command); }; diff --git a/src/generators/sqlitegenerator.cpp b/src/generators/sqlitegenerator.cpp index bddd186..9b71f2e 100644 --- a/src/generators/sqlitegenerator.cpp +++ b/src/generators/sqlitegenerator.cpp @@ -71,24 +71,24 @@ QString SqliteGenerator::fieldType(FieldModel *field) return dbType; } -QString SqliteGenerator::selectCommand(SqlGeneratorBase::AgregateType t, - QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, - int skip, int take) -{ - QString command = SqlGeneratorBase::selectCommand(t, agregateArg, - tableName, - wheres, orders, - joins, skip, take); +//QString SqliteGenerator::selectCommand(SqlGeneratorBase::AgregateType t, +// QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, +// int skip, int take) +//{ +// QString command = SqlGeneratorBase::selectCommand(t, agregateArg, +// tableName, +// wheres, orders, +// joins, skip, take); - if (take != -1 && skip != -1) - command.append(QString(" LIMIT %1 OFFSET %2") - .arg(take) - .arg(skip)); - return command; -} +// if (take != -1 && skip != -1) +// command.append(QString(" LIMIT %1 OFFSET %2") +// .arg(take) +// .arg(skip)); +// return command; +//} NUT_END_NAMESPACE diff --git a/src/generators/sqlitegenerator.h b/src/generators/sqlitegenerator.h index eeefffa..d1140a9 100644 --- a/src/generators/sqlitegenerator.h +++ b/src/generators/sqlitegenerator.h @@ -33,11 +33,11 @@ public: QString fieldType(FieldModel *field); - QString selectCommand(AgregateType t, QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, int skip, int take); +// QString selectCommand(AgregateType t, QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, int skip, int take); }; NUT_END_NAMESPACE diff --git a/src/generators/sqlservergenerator.cpp b/src/generators/sqlservergenerator.cpp index d1c5b3c..13f43fd 100644 --- a/src/generators/sqlservergenerator.cpp +++ b/src/generators/sqlservergenerator.cpp @@ -133,23 +133,23 @@ QString SqlServerGenerator::escapeValue(const QVariant &v) const return SqlGeneratorBase::escapeValue(v); } -QString SqlServerGenerator::selectCommand(SqlGeneratorBase::AgregateType t, - QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, int skip, int take) -{ - QString command = SqlGeneratorBase::selectCommand(t, agregateArg, - tableName, - wheres, orders, - joins, skip, take); +//QString SqlServerGenerator::selectCommand(SqlGeneratorBase::AgregateType t, +// QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, int skip, int take) +//{ +// QString command = SqlGeneratorBase::selectCommand(t, agregateArg, +// tableName, +// wheres, orders, +// joins, skip, take); - if (take != -1 && skip != -1) - command.append(QString("OFFSET %1 ROWS FETCH NEXT %2 ROWS ONLY") - .arg(skip) - .arg(take)); - return command; -} +// if (take != -1 && skip != -1) +// command.append(QString("OFFSET %1 ROWS FETCH NEXT %2 ROWS ONLY") +// .arg(skip) +// .arg(take)); +// return command; +//} NUT_END_NAMESPACE diff --git a/src/generators/sqlservergenerator.h b/src/generators/sqlservergenerator.h index 9368050..db47268 100644 --- a/src/generators/sqlservergenerator.h +++ b/src/generators/sqlservergenerator.h @@ -38,11 +38,11 @@ public: QString escapeValue(const QVariant &v) const; - QString selectCommand(AgregateType t, QString agregateArg, - QString tableName, - QList &wheres, - QList &orders, - QList joins, int skip, int take); +// QString selectCommand(AgregateType t, QString agregateArg, +// QString tableName, +// QList &wheres, +// QList &orders, +// QList joins, int skip, int take); }; NUT_END_NAMESPACE diff --git a/src/phrase.cpp b/src/phrase.cpp new file mode 100644 index 0000000..ef2c143 --- /dev/null +++ b/src/phrase.cpp @@ -0,0 +1,367 @@ +/************************************************************************** +** +** 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 . +** +**************************************************************************/ + +#include "phrase.h" + +#include + +NUT_BEGIN_NAMESPACE + +#define LOG(s) qDebug() << __func__ << s; + +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) +{ } + +PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) + : className(0), fieldName(0), + type(WithoutOperand), operatorCond(o), left(l), right(0), isNot(false) +{ } + +PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, + const PhraseData *r) + : className(0), fieldName(0), + type(WithOther), operatorCond(o), left(l), right(r), isNot(false) +{ } + +PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r) + : className(0), fieldName(0), + type(WithVariant), operatorCond(o), left(l), operand(r), isNot(false) +{ } + +PhraseData::PhraseData(const PhraseData *other) +{ + left = other->left; + right = other->right; + operand = other->operand; + operatorCond = other->operatorCond; + className = other->className; + fieldName = other->fieldName; + type = other->type; +} + +QString PhraseData::toString() const +{ + return QString("[%1].%2").arg(className).arg(fieldName); +} + +PhraseData::~PhraseData() +{ +// if (type == WithOther) { +// delete left; +// delete right; +// } +// if (type == WithVariant) { +// if (left) +// delete left; +// } + LOG(""); +} + +AbstractFieldPhrase::AbstractFieldPhrase(const char *className, const char *fieldName) + :data(new PhraseData(className, fieldName)) +{ + qDebug() <<"AbstractFieldPhrase created"<toString()); + } else { + LOG(""); + } + + if (data) { + delete data; + data = 0; + } +} + +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(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 !() +{ + //TODO: classname and s + AbstractFieldPhrase f(data->className, data->fieldName); + f.data = new PhraseData(data); + 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 AbstractFieldPhrase &other) : isValid(true) +{ + data.append(other.data); +} + +PhraseList::PhraseList(AbstractFieldPhrase *left, const AbstractFieldPhrase *right) + : isValid(true) +{ + data.append(left->data); + data.append(right->data); +} + +PhraseList::PhraseList(PhraseList *left, PhraseList *right) : isValid(true) +{ + data = left->data; + data.append(right->data); +} + +PhraseList::PhraseList(PhraseList *left, const AbstractFieldPhrase *right) + : isValid(true) +{ + data = left->data; + data.append(right->data); +} + +PhraseList::~PhraseList() +{ + data.clear(); +} + +PhraseList PhraseList::operator |(const AbstractFieldPhrase &other) { + return PhraseList(this, &other); +} + +PhraseList PhraseList::operator |(PhraseList &other) { + return PhraseList(this, &other); +} + +AssignmentPhrase::AssignmentPhrase(AbstractFieldPhrase *l, 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 *l, const AssignmentPhrase *r) +//{ +//// data = new PhraseData(l->data, PhraseData::Append, r->data); +// qFatal("SS"); +//} + +AssignmentPhraseList AssignmentPhrase::operator &(const AssignmentPhrase &other) +{ + return AssignmentPhraseList(this, &other); +} + +AssignmentPhraseList::AssignmentPhraseList(const AssignmentPhrase &l) +{ + data.append(l.data); +} + +AssignmentPhraseList::AssignmentPhraseList(AssignmentPhraseList *l, const AssignmentPhrase *r) +{ + data.append(l->data); + data.append(r->data); +} + +AssignmentPhraseList::AssignmentPhraseList(AssignmentPhrase *l, const AssignmentPhrase *r) +{ + data.append(l->data); + data.append(r->data); +} + +AssignmentPhraseList AssignmentPhraseList::operator &(const AssignmentPhrase &ph) +{ + return AssignmentPhraseList(this, &ph); +} + +ConditionalPhrase::ConditionalPhrase() +{ + this->data = 0; +} + +ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &other) +{ + qDebug() << "************* ctor called:"; + this->data = new PhraseData(other.data); +} + +ConditionalPhrase::ConditionalPhrase(const ConditionalPhrase &&other) +{ + qDebug() << "************* ctor called:"; + this->data = new PhraseData(other.data); +} + +ConditionalPhrase::ConditionalPhrase(const PhraseData *data) +{ + this->data = new PhraseData(data); +} + +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() +{ + LOG(""); + if (data) + delete data; +} + +ConditionalPhrase ConditionalPhrase::operator =(const ConditionalPhrase &other) +{ + return ConditionalPhrase(other.data); + const_cast(other).data = 0; +} + +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(other)); +} + +ConditionalPhrase ConditionalPhrase::operator ||(const ConditionalPhrase &other) +{ + return ConditionalPhrase(this, PhraseData::Or, + const_cast(other)); +} + +ConditionalPhrase ConditionalPhrase::operator !() +{ + ConditionalPhrase f(data); + f.data->isNot = !data->isNot; + return f; +} + +NUT_END_NAMESPACE diff --git a/src/phrase.h b/src/phrase.h new file mode 100644 index 0000000..52bc187 --- /dev/null +++ b/src/phrase.h @@ -0,0 +1,391 @@ +/************************************************************************** +** +** 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 . +** +**************************************************************************/ + +#ifndef PHRASE_H +#define PHRASE_H + +#include +#include +#include +#include +#if __cplusplus >= 201103L +# include +#endif + +#include "defines.h" + +NUT_BEGIN_NAMESPACE + +#define SPECIALIZATION_NUMERIC_MEMBER(type, op, cond) \ +ConditionalPhrase operator op(const QVariant &other) \ +{ \ + return ConditionalPhrase(this, cond, other); \ +} + +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, + +// Append, +// Set, + + 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; + Condition operatorCond; + + const PhraseData *left; + const PhraseData *right; + + QVariant operand; + bool isNot; + + PhraseData(const char *className, const char *fieldName); + PhraseData(PhraseData *l, Condition o); + PhraseData(PhraseData *l, Condition o, const PhraseData *r); + PhraseData(PhraseData *l, Condition o, QVariant r); + + PhraseData(const PhraseData *other); + + QString toString() const; + + ~PhraseData(); +}; + +class AssignmentPhraseList +{ +public: + QList data; + AssignmentPhraseList(const AssignmentPhrase &l); + AssignmentPhraseList(AssignmentPhraseList *l, const AssignmentPhrase *r); + AssignmentPhraseList(AssignmentPhrase *l, const AssignmentPhrase *r); + + AssignmentPhraseList operator &(const AssignmentPhrase &ph); +}; + +class AssignmentPhrase +{ +public: + PhraseData *data; + AssignmentPhrase(AbstractFieldPhrase *l, QVariant r); + AssignmentPhrase(AbstractFieldPhrase *l, const AssignmentPhrase *r); +// AssignmentPhrase(AssignmentPhrase *l, const AssignmentPhrase *r); + + AssignmentPhraseList operator &(const AssignmentPhrase &other); + +}; + +class PhraseList{ +public: + bool isValid; + QList data; + PhraseList(); + PhraseList(const AbstractFieldPhrase &other); + PhraseList(AbstractFieldPhrase *left, const AbstractFieldPhrase *right); + PhraseList(PhraseList *left, PhraseList *right); + PhraseList(PhraseList *left, const AbstractFieldPhrase *right); + virtual ~PhraseList(); + + PhraseList operator |(PhraseList &other); + PhraseList operator |(const AbstractFieldPhrase &other); +}; + +class ConditionalPhrase +{ +public: + PhraseData *data; + QSharedPointer leftDataPointer; + QSharedPointer rightDataPointer; + ConditionalPhrase(); + ConditionalPhrase(const ConditionalPhrase &other); + ConditionalPhrase(const ConditionalPhrase &&other); + 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) +}; + +class AbstractFieldPhrase +{ +public: + PhraseData *data; + AbstractFieldPhrase(const char *className, const char *fieldName); + AbstractFieldPhrase(const AbstractFieldPhrase &other); + + virtual ~AbstractFieldPhrase(); + + PhraseList operator |(const AbstractFieldPhrase &other); + + template + ConditionalPhrase in(QList list) + { + QVariantList vlist; + foreach (T t, list) + vlist.append(QVariant::fromValue(t)); + + return ConditionalPhrase(this, PhraseData::In, vlist); + } +#if __cplusplus >= 201103L + ConditionalPhrase in(std::initializer_list list) { + QVariantList vlist; + std::initializer_list::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 +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 : 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 &other) { + return AssignmentPhrase(this, other); + } +}; + +#define SPECIALIZATION_NUMERIC(type) \ +template<> \ +class FieldPhrase : 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 : 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 : 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 : 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) +}; + +NUT_END_NAMESPACE + +#endif // PHRASE_H diff --git a/src/query.h b/src/query.h index 490b16e..2d37018 100644 --- a/src/query.h +++ b/src/query.h @@ -36,7 +36,7 @@ #include "tablesetbase_p.h" #include "generators/sqlgeneratorbase_p.h" #include "querybase_p.h" -#include "wherephrase.h" +#include "phrase.h" #include "tablemodel.h" NUT_BEGIN_NAMESPACE @@ -54,7 +54,6 @@ public: ~Query(); //ddl - Query *setWhere(WherePhrase where); Query *join(const QString &className); Query *join(Table *c); @@ -69,8 +68,11 @@ public: // Query *orderBy(QString fieldName, QString type); Query *skip(int n); Query *take(int n); - Query *fields(WherePhrase phrase); - Query *orderBy(WherePhrase phrase); + Query *fields(const PhraseList &ph); + Query *orderBy(const PhraseList &ph); + Query *where(const ConditionalPhrase &ph); + Query *setWhere(const ConditionalPhrase &ph); + Query *include(TableSetBase *t); Query *include(Table *t); @@ -85,7 +87,8 @@ public: QVariant average(const FieldPhrase &f); //data mailpulation - int update(WherePhrase phrase); + int update(const AssignmentPhraseList &ph); +// int insert(const AssignmentPhraseList &ph); int remove(); QSqlQueryModel *toModal(); @@ -122,6 +125,7 @@ Q_OUTOFLINE_TEMPLATE Query::~Query() { Q_D(Query); delete d; + qDebug() << "~Query"; } template @@ -133,10 +137,9 @@ Q_OUTOFLINE_TEMPLATE QList Query::toList(int count) d->select = "*"; d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::SelectAll, "", - d->tableName, - d->wheres, d->orderPhrases, d->relations, - d->skip, d->take); + d->tableName, d->fieldPhrase, d->wherePhrase, d->orderPhrase, + d->relations, d->skip, d->take); + QSqlQuery q = d->database->exec(d->sql); if (q.lastError().isValid()) { qDebug() << q.lastError().text(); @@ -300,9 +303,11 @@ Q_OUTOFLINE_TEMPLATE QList Query::select(const FieldPhrase f) d->joins.prepend(d->tableName); d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::SignleField, f.data()->text, - d->tableName, d->wheres, - d->orderPhrases, d->relations, d->skip, d->take); + d->tableName, + SqlGeneratorBase::SignleField, f.data->toString(), + d->wherePhrase, + d->relations, + d->skip, d->take); QSqlQuery q = d->database->exec(d->sql); @@ -336,12 +341,12 @@ Q_OUTOFLINE_TEMPLATE int Query::count() d->joins.prepend(d->tableName); d->select = "COUNT(*)"; - d->sql = d->database->sqlGenertor()->selectCommand(SqlGeneratorBase::Count, - QStringLiteral("*"), - d->tableName, - d->wheres, - d->orderPhrases, - d->relations); + d->sql = d->database->sqlGenertor()->selectCommand( + d->tableName, + SqlGeneratorBase::Count, + QStringLiteral("*"), + d->wherePhrase, + d->relations); QSqlQuery q = d->database->exec(d->sql); if (q.next()) @@ -356,8 +361,9 @@ Q_OUTOFLINE_TEMPLATE QVariant Query::max(const FieldPhrase &f) d->joins.prepend(d->tableName); d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::Max, f.data()->text, d->tableName, - d->wheres, d->orderPhrases, + d->tableName, + SqlGeneratorBase::Max, f.data->toString(), + d->wherePhrase, d->relations); QSqlQuery q = d->database->exec(d->sql); @@ -373,8 +379,9 @@ Q_OUTOFLINE_TEMPLATE QVariant Query::min(const FieldPhrase &f) d->joins.prepend(d->tableName); d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::Min, f.data()->text, d->tableName, - d->wheres, d->orderPhrases, + d->tableName, + SqlGeneratorBase::Min, f.data->toString(), + d->wherePhrase, d->relations); QSqlQuery q = d->database->exec(d->sql); @@ -390,8 +397,9 @@ Q_OUTOFLINE_TEMPLATE QVariant Query::average(const FieldPhrase &f) d->joins.prepend(d->tableName); d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::Average, f.data()->text, d->tableName, - d->wheres, d->orderPhrases, + d->tableName, + SqlGeneratorBase::Average, f.data->toString(), + d->wherePhrase, d->relations); QSqlQuery q = d->database->exec(d->sql); @@ -430,10 +438,18 @@ Q_OUTOFLINE_TEMPLATE Query *Query::join(Table *c) } template -Q_OUTOFLINE_TEMPLATE Query *Query::setWhere(WherePhrase where) +Q_OUTOFLINE_TEMPLATE Query *Query::where(const ConditionalPhrase &ph) { Q_D(Query); - d->wheres.append(where); + d->wherePhrase = d->wherePhrase && ph; + return this; +} + +template +Q_OUTOFLINE_TEMPLATE Query *Query::setWhere(const ConditionalPhrase &ph) +{ + Q_D(Query); + d->wherePhrase = ph; return this; } @@ -454,10 +470,10 @@ Q_OUTOFLINE_TEMPLATE Query *Query::take(int n) } template -Q_OUTOFLINE_TEMPLATE Query *Query::fields(WherePhrase phrase) +Q_OUTOFLINE_TEMPLATE Query *Query::fields(const PhraseList &ph) { Q_D(Query); - d->fields.append(phrase); + d->fieldPhrase = ph; return this; } @@ -471,10 +487,10 @@ Q_OUTOFLINE_TEMPLATE Query *Query::fields(WherePhrase phrase) //} template -Q_OUTOFLINE_TEMPLATE Query *Query::orderBy(WherePhrase phrase) +Q_OUTOFLINE_TEMPLATE Query *Query::orderBy(const PhraseList &ph) { Q_D(Query); - d->orderPhrases.append(phrase); + d->orderPhrase = ph; return this; } @@ -493,12 +509,14 @@ Q_OUTOFLINE_TEMPLATE Query *Query::include(Table *t) } template -Q_OUTOFLINE_TEMPLATE int Query::update(WherePhrase phrase) +Q_OUTOFLINE_TEMPLATE int Query::update(const AssignmentPhraseList &ph) { Q_D(Query); - d->sql = d->database->sqlGenertor()->updateCommand(phrase, d->wheres, - d->tableName); + d->sql = d->database->sqlGenertor()->updateCommand( + d->tableName, + ph, + d->wherePhrase); QSqlQuery q = d->database->exec(d->sql); if (m_autoDelete) @@ -511,7 +529,8 @@ Q_OUTOFLINE_TEMPLATE int Query::remove() { Q_D(Query); - d->sql = d->database->sqlGenertor()->deleteCommand(d->wheres, d->tableName); + d->sql = d->database->sqlGenertor()->deleteCommand( + d->tableName, d->wherePhrase); QSqlQuery q = d->database->exec(d->sql); if (m_autoDelete) @@ -522,32 +541,32 @@ Q_OUTOFLINE_TEMPLATE int Query::remove() template Q_OUTOFLINE_TEMPLATE QSqlQueryModel *Query::toModal() { - Q_D(Query); +// Q_D(Query); - QString fff = ""; +// QString fff = ""; - foreach (WherePhrase p, d->fields) { - if (fff != "") - fff.append(", "); - fff.append(d->database->sqlGenertor()->phraseOrder(p.data())); - } +// foreach (WherePhrase p, d->fields) { +// if (fff != "") +// fff.append(", "); +// fff.append(d->database->sqlGenertor()->phraseOrder(p.data())); +// } - d->sql = d->database->sqlGenertor()->selectCommand( - SqlGeneratorBase::SelectAll, "", - d->tableName, - d->wheres, d->orderPhrases, d->relations, - d->skip, d->take); - qDebug()<<"Model to" << fff; - QSqlQueryModel *model = new QSqlQueryModel; - TableModel *tableModel = d->database->model().tableByName(d->tableName); - model->setQuery(d->sql, d->database->database()); +// d->sql = d->database->sqlGenertor()->selectCommand( +// SqlGeneratorBase::SelectAll, "", +// d->tableName, +// d->wheres, d->orderPhrases, d->relations, +// d->skip, d->take); +// qDebug()<<"Model to" << fff; +// QSqlQueryModel *model = new QSqlQueryModel; +// TableModel *tableModel = d->database->model().tableByName(d->tableName); +// model->setQuery(d->sql, d->database->database()); - int fieldIndex = 0; - foreach (FieldModel *f, tableModel->fields()) { - model->setHeaderData(fieldIndex++, Qt::Horizontal, f->displayName); - } - return model; +// int fieldIndex = 0; +// foreach (FieldModel *f, tableModel->fields()) { +// model->setHeaderData(fieldIndex++, Qt::Horizontal, f->displayName); +// } +// return model; } template diff --git a/src/query_p.h b/src/query_p.h index bcf4180..75c8f3b 100644 --- a/src/query_p.h +++ b/src/query_p.h @@ -21,7 +21,7 @@ #ifndef QUERY_P_H #define QUERY_P_H -#include "wherephrase.h" +#include "phrase.h" #include #include @@ -48,12 +48,15 @@ public: TableSetBase *tableSet; QStringList joins; QList relations; - QList wheres; - QList orderPhrases; - QList fields; - QHash orders; int skip; int take; + PhraseList orderPhrase, fieldPhrase; + ConditionalPhrase wherePhrase; + +// QList wheres; +// QList orderPhrases; +// QList fields; +// QHash orders; }; NUT_END_NAMESPACE diff --git a/src/table.h b/src/table.h index 0262328..544de25 100644 --- a/src/table.h +++ b/src/table.h @@ -27,7 +27,7 @@ #include "tablemodel.h" #include "defines.h" -#include "wherephrase.h" +#include "phrase.h" NUT_BEGIN_NAMESPACE diff --git a/src/wherephrase.cpp b/src/wherephrase.cpp index af0514c..3a3213e 100644 --- a/src/wherephrase.cpp +++ b/src/wherephrase.cpp @@ -21,7 +21,7 @@ #include #include -#include "wherephrase.h" +#include "phrase.h" NUT_BEGIN_NAMESPACE diff --git a/src/wherephrase.h b/src/wherephrase.h index 371a640..8d33b75 100644 --- a/src/wherephrase.h +++ b/src/wherephrase.h @@ -18,8 +18,8 @@ ** **************************************************************************/ -#ifndef PHRASE_H -#define PHRASE_H +#ifndef WHEREPHRASE_H +#define WHEREPHRASE_H #include @@ -39,58 +39,58 @@ NUT_BEGIN_NAMESPACE class SqlGeneratorBase; -class PhraseData -{ -public: - enum Condition { - NotAssign = 0, - Equal, - Less, - LessEqual, - Null, - In, - Like, +//class PhraseData +//{ +//public: +// enum Condition { +// NotAssign = 0, +// Equal, +// Less, +// LessEqual, +// Null, +// In, +// Like, - Not = 10, - NotEqual, - GreaterEqual, - Greater, - NotNull, - NotIn, - NotLike, +// Not = 10, +// NotEqual, +// GreaterEqual, +// Greater, +// NotNull, +// NotIn, +// NotLike, - And = 20, - Or, +// And = 20, +// Or, - Append, - Set, +// Append, +// Set, - Add, - Minus, - Multiple, - Divide, +// Add, +// Minus, +// Multiple, +// Divide, - // special types - Distance - }; +// // special types +// Distance +// }; - enum Type { Field, WithVariant, WithOther, WithoutOperand }; - Type type; +// enum Type { Field, WithVariant, WithOther, WithoutOperand }; +// Type type; - Condition operatorCond; +// Condition operatorCond; - QString text; - const PhraseData *left; - const PhraseData *right; - QVariant operand; +// QString text; +// const PhraseData *left; +// const PhraseData *right; +// QVariant operand; - PhraseData(const char *className, const char *s); - PhraseData(PhraseData *l, Condition o); - PhraseData(PhraseData *l, Condition o, const PhraseData *r); - PhraseData(PhraseData *l, Condition o, QVariant r); +// PhraseData(const char *className, const char *s); +// PhraseData(PhraseData *l, Condition o); +// PhraseData(PhraseData *l, Condition o, const PhraseData *r); +// PhraseData(PhraseData *l, Condition o, QVariant r); - ~PhraseData(); -}; +// ~PhraseData(); +//}; class WherePhrase { diff --git a/test/basic/maintest.cpp b/test/basic/maintest.cpp index cc77796..5bc22f3 100644 --- a/test/basic/maintest.cpp +++ b/test/basic/maintest.cpp @@ -42,8 +42,8 @@ void MainTest::initTestCase() bool ok = db.open(); - db.comments()->query()->remove(); - db.posts()->query()->remove(); + db.commentTable()->query()->remove(); + db.postTable()->query()->remove(); QTEST_ASSERT(ok); } @@ -63,7 +63,7 @@ void MainTest::createUser() user = new User; user->setUsername("admin"); user->setPassword("123456"); - db.users()->append(user); + db.userTable()->append(user); db.saveChanges(); } @@ -73,7 +73,7 @@ void MainTest::createPost() newPost->setTitle("post title"); newPost->setSaveDate(QDateTime::currentDateTime()); - db.posts()->append(newPost); + db.postTable()->append(newPost); for(int i = 0 ; i < 3; i++){ Comment *comment = new Comment; @@ -102,7 +102,7 @@ void MainTest::createPost2() newPost->setTitle("post title"); newPost->setSaveDate(QDateTime::currentDateTime()); - db.posts()->append(newPost); + db.postTable()->append(newPost); db.saveChanges(); for(int i = 0 ; i < 3; i++){ @@ -111,7 +111,7 @@ void MainTest::createPost2() comment->setSaveDate(QDateTime::currentDateTime()); comment->setAuthor(user); comment->setPostId(newPost->id()); - db.comments()->append(comment); + db.commentTable()->append(comment); } db.saveChanges(); @@ -121,9 +121,9 @@ void MainTest::createPost2() void MainTest::selectPosts() { - auto q = db.posts()->query() + auto q = db.postTable()->query() ->join()//Comment::authorIdField() == Post::idField()) - ->orderBy(!Post::saveDateField() & Post::bodyField()) + ->orderBy(!Post::saveDateField() | Post::bodyField()) ->setWhere(Post::idField() == postId); auto posts = q->toList(); @@ -144,7 +144,7 @@ void MainTest::selectPosts() void MainTest::selectScoreAverage() { - auto a = db.scores()->query() + auto a = db.scoreTable()->query() ->join() ->setWhere(Post::idField() == 1) ->average(Score::scoreField()); @@ -153,7 +153,7 @@ void MainTest::selectScoreAverage() void MainTest::selectFirst() { - auto posts = db.posts()->query() + auto posts = db.postTable()->query() ->first(); QTEST_ASSERT(posts != Q_NULLPTR); @@ -161,7 +161,7 @@ void MainTest::selectFirst() void MainTest::selectPostsWithoutTitle() { - auto q = db.posts()->query(); + auto q = db.postTable()->query(); q->setWhere(Post::titleField().isNull()); auto count = q->count(); QTEST_ASSERT(count == 0); @@ -169,8 +169,9 @@ void MainTest::selectPostsWithoutTitle() void MainTest::selectPostIds() { - auto ids = db.posts()->query()->select(Post::idField()); - + auto q = db.postTable()->query(); + auto ids = q->select(Post::idField()); +qDebug() << q->sqlCommand(); QTEST_ASSERT(ids.count() == 2); } @@ -184,11 +185,11 @@ void MainTest::testDate() newPost->setTitle("post title"); newPost->setSaveDate(d); - db.posts()->append(newPost); + db.postTable()->append(newPost); db.saveChanges(); - auto q = db.posts()->query() + auto q = db.postTable()->query() ->setWhere(Post::idField() == newPost->id()) ->first(); @@ -198,7 +199,7 @@ void MainTest::testDate() void MainTest::join() { TIC(); - auto q = db.comments()->query() + auto q = db.commentTable()->query() ->join() ->join(); @@ -213,14 +214,14 @@ void MainTest::join() void MainTest::selectWithInvalidRelation() { - auto q = db.posts()->query(); + auto q = db.postTable()->query(); q->join("Invalid_Class_Name"); q->toList(); } void MainTest::modifyPost() { - auto q = db.posts()->query(); + auto q = db.postTable()->query(); q->setWhere(Post::idField() == postId); Post *post = q->first(); @@ -230,7 +231,7 @@ void MainTest::modifyPost() post->setTitle("new name"); db.saveChanges(); - q = db.posts()->query() + q = db.postTable()->query() ->setWhere(Post::idField() == postId); post = q->first(); @@ -240,8 +241,8 @@ void MainTest::modifyPost() void MainTest::emptyDatabase() { - auto commentsCount = db.comments()->query()->remove(); - auto postsCount = db.posts()->query()->remove(); + auto commentsCount = db.commentTable()->query()->remove(); + auto postsCount = db.postTable()->query()->remove(); QTEST_ASSERT(postsCount == 3); QTEST_ASSERT(commentsCount == 6); } diff --git a/test/common/post.h b/test/common/post.h index c8e7994..ddf7936 100644 --- a/test/common/post.h +++ b/test/common/post.h @@ -2,6 +2,7 @@ #define POST_H #include +#include #include "table.h" #include "database.h" #include "databasemodel.h" diff --git a/test/common/weblogdatabase.cpp b/test/common/weblogdatabase.cpp index cf459b9..d020e2b 100644 --- a/test/common/weblogdatabase.cpp +++ b/test/common/weblogdatabase.cpp @@ -8,9 +8,9 @@ #include "weblogdatabase.h" WeblogDatabase::WeblogDatabase() : Database(), - m_posts(new TableSet(this)), - m_comments(new TableSet(this)), - m_users(new TableSet(this)), - m_scores(new TableSet(this)) + m_postTable(new TableSet(this)), + m_commentTable(new TableSet(this)), + m_userTable(new TableSet(this)), + m_scoreTable(new TableSet(this)) { } diff --git a/test/phrases/maintest.cpp b/test/phrases/maintest.cpp new file mode 100644 index 0000000..8eaecb3 --- /dev/null +++ b/test/phrases/maintest.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include "maintest.h" +#include "phrase.h" + +using namespace Nut; + +MainTest::MainTest(QObject *parent) : QObject(parent) +{ +} + +void MainTest::initTestCase() +{ + +} + +void MainTest::no1() +{ + FieldPhrase id("main", "id"); + FieldPhrase name("main", "name"); + FieldPhrase last_name("main", "last_name"); + FieldPhrase date("main", "date"); + auto w = id == 4 && name == "salam"; +} + +QTEST_MAIN(MainTest) diff --git a/test/phrases/maintest.h b/test/phrases/maintest.h new file mode 100644 index 0000000..5c7304e --- /dev/null +++ b/test/phrases/maintest.h @@ -0,0 +1,23 @@ +#ifndef MAINTEST_H +#define MAINTEST_H + +#include +#include + +class Post; +class User; +class MainTest : public QObject +{ + Q_OBJECT + +public: + explicit MainTest(QObject *parent = 0); + +signals: + +private slots: + void initTestCase(); + void no1(); +}; + +#endif // MAINTEST_H diff --git a/test/phrases/tst_phrases.pro b/test/phrases/tst_phrases.pro new file mode 100644 index 0000000..5dd3829 --- /dev/null +++ b/test/phrases/tst_phrases.pro @@ -0,0 +1,15 @@ +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