diff --git a/doc/nut.index b/doc/nut.index new file mode 100644 index 0000000..deb4f4e --- /dev/null +++ b/doc/nut.index @@ -0,0 +1,5 @@ + + + + + diff --git a/doc/nut.qhp b/doc/nut.qhp new file mode 100644 index 0000000..5d4c609 --- /dev/null +++ b/doc/nut.qhp @@ -0,0 +1,14 @@ + + + + + + +
+
+
+ + + + + diff --git a/doc/nut.qhp.sha1 b/doc/nut.qhp.sha1 new file mode 100644 index 0000000..d04ba34 --- /dev/null +++ b/doc/nut.qhp.sha1 @@ -0,0 +1 @@ +da39a3ee5e6b4b0d3255bfef95601890afd80709 \ No newline at end of file diff --git a/include.tar.gz b/include.tar.gz new file mode 100644 index 0000000..b9d2984 Binary files /dev/null and b/include.tar.gz differ 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 82e7dbe..bd2f947 100644 --- a/nut.pri +++ b/nut.pri @@ -20,7 +20,8 @@ HEADERS += \ $$PWD/src/sqlitegenerator.h \ $$PWD/src/tablemodel.h \ $$PWD/src/sqlservergenerator.h \ - $$PWD/src/wherephrase.h + $$PWD/src/wherephrase.h \ + $$PWD/src/query_p.h SOURCES += \ $$PWD/src/database.cpp \ diff --git a/nut.qdocconf b/nut.qdocconf new file mode 100644 index 0000000..6134af9 --- /dev/null +++ b/nut.qdocconf @@ -0,0 +1,24 @@ +project = Nut +description = Advanced, Powerful and easy to use ORM for Qt5 +version = 0.1 + +outputdir = doc + +source += src/query.cpp +headerdirs += src +sourcedirs += src +exampledirs = . + + + +qhp.projects = Nut + +qhp.qtestclass.file = nut.qhp +qhp.qtestclass.namespace = org.kaj.nut.0.1 +qhp.qtestclass.virtualFolder = nut +qhp.qtestclass.indexTitle = nut +qhp.qtestclass.indexRoot = + +qhp.qtestclass.filterAttributes = nut 0.1 qtrefdoc +qhp.qtestclass.customFilters.Qt.name = qtestclass 0.1 +qhp.qtestclass.customFilters.Qt.filterAttributes = qtestclass 0.1 \ No newline at end of file diff --git a/src/database.cpp b/src/database.cpp index 4139022..75cc7f3 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -65,10 +65,11 @@ bool DatabasePrivate::open() qWarning(db.lastError().text().toLocal8Bit().data()); if(db.lastError().text().contains("database \"" + databaseName + "\" does not exist") - || db.lastError().text().contains("Cannot open database")){ + || db.lastError().text().contains("Cannot open database") + || db.lastError().text().contains("Unknown database '" + databaseName + "'")){ db.setDatabaseName(sqlGenertor->masterDatabaseName(databaseName)); ok = db.open(); - qInfo("Creating database"); + qDebug("Creating database"); if(ok){ db.exec("CREATE DATABASE " + databaseName); db.close(); @@ -89,18 +90,20 @@ bool DatabasePrivate::open() bool DatabasePrivate::updateDatabase() { + Q_Q(Database); + DatabaseModel last = getLastScheema(); DatabaseModel current = currentModel; if(last == current){ - qInfo("Databse is up-to-date"); + qDebug("Databse is up-to-date"); return true; } if(!last.count()) - qInfo("Databse is new"); + qDebug("Databse is new"); else - qInfo("Databse is changed"); + qDebug("Databse is changed"); QStringList sql = sqlGenertor->diff(last, current); db.transaction(); @@ -108,13 +111,26 @@ bool DatabasePrivate::updateDatabase() qDebug() << "going to exec " << s; db.exec(s); - if(!db.lastError().type() == QSqlError::NoError) + if(db.lastError().type() != QSqlError::NoError) qWarning(db.lastError().text().toLatin1().data()); } bool ok = db.commit(); if(ok){ storeScheemaInDB(); + + q->databaseUpdated(last.versionMajor(), last.versionMinor(), current.versionMajor(), current.versionMinor()); + QString versionText = QString::number(current.versionMajor()) + "_" + QString::number(current.versionMinor()); + + for(int i = 0; i < q->metaObject()->methodCount(); i++){ + QMetaMethod m = q->metaObject()->method(i); + if(m.name() == "update" + versionText){ + m.invoke(q, Qt::DirectConnection, + Q_ARG(int, current.versionMajor()), + Q_ARG(int, current.versionMinor())); + break; + } + } }else{ qWarning("Unable update database"); qWarning(db.lastError().text().toLatin1().data()); @@ -135,12 +151,12 @@ QVariantMap DatabasePrivate::getCurrectScheema() for(int i = 0; i < q->metaObject()->classInfoCount(); i++){ QMetaClassInfo ci = q->metaObject()->classInfo(i); - QString ciName = QString(ci.name()).replace(__nut_NAME_PERFIX, ""); + QString ciName = QString(ci.name()).replace(__nut_NAME_PERFIX, "").replace("\"", ""); if(ciName.startsWith(__nut_TABLE)) - tables.insert(QString(ci.name()).replace(__nut_NAME_PERFIX, "").split(" ").at(1), ci.value()); + tables.insert(ciName.split(" ").at(1), ci.value()); if(ciName == __nut_DB_VERSION){ - QStringList version = QString(ci.value()).split('.'); + QStringList version = QString(ci.value()).replace("\"", "").split('.'); bool ok = false; if(version.length() == 1){ currentModel.setVersionMajor(version.at(0).toInt(&ok)); @@ -150,14 +166,14 @@ QVariantMap DatabasePrivate::getCurrectScheema() } 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' or 'x[.y]' only, and x,y must be integer values\n"); } } QVariantMap databaseVariant; for(int i = 1; i < q->metaObject()->propertyCount(); i++){ QMetaProperty tableProperty = q->metaObject()->property(i); - uint typeId = QMetaType::type(tableProperty.typeName()); + int typeId = QMetaType::type(tableProperty.typeName()); if(tables.values().contains(tableProperty.name()) && typeId >= QVariant::UserType){ TableModel *sch = new TableModel(typeId, tableProperty.name()); @@ -220,6 +236,12 @@ void DatabasePrivate::createChangeLogs() db.exec(diff); } + +/*! + * \class Database + * \brief Database class + */ + Database::Database(QObject *parent) : QObject(parent), d_ptr(new DatabasePrivate(this)) { Q_D(Database); @@ -268,6 +290,10 @@ QString Database::driver() const return d->driver; } +/*! + * \brief Database::model + * \return The model of this database + */ DatabaseModel Database::model() const { Q_D(const Database); @@ -328,6 +354,14 @@ SqlGeneratorBase *Database::sqlGenertor() const return d->sqlGenertor; } +void Database::databaseUpdated(int oldMajor, int oldMinor, int newMajor, int newMinor) +{ + Q_UNUSED(oldMajor); + Q_UNUSED(oldMinor); + Q_UNUSED(newMajor); + Q_UNUSED(newMinor); +} + bool Database::open() { Q_D(Database); @@ -357,9 +391,16 @@ bool Database::open() } } +void Database::close() +{ + Q_D(Database); + d->db.close(); +} + QSqlQuery Database::exec(QString sql) { Q_D(Database); + qDebug() <db.exec(sql); if(d->db.lastError().type() != QSqlError::NoError) qWarning(d->db.lastError().text().toLatin1().data()); diff --git a/src/database.h b/src/database.h index 91896da..18de998 100644 --- a/src/database.h +++ b/src/database.h @@ -45,6 +45,7 @@ public: Database(QObject *parent = 0); bool open(); + void close(); QSqlQuery exec(QString sql); @@ -65,6 +66,9 @@ public: SqlGeneratorBase *sqlGenertor() const; +protected: + virtual void databaseUpdated(int oldMajor, int oldMinor, int newMajor, int newMinor); + public slots: void setDatabaseName(QString databaseName); void setHostName(QString hostName); diff --git a/src/database_p.h b/src/database_p.h index 2382105..6ce02b0 100644 --- a/src/database_p.h +++ b/src/database_p.h @@ -27,6 +27,7 @@ #include +QT_BEGIN_NAMESPACE class DatabasePrivate { @@ -63,4 +64,6 @@ public: TableSet *changeLogs; }; +QT_END_NAMESPACE + #endif // DATABASE_P_H diff --git a/src/defines.h b/src/defines.h index 390e54d..d7bd16b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -33,10 +33,10 @@ #endif // Database -#define NUT_DB_VERSION(major, minor) Q_CLASSINFO(__nut_NAME_PERFIX __nut_DB_VERSION, #major "." #minor) +#define NUT_DB_VERSION(major, minor) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX __nut_DB_VERSION), QT_STRINGIFY(#major "." #minor)) #define NUT_DECLARE_TABLE(type, name) \ - Q_CLASSINFO(__nut_NAME_PERFIX __nut_TABLE " " #type, #name) \ + Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX __nut_TABLE " " #type), #name) \ Q_PROPERTY(type* name READ name) \ Q_PROPERTY(TableSet name##s READ name##s) \ type* m_##name; \ @@ -49,7 +49,7 @@ public: \ //Table #define NUT_DECLARE_FIELD(type, name, read, write) \ Q_PROPERTY(type name READ read WRITE write) \ - Q_CLASSINFO(__nut_NAME_PERFIX #name " " __nut_FIELD, #name) \ + Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #name " " __nut_FIELD), #name) \ type m_##name; \ public: \ static FieldPhrase name##Field(){ \ @@ -67,7 +67,7 @@ public: \ #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) \ - Q_CLASSINFO(__nut_NAME_PERFIX #name "Id " __nut_FOREGION_KEY, #type) \ + Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #name "Id " __nut_FOREGION_KEY), #type) \ type *m_##name; \ public: \ type *read() const { return m_##name ; } \ @@ -89,14 +89,14 @@ public: \ #define NUT_INDEX(name, field, order) -#define NUT_PRIMARY_KEY(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_PRIMARY_KEY, #x) -#define NUT_AUTO_INCREMENT(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_AUTO_INCREMENT, #x) +#define NUT_PRIMARY_KEY(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_PRIMARY_KEY), #x) +#define NUT_AUTO_INCREMENT(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_AUTO_INCREMENT), #x) #define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_PRIMARY_KEY(x) \ NUT_AUTO_INCREMENT(x) -#define NUT_UNIQUE(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_UNIQUE, #x) -#define NUT_LEN(x, n) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_LEN, #n) -#define NUT_DEFAULT_VALUE(x, n) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_DEFAULT_VALUE, #n) -#define NUT_NOT_NULL(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_NOT_NULL, "1") +#define NUT_UNIQUE(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_UNIQUE), #x) +#define NUT_LEN(x, n) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_LEN), #n) +#define NUT_DEFAULT_VALUE(x, n) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_DEFAULT_VALUE), #n) +#define NUT_NOT_NULL(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_NOT_NULL), "1") #ifndef NUT_NO_KEYWORDS # define FROM(x) /*QScopedPointer*/(x->createQuery()) @@ -111,4 +111,6 @@ public: \ # define FIRST() ->first() #endif // NUT_NO_KEYWORDS + + #endif // SYNTAX_DEFINES_H diff --git a/src/query.cpp b/src/query.cpp index de01254..4412232 100644 --- a/src/query.cpp +++ b/src/query.cpp @@ -1,4 +1,4 @@ -/************************************************************************** +/*!************************************************************************ ** ** This file is part of Nut project. ** https://github.com/HamedMasafi/Nut @@ -20,4 +20,48 @@ #include "query.h" +QT_BEGIN_NAMESPACE +QueryPrivate::QueryPrivate(QueryBase *parent) : q_ptr(parent), + joinClassName(QString::null) +{ + +} + +/*! + * \class Query + * \brief This class hold a query. A query can be used for getting database rows, editing or deleting without row fetching. + */ + +/*! + * \brief toList + * \param count Total rows must be returned + * \return This function return class itself + * This function return rows + */ + +/*! + * \brief setWhere + * \param where Where phrase + * \return This function return class itself + */ + +/*! + * \brief orderBy + * \param phrase Order phrase + * \return This function return class itself + * orderBy set a new order for this query. Order can be a hrase like that: + * \code + * query->orderBy(Post::idField()); + * \endcode + * If you need more than one order field seprate them by & operator, example: + * \code + * query->orderBy(Post::idField() & Post::bodyField()); + * \endcode + * Order can be also DESC, for that put exclamation mark near field + * \code + * query->orderBy(!Post::idField & Post::bodyField()); + * \endcode + */ + +QT_END_NAMESPACE diff --git a/src/query.h b/src/query.h index 99c32d3..029f675 100644 --- a/src/query.h +++ b/src/query.h @@ -26,6 +26,7 @@ #include #include +#include "query_p.h" #include "database.h" #include "databasemodel.h" #include "tablesetbase_p.h" @@ -38,74 +39,87 @@ QT_BEGIN_NAMESPACE template class NUT_EXPORT Query : public QueryBase { - QString _tableName; - QString _select; -// QString _where; - Database *_database; - TableSetBase *_tableSet; - QString _joinClassName; - QList _wheres; + QueryPrivate *d_ptr; + Q_DECLARE_PRIVATE(Query) + public: Query(Database *database, TableSetBase *tableSet); - - Query(TableSet *tset){ - _database = tset->database(); - _tableName = _database->tableName(T::staticMetaObject.className()); - } + ~Query(); QList toList(int count = -1); - T *first(); - int count(); int remove(); + T *first(); + + int count(); + + QVariant max(FieldPhrase &f); + QVariant min(FieldPhrase &f); + QVariant average(FieldPhrase &f){ + //TODO: ... + return QVariant(); + } Query *join(const QString &tableName); Query *setWhere(WherePhrase where); + + Query *join(Table *c){ + join(c->metaObject()->className()); + return this; + } + // Query *setWhere(const QString &where); Query *orderBy(QString fieldName, QString type); - -private: - static QHash _compiledCommands; - QString compileCommand(QString command); - QString queryText(); - QHash _orders; + Query *orderBy(WherePhrase phrase); }; -//template -//inline Query createQuery(TableSet *tset) -//{ -// return Query(tset); -//} - -template -QHash Query::_compiledCommands; - template Q_OUTOFLINE_TEMPLATE Query::Query(Database *database, TableSetBase *tableSet) : QueryBase(database), - _database(database), _tableSet(tableSet), _joinClassName(QString::null) + d_ptr(new QueryPrivate(this)) { - _tableName = _database->tableName(T::staticMetaObject.className()); + Q_D(Query); + + d->database = database; + d->tableSet = tableSet; + d->tableName = d->database->tableName(T::staticMetaObject.className()); +} + +template +Q_OUTOFLINE_TEMPLATE Query::~Query() +{ + qDebug() << "Query::~Query()"; + Q_D(Query); + delete d; } template Q_OUTOFLINE_TEMPLATE QList Query::toList(int count) { + Q_D(Query); QList result; - _select = "*"; - qDebug()<exec(_database->sqlGenertor()->selectCommand(_wheres, _orders, _tableName, _joinClassName)); + d->select = "*"; - QString pk =_database->model().model(_tableName)->primaryKey(); +// QSqlQuery q = d->database->exec(d->database->sqlGenertor()->selectCommand(d->wheres, d->orders, d->tableName, d->joinClassName)); + QSqlQuery q = d->database->exec(d->database->sqlGenertor()->selectCommand( + SqlGeneratorBase::SelectALl, + "", + d->wheres, + d->orderPhrases, + d->tableName, + d->joinClassName)); + + QString pk =d->database->model().model(d->tableName)->primaryKey(); QVariant lastPkValue = QVariant(); int childTypeId = 0; T *lastRow = 0; TableSetBase *childTableSet; - QStringList masterFields = _database->model().model(_tableName)->fieldsNames(); + QStringList masterFields = d->database->model().model(d->tableName)->fieldsNames(); QStringList childFields; - if(!_joinClassName.isNull()){ - childFields = _database->model().modelByClass(_joinClassName)->fieldsNames(); - QString joinTableName = _database->tableName(_joinClassName); - childTypeId = _database->model().model(joinTableName)->typeId(); - } + if(!d->joinClassName.isNull()) + if(d->database->model().modelByClass(d->joinClassName)){ + childFields = d->database->model().modelByClass(d->joinClassName)->fieldsNames(); + QString joinTableName = d->database->tableName(d->joinClassName); + childTypeId = d->database->model().model(joinTableName)->typeId(); + } while (q.next()) { if(lastPkValue != q.value(pk)){ @@ -114,7 +128,7 @@ Q_OUTOFLINE_TEMPLATE QList Query::toList(int count) foreach (QString field, masterFields) t->setProperty(field.toLatin1().data(), q.value(field)); - t->setTableSet(_tableSet); + t->setTableSet(d->tableSet); t->setStatus(Table::FeatchedFromDB); t->setParent(this); @@ -124,7 +138,7 @@ Q_OUTOFLINE_TEMPLATE QList Query::toList(int count) if(childTypeId){ QSet tableSets = t->tableSets; foreach (TableSetBase *ts, tableSets) - if(ts->childClassName() == _joinClassName) + if(ts->childClassName() == d->joinClassName) childTableSet = ts; } } @@ -166,8 +180,33 @@ Q_OUTOFLINE_TEMPLATE T *Query::first() template Q_OUTOFLINE_TEMPLATE int Query::count() { - _select = "COUNT(*)"; - QSqlQuery q = _database->exec(queryText()); + Q_D(Query); + + d->select = "COUNT(*)"; + QSqlQuery q = d->database->exec(d->database->sqlGenertor()->selectCommand("COUNT(*)", d->wheres, d->orders, d->tableName, d->joinClassName)); + + if(q.next()) + return q.value(0).toInt(); + return 0; +} + +template +Q_OUTOFLINE_TEMPLATE QVariant Query::max(FieldPhrase &f){ + Q_D(Query); + + QSqlQuery q = d->database->exec(d->database->sqlGenertor()->selectCommand("MAX(" + f.data()->text + ")", d->wheres, d->orders, d->tableName, d->joinClassName)); + + if(q.next()) + return q.value(0).toInt(); + return 0; +} + +template +Q_OUTOFLINE_TEMPLATE QVariant Query::min(FieldPhrase &f){ + Q_D(Query); + + QSqlQuery q = d->database->exec(d->database->sqlGenertor()->selectCommand("MIN(" + f.data()->text + ")", d->wheres, d->orders, d->tableName, d->joinClassName)); + if(q.next()) return q.value(0).toInt(); return 0; @@ -176,119 +215,45 @@ Q_OUTOFLINE_TEMPLATE int Query::count() template Q_OUTOFLINE_TEMPLATE int Query::remove() { - QString sql = _database->sqlGenertor()->deleteCommand(_wheres, _tableName); -// _database->sqlGenertor()->deleteRecords(_tableName, queryText()); + Q_D(Query); + + QString sql = d->database->sqlGenertor()->deleteCommand(d->wheres, d->tableName); +// d->_database->sqlGenertor()->deleteRecords(_tableName, queryText()); // sql = compileCommand(sql); - QSqlQuery q = _database->exec(sql); + QSqlQuery q = d->database->exec(sql); return q.numRowsAffected(); } template Q_OUTOFLINE_TEMPLATE Query *Query::join(const QString &tableName) { - _joinClassName = tableName; + Q_D(Query); + d->joinClassName = tableName; return this; } template Q_OUTOFLINE_TEMPLATE Query *Query::setWhere(WherePhrase where) { - _wheres.append(where); + Q_D(Query); + d->wheres.append(where); return this; } -//template -//Q_OUTOFLINE_TEMPLATE Query *Query::setWhere(const QString &where) -//{ -// _where = where; -// return this; -//} - template Q_OUTOFLINE_TEMPLATE Query *Query::orderBy(QString fieldName, QString type) { - _orders.insert(fieldName, type); + Q_D(Query); + d->orders.insert(fieldName, type); return this; } template -Q_OUTOFLINE_TEMPLATE QString Query::compileCommand(QString command) +Q_OUTOFLINE_TEMPLATE Query *Query::orderBy(WherePhrase phrase) { - if(!_compiledCommands.contains(command)){ - QString q = command - .replace("::", ".") - .replace("()", "") - .replace("==", "=") - .replace("!=", "<>"); - - QRegularExpression r("(\\w+)\\.(\\w+)"); - QRegularExpressionMatchIterator i = r.globalMatch(command); - while (i.hasNext()) { - QRegularExpressionMatch match = i.next(); - QString tableName = match.captured(1); - QString fieldName = match.captured(2); - tableName = _database->tableName(tableName); - q = command.replace(match.captured(), tableName + "." + fieldName); - } - _compiledCommands.insert(command, q); - } - - return _compiledCommands[command]; -} - -template -Q_OUTOFLINE_TEMPLATE QString Query::queryText() -{ - QStringList orderby; - QString q = "";//compileCommand(_where); - foreach (WherePhrase p, _wheres) { - if(q != "") - q.append(" AND "); - q.append(p.command(_database->sqlGenertor())); - } - - QString t = _tableName; - if(!_joinClassName.isNull()){ - QString joinTableName = _database->tableName(_joinClassName); - RelationModel *rel = _database->model().relationByTableNames(_tableName, joinTableName); - if(rel){ - QString pk = _database->model().model(_tableName)->primaryKey(); - t = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)") - .arg(_tableName) - .arg(joinTableName) - .arg(pk) - .arg(rel->localColumn); - orderby.append(_tableName + "." + pk); - }else{ - qWarning(QString("Relation between table %1 and class %2 (%3) not exists!") - .arg(_tableName) - .arg(_joinClassName) - .arg(joinTableName.isNull() ? "NULL" : joinTableName) - .toLatin1().data()); - _joinClassName = QString::null; - } - } - - QString orderText = ""; - if(_orders.count()) - foreach (QString o, _orders.keys()) - orderby.append(o + " " + _orders.value(o)); - - if(orderby.count()) - orderText = " ORDER BY " + orderby.join(", "); - - QString command = QString("SELECT %1 FROM %2 %3%4") - .arg(_select) - .arg(t) - .arg(q.isEmpty() ? "" : "WHERE " + q) - .arg(orderText); - - for(int i = 0; i < _database->model().count(); i++) - command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + "."); - - qDebug() << command - << _database->sqlGenertor()->selectCommand(_wheres, _orders, _tableName, _joinClassName); - return command; + Q_D(Query); + d->orderPhrases.append(phrase); + return this; } QT_END_NAMESPACE diff --git a/src/query_p.h b/src/query_p.h new file mode 100644 index 0000000..3c01804 --- /dev/null +++ b/src/query_p.h @@ -0,0 +1,49 @@ +/************************************************************************** +** +** 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 QUERY_P_H +#define QUERY_P_H + +#include "wherephrase.h" + +#include +#include + +class Database; +class TableSetBase; +//template +class QueryBase; +class QueryPrivate{ + QueryBase *q_ptr; + Q_DECLARE_PUBLIC(QueryBase) + +public: + QueryPrivate(QueryBase *parent); + QString tableName; + QString select; + Database *database; + TableSetBase *tableSet; + QString joinClassName; + QList wheres; + QHash orders; + QList orderPhrases; +}; + +#endif // QUERY_P_H diff --git a/src/sqlgeneratorbase.cpp b/src/sqlgeneratorbase.cpp index ef3ac62..e790775 100644 --- a/src/sqlgeneratorbase.cpp +++ b/src/sqlgeneratorbase.cpp @@ -28,6 +28,7 @@ #include "sqlgeneratorbase_p.h" #include "table.h" #include "tablemodel.h" +#include "wherephrase.h" QT_BEGIN_NAMESPACE @@ -174,9 +175,16 @@ QString SqlGeneratorBase::insertRecord(Table *t, QString tableName) if(f != key) values.append("'" + t->property(f.toLatin1().data()).toString() + "'"); + QString changedPropertiesText = ""; + QSet props = t->changedProperties(); + foreach (QString s, props) { + if(changedPropertiesText != "") + changedPropertiesText.append(", "); + changedPropertiesText.append(s); + } sql = QString("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableName) - .arg(t->changedProperties().toList().join(", ")) + .arg(changedPropertiesText) .arg(values.join(", ")); return sql; @@ -208,6 +216,61 @@ QString SqlGeneratorBase::deleteRecord(Table *t, QString tableName) .arg(t->primaryValue().toString()); } +QString SqlGeneratorBase::agregateText(const AgregateType &t, const QString &arg) const +{ + switch (t) { + case SelectALl: + return "*"; + break; + + case Min: + return "MIN(" + arg + ")"; + break; + + case Max: + return "MAX(" + arg + ")"; + break; + + case Average: + return "AVERAGE(" + arg + ")"; + break; + + case Count: + return "COUNT(" + arg + ")"; + break; + + default: + return QString::null; + } +} + +QString SqlGeneratorBase::fromTableText(const QString &tableName, QString &joinClassName, QString &orderBy) const +{ + QString tableNameText = tableName; + if(!joinClassName.isNull()){ + QString joinTableName = _database->tableName(joinClassName); + RelationModel *rel = _database->model().relationByTableNames(tableName, joinTableName); + if(rel){ + QString pk = _database->model().model(tableName)->primaryKey(); + tableNameText = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)") + .arg(tableName) + .arg(joinTableName) + .arg(pk) + .arg(rel->localColumn); + orderBy = tableName + "." + pk; + }else{ + qWarning(QString("Relation between table %1 and class %2 (%3) not exists!") + .arg(tableName) + .arg(joinClassName) + .arg(joinTableName.isNull() ? "NULL" : joinTableName) + .toLatin1().data()); + joinClassName = QString::null; + } + } + + return tableNameText; +} + QString SqlGeneratorBase::deleteRecords(QString tableName, QString where) { QString sql = ""; @@ -218,60 +281,70 @@ QString SqlGeneratorBase::deleteRecords(QString tableName, QString where) return sql; } -QString SqlGeneratorBase::escapeFieldValue(QVariant &field) const +QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t, QString agregateArg, QList &wheres, QList &orders, QString tableName, QString joinClassName) { - switch (field.type()) { - case QVariant::Int: - case QVariant::Double: - return field.toString(); - break; + QString select = agregateText(t, agregateArg); + QString where = createWhere(wheres); + QString order = ""; + QString from = fromTableText(tableName, joinClassName, order); - case QVariant::String: - return "'" + field.toString() + "'"; - - case QVariant::DateTime: - return "'" + field.toDateTime().toString(Qt::ISODate) + "'"; - - case QVariant::Date: - return "'" + field.toDate().toString(Qt::ISODate) + "'"; - - case QVariant::Time: - return "'" + field.toTime().toString(Qt::ISODate) + "'"; - - case QVariant::StringList: - case QVariant::List: - return "['" + field.toStringList().join("', '") + "']"; - - case QVariant::Invalid: - qFatal("Invalud field value"); - return ""; - - default: - return ""; + foreach(WherePhrase p, orders){ + if(order != "") + order.append(", "); + order.append(phraseOrder(p.data())); } + + QString sql = "SELECT " + select + " FROM " + from; + + if(where != "") + sql.append(" WHERE " + where); + + if(order != "") + sql.append(" ORDER BY " + order); + + for(int i = 0; i < _database->model().count(); i++) + sql = sql.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + "."); + + qDebug() << "new sql" << sql; + return sql; +} + +QString SqlGeneratorBase::selectCommand(QList &wheres, QHash &orders, QString tableName, QString joinClassName) +{ + return selectCommand("*", wheres, orders, tableName, joinClassName); } QString SqlGeneratorBase::createWhere(QList &wheres) { QString whereText = ""; - foreach (WherePhrase p, wheres) { +// for (int i = 0; i < wheres.count(); i++) { +// if(whereText != "") +// whereText.append(" AND "); +// whereText.append(phrase(wheres[i].data())); +// } + foreach (WherePhrase w, wheres) { if(whereText != "") whereText.append(" AND "); - whereText.append(p.command(this)); + + whereText.append(phrase(w.data())); } - if(whereText != "") - whereText.prepend(" WHERE "); +qDebug() << "WHWRE="<< whereText; +// if(whereText != "") +// whereText.prepend(" WHERE "); return whereText; } -QString SqlGeneratorBase::selectCommand(QList &wheres, QHash &orders, QString tableName, QString joinClassName) +QString SqlGeneratorBase::selectCommand(QString selectPhrase, QList &wheres, QHash &orders, QString tableName, QString joinClassName) { QString orderText = ""; QStringList orderby; QString whereText = createWhere(wheres); + if(whereText != "") + whereText.prepend(" WHERE "); + QString tableNameText = tableName; if(!joinClassName.isNull()){ QString joinTableName = _database->tableName(joinClassName); @@ -302,27 +375,184 @@ QString SqlGeneratorBase::selectCommand(QList &wheres, QHashmodel().count(); i++) command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + "."); + + qDebug() << command; return command; } QString SqlGeneratorBase::deleteCommand(QList &wheres, QString tableName) { - QString command = "DELETE FROM " - + tableName - + createWhere(wheres); + QString command = "DELETE FROM " + tableName; + QString where = createWhere(wheres); + + 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() + "."); return command; } +QString SqlGeneratorBase::escapeValue(const QVariant &v)const +{ + switch (v.type()) { + case QVariant::Int: + case QVariant::UInt: + case QVariant::ULongLong: + case QVariant::LongLong: + case QVariant::Double: + return v.toString(); + break; + + case QVariant::Char: + case QVariant::String: + return "'" + v.toString() + "'"; + + case QVariant::DateTime: + return "'" + v.toDateTime().toString() + "'"; + + case QVariant::Date: + return "'" + v.toDate().toString() + "'"; + + case QVariant::Time: + return "'" + v.toTime().toString() + "'"; + + case QVariant::StringList: + case QVariant::List: + return "['" + v.toStringList().join("', '") + "']"; + + case QVariant::Invalid: + qFatal("Invalud field value"); + return ""; + } + return ""; +} + +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 = ""; + + qDebug() << "type"<type; + 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::operatorString(const PhraseData::Condition &cond) const +{ + switch (cond){ + case PhraseData::Equal: + return "="; + case PhraseData::NotEqual: + return "<>"; + case PhraseData::Less: + return "<"; + case PhraseData::Greater: + return ">"; + case PhraseData::LessEqual: + return "<="; + case PhraseData::GreaterEqual: + return ">="; + case PhraseData::Null: + return "IS NULL"; + + case PhraseData::NotNull: + return "IS NOT NULL"; + + case PhraseData::In: + return "IN"; + + case PhraseData::NotIn: + return "NOT IN"; + + case PhraseData::And: + return "AND"; + case PhraseData::Or: + return "OR"; + + case PhraseData::Like: + return "LIKE"; + case PhraseData::NotLike: + return "NOT LIKE"; + + case PhraseData::Add: + return "+"; + case PhraseData::Minus: + return "-"; + case PhraseData::Multiple: + return "*"; + case PhraseData::Divide: + return "/"; + + case PhraseData::Set: + return "="; + + case PhraseData::Append: + return ","; + } + + return QString(""); +} + QT_END_NAMESPACE diff --git a/src/sqlgeneratorbase_p.h b/src/sqlgeneratorbase_p.h index 0390dc6..06102b2 100644 --- a/src/sqlgeneratorbase_p.h +++ b/src/sqlgeneratorbase_p.h @@ -24,6 +24,7 @@ #include #include #include +#include "wherephrase.h" QT_BEGIN_NAMESPACE @@ -31,8 +32,9 @@ class Table; struct FieldModel; class DatabaseModel; class TableModel; -class WherePhrase; class Database; +//struct PhraseData; +//class WherePhrase; class SqlGeneratorBase : public QObject { // Q_OBJECT @@ -45,6 +47,13 @@ public: Update, Delete }; + enum AgregateType{ + SelectALl, + Count, + Min, + Max, + Average + }; SqlGeneratorBase(Database *parent); virtual ~SqlGeneratorBase(); @@ -58,23 +67,35 @@ public: virtual QString diff(FieldModel *oldField, FieldModel *newField); virtual QString diff(TableModel *oldTable, TableModel *newTable); - virtual QString saveRecord(Table *t, QString tableName); 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 escapeFieldValue(QVariant &field) const; + virtual QString selectCommand(AgregateType t, QString agregateArg, + QList &wheres, QList &orders, + QString tableName, QString joinClassName); virtual QString selectCommand(QList &wheres, QHash &orders, QString tableName, QString joinClassName); + virtual QString selectCommand(QString selectPhrase, + QList &wheres, QHash &orders, + QString tableName, QString joinClassName); virtual QString deleteCommand(QList &wheres, QString tableName); + virtual QString escapeValue(const QVariant &v) const; + virtual QString phrase(const PhraseData *d) const; + virtual QString operatorString(const PhraseData::Condition &cond) const; + private: + 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 phraseOrder(const PhraseData *d) const; }; QT_END_NAMESPACE diff --git a/src/sqlservergenerator.cpp b/src/sqlservergenerator.cpp index ef35b11..77bc8d1 100644 --- a/src/sqlservergenerator.cpp +++ b/src/sqlservergenerator.cpp @@ -102,4 +102,12 @@ QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField) return sql; } +QString SqlServerGenerator::escapeValue(const QVariant &v) const +{ + if(v.type() == QVariant::String || v.type() == QVariant::Char) + return "N'" + v.toString() + "'"; + else + return SqlGeneratorBase::escapeValue(v); +} + QT_END_NAMESPACE diff --git a/src/sqlservergenerator.h b/src/sqlservergenerator.h index c71f21b..71a6825 100644 --- a/src/sqlservergenerator.h +++ b/src/sqlservergenerator.h @@ -35,6 +35,8 @@ public: QString fieldType(FieldModel *field); QString diff(FieldModel *oldField, FieldModel *newField); + + QString escapeValue(const QVariant &v) const; }; QT_END_NAMESPACE diff --git a/src/tablemodel.cpp b/src/tablemodel.cpp index de22f6e..d92093d 100644 --- a/src/tablemodel.cpp +++ b/src/tablemodel.cpp @@ -148,6 +148,7 @@ TableModel::TableModel(int typeId, QString tableName) // get fields names for(int j = 0; j < tableMetaObject->classInfoCount(); j++){ QString name = tableMetaObject->classInfo(j).name(); + name = name.replace("\"", ""); name = name.remove(__nut_NAME_PERFIX); @@ -181,8 +182,8 @@ TableModel::TableModel(int typeId, QString tableName) QString name = tableMetaObject->classInfo(j).name(); QString value = tableMetaObject->classInfo(j).value(); - name = name.remove(__nut_NAME_PERFIX); - + name = name.replace("\"", "").remove(__nut_NAME_PERFIX); + value = value.replace("\"", ""); if(name.contains(" ")){ QStringList parts = name.split(" "); diff --git a/src/wherephrase.cpp b/src/wherephrase.cpp index 0a442d1..ef08143 100644 --- a/src/wherephrase.cpp +++ b/src/wherephrase.cpp @@ -28,327 +28,249 @@ QT_BEGIN_NAMESPACE PhraseData::PhraseData(const char *className, const char *s){ text = QString(className) + "." + s; type = Field; + qDebug() << "(" << this << ")" << "Data type 0"; } PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) : left(l){ operatorCond = o; type = WithoutOperand; + qDebug() << "(" << this << ")" << "Data type 1"; } PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, const PhraseData *r) : left(l), right(r){ operatorCond = o; type = WithOther; + qDebug() << "(" << this << ")" << "Data type 2"; } PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r) : left(l), operand(r){ operatorCond = o; type = WithVariant; + qDebug() << "(" << this << ")" << "Data type 1"; } PhraseData::~PhraseData(){ - // if(type == WithOther){ - // delete left; - // delete right; - // } - // if(type == WithVariant){ - //// qDebug() << operator - // delete left; -} - -QString PhraseData::operatorString() const -{ - switch (operatorCond){ - case PhraseData::Equal: - return "="; - case PhraseData::NotEqual: - return "<>"; - case PhraseData::Less: - return "<"; - case PhraseData::Greater: - return ">"; - case PhraseData::LessEqual: - return "<="; - case PhraseData::GreaterEqual: - return ">="; - case PhraseData::Null: - return "IS NULL"; - - case PhraseData::NotNull: - return "IS NOT NULL"; - - case PhraseData::In: - return "IN"; - - case PhraseData::NotIn: - return "NOT IN"; - - case PhraseData::And: - return "AND"; - case PhraseData::Or: - return "OR"; - - case PhraseData::Like: - return "LIKE"; - case PhraseData::NotLike: - return "NOT LIKE"; - - case PhraseData::Add: - return "+"; - case PhraseData::Minus: - return "-"; - case PhraseData::Multiple: - return "*"; - case PhraseData::Divide: - return "/"; - - case PhraseData::Set: - return "="; - - case PhraseData::Append: - return ","; + qDebug() << "(" << this << ")" << "Data Deleting..." << type; + if(type == WithOther){ + qDebug() << " - Other" << left << right; + delete left; + delete right; } - - return QString(""); -} - -QString PhraseData::escapeVariant() const -{ - switch (operand.type()) { - case QVariant::Int: - case QVariant::Double: - return operand.toString(); - break; - - case QVariant::String: - return "'" + operand.toString() + "'"; - - case QVariant::DateTime: - return "'" + operand.toDateTime().toString() + "'"; - - case QVariant::Date: - return "'" + operand.toDate().toString() + "'"; - - case QVariant::Time: - return "'" + operand.toTime().toString() + "'"; - - case QVariant::StringList: - case QVariant::List: - return "['" + operand.toStringList().join("', '") + "']"; - - case QVariant::Invalid: - return ""; - - default: - return ""; + if(type == WithVariant){ + qDebug() << " - Variant" << left; + if(left) + delete left; } } -QString PhraseData::command(SqlGeneratorBase *generator) const +PhraseData *WherePhrase::data() const { - QString ret = ""; + return _data; +} - switch(type){ - case Field: - ret = text; - break; +WherePhrase::WherePhrase(const char *className, const char *s) +{ + qDebug() << "(" << this << ")" << "class ctor" << className << s; + _data = new PhraseData(className, s); +} - case WithVariant: - ret = left->command(generator) + " " + operatorString() + " " + escapeVariant(); - break; +WherePhrase::WherePhrase(const WherePhrase &l) +{ + _data = l._data; + // l._data = 0; + qDebug() << "(" << this << ")" << "Copy ctor, from" << _data << (&l); + _dataPointer = QSharedPointer(l._dataPointer); +} - case WithOther: - ret = left->command(generator) + " " + operatorString() + " " + right->command(generator); - break; +WherePhrase::WherePhrase(WherePhrase *l) +{ + _data = l->_data; - case WithoutOperand: - ret = left->command(generator) + " " + operatorString(); - break; - } + qDebug() << "(" << this << ")" << "From pointer" << _data; +// _dataPointer = QSharedPointer(_data); + l->_data = 0; + l->_dataPointer.reset(0); +} - if(operatorCond == PhraseData::And || operatorCond == PhraseData::Or) - ret = "(" + ret + ")"; - - return ret; +WherePhrase::WherePhrase(WherePhrase *l, PhraseData::Condition o) +{ + _data = new PhraseData(l->_data, o); +// _dataPointer = QSharedPointer(_data); + l->_data = 0; + qDebug() << "(" << this << ")" << "From cond, " << _data << o; + l->_dataPointer.reset(0); } -WherePhrase::WherePhrase(const char *className, const char *s) : willDeleteData(false) +WherePhrase::WherePhrase(WherePhrase *l, PhraseData::Condition o, WherePhrase *r) { - data = new PhraseData(className, s); - text = QString(className) + "." + s; + _data = new PhraseData(l->_data, o, r->_data); +// _dataPointer = QSharedPointer(_data); + l->_data = 0; + r->_data = 0; + + qDebug() << "(" << this << ")" << "From two pointer" << _data; + l->_dataPointer.reset(0); + r->_dataPointer.reset(0); } -WherePhrase::WherePhrase(PhraseData *l) : willDeleteData(false) +WherePhrase::WherePhrase(WherePhrase *l, PhraseData::Condition o, QVariant r) { - data = l; -} + _data = new PhraseData(l->_data, o, r); +// _dataPointer = QSharedPointer(_data); + l->_data = 0; -WherePhrase::WherePhrase(PhraseData *l, PhraseData::Condition o) : willDeleteData(false) -{ - data = new PhraseData(l, o); -} - - -WherePhrase::WherePhrase(PhraseData *l, PhraseData::Condition o, PhraseData *r) : willDeleteData(false) -{ - data = new PhraseData(l, o, r); -} - -WherePhrase::WherePhrase(PhraseData *l, PhraseData::Condition o, QVariant r) : willDeleteData(false) -{ - data = new PhraseData(l, o, r); + qDebug() << "(" << this << ")" << "From variant," << _data << l << r; + l->_dataPointer.reset(0); } WherePhrase::~WherePhrase() { -// if(willDeleteData) -// delete data; + qDebug() << "(" << this << ")" << "Dtor" << _data << _dataPointer.data(); + // if(_data){ + // delete _data; + // qDebug() << "deleted"; + // } } - -QString WherePhrase::command(SqlGeneratorBase *generator) +WherePhrase WherePhrase::operator ==(const WherePhrase &other) { - willDeleteData = true; - return data->command(generator); + return WherePhrase(this, PhraseData::Equal, (WherePhrase*)&other); } -void WherePhrase::deleteData(PhraseData *d) +WherePhrase WherePhrase::operator !=(const WherePhrase &other) { - deleteData(d); - if(d->type == PhraseData::WithOther){ - delete d->left; - delete d->right; - } - if(d->type == PhraseData::WithVariant) - delete d->left; + return WherePhrase(this, PhraseData::NotEqual, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator ==(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Equal, other.data); +WherePhrase WherePhrase::operator <(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Less, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator !=(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::NotEqual, other.data); +WherePhrase WherePhrase::operator >(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Greater, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator <(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Less, other.data); +WherePhrase WherePhrase::operator <=(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::LessEqual, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator >(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Greater, other.data); -} - -WherePhrase WherePhrase::operator <=(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::LessEqual, other.data); -} - -WherePhrase WherePhrase::operator >=(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::GreaterEqual, other.data); +WherePhrase WherePhrase::operator >=(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::GreaterEqual, (WherePhrase*)&other); } WherePhrase WherePhrase::operator =(const WherePhrase &other) { - return WherePhrase(this->data, PhraseData::Set, other.data); + return WherePhrase(this, PhraseData::Set, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator +(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Add, other.data); +WherePhrase WherePhrase::operator +(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Add, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator -(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Minus, other.data); +WherePhrase WherePhrase::operator -(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Minus, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator *(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Multiple, other.data); +WherePhrase WherePhrase::operator *(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Multiple, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator /(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Divide, other.data); +WherePhrase WherePhrase::operator /(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Divide, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator &&(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::And, other.data); +WherePhrase WherePhrase::operator &&(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::And, (WherePhrase*)&other); } -WherePhrase WherePhrase::operator ||(const WherePhrase &other){ - return WherePhrase(this->data, PhraseData::Or, other.data); +WherePhrase WherePhrase::operator ||(const WherePhrase &other) +{ + return WherePhrase(this, PhraseData::Or, (WherePhrase*)&other); } WherePhrase WherePhrase::operator &(const WherePhrase &other) { - return WherePhrase(this->data, PhraseData::Append, other.data); + qDebug() << "append" << this << (&other); + return WherePhrase(this, PhraseData::Append, (WherePhrase*)&other); } -WherePhrase FieldPhrase::operator !(){ - if(data->operatorCond < 20) - data->operatorCond = (PhraseData::Condition)((data->operatorCond + 10) % 20); +WherePhrase FieldPhrase::operator !() +{ + if(_data->operatorCond < 20) + _data->operatorCond = (PhraseData::Condition)((_data->operatorCond + 10) % 20); else qFatal("Operator ! can not aplied to non condition statements"); - return WherePhrase(data); + return this;//WherePhrase(this, PhraseData::Not); } -WherePhrase WherePhrase::operator ==(const QVariant &other){ - return WherePhrase(this->data, PhraseData::Equal, other); -} - -WherePhrase WherePhrase::operator !=(const QVariant &other){ - return WherePhrase(this->data, PhraseData::NotEqual, other); -} - -WherePhrase WherePhrase::operator <(const QVariant &other){ - return WherePhrase(this->data, PhraseData::Less, other); -} - -WherePhrase WherePhrase::operator >(const QVariant &other){ - qDebug() << "var"; - return WherePhrase(this->data, PhraseData::Greater, other); -} - -WherePhrase WherePhrase::operator <=(const QVariant &other){ - return WherePhrase(this->data, PhraseData::LessEqual, other); -} - -WherePhrase WherePhrase::operator >=(const QVariant &other){ - return WherePhrase(this->data, PhraseData::GreaterEqual, other); -} - -WherePhrase FieldPhrase::operator =(const QVariant &other) +WherePhrase WherePhrase::operator ==(const QVariant &other) { - return WherePhrase(this->data, PhraseData::Set, other); + return WherePhrase(this, PhraseData::Equal, other); +} + +WherePhrase WherePhrase::operator !=(const QVariant &other) +{ + return WherePhrase(this, PhraseData::NotEqual, other); +} + +WherePhrase WherePhrase::operator <(const QVariant &other) +{ + return WherePhrase(this, PhraseData::Less, other); +} + +WherePhrase WherePhrase::operator >(const QVariant &other) +{ + return WherePhrase(this, PhraseData::Greater, other); +} + +WherePhrase WherePhrase::operator <=(const QVariant &other) +{ + return WherePhrase(this, PhraseData::LessEqual, other); +} + +WherePhrase WherePhrase::operator >=(const QVariant &other) +{ + return WherePhrase(this, PhraseData::GreaterEqual, other); } FieldPhrase::FieldPhrase(const char *className, const char *s) : WherePhrase(className, s) { - data = new PhraseData(className, s); - text = QString(className) + "." + s; + qDebug() << "(" << this << ")" << "FieldPhrase ctor" << className << s; } -WherePhrase FieldPhrase::operator &(const QVariant &other) +WherePhrase FieldPhrase::operator =(const QVariant &other) { - Q_UNUSED(other); - qFatal("The operator & can not applied for two fields"); + return WherePhrase(this, PhraseData::Set, other); } WherePhrase FieldPhrase::isNull(){ - return WherePhrase(this->data, PhraseData::Null); + return WherePhrase(this, PhraseData::Null); } WherePhrase FieldPhrase::in(QVariantList list) { - return WherePhrase(this->data, PhraseData::In, list); + return WherePhrase(this, PhraseData::In, list); } WherePhrase FieldPhrase::in(QStringList list) { - return WherePhrase(this->data, PhraseData::In, list); + return WherePhrase(this, PhraseData::In, list); } WherePhrase FieldPhrase::like(QString pattern) { - return WherePhrase(this->data, PhraseData::Like, pattern); + return WherePhrase(this, PhraseData::Like, pattern); } QT_END_NAMESPACE diff --git a/src/wherephrase.h b/src/wherephrase.h index e60a4e1..d767c9f 100644 --- a/src/wherephrase.h +++ b/src/wherephrase.h @@ -27,21 +27,25 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class SqlGeneratorBase; -struct PhraseData{ +class PhraseData{ +public: enum Condition { - Equal = 0, + NotAssign = 0, + Equal, Less, LessEqual, Null, In, Like, - NotEqual = 10, + Not = 10, + NotEqual, GreaterEqual, Greater, NotNull, @@ -51,6 +55,7 @@ struct PhraseData{ And = 20, Or, + Append, Set, @@ -81,34 +86,24 @@ struct PhraseData{ PhraseData(PhraseData *l, Condition o, QVariant r); ~PhraseData(); - - QString operatorString() const; - QString escapeVariant() const; - QString command(SqlGeneratorBase *generator) const; }; class WherePhrase{ protected: - PhraseData *data; - bool willDeleteData; + PhraseData *_data; + QSharedPointer _dataPointer; public: - - QString text; - WherePhrase(const char *className, const char* s); - WherePhrase(PhraseData *l); - WherePhrase(PhraseData *l, PhraseData::Condition o); - WherePhrase(PhraseData *l, PhraseData::Condition o, PhraseData *r); - WherePhrase(PhraseData *l, PhraseData::Condition o, QVariant r); + WherePhrase(const WherePhrase &l); + WherePhrase(WherePhrase *l); + WherePhrase(WherePhrase *l, PhraseData::Condition o); + WherePhrase(WherePhrase *l, PhraseData::Condition o, WherePhrase *r); + WherePhrase(WherePhrase *l, PhraseData::Condition o, QVariant r); ~WherePhrase(); - QString command(SqlGeneratorBase *generator); - - void deleteData(PhraseData *d); - WherePhrase operator ==(const WherePhrase &other); WherePhrase operator !=(const WherePhrase &other); WherePhrase operator <(const WherePhrase &other); @@ -137,14 +132,13 @@ public: WherePhrase operator >=(const QVariant &other); + PhraseData *data() const; }; class FieldPhrase: public WherePhrase{ public: FieldPhrase(const char *className, const char* s); - WherePhrase operator &(const QVariant &other); - WherePhrase operator =(const QVariant &other); WherePhrase operator !(); @@ -154,6 +148,13 @@ public: WherePhrase like(QString pattern); }; + +//TODO: make FieldPhrase template class +//template +//class FieldPhrase: public WherePhrase{ + +//}; + QT_END_NAMESPACE #endif // PHRASE_H diff --git a/test/basic/maintest.cpp b/test/basic/maintest.cpp index 4d66ea2..281147c 100644 --- a/test/basic/maintest.cpp +++ b/test/basic/maintest.cpp @@ -33,6 +33,11 @@ void MainTest::initTestCase() bool ok = db.open(); QTEST_ASSERT(ok); + + FROM(db.comments()) + DELETE(); + FROM(db.posts()) + DELETE(); } void MainTest::dataScheema() @@ -67,13 +72,36 @@ void MainTest::createPost() qDebug() << "New post inserted with id:" << newPost->id(); } +void MainTest::createPost2() +{ + Post *newPost = new Post; + newPost->setTitle("post title"); + newPost->setSaveDate(QDateTime::currentDateTime()); + + db.posts()->append(newPost); + db.saveChanges(); + + for(int i = 0 ; i < 3; i++){ + Comment *comment = new Comment; + comment->setMessage("comment #" + QString::number(i)); + comment->setSaveDate(QDateTime::currentDateTime()); + comment->setPostId(newPost->id()); + db.comments()->append(comment); + } + db.saveChanges(); + + QTEST_ASSERT(newPost->id() != 0); + qDebug() << "New post2 inserted with id:" << newPost->id(); +} + void MainTest::selectPosts() { // auto q = FROM(db.posts()) // JOIN(Comment) // WHERE(Post::idField() == postId); auto q = db.posts()->createQuery(); - q->join("Comment"); + q->join(Post::commentsTable()); + q->orderBy(!Post::saveDateField() & Post::bodyField()); q->setWhere(Post::idField() == postId); auto posts = q->toList(); @@ -91,6 +119,15 @@ void MainTest::selectPosts() db.cleanUp(); } +void MainTest::selectPostsWithoutTitle() +{ + auto q = db.posts()->createQuery(); + q->setWhere(Post::titleField().isNull()); + auto count = q->count(); + qDebug() << "selectPostsWithoutTitle, count=" << count; + QTEST_ASSERT(count == 0); +} + void MainTest::testDate() { QDateTime d = QDateTime::currentDateTime(); @@ -116,15 +153,22 @@ void MainTest::testDate() void MainTest::selectWithInvalidRelation() { - auto q = FROM(db.posts()) - JOIN(Invalid_Class_Name) - SELECT(); + auto q = db.posts()->createQuery(); + q->join("Invalid_Class_Name"); + q->toList(); +} + +void MainTest::select10NewstPosts() +{ + auto q = db.posts()->createQuery(); + q->orderBy(!Post::saveDateField()); + q->toList(10); } void MainTest::modifyPost() { - auto q = FROM(db.posts()) - WHERE(Post::idField() == postId); + auto q = db.posts()->createQuery(); + q->setWhere(Post::idField() == postId); Post *post = q->first(); diff --git a/test/basic/maintest.h b/test/basic/maintest.h index 4b69640..edcee0e 100644 --- a/test/basic/maintest.h +++ b/test/basic/maintest.h @@ -22,9 +22,12 @@ private slots: void dataScheema(); void createPost(); + void createPost2(); void selectPosts(); + void selectPostsWithoutTitle(); void testDate(); void selectWithInvalidRelation(); + void select10NewstPosts(); void modifyPost(); void deletePost(); }; diff --git a/test/basic/tst_basic.pro b/test/basic/tst_basic.pro index ff00896..b072765 100644 --- a/test/basic/tst_basic.pro +++ b/test/basic/tst_basic.pro @@ -16,6 +16,7 @@ SOURCES += \ HEADERS += \ maintest.h \ + ../common/consts.h \ ../common/comment.h \ ../common/post.h \ ../common/weblogdatabase.h diff --git a/test/benckmark/maintest.cpp b/test/benckmark/maintest.cpp index c456dca..f8b8877 100644 --- a/test/benckmark/maintest.cpp +++ b/test/benckmark/maintest.cpp @@ -33,8 +33,6 @@ void MainTest::initTestCase() bool ok = db.open(); QTEST_ASSERT(ok); - - QTEST_ASSERT(ok); } void MainTest::insert1kPost() diff --git a/test/common/consts.h b/test/common/consts.h index 08c7658..41c8154 100644 --- a/test/common/consts.h +++ b/test/common/consts.h @@ -1,11 +1,17 @@ #ifndef CONSTS_H #define CONSTS_H -#define DRIVER "QPSQL" +//#define DRIVER "QPSQL" +//#define HOST "127.0.0.1" +//#define DATABASE "nutdb3" +//#define USERNAME "postgres" +//#define PASSWORD "856856" + +#define DRIVER "QMYSQL" #define HOST "127.0.0.1" -#define DATABASE "nutdb3" -#define USERNAME "postgres" -#define PASSWORD "856856" +#define DATABASE "nutdb" +#define USERNAME "root" +#define PASSWORD "onlyonlyi" // db.setDriver("QODBC"); // db.setHostName("127.0.0.1");