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/sqlitegenerator.h \
$$PWD/src/tablemodel.h \ $$PWD/src/tablemodel.h \
$$PWD/src/sqlservergenerator.h \ $$PWD/src/sqlservergenerator.h \
$$PWD/src/wherephrase.h $$PWD/src/wherephrase.h \
$$PWD/src/query_p.h
SOURCES += \ SOURCES += \
$$PWD/src/database.cpp \ $$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()); qWarning(db.lastError().text().toLocal8Bit().data());
if(db.lastError().text().contains("database \"" + databaseName + "\" does not exist") 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)); db.setDatabaseName(sqlGenertor->masterDatabaseName(databaseName));
ok = db.open(); ok = db.open();
qInfo("Creating database"); qDebug("Creating database");
if(ok){ if(ok){
db.exec("CREATE DATABASE " + databaseName); db.exec("CREATE DATABASE " + databaseName);
db.close(); db.close();
@ -89,18 +90,20 @@ bool DatabasePrivate::open()
bool DatabasePrivate::updateDatabase() bool DatabasePrivate::updateDatabase()
{ {
Q_Q(Database);
DatabaseModel last = getLastScheema(); DatabaseModel last = getLastScheema();
DatabaseModel current = currentModel; DatabaseModel current = currentModel;
if(last == current){ if(last == current){
qInfo("Databse is up-to-date"); qDebug("Databse is up-to-date");
return true; return true;
} }
if(!last.count()) if(!last.count())
qInfo("Databse is new"); qDebug("Databse is new");
else else
qInfo("Databse is changed"); qDebug("Databse is changed");
QStringList sql = sqlGenertor->diff(last, current); QStringList sql = sqlGenertor->diff(last, current);
db.transaction(); db.transaction();
@ -108,13 +111,26 @@ bool DatabasePrivate::updateDatabase()
qDebug() << "going to exec " << s; qDebug() << "going to exec " << s;
db.exec(s); db.exec(s);
if(!db.lastError().type() == QSqlError::NoError) if(db.lastError().type() != QSqlError::NoError)
qWarning(db.lastError().text().toLatin1().data()); qWarning(db.lastError().text().toLatin1().data());
} }
bool ok = db.commit(); bool ok = db.commit();
if(ok){ if(ok){
storeScheemaInDB(); 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{ }else{
qWarning("Unable update database"); qWarning("Unable update database");
qWarning(db.lastError().text().toLatin1().data()); qWarning(db.lastError().text().toLatin1().data());
@ -135,12 +151,12 @@ QVariantMap DatabasePrivate::getCurrectScheema()
for(int i = 0; i < q->metaObject()->classInfoCount(); i++){ for(int i = 0; i < q->metaObject()->classInfoCount(); i++){
QMetaClassInfo ci = q->metaObject()->classInfo(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)) 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){ if(ciName == __nut_DB_VERSION){
QStringList version = QString(ci.value()).split('.'); QStringList version = QString(ci.value()).replace("\"", "").split('.');
bool ok = false; bool ok = false;
if(version.length() == 1){ if(version.length() == 1){
currentModel.setVersionMajor(version.at(0).toInt(&ok)); currentModel.setVersionMajor(version.at(0).toInt(&ok));
@ -150,14 +166,14 @@ QVariantMap DatabasePrivate::getCurrectScheema()
} }
if(!ok) 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; QVariantMap databaseVariant;
for(int i = 1; i < q->metaObject()->propertyCount(); i++){ for(int i = 1; i < q->metaObject()->propertyCount(); i++){
QMetaProperty tableProperty = q->metaObject()->property(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){ if(tables.values().contains(tableProperty.name()) && typeId >= QVariant::UserType){
TableModel *sch = new TableModel(typeId, tableProperty.name()); TableModel *sch = new TableModel(typeId, tableProperty.name());
@ -220,6 +236,12 @@ void DatabasePrivate::createChangeLogs()
db.exec(diff); db.exec(diff);
} }
/*!
* \class Database
* \brief Database class
*/
Database::Database(QObject *parent) : QObject(parent), d_ptr(new DatabasePrivate(this)) Database::Database(QObject *parent) : QObject(parent), d_ptr(new DatabasePrivate(this))
{ {
Q_D(Database); Q_D(Database);
@ -268,6 +290,10 @@ QString Database::driver() const
return d->driver; return d->driver;
} }
/*!
* \brief Database::model
* \return The model of this database
*/
DatabaseModel Database::model() const DatabaseModel Database::model() const
{ {
Q_D(const Database); Q_D(const Database);
@ -328,6 +354,14 @@ SqlGeneratorBase *Database::sqlGenertor() const
return d->sqlGenertor; 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() bool Database::open()
{ {
Q_D(Database); Q_D(Database);
@ -357,9 +391,16 @@ bool Database::open()
} }
} }
void Database::close()
{
Q_D(Database);
d->db.close();
}
QSqlQuery Database::exec(QString sql) QSqlQuery Database::exec(QString sql)
{ {
Q_D(Database); Q_D(Database);
qDebug() <<sql;
QSqlQuery q = d->db.exec(sql); QSqlQuery q = d->db.exec(sql);
if(d->db.lastError().type() != QSqlError::NoError) if(d->db.lastError().type() != QSqlError::NoError)
qWarning(d->db.lastError().text().toLatin1().data()); qWarning(d->db.lastError().text().toLatin1().data());

View File

@ -45,6 +45,7 @@ public:
Database(QObject *parent = 0); Database(QObject *parent = 0);
bool open(); bool open();
void close();
QSqlQuery exec(QString sql); QSqlQuery exec(QString sql);
@ -65,6 +66,9 @@ public:
SqlGeneratorBase *sqlGenertor() const; SqlGeneratorBase *sqlGenertor() const;
protected:
virtual void databaseUpdated(int oldMajor, int oldMinor, int newMajor, int newMinor);
public slots: public slots:
void setDatabaseName(QString databaseName); void setDatabaseName(QString databaseName);
void setHostName(QString hostName); void setHostName(QString hostName);

View File

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

View File

@ -33,10 +33,10 @@
#endif #endif
// Database // 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) \ #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(type* name READ name) \
Q_PROPERTY(TableSet<type> name##s READ name##s) \ Q_PROPERTY(TableSet<type> name##s READ name##s) \
type* m_##name; \ type* m_##name; \
@ -49,7 +49,7 @@ public: \
//Table //Table
#define NUT_DECLARE_FIELD(type, name, read, write) \ #define NUT_DECLARE_FIELD(type, name, read, write) \
Q_PROPERTY(type name READ read WRITE 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; \ type m_##name; \
public: \ public: \
static FieldPhrase name##Field(){ \ static FieldPhrase name##Field(){ \
@ -67,7 +67,7 @@ public: \
#define NUT_FOREGION_KEY(type, keytype, name, read, write) \ #define NUT_FOREGION_KEY(type, keytype, name, read, write) \
Q_PROPERTY(type* name READ read WRITE write) \ Q_PROPERTY(type* name READ read WRITE write) \
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \ 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; \ type *m_##name; \
public: \ public: \
type *read() const { return m_##name ; } \ type *read() const { return m_##name ; } \
@ -89,14 +89,14 @@ public: \
#define NUT_INDEX(name, field, order) #define NUT_INDEX(name, field, order)
#define NUT_PRIMARY_KEY(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_PRIMARY_KEY, #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(__nut_NAME_PERFIX #x " " __nut_AUTO_INCREMENT, #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) \ #define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_PRIMARY_KEY(x) \
NUT_AUTO_INCREMENT(x) NUT_AUTO_INCREMENT(x)
#define NUT_UNIQUE(x) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_UNIQUE, #x) #define NUT_UNIQUE(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_UNIQUE), #x)
#define NUT_LEN(x, n) Q_CLASSINFO(__nut_NAME_PERFIX #x " " __nut_LEN, #n) #define NUT_LEN(x, n) Q_CLASSINFO(QT_STRINGIFY(__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_DEFAULT_VALUE(x, n) Q_CLASSINFO(QT_STRINGIFY(__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_NOT_NULL(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_NOT_NULL), "1")
#ifndef NUT_NO_KEYWORDS #ifndef NUT_NO_KEYWORDS
# define FROM(x) /*QScopedPointer<QueryBase*>*/(x->createQuery()) # define FROM(x) /*QScopedPointer<QueryBase*>*/(x->createQuery())
@ -111,4 +111,6 @@ public: \
# define FIRST() ->first() # define FIRST() ->first()
#endif // NUT_NO_KEYWORDS #endif // NUT_NO_KEYWORDS
#endif // SYNTAX_DEFINES_H #endif // SYNTAX_DEFINES_H

View File

@ -1,4 +1,4 @@
/************************************************************************** /*!************************************************************************
** **
** This file is part of Nut project. ** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut ** https://github.com/HamedMasafi/Nut
@ -20,4 +20,48 @@
#include "query.h" #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/QScopedPointer>
#include <QtCore/QRegularExpression> #include <QtCore/QRegularExpression>
#include "query_p.h"
#include "database.h" #include "database.h"
#include "databasemodel.h" #include "databasemodel.h"
#include "tablesetbase_p.h" #include "tablesetbase_p.h"
@ -38,74 +39,87 @@ QT_BEGIN_NAMESPACE
template<class T> template<class T>
class NUT_EXPORT Query : public QueryBase class NUT_EXPORT Query : public QueryBase
{ {
QString _tableName; QueryPrivate *d_ptr;
QString _select; Q_DECLARE_PRIVATE(Query)
// QString _where;
Database *_database;
TableSetBase *_tableSet;
QString _joinClassName;
QList<WherePhrase> _wheres;
public: public:
Query(Database *database, TableSetBase *tableSet); Query(Database *database, TableSetBase *tableSet);
~Query();
Query(TableSet<T> *tset){
_database = tset->database();
_tableName = _database->tableName(T::staticMetaObject.className());
}
QList<T *> toList(int count = -1); QList<T *> toList(int count = -1);
T *first();
int count();
int remove(); 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> *join(const QString &tableName);
Query<T> *setWhere(WherePhrase where); Query<T> *setWhere(WherePhrase where);
Query<T> *join(Table *c){
join(c->metaObject()->className());
return this;
}
// Query<T> *setWhere(const QString &where); // Query<T> *setWhere(const QString &where);
Query<T> *orderBy(QString fieldName, QString type); Query<T> *orderBy(QString fieldName, QString type);
Query<T> *orderBy(WherePhrase phrase);
private:
static QHash<QString, QString> _compiledCommands;
QString compileCommand(QString command);
QString queryText();
QHash<QString, QString> _orders;
}; };
//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> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet) : QueryBase(database), 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> template<class T>
Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count) Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
{ {
Q_D(Query);
QList<T*> result; QList<T*> result;
_select = "*"; d->select = "*";
qDebug()<<queryText();
QSqlQuery q = _database->exec(_database->sqlGenertor()->selectCommand(_wheres, _orders, _tableName, _joinClassName));
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(); QVariant lastPkValue = QVariant();
int childTypeId = 0; int childTypeId = 0;
T *lastRow = 0; T *lastRow = 0;
TableSetBase *childTableSet; TableSetBase *childTableSet;
QStringList masterFields = _database->model().model(_tableName)->fieldsNames(); QStringList masterFields = d->database->model().model(d->tableName)->fieldsNames();
QStringList childFields; QStringList childFields;
if(!_joinClassName.isNull()){ if(!d->joinClassName.isNull())
childFields = _database->model().modelByClass(_joinClassName)->fieldsNames(); if(d->database->model().modelByClass(d->joinClassName)){
QString joinTableName = _database->tableName(_joinClassName); childFields = d->database->model().modelByClass(d->joinClassName)->fieldsNames();
childTypeId = _database->model().model(joinTableName)->typeId(); QString joinTableName = d->database->tableName(d->joinClassName);
} childTypeId = d->database->model().model(joinTableName)->typeId();
}
while (q.next()) { while (q.next()) {
if(lastPkValue != q.value(pk)){ if(lastPkValue != q.value(pk)){
@ -114,7 +128,7 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
foreach (QString field, masterFields) foreach (QString field, masterFields)
t->setProperty(field.toLatin1().data(), q.value(field)); t->setProperty(field.toLatin1().data(), q.value(field));
t->setTableSet(_tableSet); t->setTableSet(d->tableSet);
t->setStatus(Table::FeatchedFromDB); t->setStatus(Table::FeatchedFromDB);
t->setParent(this); t->setParent(this);
@ -124,7 +138,7 @@ Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
if(childTypeId){ if(childTypeId){
QSet<TableSetBase*> tableSets = t->tableSets; QSet<TableSetBase*> tableSets = t->tableSets;
foreach (TableSetBase *ts, tableSets) foreach (TableSetBase *ts, tableSets)
if(ts->childClassName() == _joinClassName) if(ts->childClassName() == d->joinClassName)
childTableSet = ts; childTableSet = ts;
} }
} }
@ -166,8 +180,33 @@ Q_OUTOFLINE_TEMPLATE T *Query<T>::first()
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::count() Q_OUTOFLINE_TEMPLATE int Query<T>::count()
{ {
_select = "COUNT(*)"; Q_D(Query);
QSqlQuery q = _database->exec(queryText());
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()) if(q.next())
return q.value(0).toInt(); return q.value(0).toInt();
return 0; return 0;
@ -176,119 +215,45 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::count()
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::remove() Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
{ {
QString sql = _database->sqlGenertor()->deleteCommand(_wheres, _tableName); Q_D(Query);
// _database->sqlGenertor()->deleteRecords(_tableName, queryText());
QString sql = d->database->sqlGenertor()->deleteCommand(d->wheres, d->tableName);
// d->_database->sqlGenertor()->deleteRecords(_tableName, queryText());
// sql = compileCommand(sql); // sql = compileCommand(sql);
QSqlQuery q = _database->exec(sql); QSqlQuery q = d->database->exec(sql);
return q.numRowsAffected(); return q.numRowsAffected();
} }
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &tableName) Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &tableName)
{ {
_joinClassName = tableName; Q_D(Query);
d->joinClassName = tableName;
return this; return this;
} }
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(WherePhrase where) Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(WherePhrase where)
{ {
_wheres.append(where); Q_D(Query);
d->wheres.append(where);
return this; return this;
} }
//template<class T>
//Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(const QString &where)
//{
// _where = where;
// return this;
//}
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(QString fieldName, QString type) 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; return this;
} }
template<class T> 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)){ Q_D(Query);
QString q = command d->orderPhrases.append(phrase);
.replace("::", ".") return this;
.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;
} }
QT_END_NAMESPACE 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 "sqlgeneratorbase_p.h"
#include "table.h" #include "table.h"
#include "tablemodel.h" #include "tablemodel.h"
#include "wherephrase.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -174,9 +175,16 @@ QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
if(f != key) if(f != key)
values.append("'" + t->property(f.toLatin1().data()).toString() + "'"); 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)") sql = QString("INSERT INTO %1 (%2) VALUES (%3)")
.arg(tableName) .arg(tableName)
.arg(t->changedProperties().toList().join(", ")) .arg(changedPropertiesText)
.arg(values.join(", ")); .arg(values.join(", "));
return sql; return sql;
@ -208,6 +216,61 @@ QString SqlGeneratorBase::deleteRecord(Table *t, QString tableName)
.arg(t->primaryValue().toString()); .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 SqlGeneratorBase::deleteRecords(QString tableName, QString where)
{ {
QString sql = ""; QString sql = "";
@ -218,60 +281,70 @@ QString SqlGeneratorBase::deleteRecords(QString tableName, QString where)
return sql; 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()) { QString select = agregateText(t, agregateArg);
case QVariant::Int: QString where = createWhere(wheres);
case QVariant::Double: QString order = "";
return field.toString(); QString from = fromTableText(tableName, joinClassName, order);
break;
case QVariant::String: foreach(WherePhrase p, orders){
return "'" + field.toString() + "'"; if(order != "")
order.append(", ");
case QVariant::DateTime: order.append(phraseOrder(p.data()));
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 "";
} }
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 SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
{ {
QString whereText = ""; 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 != "") if(whereText != "")
whereText.append(" AND "); whereText.append(" AND ");
whereText.append(p.command(this));
whereText.append(phrase(w.data()));
} }
if(whereText != "") qDebug() << "WHWRE="<< whereText;
whereText.prepend(" WHERE "); // if(whereText != "")
// whereText.prepend(" WHERE ");
return whereText; 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 = ""; QString orderText = "";
QStringList orderby; QStringList orderby;
QString whereText = createWhere(wheres); QString whereText = createWhere(wheres);
if(whereText != "")
whereText.prepend(" WHERE ");
QString tableNameText = tableName; QString tableNameText = tableName;
if(!joinClassName.isNull()){ if(!joinClassName.isNull()){
QString joinTableName = _database->tableName(joinClassName); QString joinTableName = _database->tableName(joinClassName);
@ -302,27 +375,184 @@ QString SqlGeneratorBase::selectCommand(QList<WherePhrase> &wheres, QHash<QStrin
if(orderby.count()) if(orderby.count())
orderText = " ORDER BY " + orderby.join(", "); orderText = " ORDER BY " + orderby.join(", ");
QString command = "SELECT * FROM " QString command = "SELECT "
+selectPhrase
+ " FROM "
+ tableNameText + tableNameText
+ whereText + whereText
+ orderText; + orderText;
for(int i = 0; i < _database->model().count(); i++) for(int i = 0; i < _database->model().count(); i++)
command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + "."); command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + ".");
qDebug() << command;
return command; return command;
} }
QString SqlGeneratorBase::deleteCommand(QList<WherePhrase> &wheres, QString tableName) QString SqlGeneratorBase::deleteCommand(QList<WherePhrase> &wheres, QString tableName)
{ {
QString command = "DELETE FROM " QString command = "DELETE FROM " + tableName;
+ tableName QString where = createWhere(wheres);
+ createWhere(wheres);
if(where != "")
command.append(" WHERE " + where);
for(int i = 0; i < _database->model().count(); i++) for(int i = 0; i < _database->model().count(); i++)
command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + "."); command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + ".");
return command; 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 QT_END_NAMESPACE

View File

@ -24,6 +24,7 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include "wherephrase.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -31,8 +32,9 @@ class Table;
struct FieldModel; struct FieldModel;
class DatabaseModel; class DatabaseModel;
class TableModel; class TableModel;
class WherePhrase;
class Database; class Database;
//struct PhraseData;
//class WherePhrase;
class SqlGeneratorBase : public QObject class SqlGeneratorBase : public QObject
{ {
// Q_OBJECT // Q_OBJECT
@ -45,6 +47,13 @@ public:
Update, Update,
Delete Delete
}; };
enum AgregateType{
SelectALl,
Count,
Min,
Max,
Average
};
SqlGeneratorBase(Database *parent); SqlGeneratorBase(Database *parent);
virtual ~SqlGeneratorBase(); virtual ~SqlGeneratorBase();
@ -58,23 +67,35 @@ public:
virtual QString diff(FieldModel *oldField, FieldModel *newField); virtual QString diff(FieldModel *oldField, FieldModel *newField);
virtual QString diff(TableModel *oldTable, TableModel *newTable); virtual QString diff(TableModel *oldTable, TableModel *newTable);
virtual QString saveRecord(Table *t, QString tableName); virtual QString saveRecord(Table *t, QString tableName);
virtual QString insertRecord(Table *t, QString tableName); virtual QString insertRecord(Table *t, QString tableName);
virtual QString updateRecord(Table *t, QString tableName); virtual QString updateRecord(Table *t, QString tableName);
virtual QString deleteRecord(Table *t, QString tableName); virtual QString deleteRecord(Table *t, QString tableName);
virtual QString deleteRecords(QString tableName, QString where); 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, virtual QString selectCommand(QList<WherePhrase> &wheres, QHash<QString, QString> &orders,
QString tableName, QString joinClassName); 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 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: 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 createWhere(QList<WherePhrase> &wheres);
QString phraseOrder(const PhraseData *d) const;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -102,4 +102,12 @@ QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField)
return sql; 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 QT_END_NAMESPACE

View File

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

View File

@ -148,6 +148,7 @@ TableModel::TableModel(int typeId, QString tableName)
// get fields names // get fields names
for(int j = 0; j < tableMetaObject->classInfoCount(); j++){ for(int j = 0; j < tableMetaObject->classInfoCount(); j++){
QString name = tableMetaObject->classInfo(j).name(); QString name = tableMetaObject->classInfo(j).name();
name = name.replace("\"", "");
name = name.remove(__nut_NAME_PERFIX); name = name.remove(__nut_NAME_PERFIX);
@ -181,8 +182,8 @@ TableModel::TableModel(int typeId, QString tableName)
QString name = tableMetaObject->classInfo(j).name(); QString name = tableMetaObject->classInfo(j).name();
QString value = tableMetaObject->classInfo(j).value(); 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(" ")){ if(name.contains(" ")){
QStringList parts = name.split(" "); QStringList parts = name.split(" ");

View File

@ -28,327 +28,249 @@ QT_BEGIN_NAMESPACE
PhraseData::PhraseData(const char *className, const char *s){ PhraseData::PhraseData(const char *className, const char *s){
text = QString(className) + "." + s; text = QString(className) + "." + s;
type = Field; type = Field;
qDebug() << "(" << this << ")" << "Data type 0";
} }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) : left(l){ PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) : left(l){
operatorCond = o; operatorCond = o;
type = WithoutOperand; type = WithoutOperand;
qDebug() << "(" << this << ")" << "Data type 1";
} }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, const PhraseData *r) : left(l), right(r){ PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, const PhraseData *r) : left(l), right(r){
operatorCond = o; operatorCond = o;
type = WithOther; type = WithOther;
qDebug() << "(" << this << ")" << "Data type 2";
} }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r) : left(l), operand(r){ PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o, QVariant r) : left(l), operand(r){
operatorCond = o; operatorCond = o;
type = WithVariant; type = WithVariant;
qDebug() << "(" << this << ")" << "Data type 1";
} }
PhraseData::~PhraseData(){ PhraseData::~PhraseData(){
// if(type == WithOther){ qDebug() << "(" << this << ")" << "Data Deleting..." << type;
// delete left; if(type == WithOther){
// delete right; qDebug() << " - Other" << left << right;
// } delete left;
// if(type == WithVariant){ delete right;
//// 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 ",";
} }
if(type == WithVariant){
return QString("<FAIL>"); qDebug() << " - Variant" << left;
} if(left)
delete left;
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 "";
} }
} }
QString PhraseData::command(SqlGeneratorBase *generator) const PhraseData *WherePhrase::data() const
{ {
QString ret = ""; return _data;
}
switch(type){ WherePhrase::WherePhrase(const char *className, const char *s)
case Field: {
ret = text; qDebug() << "(" << this << ")" << "class ctor" << className << s;
break; _data = new PhraseData(className, s);
}
case WithVariant: WherePhrase::WherePhrase(const WherePhrase &l)
ret = left->command(generator) + " " + operatorString() + " " + escapeVariant(); {
break; _data = l._data;
// l._data = 0;
qDebug() << "(" << this << ")" << "Copy ctor, from" << _data << (&l);
_dataPointer = QSharedPointer<PhraseData>(l._dataPointer);
}
case WithOther: WherePhrase::WherePhrase(WherePhrase *l)
ret = left->command(generator) + " " + operatorString() + " " + right->command(generator); {
break; _data = l->_data;
case WithoutOperand: qDebug() << "(" << this << ")" << "From pointer" << _data;
ret = left->command(generator) + " " + operatorString(); // _dataPointer = QSharedPointer<PhraseData>(_data);
break; l->_data = 0;
} l->_dataPointer.reset(0);
}
if(operatorCond == PhraseData::And || operatorCond == PhraseData::Or) WherePhrase::WherePhrase(WherePhrase *l, PhraseData::Condition o)
ret = "(" + ret + ")"; {
_data = new PhraseData(l->_data, o);
return ret; // _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); _data = new PhraseData(l->_data, o, r->_data);
text = QString(className) + "." + s; // _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) qDebug() << "(" << this << ")" << "From variant," << _data << l << r;
{ l->_dataPointer.reset(0);
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);
} }
WherePhrase::~WherePhrase() WherePhrase::~WherePhrase()
{ {
// if(willDeleteData) qDebug() << "(" << this << ")" << "Dtor" << _data << _dataPointer.data();
// delete data; // if(_data){
// delete _data;
// qDebug() << "deleted";
// }
} }
WherePhrase WherePhrase::operator ==(const WherePhrase &other)
QString WherePhrase::command(SqlGeneratorBase *generator)
{ {
willDeleteData = true; return WherePhrase(this, PhraseData::Equal, (WherePhrase*)&other);
return data->command(generator);
} }
void WherePhrase::deleteData(PhraseData *d) WherePhrase WherePhrase::operator !=(const WherePhrase &other)
{ {
deleteData(d); return WherePhrase(this, PhraseData::NotEqual, (WherePhrase*)&other);
if(d->type == PhraseData::WithOther){
delete d->left;
delete d->right;
}
if(d->type == PhraseData::WithVariant)
delete d->left;
} }
WherePhrase WherePhrase::operator ==(const WherePhrase &other){ WherePhrase WherePhrase::operator <(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Equal, other.data); {
return WherePhrase(this, PhraseData::Less, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator !=(const WherePhrase &other){ WherePhrase WherePhrase::operator >(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::NotEqual, other.data); {
return WherePhrase(this, PhraseData::Greater, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator <(const WherePhrase &other){ WherePhrase WherePhrase::operator <=(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Less, other.data); {
return WherePhrase(this, PhraseData::LessEqual, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator >(const WherePhrase &other){ WherePhrase WherePhrase::operator >=(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Greater, other.data); {
} return WherePhrase(this, PhraseData::GreaterEqual, (WherePhrase*)&other);
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) 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){ WherePhrase WherePhrase::operator +(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Add, other.data); {
return WherePhrase(this, PhraseData::Add, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator -(const WherePhrase &other){ WherePhrase WherePhrase::operator -(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Minus, other.data); {
return WherePhrase(this, PhraseData::Minus, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator *(const WherePhrase &other){ WherePhrase WherePhrase::operator *(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Multiple, other.data); {
return WherePhrase(this, PhraseData::Multiple, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator /(const WherePhrase &other){ WherePhrase WherePhrase::operator /(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Divide, other.data); {
return WherePhrase(this, PhraseData::Divide, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator &&(const WherePhrase &other){ WherePhrase WherePhrase::operator &&(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::And, other.data); {
return WherePhrase(this, PhraseData::And, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator ||(const WherePhrase &other){ WherePhrase WherePhrase::operator ||(const WherePhrase &other)
return WherePhrase(this->data, PhraseData::Or, other.data); {
return WherePhrase(this, PhraseData::Or, (WherePhrase*)&other);
} }
WherePhrase WherePhrase::operator &(const 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 !(){ WherePhrase FieldPhrase::operator !()
if(data->operatorCond < 20) {
data->operatorCond = (PhraseData::Condition)((data->operatorCond + 10) % 20); if(_data->operatorCond < 20)
_data->operatorCond = (PhraseData::Condition)((_data->operatorCond + 10) % 20);
else else
qFatal("Operator ! can not aplied to non condition statements"); qFatal("Operator ! can not aplied to non condition statements");
return WherePhrase(data); return this;//WherePhrase(this, PhraseData::Not);
} }
WherePhrase WherePhrase::operator ==(const QVariant &other){ 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)
{ {
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) FieldPhrase::FieldPhrase(const char *className, const char *s) : WherePhrase(className, s)
{ {
data = new PhraseData(className, s); qDebug() << "(" << this << ")" << "FieldPhrase ctor" << className << s;
text = QString(className) + "." + s;
} }
WherePhrase FieldPhrase::operator &(const QVariant &other) WherePhrase FieldPhrase::operator =(const QVariant &other)
{ {
Q_UNUSED(other); return WherePhrase(this, PhraseData::Set, other);
qFatal("The operator & can not applied for two fields");
} }
WherePhrase FieldPhrase::isNull(){ WherePhrase FieldPhrase::isNull(){
return WherePhrase(this->data, PhraseData::Null); return WherePhrase(this, PhraseData::Null);
} }
WherePhrase FieldPhrase::in(QVariantList list) WherePhrase FieldPhrase::in(QVariantList list)
{ {
return WherePhrase(this->data, PhraseData::In, list); return WherePhrase(this, PhraseData::In, list);
} }
WherePhrase FieldPhrase::in(QStringList list) WherePhrase FieldPhrase::in(QStringList list)
{ {
return WherePhrase(this->data, PhraseData::In, list); return WherePhrase(this, PhraseData::In, list);
} }
WherePhrase FieldPhrase::like(QString pattern) WherePhrase FieldPhrase::like(QString pattern)
{ {
return WherePhrase(this->data, PhraseData::Like, pattern); return WherePhrase(this, PhraseData::Like, pattern);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -27,21 +27,25 @@
#include <QDate> #include <QDate>
#include <QDateTime> #include <QDateTime>
#include <QTime> #include <QTime>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class SqlGeneratorBase; class SqlGeneratorBase;
struct PhraseData{ class PhraseData{
public:
enum Condition enum Condition
{ {
Equal = 0, NotAssign = 0,
Equal,
Less, Less,
LessEqual, LessEqual,
Null, Null,
In, In,
Like, Like,
NotEqual = 10, Not = 10,
NotEqual,
GreaterEqual, GreaterEqual,
Greater, Greater,
NotNull, NotNull,
@ -51,6 +55,7 @@ struct PhraseData{
And = 20, And = 20,
Or, Or,
Append, Append,
Set, Set,
@ -81,34 +86,24 @@ struct PhraseData{
PhraseData(PhraseData *l, Condition o, QVariant r); PhraseData(PhraseData *l, Condition o, QVariant r);
~PhraseData(); ~PhraseData();
QString operatorString() const;
QString escapeVariant() const;
QString command(SqlGeneratorBase *generator) const;
}; };
class WherePhrase{ class WherePhrase{
protected: protected:
PhraseData *data; PhraseData *_data;
bool willDeleteData; QSharedPointer<PhraseData> _dataPointer;
public: public:
QString text;
WherePhrase(const char *className, const char* s); WherePhrase(const char *className, const char* s);
WherePhrase(PhraseData *l); WherePhrase(const WherePhrase &l);
WherePhrase(PhraseData *l, PhraseData::Condition o); WherePhrase(WherePhrase *l);
WherePhrase(PhraseData *l, PhraseData::Condition o, PhraseData *r); WherePhrase(WherePhrase *l, PhraseData::Condition o);
WherePhrase(PhraseData *l, PhraseData::Condition o, QVariant r); WherePhrase(WherePhrase *l, PhraseData::Condition o, WherePhrase *r);
WherePhrase(WherePhrase *l, PhraseData::Condition o, QVariant r);
~WherePhrase(); ~WherePhrase();
QString command(SqlGeneratorBase *generator);
void deleteData(PhraseData *d);
WherePhrase operator ==(const WherePhrase &other); WherePhrase operator ==(const WherePhrase &other);
WherePhrase operator !=(const WherePhrase &other); 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); WherePhrase operator >=(const QVariant &other);
PhraseData *data() const;
}; };
class FieldPhrase: public WherePhrase{ class FieldPhrase: public WherePhrase{
public: public:
FieldPhrase(const char *className, const char* s); FieldPhrase(const char *className, const char* s);
WherePhrase operator &(const QVariant &other);
WherePhrase operator =(const QVariant &other); WherePhrase operator =(const QVariant &other);
WherePhrase operator !(); WherePhrase operator !();
@ -154,6 +148,13 @@ public:
WherePhrase like(QString pattern); WherePhrase like(QString pattern);
}; };
//TODO: make FieldPhrase template class
//template <typename T>
//class FieldPhrase: public WherePhrase{
//};
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // PHRASE_H #endif // PHRASE_H

View File

@ -33,6 +33,11 @@ void MainTest::initTestCase()
bool ok = db.open(); bool ok = db.open();
QTEST_ASSERT(ok); QTEST_ASSERT(ok);
FROM(db.comments())
DELETE();
FROM(db.posts())
DELETE();
} }
void MainTest::dataScheema() void MainTest::dataScheema()
@ -67,13 +72,36 @@ void MainTest::createPost()
qDebug() << "New post inserted with id:" << newPost->id(); 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() void MainTest::selectPosts()
{ {
// auto q = FROM(db.posts()) // auto q = FROM(db.posts())
// JOIN(Comment) // JOIN(Comment)
// WHERE(Post::idField() == postId); // WHERE(Post::idField() == postId);
auto q = db.posts()->createQuery(); auto q = db.posts()->createQuery();
q->join("Comment"); q->join(Post::commentsTable());
q->orderBy(!Post::saveDateField() & Post::bodyField());
q->setWhere(Post::idField() == postId); q->setWhere(Post::idField() == postId);
auto posts = q->toList(); auto posts = q->toList();
@ -91,6 +119,15 @@ void MainTest::selectPosts()
db.cleanUp(); 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() void MainTest::testDate()
{ {
QDateTime d = QDateTime::currentDateTime(); QDateTime d = QDateTime::currentDateTime();
@ -116,15 +153,22 @@ void MainTest::testDate()
void MainTest::selectWithInvalidRelation() void MainTest::selectWithInvalidRelation()
{ {
auto q = FROM(db.posts()) auto q = db.posts()->createQuery();
JOIN(Invalid_Class_Name) q->join("Invalid_Class_Name");
SELECT(); q->toList();
}
void MainTest::select10NewstPosts()
{
auto q = db.posts()->createQuery();
q->orderBy(!Post::saveDateField());
q->toList(10);
} }
void MainTest::modifyPost() void MainTest::modifyPost()
{ {
auto q = FROM(db.posts()) auto q = db.posts()->createQuery();
WHERE(Post::idField() == postId); q->setWhere(Post::idField() == postId);
Post *post = q->first(); Post *post = q->first();

View File

@ -22,9 +22,12 @@ private slots:
void dataScheema(); void dataScheema();
void createPost(); void createPost();
void createPost2();
void selectPosts(); void selectPosts();
void selectPostsWithoutTitle();
void testDate(); void testDate();
void selectWithInvalidRelation(); void selectWithInvalidRelation();
void select10NewstPosts();
void modifyPost(); void modifyPost();
void deletePost(); void deletePost();
}; };

View File

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

View File

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

View File

@ -1,11 +1,17 @@
#ifndef CONSTS_H #ifndef CONSTS_H
#define 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 HOST "127.0.0.1"
#define DATABASE "nutdb3" #define DATABASE "nutdb"
#define USERNAME "postgres" #define USERNAME "root"
#define PASSWORD "856856" #define PASSWORD "onlyonlyi"
// db.setDriver("QODBC"); // db.setDriver("QODBC");
// db.setHostName("127.0.0.1"); // db.setHostName("127.0.0.1");