order phrase completed

This commit is contained in:
Hamed Masafi 2016-06-05 16:52:26 +04:30
parent e7653ddae1
commit 0a971815c4
26 changed files with 841 additions and 451 deletions

5
doc/nut.index Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QDOCINDEX>
<INDEX url="" title="Advanced, Powerful and easy to use ORM for Qt5" version="0.1" project="Nut">
<namespace threadsafety="unspecified" name="" status="active" access="public" module="nut"/>
</INDEX>

14
doc/nut.qhp Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<QtHelpProject version="1.0">
<namespace></namespace>
<virtualFolder></virtualFolder>
<filterSection>
<toc>
<section ref="index.html" title="">
<section ref="" title=""/>
</section>
</toc>
<keywords/>
<files/>
</filterSection>
</QtHelpProject>

1
doc/nut.qhp.sha1 Normal file
View File

@ -0,0 +1 @@
da39a3ee5e6b4b0d3255bfef95601890afd80709

BIN
include.tar.gz Normal file

Binary file not shown.

0
include/header_copier Executable file → Normal file
View File

View File

@ -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 \

24
nut.qdocconf Normal file
View File

@ -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

View File

@ -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() <<sql;
QSqlQuery q = d->db.exec(sql);
if(d->db.lastError().type() != QSqlError::NoError)
qWarning(d->db.lastError().text().toLatin1().data());

View File

@ -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);

View File

@ -27,6 +27,7 @@
#include <QDebug>
QT_BEGIN_NAMESPACE
class DatabasePrivate
{
@ -63,4 +64,6 @@ public:
TableSet<ChangeLogTable> *changeLogs;
};
QT_END_NAMESPACE
#endif // DATABASE_P_H

View File

@ -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<type> 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<QueryBase*>*/(x->createQuery())
@ -111,4 +111,6 @@ public: \
# define FIRST() ->first()
#endif // NUT_NO_KEYWORDS
#endif // SYNTAX_DEFINES_H

View File

@ -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

View File

@ -26,6 +26,7 @@
#include <QtCore/QScopedPointer>
#include <QtCore/QRegularExpression>
#include "query_p.h"
#include "database.h"
#include "databasemodel.h"
#include "tablesetbase_p.h"
@ -38,73 +39,86 @@ QT_BEGIN_NAMESPACE
template<class T>
class NUT_EXPORT Query : public QueryBase
{
QString _tableName;
QString _select;
// QString _where;
Database *_database;
TableSetBase *_tableSet;
QString _joinClassName;
QList<WherePhrase> _wheres;
QueryPrivate *d_ptr;
Q_DECLARE_PRIVATE(Query)
public:
Query(Database *database, TableSetBase *tableSet);
Query(TableSet<T> *tset){
_database = tset->database();
_tableName = _database->tableName(T::staticMetaObject.className());
}
~Query();
QList<T *> 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<T> *join(const QString &tableName);
Query<T> *setWhere(WherePhrase where);
Query<T> *join(Table *c){
join(c->metaObject()->className());
return this;
}
// Query<T> *setWhere(const QString &where);
Query<T> *orderBy(QString fieldName, QString type);
private:
static QHash<QString, QString> _compiledCommands;
QString compileCommand(QString command);
QString queryText();
QHash<QString, QString> _orders;
Query<T> *orderBy(WherePhrase phrase);
};
//template <typename T>
//inline Query<T> createQuery(TableSet<T> *tset)
//{
// return Query<T>(tset);
//}
template<class T>
QHash<QString, QString> Query<T>::_compiledCommands;
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T>::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<class T>
Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
{
qDebug() << "Query::~Query()";
Q_D(Query);
delete d;
}
template<class T>
Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
{
Q_D(Query);
QList<T*> result;
_select = "*";
qDebug()<<queryText();
QSqlQuery q = _database->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()) {
@ -114,7 +128,7 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::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<T *> Query<T>::toList(int count)
if(childTypeId){
QSet<TableSetBase*> 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<T>::first()
template<class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::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<class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::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<class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::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<T>::count()
template<class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::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<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &tableName)
{
_joinClassName = tableName;
Q_D(Query);
d->joinClassName = tableName;
return this;
}
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(WherePhrase where)
{
_wheres.append(where);
Q_D(Query);
d->wheres.append(where);
return this;
}
//template<class T>
//Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(const QString &where)
//{
// _where = where;
// return this;
//}
template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(QString fieldName, QString type)
{
_orders.insert(fieldName, type);
Q_D(Query);
d->orders.insert(fieldName, type);
return this;
}
template<class T>
Q_OUTOFLINE_TEMPLATE QString Query<T>::compileCommand(QString command)
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::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<class T>
Q_OUTOFLINE_TEMPLATE QString Query<T>::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

49
src/query_p.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#ifndef QUERY_P_H
#define QUERY_P_H
#include "wherephrase.h"
#include <QList>
#include <QString>
class Database;
class TableSetBase;
//template<class T>
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<WherePhrase> wheres;
QHash<QString, QString> orders;
QList<WherePhrase> orderPhrases;
};
#endif // QUERY_P_H

View File

@ -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<QString> 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<WherePhrase> &wheres, QList<WherePhrase> &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 "<Invalid>";
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<WherePhrase> &wheres, QHash<QString, QString> &orders, QString tableName, QString joinClassName)
{
return selectCommand("*", wheres, orders, tableName, joinClassName);
}
QString SqlGeneratorBase::createWhere(QList<WherePhrase> &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<WherePhrase> &wheres, QHash<QString, QString> &orders, QString tableName, QString joinClassName)
QString SqlGeneratorBase::selectCommand(QString selectPhrase, QList<WherePhrase> &wheres, QHash<QString, QString> &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<WherePhrase> &wheres, QHash<QStrin
if(orderby.count())
orderText = " ORDER BY " + orderby.join(", ");
QString command = "SELECT * FROM "
QString command = "SELECT "
+selectPhrase
+ " FROM "
+ tableNameText
+ whereText
+ 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;
return command;
}
QString SqlGeneratorBase::deleteCommand(QList<WherePhrase> &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 "<FAIL>";
}
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"<<d->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 = "<FAIL>";
}
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("<FAIL>");
}
QT_END_NAMESPACE

View File

@ -24,6 +24,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/QObject>
#include <QtCore/QStringList>
#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<WherePhrase> &wheres, QList<WherePhrase> &orders,
QString tableName, QString joinClassName);
virtual QString selectCommand(QList<WherePhrase> &wheres, QHash<QString, QString> &orders,
QString tableName, QString joinClassName);
virtual QString selectCommand(QString selectPhrase,
QList<WherePhrase> &wheres, QHash<QString, QString> &orders,
QString tableName, QString joinClassName);
virtual QString deleteCommand(QList<WherePhrase> &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<WherePhrase> &wheres);
QString phraseOrder(const PhraseData *d) const;
};
QT_END_NAMESPACE

View File

@ -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

View File

@ -35,6 +35,8 @@ public:
QString fieldType(FieldModel *field);
QString diff(FieldModel *oldField, FieldModel *newField);
QString escapeValue(const QVariant &v) const;
};
QT_END_NAMESPACE

View File

@ -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(" ");

View File

@ -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("<FAIL>");
}
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 "<FAIL>";
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<PhraseData>(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<PhraseData>(_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<PhraseData>(_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<PhraseData>(_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<PhraseData>(_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

View File

@ -27,21 +27,25 @@
#include <QDate>
#include <QDateTime>
#include <QTime>
#include <QSharedPointer>
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<PhraseData> _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 <typename T>
//class FieldPhrase: public WherePhrase{
//};
QT_END_NAMESPACE
#endif // PHRASE_H

View File

@ -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();

View File

@ -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();
};

View File

@ -16,6 +16,7 @@ SOURCES += \
HEADERS += \
maintest.h \
../common/consts.h \
../common/comment.h \
../common/post.h \
../common/weblogdatabase.h

View File

@ -33,8 +33,6 @@ void MainTest::initTestCase()
bool ok = db.open();
QTEST_ASSERT(ok);
QTEST_ASSERT(ok);
}
void MainTest::insert1kPost()

View File

@ -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");