commit
ac6e55b60d
|
|
@ -7,6 +7,3 @@ before_install:
|
||||||
script:
|
script:
|
||||||
- qmake nut.pro
|
- qmake nut.pro
|
||||||
- make
|
- make
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class ChangeLogTable : public Table
|
||||||
NUT_DECLARE_FIELD(QString, version, version, setVersion)
|
NUT_DECLARE_FIELD(QString, version, version, setVersion)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChangeLogTable(QObject *tableSet = Q_NULLPTR);
|
ChangeLogTable(QObject *parentTableSet = Q_NULLPTR);
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -188,16 +188,20 @@ bool DatabasePrivate::getCurrectScheema()
|
||||||
changeLogs = new TableSet<ChangeLogTable>(q);
|
changeLogs = new TableSet<ChangeLogTable>(q);
|
||||||
|
|
||||||
for (int i = 0; i < q->metaObject()->classInfoCount(); i++) {
|
for (int i = 0; i < q->metaObject()->classInfoCount(); i++) {
|
||||||
QMetaClassInfo ci = q->metaObject()->classInfo(i);
|
QString type;
|
||||||
QString ciName = QString(ci.name())
|
QString name;
|
||||||
.replace(__nut_NAME_PERFIX, "")
|
QString value;
|
||||||
.replace("\"", "");
|
|
||||||
|
|
||||||
if (ciName.startsWith(__nut_TABLE))
|
if (!checkClassInfo(q->metaObject()->classInfo(i),
|
||||||
tables.insert(ciName.split(" ").at(1), ci.value());
|
type, name, value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ciName == __nut_DB_VERSION) {
|
if (type == __nut_TABLE)
|
||||||
currentModel.setVersion(QString(ci.value()));
|
tables.insert(name, value);
|
||||||
|
|
||||||
|
if (type == __nut_DB_VERSION)
|
||||||
|
currentModel.setVersion(name);
|
||||||
|
|
||||||
/* TODO: remove
|
/* TODO: remove
|
||||||
QStringList version
|
QStringList version
|
||||||
|
|
@ -213,7 +217,6 @@ bool DatabasePrivate::getCurrectScheema()
|
||||||
if (!ok)
|
if (!ok)
|
||||||
qFatal("NUT_DB_VERSION macro accept version in format 'x' or "
|
qFatal("NUT_DB_VERSION macro accept version in format 'x' or "
|
||||||
"'x[.y]' only, and x,y must be integer values\n");*/
|
"'x[.y]' only, and x,y must be integer values\n");*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < q->metaObject()->propertyCount(); i++) {
|
for (int i = 1; i < q->metaObject()->propertyCount(); i++) {
|
||||||
|
|
@ -227,14 +230,30 @@ bool DatabasePrivate::getCurrectScheema()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (TableModel *sch, currentModel)
|
foreach (TableModel *table, currentModel)
|
||||||
foreach (RelationModel *fk, sch->foregionKeys())
|
foreach (RelationModel *fk, table->foregionKeys())
|
||||||
fk->table = currentModel.tableByClassName(fk->className);
|
fk->masterTable = currentModel.tableByClassName(fk->masterClassName);
|
||||||
|
|
||||||
allTableMaps.insert(q->metaObject()->className(), currentModel);
|
allTableMaps.insert(q->metaObject()->className(), currentModel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DatabasePrivate::checkClassInfo(const QMetaClassInfo &classInfo, QString &type, QString &name, QString &value)
|
||||||
|
{
|
||||||
|
if (!QString(classInfo.name()).startsWith(__nut_NAME_PERFIX)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
QStringList parts = QString(classInfo.value()).split("\n");
|
||||||
|
if (parts.count() != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
type = parts[0];
|
||||||
|
name = parts[1];
|
||||||
|
value = parts[2];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DatabaseModel DatabasePrivate::getLastScheema()
|
DatabaseModel DatabasePrivate::getLastScheema()
|
||||||
{
|
{
|
||||||
ChangeLogTable *u = changeLogs->query()
|
ChangeLogTable *u = changeLogs->query()
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ public:
|
||||||
DatabaseModel getLastScheema();
|
DatabaseModel getLastScheema();
|
||||||
bool getCurrectScheema();
|
bool getCurrectScheema();
|
||||||
|
|
||||||
|
bool checkClassInfo(const QMetaClassInfo &classInfo,
|
||||||
|
QString &type, QString &name, QString &value);
|
||||||
QSqlDatabase db;
|
QSqlDatabase db;
|
||||||
|
|
||||||
QString hostName;
|
QString hostName;
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,20 @@ QMap<QString, DatabaseModel*> DatabaseModel::_models;
|
||||||
|
|
||||||
#define NODE_VERSION "version"
|
#define NODE_VERSION "version"
|
||||||
#define NODE_TABLES "tables"
|
#define NODE_TABLES "tables"
|
||||||
DatabaseModel::DatabaseModel(const QString &name) : QList<TableModel*>(), _databaseClassName(name), _version(QString::null)
|
DatabaseModel::DatabaseModel(const QString &name) :
|
||||||
|
QList<TableModel*>(), _databaseClassName(name), _version(QString::null)
|
||||||
{
|
{
|
||||||
_models.insert(name, this);
|
_models.insert(name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseModel::DatabaseModel(const DatabaseModel &other) : QList<TableModel*>(other), _version(QString::null)
|
DatabaseModel::DatabaseModel(const DatabaseModel &other) :
|
||||||
|
QList<TableModel*>(other), _version(QString::null)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseModel::DatabaseModel(const QJsonObject &json) : QList<TableModel*>()
|
DatabaseModel::DatabaseModel(const QJsonObject &json) :
|
||||||
|
QList<TableModel*>()
|
||||||
{
|
{
|
||||||
setVersion(json.value(NODE_VERSION).toString());
|
setVersion(json.value(NODE_VERSION).toString());
|
||||||
|
|
||||||
|
|
@ -70,16 +73,15 @@ TableModel *DatabaseModel::tableByName(QString tableName) const
|
||||||
|
|
||||||
TableModel *DatabaseModel::tableByClassName(QString className) const
|
TableModel *DatabaseModel::tableByClassName(QString className) const
|
||||||
{
|
{
|
||||||
|
QStringList l;
|
||||||
for(int i = 0; i < size(); i++){
|
for(int i = 0; i < size(); i++){
|
||||||
TableModel *s = at(i);
|
TableModel *s = at(i);
|
||||||
|
|
||||||
|
l.append(s->className());
|
||||||
if(s->className() == className)
|
if(s->className() == className)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// qWarning("Table with class name '%s' not found in model",
|
|
||||||
// qUtf8Printable(className));
|
|
||||||
// Q_UNREACHABLE();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,7 +147,7 @@ RelationModel *DatabaseModel::relationByClassNames(const QString &masterClassNam
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
foreach (RelationModel *rel, childTable->foregionKeys())
|
foreach (RelationModel *rel, childTable->foregionKeys())
|
||||||
if(rel->className == masterClassName)
|
if(rel->masterClassName == masterClassName)
|
||||||
return rel;
|
return rel;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -159,7 +161,7 @@ RelationModel *DatabaseModel::relationByTableNames(const QString &masterTableNam
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
foreach (RelationModel *rel, childTable->foregionKeys())
|
foreach (RelationModel *rel, childTable->foregionKeys())
|
||||||
if(rel->table->name() == masterTableName)
|
if(rel->masterTable->name() == masterTableName)
|
||||||
return rel;
|
return rel;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -204,6 +206,15 @@ bool DatabaseModel::remove(const QString &tableName)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseModel::fixRelations()
|
||||||
|
{
|
||||||
|
/*TODO: fixme
|
||||||
|
foreach (TableModel *table, currentModel)
|
||||||
|
foreach (RelationModel *fk, table->foregionKeys())
|
||||||
|
fk->masterTable = currentModel.tableByClassName(fk->masterClassName);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
DatabaseModel *DatabaseModel::modelByName(const QString &name)
|
DatabaseModel *DatabaseModel::modelByName(const QString &name)
|
||||||
{
|
{
|
||||||
if (_models.contains(name))
|
if (_models.contains(name))
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ public:
|
||||||
|
|
||||||
bool remove(const QString &tableName);
|
bool remove(const QString &tableName);
|
||||||
|
|
||||||
|
//TODO: may be private (called from DatabasePrivate::getCurrectScheema only)
|
||||||
|
void fixRelations();
|
||||||
|
|
||||||
static DatabaseModel *modelByName(const QString &name);
|
static DatabaseModel *modelByName(const QString &name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,15 @@
|
||||||
# define NUT_EXPORT Q_DECL_EXPORT
|
# define NUT_EXPORT Q_DECL_EXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define NUT_INFO(type, name, value) \
|
||||||
|
Q_CLASSINFO(__nut_NAME_PERFIX type #name #value, type "\n" #name "\n" #value)
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
//TODO: remove minor version
|
|
||||||
#define NUT_DB_VERSION(version) \
|
#define NUT_DB_VERSION(version) \
|
||||||
Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX __nut_DB_VERSION), #version)
|
NUT_INFO(__nut_DB_VERSION, version, 0)
|
||||||
|
|
||||||
#define NUT_DECLARE_TABLE(type, name) \
|
#define NUT_DECLARE_TABLE(type, name) \
|
||||||
Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX __nut_TABLE " " #type), #name) \
|
NUT_INFO(__nut_TABLE, type, name) \
|
||||||
Q_PROPERTY(type* name READ name) \
|
Q_PROPERTY(type* name READ name) \
|
||||||
Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name##s READ name##s) \
|
Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name##s READ name##s) \
|
||||||
type* m_##name; \
|
type* m_##name; \
|
||||||
|
|
@ -51,7 +53,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(QT_STRINGIFY(__nut_NAME_PERFIX #name " " __nut_FIELD), #name) \
|
NUT_INFO(__nut_FIELD, name, 0) \
|
||||||
type m_##name; \
|
type m_##name; \
|
||||||
public: \
|
public: \
|
||||||
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) name ## Field(){ \
|
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) name ## Field(){ \
|
||||||
|
|
@ -69,7 +71,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(QT_STRINGIFY(__nut_NAME_PERFIX #name "Id " __nut_FOREGION_KEY), #type) \
|
NUT_INFO(__nut_FOREGION_KEY, name, type) \
|
||||||
type *m_##name; \
|
type *m_##name; \
|
||||||
public: \
|
public: \
|
||||||
type *read() const { return m_##name ; } \
|
type *read() const { return m_##name ; } \
|
||||||
|
|
@ -94,27 +96,14 @@ public: \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define NUT_PRIMARY_KEY(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_PRIMARY_KEY), #x)
|
#define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0)
|
||||||
#define NUT_AUTO_INCREMENT(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_AUTO_INCREMENT), #x)
|
#define NUT_AUTO_INCREMENT(x) NUT_INFO(__nut_AUTO_INCREMENT, x, 0)
|
||||||
#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(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_UNIQUE), #x)
|
#define NUT_UNIQUE(x) NUT_INFO(__nut_UNIQUE, x, 0)
|
||||||
#define NUT_LEN(field, len) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #field " " __nut_LEN), #len)
|
#define NUT_LEN(field, len) NUT_INFO(__nut_LEN, field, len)
|
||||||
#define NUT_DEFAULT_VALUE(x, n) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_DEFAULT_VALUE), #n)
|
#define NUT_DEFAULT_VALUE(x, n) NUT_INFO(__nut_DEFAULT_VALUE, x, n)
|
||||||
#define NUT_NOT_NULL(x) Q_CLASSINFO(QT_STRINGIFY(__nut_NAME_PERFIX #x " " __nut_NOT_NULL), "1")
|
#define NUT_NOT_NULL(x) NUT_INFO(__nut_NOT_NULL, x, 1)
|
||||||
#define NUT_INDEX(name, field, order)
|
#define NUT_INDEX(name, field, order)
|
||||||
|
|
||||||
#ifndef NUT_NO_KEYWORDS
|
|
||||||
# define FROM(x) (x->query())
|
|
||||||
# define WHERE(x) ->setWhere(x)
|
|
||||||
# define JOIN(x) ->join<x>()
|
|
||||||
# define ORDERBY(x) ->orderBy(#x);
|
|
||||||
# define ORDERBY_DESC(x) ->orderBy(!#x);
|
|
||||||
|
|
||||||
# define SELECT() ->toList()
|
|
||||||
# define COUNT() ->count()
|
|
||||||
# define DELETE() ->remove()
|
|
||||||
# define FIRST() ->first()
|
|
||||||
#endif // NUT_NO_KEYWORDS
|
|
||||||
|
|
||||||
#endif // SYNTAX_DEFINES_H
|
#endif // SYNTAX_DEFINES_H
|
||||||
|
|
|
||||||
|
|
@ -134,4 +134,24 @@ QString MySqlGenerator::phrase(const PhraseData *d) const
|
||||||
return SqlGeneratorBase::phrase(d);
|
return SqlGeneratorBase::phrase(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString MySqlGenerator::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
|
QString agregateArg,
|
||||||
|
QString tableName,
|
||||||
|
QList<WherePhrase> &wheres,
|
||||||
|
QList<WherePhrase> &orders,
|
||||||
|
QList<RelationModel*> joins,
|
||||||
|
int skip, int take)
|
||||||
|
{
|
||||||
|
QString command = SqlGeneratorBase::selectCommand(t, agregateArg,
|
||||||
|
tableName,
|
||||||
|
wheres, orders,
|
||||||
|
joins, skip, take);
|
||||||
|
|
||||||
|
if (take != -1 && skip != -1)
|
||||||
|
command.append(QString(" LIMIT %1 OFFSET %2")
|
||||||
|
.arg(take)
|
||||||
|
.arg(skip));
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ public:
|
||||||
QString escapeValue(const QVariant &v) const;
|
QString escapeValue(const QVariant &v) const;
|
||||||
QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
|
QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
|
||||||
QString phrase(const PhraseData *d) const;
|
QString phrase(const PhraseData *d) const;
|
||||||
|
QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QList<RelationModel *> joins, int skip, int take);
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,11 @@
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
|
#include <QDebug>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QUuid>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include "sqlgeneratorbase_p.h"
|
#include "sqlgeneratorbase_p.h"
|
||||||
|
|
@ -44,6 +46,11 @@ NUT_BEGIN_NAMESPACE
|
||||||
* REFERENCES `account` (`id`)
|
* REFERENCES `account` (`id`)
|
||||||
* ON DELETE CASCADE
|
* ON DELETE CASCADE
|
||||||
* ON UPDATE CASCADE;
|
* ON UPDATE CASCADE;
|
||||||
|
*
|
||||||
|
* SELECT
|
||||||
|
* FROM dbo.GiftTypes
|
||||||
|
* INNER JOIN dbo.GiftCards ON dbo.GiftTypes.GiftTypeID = dbo.GiftCards.GiftTypeID
|
||||||
|
* INNER JOIN dbo.Entities ON dbo.GiftCards.GiftCardID = dbo.Entities.GiftCardID
|
||||||
*/
|
*/
|
||||||
SqlGeneratorBase::SqlGeneratorBase(Database *parent)
|
SqlGeneratorBase::SqlGeneratorBase(Database *parent)
|
||||||
: QObject((QObject *)parent)
|
: QObject((QObject *)parent)
|
||||||
|
|
@ -64,7 +71,8 @@ QString SqlGeneratorBase::masterDatabaseName(QString databaseName)
|
||||||
|
|
||||||
QString SqlGeneratorBase::createTable(TableModel *table)
|
QString SqlGeneratorBase::createTable(TableModel *table)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(table);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
|
QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
|
||||||
|
|
@ -88,6 +96,20 @@ QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SqlGeneratorBase::recordsPhrase(TableModel *table)
|
||||||
|
{
|
||||||
|
if (!table)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
QString ret = "";
|
||||||
|
foreach (FieldModel *f, table->fields()) {
|
||||||
|
if (!ret.isEmpty())
|
||||||
|
ret.append(", ");
|
||||||
|
ret.append(QString("%1.%2 AS [%1.%2]").arg(table->name()).arg(f->name));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
|
QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
|
||||||
{
|
{
|
||||||
return field->name + " " + fieldType(field) + (field->notNull ? " NOT NULL" : "");
|
return field->name + " " + fieldType(field) + (field->notNull ? " NOT NULL" : "");
|
||||||
|
|
@ -178,27 +200,93 @@ QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SqlGeneratorBase::join(const QStringList &list)
|
QString SqlGeneratorBase::join(const QString &mainTable,
|
||||||
|
const QList<RelationModel*> list,
|
||||||
|
QStringList *order)
|
||||||
{
|
{
|
||||||
|
QString ret = mainTable;
|
||||||
|
QList<RelationModel*>::const_iterator i;
|
||||||
|
for (i = list.begin(); i != list.end(); ++i) {
|
||||||
|
if ((*i)->masterTable->name() == mainTable) {
|
||||||
|
ret.append(QString(" INNER JOIN %3 ON %1.%2 = %3.%4")
|
||||||
|
.arg((*i)->masterTable->name())
|
||||||
|
.arg((*i)->masterTable->primaryKey())
|
||||||
|
.arg((*i)->slaveTable->name())
|
||||||
|
.arg((*i)->localColumn));
|
||||||
|
|
||||||
|
if (order != Q_NULLPTR)
|
||||||
|
order->append((*i)->slaveTable->name() + "." + (*i)->slaveTable->primaryKey());
|
||||||
|
} else {
|
||||||
|
ret.append(QString(" INNER JOIN %3 ON %1.%2 = %3.%4")
|
||||||
|
.arg(mainTable)
|
||||||
|
.arg((*i)->localColumn)
|
||||||
|
.arg((*i)->masterTable->name())
|
||||||
|
.arg((*i)->masterTable->primaryKey()));
|
||||||
|
|
||||||
|
if (order != Q_NULLPTR)
|
||||||
|
order->append((*i)->masterTable->name() + "." + (*i)->masterTable->primaryKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
|
||||||
|
{
|
||||||
|
//TODO: reorder list first!
|
||||||
|
//TODO: make this ungly code better and bugless :-)
|
||||||
|
/*
|
||||||
|
* Known issues:
|
||||||
|
* Support onle near joins, far supports with medium table finding not support yet
|
||||||
|
*/
|
||||||
|
|
||||||
if (!list.count())
|
if (!list.count())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
if (list.count() == 1)
|
if (list.count() == 1)
|
||||||
return list.first();
|
return "[" + list.first() + "]";
|
||||||
|
|
||||||
DatabaseModel model = _database->model();
|
DatabaseModel model = _database->model();
|
||||||
QStringList clone = list;
|
QStringList clone = list;
|
||||||
QString mainTable = clone.takeFirst();
|
QString mainTable = clone.takeFirst();
|
||||||
QString ret = mainTable;
|
QString ret = "[" + mainTable + "]";
|
||||||
|
|
||||||
do {
|
do {
|
||||||
QString t = model.tableByClassName(clone.first())->name();
|
if (!clone.count())
|
||||||
RelationModel *rel = model.relationByTableNames(mainTable, t);
|
break;
|
||||||
|
|
||||||
|
QString table = clone.first();// model.tableByClassName(clone.first())->name();
|
||||||
|
RelationModel *rel = model.relationByClassNames(mainTable, clone.first());
|
||||||
if (rel) {
|
if (rel) {
|
||||||
clone.takeFirst();
|
//mainTable is master of table
|
||||||
ret.append(", " + _database->tableName(clone.takeFirst()));
|
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
|
||||||
|
.arg(table)
|
||||||
|
.arg(rel->masterTable->primaryKey())
|
||||||
|
.arg(rel->localColumn)
|
||||||
|
.arg(mainTable));
|
||||||
|
|
||||||
|
if (order != Q_NULLPTR)
|
||||||
|
order->append(mainTable + "." + rel->masterTable->primaryKey());
|
||||||
|
|
||||||
|
} else{
|
||||||
|
rel = model.relationByClassNames(clone.first(), mainTable);
|
||||||
|
if (rel) {
|
||||||
|
// table is master of mainTable
|
||||||
|
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
|
||||||
|
.arg(table)
|
||||||
|
.arg(rel->localColumn)
|
||||||
|
.arg(rel->masterTable->primaryKey())
|
||||||
|
.arg(mainTable));
|
||||||
|
|
||||||
|
if (order != Q_NULLPTR)
|
||||||
|
order->append(mainTable + "." + rel->localColumn);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qInfo("Relation for %s and %s not exists",
|
||||||
|
qPrintable(table), qPrintable(mainTable));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clone.takeFirst();
|
||||||
} while (clone.count());
|
} while (clone.count());
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -340,23 +428,40 @@ QString SqlGeneratorBase::deleteRecords(QString tableName, QString where)
|
||||||
|
|
||||||
QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
|
QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
QString agregateArg,
|
QString agregateArg,
|
||||||
|
QString tableName,
|
||||||
QList<WherePhrase> &wheres,
|
QList<WherePhrase> &wheres,
|
||||||
QList<WherePhrase> &orders,
|
QList<WherePhrase> &orders,
|
||||||
QString tableName,
|
QList<RelationModel*> joins,
|
||||||
QString joinClassName, int skip, int take)
|
int skip, int take)
|
||||||
{
|
{
|
||||||
Q_UNUSED(take);
|
Q_UNUSED(take);
|
||||||
Q_UNUSED(skip);
|
Q_UNUSED(skip);
|
||||||
|
|
||||||
|
QStringList joinedOrders;
|
||||||
QString select = agregateText(t, agregateArg);
|
QString select = agregateText(t, agregateArg);
|
||||||
|
|
||||||
|
//TODO: temporatory disabled
|
||||||
|
if (t == SelectAll) {
|
||||||
|
QSet<TableModel*> tables;
|
||||||
|
tables.insert(_database->model().tableByName(tableName));
|
||||||
|
foreach (RelationModel *rel, joins)
|
||||||
|
tables << rel->masterTable << rel->slaveTable;
|
||||||
|
|
||||||
|
select = "";
|
||||||
|
foreach (TableModel *t, tables) {
|
||||||
|
if (!select.isEmpty())
|
||||||
|
select.append(", ");
|
||||||
|
select.append(recordsPhrase(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString from = join(tableName, joins, &joinedOrders);
|
||||||
QString where = createWhere(wheres);
|
QString where = createWhere(wheres);
|
||||||
QString order = "";
|
QString orderText = joinedOrders.join(", ");
|
||||||
QString from = fromTableText(tableName, joinClassName, order);
|
|
||||||
|
|
||||||
foreach (WherePhrase p, orders) {
|
foreach (WherePhrase p, orders) {
|
||||||
if (order != "")
|
if (orderText != "")
|
||||||
order.append(", ");
|
orderText.append(", ");
|
||||||
order.append(phraseOrder(p.data()));
|
orderText.append(phraseOrder(p.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString sql = "SELECT " + select + " FROM " + from;
|
QString sql = "SELECT " + select + " FROM " + from;
|
||||||
|
|
@ -364,8 +469,8 @@ QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
if (where != "")
|
if (where != "")
|
||||||
sql.append(" WHERE " + where);
|
sql.append(" WHERE " + where);
|
||||||
|
|
||||||
if (order != "")
|
if (orderText != "")
|
||||||
sql.append(" ORDER BY " + order);
|
sql.append(" ORDER BY " + orderText);
|
||||||
|
|
||||||
for (int i = 0; i < _database->model().count(); i++)
|
for (int i = 0; i < _database->model().count(); i++)
|
||||||
sql = sql.replace(_database->model().at(i)->className() + ".",
|
sql = sql.replace(_database->model().at(i)->className() + ".",
|
||||||
|
|
@ -373,7 +478,7 @@ QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
|
|
||||||
replaceTableNames(sql);
|
replaceTableNames(sql);
|
||||||
|
|
||||||
return sql;
|
return sql + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
|
QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
|
||||||
|
|
@ -393,7 +498,8 @@ QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
|
||||||
void SqlGeneratorBase::replaceTableNames(QString &command)
|
void SqlGeneratorBase::replaceTableNames(QString &command)
|
||||||
{
|
{
|
||||||
foreach (TableModel *m, TableModel::allModels())
|
foreach (TableModel *m, TableModel::allModels())
|
||||||
command = command.replace("[" + m->className() + "].", "`" + m->name() + "`.");
|
command = command
|
||||||
|
.replace("[" + m->className() + "]", "`" + m->name() + "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SqlGeneratorBase::removeTableNames(QString &command)
|
void SqlGeneratorBase::removeTableNames(QString &command)
|
||||||
|
|
@ -441,14 +547,6 @@ QString SqlGeneratorBase::updateCommand(WherePhrase &phrase,
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SqlGeneratorBase::joinTables(QStringList tables)
|
|
||||||
{
|
|
||||||
Q_UNUSED(tables);
|
|
||||||
//TODO: implement me
|
|
||||||
// _database->model().relationByClassNames()
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SqlGeneratorBase::escapeValue(const QVariant &v) const
|
QString SqlGeneratorBase::escapeValue(const QVariant &v) const
|
||||||
{
|
{
|
||||||
switch (v.type()) {
|
switch (v.type()) {
|
||||||
|
|
@ -464,18 +562,22 @@ QString SqlGeneratorBase::escapeValue(const QVariant &v) const
|
||||||
return v.toString();
|
return v.toString();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QVariant::Uuid:
|
||||||
|
return v.toUuid().toString();
|
||||||
|
break;
|
||||||
|
|
||||||
case QVariant::Char:
|
case QVariant::Char:
|
||||||
case QVariant::String:
|
case QVariant::String:
|
||||||
return "'" + v.toString() + "'";
|
return "'" + v.toString() + "'";
|
||||||
|
|
||||||
case QVariant::DateTime:
|
case QVariant::DateTime:
|
||||||
return "'" + v.toDateTime().toString() + "'";
|
return "'" + v.toDateTime().toString(Qt::ISODate) + "'";
|
||||||
|
|
||||||
case QVariant::Date:
|
case QVariant::Date:
|
||||||
return "'" + v.toDate().toString() + "'";
|
return "'" + v.toDate().toString(Qt::ISODate) + "'";
|
||||||
|
|
||||||
case QVariant::Time:
|
case QVariant::Time:
|
||||||
return "'" + v.toTime().toString() + "'";
|
return "'" + v.toTime().toString(Qt::ISODate) + "'";
|
||||||
|
|
||||||
case QVariant::StringList:
|
case QVariant::StringList:
|
||||||
case QVariant::List:
|
case QVariant::List:
|
||||||
|
|
@ -496,6 +598,7 @@ QString SqlGeneratorBase::escapeValue(const QVariant &v) const
|
||||||
return "<FAIL>";
|
return "<FAIL>";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ struct FieldModel;
|
||||||
class DatabaseModel;
|
class DatabaseModel;
|
||||||
class TableModel;
|
class TableModel;
|
||||||
class Database;
|
class Database;
|
||||||
|
class RelationModel;
|
||||||
class SqlGeneratorBase : public QObject
|
class SqlGeneratorBase : public QObject
|
||||||
{
|
{
|
||||||
// Q_OBJECT
|
// Q_OBJECT
|
||||||
|
|
@ -68,30 +69,31 @@ 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 join(const QStringList &list);
|
virtual QString join(const QString &mainTable,
|
||||||
|
const QList<RelationModel*> list,
|
||||||
|
QStringList *order = Q_NULLPTR);
|
||||||
|
virtual QString join(const QStringList &list, QStringList *order = Q_NULLPTR);
|
||||||
|
|
||||||
virtual QString saveRecord(Table *t, QString tableName);
|
virtual QString saveRecord(Table *t, QString tableName);
|
||||||
|
|
||||||
|
virtual QString recordsPhrase(TableModel *table);
|
||||||
|
|
||||||
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 selectCommand(AgregateType t,
|
virtual QString selectCommand(AgregateType t,
|
||||||
QString agregateArg,
|
QString agregateArg, QString tableName,
|
||||||
QList<WherePhrase> &wheres,
|
QList<WherePhrase> &wheres,
|
||||||
QList<WherePhrase> &orders,
|
QList<WherePhrase> &orders,
|
||||||
QString tableName,
|
QList<RelationModel*> joins,
|
||||||
QString joinClassName,
|
|
||||||
int skip = -1, int take = -1);
|
int skip = -1, int take = -1);
|
||||||
|
|
||||||
virtual QString deleteCommand(QList<WherePhrase> &wheres, QString tableName);
|
virtual QString deleteCommand(QList<WherePhrase> &wheres, QString tableName);
|
||||||
|
|
||||||
virtual QString updateCommand(WherePhrase &phrase, QList<WherePhrase> &wheres, QString tableName);
|
virtual QString updateCommand(WherePhrase &phrase, QList<WherePhrase> &wheres, QString tableName);
|
||||||
|
|
||||||
virtual QString joinTables(QStringList tables);
|
|
||||||
|
|
||||||
virtual QString escapeValue(const QVariant &v) const;
|
virtual QString escapeValue(const QVariant &v) const;
|
||||||
virtual QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
|
virtual QVariant readValue(const QVariant::Type &type, const QVariant &dbValue);
|
||||||
virtual QString phrase(const PhraseData *d) const;
|
virtual QString phrase(const PhraseData *d) const;
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,9 @@ QString SqliteGenerator::fieldType(FieldModel *field)
|
||||||
dbType = "real";
|
dbType = "real";
|
||||||
break;
|
break;
|
||||||
case QVariant::Int:
|
case QVariant::Int:
|
||||||
// if(field->isPrimaryKey)
|
dbType = "integer";
|
||||||
// dbType = "INTEGER PRIMARY KEY";
|
// if (field->isAutoIncrement)
|
||||||
// else
|
// dbType.append(" PRIMARY KEY AUTOINCREMENT");
|
||||||
dbType = "integer";
|
|
||||||
break;
|
break;
|
||||||
case QVariant::String:
|
case QVariant::String:
|
||||||
if(field->length)
|
if(field->length)
|
||||||
|
|
@ -72,4 +71,24 @@ QString SqliteGenerator::fieldType(FieldModel *field)
|
||||||
return dbType;
|
return dbType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SqliteGenerator::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
|
QString agregateArg,
|
||||||
|
QString tableName,
|
||||||
|
QList<WherePhrase> &wheres,
|
||||||
|
QList<WherePhrase> &orders,
|
||||||
|
QList<RelationModel*> joins,
|
||||||
|
int skip, int take)
|
||||||
|
{
|
||||||
|
QString command = SqlGeneratorBase::selectCommand(t, agregateArg,
|
||||||
|
tableName,
|
||||||
|
wheres, orders,
|
||||||
|
joins, skip, take);
|
||||||
|
|
||||||
|
if (take != -1 && skip != -1)
|
||||||
|
command.append(QString(" LIMIT %1 OFFSET %2")
|
||||||
|
.arg(take)
|
||||||
|
.arg(skip));
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,12 @@ public:
|
||||||
SqliteGenerator(Database *parent = 0);
|
SqliteGenerator(Database *parent = 0);
|
||||||
|
|
||||||
QString fieldType(FieldModel *field);
|
QString fieldType(FieldModel *field);
|
||||||
|
|
||||||
|
QString selectCommand(AgregateType t, QString agregateArg,
|
||||||
|
QString tableName,
|
||||||
|
QList<WherePhrase> &wheres,
|
||||||
|
QList<WherePhrase> &orders,
|
||||||
|
QList<RelationModel *> joins, int skip, int take);
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -133,12 +133,17 @@ QString SqlServerGenerator::escapeValue(const QVariant &v) const
|
||||||
return SqlGeneratorBase::escapeValue(v);
|
return SqlGeneratorBase::escapeValue(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SqlServerGenerator::selectCommand(
|
QString SqlServerGenerator::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||||
SqlGeneratorBase::AgregateType t, QString agregateArg,
|
QString agregateArg,
|
||||||
QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QString tableName,
|
QString tableName,
|
||||||
QString joinClassName, int skip, int take)
|
QList<WherePhrase> &wheres,
|
||||||
|
QList<WherePhrase> &orders,
|
||||||
|
QList<RelationModel*> joins, int skip, int take)
|
||||||
{
|
{
|
||||||
QString command = SqlGeneratorBase::selectCommand(t, agregateArg, wheres, orders, tableName, joinClassName, skip, take);
|
QString command = SqlGeneratorBase::selectCommand(t, agregateArg,
|
||||||
|
tableName,
|
||||||
|
wheres, orders,
|
||||||
|
joins, skip, take);
|
||||||
|
|
||||||
if (take != -1 && skip != -1)
|
if (take != -1 && skip != -1)
|
||||||
command.append(QString("OFFSET %1 ROWS FETCH NEXT %2 ROWS ONLY")
|
command.append(QString("OFFSET %1 ROWS FETCH NEXT %2 ROWS ONLY")
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,10 @@ public:
|
||||||
QString escapeValue(const QVariant &v) const;
|
QString escapeValue(const QVariant &v) const;
|
||||||
|
|
||||||
QString selectCommand(AgregateType t, QString agregateArg,
|
QString selectCommand(AgregateType t, QString agregateArg,
|
||||||
|
QString tableName,
|
||||||
QList<WherePhrase> &wheres,
|
QList<WherePhrase> &wheres,
|
||||||
QList<WherePhrase> &orders, QString tableName,
|
QList<WherePhrase> &orders,
|
||||||
QString joinClassName, int skip, int take);
|
QList<RelationModel *> joins, int skip, int take);
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
NUT_BEGIN_NAMESPACE
|
NUT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QueryPrivate::QueryPrivate(QueryBase *parent) : q_ptr(parent),
|
QueryPrivate::QueryPrivate(QueryBase *parent) : q_ptr(parent),
|
||||||
joinClassName(QString::null), skip(-1), take(-1)
|
skip(-1), take(-1)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
296
src/query.h
296
src/query.h
|
|
@ -26,6 +26,9 @@
|
||||||
#include <QtCore/QScopedPointer>
|
#include <QtCore/QScopedPointer>
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
#include <QtCore/QMetaObject>
|
#include <QtCore/QMetaObject>
|
||||||
|
#include <QtSql/QSqlResult>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QSqlError>
|
||||||
|
|
||||||
#include "query_p.h"
|
#include "query_p.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
@ -39,7 +42,7 @@
|
||||||
NUT_BEGIN_NAMESPACE
|
NUT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class NUT_EXPORT Query : public QueryBase
|
class NUT_EXPORT Query : public QueryBase
|
||||||
{
|
{
|
||||||
QueryPrivate *d_ptr;
|
QueryPrivate *d_ptr;
|
||||||
Q_DECLARE_PRIVATE(Query)
|
Q_DECLARE_PRIVATE(Query)
|
||||||
|
|
@ -63,7 +66,8 @@ public:
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query<T> *orderBy(QString fieldName, QString type);
|
|
||||||
|
// Query<T> *orderBy(QString fieldName, QString type);
|
||||||
Query<T> *skip(int n);
|
Query<T> *skip(int n);
|
||||||
Query<T> *take(int n);
|
Query<T> *take(int n);
|
||||||
Query<T> *orderBy(WherePhrase phrase);
|
Query<T> *orderBy(WherePhrase phrase);
|
||||||
|
|
@ -104,9 +108,10 @@ Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet,
|
||||||
|
|
||||||
d->database = database;
|
d->database = database;
|
||||||
d->tableSet = tableSet;
|
d->tableSet = tableSet;
|
||||||
|
d->className = T::staticMetaObject.className();
|
||||||
d->tableName
|
d->tableName
|
||||||
= // TableModel::findByClassName(T::staticMetaObject.className())->name();
|
= // TableModel::findByClassName(T::staticMetaObject.className())->name();
|
||||||
d->database->model()
|
d->database->model()
|
||||||
.tableByClassName(T::staticMetaObject.className())
|
.tableByClassName(T::staticMetaObject.className())
|
||||||
->name();
|
->name();
|
||||||
}
|
}
|
||||||
|
|
@ -121,105 +126,177 @@ Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
|
||||||
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_UNUSED(count);
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
QList<T*> result;
|
QList<T*> returnList;
|
||||||
d->select = "*";
|
d->select = "*";
|
||||||
|
QElapsedTimer t;
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
|
||||||
d->joins.prepend(d->tableName);
|
|
||||||
qDebug() << "JOINS="<< d->database->sqlGenertor()->join(d->joins);
|
|
||||||
// QSqlQuery q =
|
|
||||||
// d->database->exec(d->database->sqlGenertor()->selectCommand(d->wheres,
|
|
||||||
// d->orders, d->tableName, d->joinClassName));
|
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||||
SqlGeneratorBase::SelectAll, "", d->wheres, d->orderPhrases,
|
SqlGeneratorBase::SelectAll, "",
|
||||||
d->tableName, d->joinClassName, d->skip, d->take);
|
d->tableName,
|
||||||
|
d->wheres, d->orderPhrases, d->relations,
|
||||||
|
d->skip, d->take);
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
if (q.lastError().isValid()) {
|
||||||
// QString pk = TableModel::findByName(d->tableName)->primaryKey();
|
qDebug() << q.lastError().text();
|
||||||
QString pk = d->database->model().tableByName(d->tableName)->primaryKey();
|
return returnList;
|
||||||
QVariant lastPkValue = QVariant();
|
|
||||||
int childTypeId = 0;
|
|
||||||
T *lastRow = 0;
|
|
||||||
TableSetBase *childTableSet = Q_NULLPTR;
|
|
||||||
|
|
||||||
// FIXME: getting table error
|
|
||||||
// QStringList masterFields =
|
|
||||||
// TableModel::findByName(d->tableName)->fieldsNames();
|
|
||||||
QStringList masterFields
|
|
||||||
= d->database->model().tableByName(d->tableName)->fieldsNames();
|
|
||||||
QStringList childFields;
|
|
||||||
if (!d->joinClassName.isNull()) {
|
|
||||||
TableModel *joinTableModel
|
|
||||||
= TableModel::findByClassName(d->joinClassName);
|
|
||||||
if (joinTableModel) {
|
|
||||||
// childFields =
|
|
||||||
// d->database->model().modelByClass(d->joinClassName)->fieldsNames();
|
|
||||||
childFields
|
|
||||||
= TableModel::findByClassName(d->joinClassName)->fieldsNames();
|
|
||||||
QString joinTableName = d->database->tableName(d->joinClassName);
|
|
||||||
childTypeId = d->database->model().tableByName(joinTableName)->typeId();
|
|
||||||
// childTypeId =
|
|
||||||
// TableModel::findByName(joinTableName)->typeId();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (q.next()) {
|
QSet<TableModel*> relatedTables;
|
||||||
if (lastPkValue != q.value(pk)) {
|
relatedTables << d->database->model().tableByName(d->tableName);
|
||||||
T *t = new T();
|
foreach (RelationModel *rel, d->relations)
|
||||||
foreach (QString field, masterFields)
|
relatedTables << rel->slaveTable << rel->masterTable;
|
||||||
t->setProperty(field.toLatin1().data(), q.value(field));
|
|
||||||
// for (int i = 0; i < t->metaObject()->propertyCount();
|
|
||||||
// i++) {
|
|
||||||
// const QMetaProperty p =
|
|
||||||
// t->metaObject()->property(i);
|
|
||||||
|
|
||||||
// p.write(t,
|
|
||||||
// d->database->sqlGenertor()->readValue(p.type(),
|
|
||||||
// q.value(p.name())));
|
|
||||||
// }
|
|
||||||
|
|
||||||
t->setTableSet(d->tableSet);
|
struct LevelData{
|
||||||
t->setStatus(Table::FeatchedFromDB);
|
QList<int> masters;
|
||||||
t->setParent(this);
|
QList<int> slaves;
|
||||||
t->clear();
|
QList<QString> masterFields;
|
||||||
|
QString keyFiledname;
|
||||||
|
QVariant lastKeyValue;
|
||||||
|
TableModel *table;
|
||||||
|
Table *lastRow;
|
||||||
|
};
|
||||||
|
QVector<LevelData> levels;
|
||||||
|
QSet<QString> importedTables;
|
||||||
|
auto add_table = [&](int i, TableModel* table) {
|
||||||
|
if (importedTables.contains(table->name()))
|
||||||
|
return;
|
||||||
|
importedTables.insert(table->name());
|
||||||
|
|
||||||
result.append(t);
|
LevelData data;
|
||||||
lastRow = t;
|
data.table = table;
|
||||||
|
data.keyFiledname = data.table->name() + "." + data.table->primaryKey();
|
||||||
|
data.lastKeyValue = QVariant();
|
||||||
|
|
||||||
if (childTypeId) {
|
QHash<QString, QString> masters;
|
||||||
QSet<TableSetBase *> tableSets = t->tableSets;
|
foreach (RelationModel *rel, d->relations)
|
||||||
foreach (TableSetBase *ts, tableSets)
|
if (rel->slaveTable->name() == table->name())
|
||||||
if (ts->childClassName() == d->joinClassName)
|
masters.insert(rel->masterTable->name(), rel->localProperty);
|
||||||
childTableSet = ts;
|
|
||||||
|
for (int j = 0; j < levels.count(); ++j) {
|
||||||
|
LevelData &dt = levels[j];
|
||||||
|
qDebug() <<"[check]"<<table->name() << dt.table->name();
|
||||||
|
|
||||||
|
QHashIterator<QString, QString> it(masters);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
|
||||||
|
if (dt.table->name() == it.key()) {
|
||||||
|
data.masters.append(j);
|
||||||
|
data.masterFields.append(it.value());
|
||||||
|
dt.slaves.append(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
qDebug() << data.table->name() <<"added";
|
||||||
if (childTypeId) {
|
levels.append(data);
|
||||||
const QMetaObject *childMetaObject
|
};
|
||||||
= QMetaType::metaObjectForType(childTypeId);
|
for (int i = 0; i < d->relations.count(); ++i) {
|
||||||
Table *childTable
|
RelationModel *rel = d->relations[i];
|
||||||
= qobject_cast<Table *>(childMetaObject->newInstance());
|
add_table(i, rel->masterTable);
|
||||||
|
add_table(i, rel->slaveTable);
|
||||||
foreach (QString field, childFields)
|
|
||||||
childTable->setProperty(field.toLatin1().data(),
|
|
||||||
q.value(field));
|
|
||||||
// TODO: set database for table
|
|
||||||
childTable->setParent(this);
|
|
||||||
childTable->setParentTable(lastRow);
|
|
||||||
childTable->setStatus(Table::FeatchedFromDB);
|
|
||||||
childTable->setTableSet(childTableSet);
|
|
||||||
childTable->clear();
|
|
||||||
childTableSet->add(childTable);
|
|
||||||
}
|
|
||||||
lastPkValue = q.value(pk);
|
|
||||||
|
|
||||||
if (!--count)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!importedTables.count()) {
|
||||||
|
LevelData data;
|
||||||
|
data.table = d->database->model().tableByName(d->tableName);
|
||||||
|
data.keyFiledname = d->tableName + "." + data.table->primaryKey();
|
||||||
|
data.lastKeyValue = QVariant();
|
||||||
|
|
||||||
|
levels.append(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> checked;
|
||||||
|
checked.reserve(levels.count());
|
||||||
|
for (int i = 0; i < levels.count(); ++i)
|
||||||
|
checked.append(false);
|
||||||
|
qDebug() << "Elapsed time:" << QString("%1ms").arg(t.elapsed() / 1000.);
|
||||||
|
while (q.next()) {
|
||||||
|
checked.fill(false);
|
||||||
|
|
||||||
|
int p = levels.count();
|
||||||
|
qDebug() << "p is"<<p;
|
||||||
|
int n = -1;
|
||||||
|
int lastP = p;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
// Q_ASSERT(p != lastP);
|
||||||
|
// if (p == lastP)
|
||||||
|
// qFatal("NULL Loop detected");
|
||||||
|
|
||||||
|
n = (++n) % levels.count();
|
||||||
|
if (checked[n])
|
||||||
|
continue;
|
||||||
|
LevelData &data = levels[n];
|
||||||
|
|
||||||
|
// check if key value is changed
|
||||||
|
if (data.lastKeyValue == q.value(data.keyFiledname)) {
|
||||||
|
--p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if master if current table has processed
|
||||||
|
foreach (int m, data.masters)
|
||||||
|
if (!checked[m])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
checked[n] = true;
|
||||||
|
--p;
|
||||||
|
data.lastKeyValue = q.value(data.keyFiledname);
|
||||||
|
|
||||||
|
//create table row
|
||||||
|
Table *table;
|
||||||
|
if (data.table->className() == d->className) {
|
||||||
|
table = new T();
|
||||||
|
table->setParentTableSet(d->tableSet);
|
||||||
|
returnList.append(dynamic_cast<T*>(table));
|
||||||
|
} else {
|
||||||
|
const QMetaObject *childMetaObject
|
||||||
|
= QMetaType::metaObjectForType(data.table->typeId());
|
||||||
|
table = qobject_cast<Table *>(childMetaObject->newInstance());
|
||||||
|
|
||||||
|
}
|
||||||
|
qDebug() << "table created" << table;
|
||||||
|
|
||||||
|
QStringList childFields = data.table->fieldsNames();
|
||||||
|
foreach (QString field, childFields)
|
||||||
|
table->setProperty(field.toLatin1().data(),
|
||||||
|
q.value(data.table->name() + "." + field));
|
||||||
|
|
||||||
|
for (int i = 0; i < data.masters.count(); ++i) {
|
||||||
|
int master = data.masters[i];
|
||||||
|
table->setProperty(data.masterFields[i].toLocal8Bit().data(),
|
||||||
|
QVariant::fromValue(levels[master].lastRow));
|
||||||
|
|
||||||
|
table->setParentTableSet(levels[master].lastRow->childTableSet(data.table->className()));
|
||||||
|
TableSetBase *ts = levels[master].lastRow->childTableSet(data.table->className());
|
||||||
|
qDebug() << table << "added to"
|
||||||
|
<< levels[master].lastRow
|
||||||
|
<< ts->childClassName()
|
||||||
|
<< data.masterFields[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
table->setStatus(Table::FeatchedFromDB);
|
||||||
|
table->setParent(this);
|
||||||
|
table->clear();
|
||||||
|
|
||||||
|
//set last created row
|
||||||
|
data.lastRow = table;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
lastP = p;
|
||||||
|
} //while
|
||||||
|
} // while
|
||||||
if (m_autoDelete)
|
if (m_autoDelete)
|
||||||
deleteLater();
|
deleteLater();
|
||||||
return result;
|
|
||||||
|
qDebug() << "Elapsed time:" << QString("%1ms").arg(t.elapsed() / 1000.);
|
||||||
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -228,9 +305,12 @@ Q_OUTOFLINE_TEMPLATE QList<F> Query<T>::select(const FieldPhrase<F> f)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
QList<F> ret;
|
QList<F> ret;
|
||||||
|
|
||||||
|
d->joins.prepend(d->tableName);
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||||
SqlGeneratorBase::SignleField, f.data()->text, d->wheres,
|
SqlGeneratorBase::SignleField, f.data()->text,
|
||||||
d->orderPhrases, d->tableName, d->joinClassName, d->skip, d->take);
|
d->tableName, d->wheres,
|
||||||
|
d->orderPhrases, d->relations, d->skip, d->take);
|
||||||
|
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
|
||||||
|
|
@ -262,9 +342,14 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::count()
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
|
|
||||||
|
d->joins.prepend(d->tableName);
|
||||||
d->select = "COUNT(*)";
|
d->select = "COUNT(*)";
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(SqlGeneratorBase::Count,
|
d->sql = d->database->sqlGenertor()->selectCommand(SqlGeneratorBase::Count,
|
||||||
QStringLiteral("*"), d->wheres, d->orderPhrases, d->tableName, d->joinClassName);
|
QStringLiteral("*"),
|
||||||
|
d->tableName,
|
||||||
|
d->wheres,
|
||||||
|
d->orderPhrases,
|
||||||
|
d->relations);
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
|
||||||
if (q.next())
|
if (q.next())
|
||||||
|
|
@ -277,9 +362,11 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::max(FieldPhrase<int> &f)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
|
|
||||||
|
d->joins.prepend(d->tableName);
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||||
SqlGeneratorBase::Max, f.data()->text, d->wheres, d->orderPhrases,
|
SqlGeneratorBase::Max, f.data()->text, d->tableName,
|
||||||
d->tableName, d->joinClassName);
|
d->wheres, d->orderPhrases,
|
||||||
|
d->relations);
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
|
||||||
if (q.next())
|
if (q.next())
|
||||||
|
|
@ -292,9 +379,11 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::min(FieldPhrase<int> &f)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
|
|
||||||
|
d->joins.prepend(d->tableName);
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||||
SqlGeneratorBase::Min, f.data()->text, d->wheres, d->orderPhrases,
|
SqlGeneratorBase::Min, f.data()->text, d->tableName,
|
||||||
d->tableName, d->joinClassName);
|
d->wheres, d->orderPhrases,
|
||||||
|
d->relations);
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
|
||||||
if (q.next())
|
if (q.next())
|
||||||
|
|
@ -307,9 +396,11 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(FieldPhrase<int> &f)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
|
|
||||||
|
d->joins.prepend(d->tableName);
|
||||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||||
SqlGeneratorBase::Average, f.data()->text, d->wheres, d->orderPhrases,
|
SqlGeneratorBase::Average, f.data()->text, d->tableName,
|
||||||
d->tableName, d->joinClassName);
|
d->wheres, d->orderPhrases,
|
||||||
|
d->relations);
|
||||||
QSqlQuery q = d->database->exec(d->sql);
|
QSqlQuery q = d->database->exec(d->sql);
|
||||||
|
|
||||||
if (q.next())
|
if (q.next())
|
||||||
|
|
@ -321,7 +412,18 @@ template <class T>
|
||||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &className)
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &className)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
d->joinClassName = className;
|
|
||||||
|
RelationModel *rel = d->database->model().relationByClassNames(d->className, className);
|
||||||
|
if (!rel)
|
||||||
|
rel = d->database->model().relationByClassNames(className, d->className);
|
||||||
|
|
||||||
|
if (!rel) {
|
||||||
|
qInfo("No relation between %s and %s",
|
||||||
|
qPrintable(d->className), qPrintable(className));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->relations.append(rel);
|
||||||
d->joins.append(className);
|
d->joins.append(className);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -378,7 +480,6 @@ template <class T>
|
||||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::include(TableSetBase *t)
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::include(TableSetBase *t)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
d->joinClassName = t->childClassName();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,7 +487,6 @@ template <class T>
|
||||||
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::include(Table *t)
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::include(Table *t)
|
||||||
{
|
{
|
||||||
Q_D(Query);
|
Q_D(Query);
|
||||||
d->joinClassName = t->metaObject()->className();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ NUT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
class TableSetBase;
|
class TableSetBase;
|
||||||
//template<class T>
|
|
||||||
class QueryBase;
|
class QueryBase;
|
||||||
|
class RelationModel;
|
||||||
class QueryPrivate{
|
class QueryPrivate{
|
||||||
QueryBase *q_ptr;
|
QueryBase *q_ptr;
|
||||||
Q_DECLARE_PUBLIC(QueryBase)
|
Q_DECLARE_PUBLIC(QueryBase)
|
||||||
|
|
@ -41,12 +41,13 @@ public:
|
||||||
~QueryPrivate();
|
~QueryPrivate();
|
||||||
|
|
||||||
QString sql;
|
QString sql;
|
||||||
|
QString className;
|
||||||
QString tableName;
|
QString tableName;
|
||||||
QString select;
|
QString select;
|
||||||
Database *database;
|
Database *database;
|
||||||
TableSetBase *tableSet;
|
TableSetBase *tableSet;
|
||||||
QString joinClassName;
|
|
||||||
QStringList joins;
|
QStringList joins;
|
||||||
|
QList<RelationModel*> relations;
|
||||||
QList<WherePhrase> wheres;
|
QList<WherePhrase> wheres;
|
||||||
QList<WherePhrase> orderPhrases;
|
QList<WherePhrase> orderPhrases;
|
||||||
QHash<QString, QString> orders;
|
QHash<QString, QString> orders;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
#include "querybase_p.h"
|
#include "querybase_p.h"
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
#include "tablesetbase_p.h"
|
||||||
|
|
||||||
|
|
||||||
NUT_BEGIN_NAMESPACE
|
NUT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QueryBase::QueryBase(QObject *parent) : QObject(parent)
|
QueryBase::QueryBase(QObject *parent) : QObject(parent)
|
||||||
|
|
@ -7,4 +11,9 @@ QueryBase::QueryBase(QObject *parent) : QObject(parent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QueryBase::addTableToSet(TableSetBase *set, Table *table)
|
||||||
|
{
|
||||||
|
set->add(table);
|
||||||
|
}
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,16 @@
|
||||||
NUT_BEGIN_NAMESPACE
|
NUT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//TODO: remove this class
|
//TODO: remove this class
|
||||||
|
class Table;
|
||||||
|
class TableSetBase;
|
||||||
class QueryBase : public QObject
|
class QueryBase : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QueryBase(QObject *parent = 0);
|
explicit QueryBase(QObject *parent = 0);
|
||||||
|
|
||||||
signals:
|
protected:
|
||||||
|
void addTableToSet(TableSetBase *set, Table *table);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "databasemodel.h"
|
||||||
#include "generators/sqlgeneratorbase_p.h"
|
#include "generators/sqlgeneratorbase_p.h"
|
||||||
|
|
||||||
NUT_BEGIN_NAMESPACE
|
NUT_BEGIN_NAMESPACE
|
||||||
|
|
@ -33,7 +34,7 @@ Table::Table(QObject *parent) : QObject(parent)
|
||||||
|
|
||||||
void Table::add(TableSetBase *t)
|
void Table::add(TableSetBase *t)
|
||||||
{
|
{
|
||||||
this->tableSets.insert(t);
|
this->childTableSets.insert(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -67,7 +68,10 @@ QString Table::primaryKey() const
|
||||||
|
|
||||||
bool Table::isPrimaryKeyAutoIncrement() const
|
bool Table::isPrimaryKeyAutoIncrement() const
|
||||||
{
|
{
|
||||||
return TableModel::findByClassName(metaObject()->className())->field(primaryKey())->isAutoIncrement;
|
auto m = TableModel::findByClassName(metaObject()->className());
|
||||||
|
auto pk = m->primaryKey();
|
||||||
|
auto f = m->field(pk);
|
||||||
|
return f->isAutoIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -105,7 +109,7 @@ bool Table::setParentTable(Table *master)
|
||||||
TableModel *myModel = TableModel::findByClassName(metaObject()->className());
|
TableModel *myModel = TableModel::findByClassName(metaObject()->className());
|
||||||
|
|
||||||
foreach (RelationModel *r, myModel->foregionKeys())
|
foreach (RelationModel *r, myModel->foregionKeys())
|
||||||
if(r->className == masterClassName)
|
if(r->masterClassName == masterClassName)
|
||||||
{
|
{
|
||||||
setProperty(QString(r->localColumn).toLatin1().data(), master->primaryValue());
|
setProperty(QString(r->localColumn).toLatin1().data(), master->primaryValue());
|
||||||
_changedProperties.insert(r->localColumn);
|
_changedProperties.insert(r->localColumn);
|
||||||
|
|
@ -115,15 +119,23 @@ bool Table::setParentTable(Table *master)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableSetBase *Table::tableSet() const
|
TableSetBase *Table::parentTableSet() const
|
||||||
{
|
{
|
||||||
return _tableSet;
|
return _parentTableSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Table::setTableSet(TableSetBase *parent)
|
void Table::setParentTableSet(TableSetBase *parent)
|
||||||
{
|
{
|
||||||
_tableSet = parent;
|
_parentTableSet = parent;
|
||||||
_tableSet->add(this);
|
_parentTableSet->add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TableSetBase *Table::childTableSet(const QString &name) const
|
||||||
|
{
|
||||||
|
foreach (TableSetBase *t, childTableSets)
|
||||||
|
if (t->childClassName() == name)
|
||||||
|
return t;
|
||||||
|
return Q_NULLPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Table::save(Database *db)
|
int Table::save(Database *db)
|
||||||
|
|
@ -133,7 +145,7 @@ int Table::save(Database *db)
|
||||||
if(status() == Added && isPrimaryKeyAutoIncrement())
|
if(status() == Added && isPrimaryKeyAutoIncrement())
|
||||||
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
|
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
|
||||||
|
|
||||||
foreach(TableSetBase *ts, tableSets)
|
foreach(TableSetBase *ts, childTableSets)
|
||||||
ts->save(db);
|
ts->save(db);
|
||||||
setStatus(FeatchedFromDB);
|
setStatus(FeatchedFromDB);
|
||||||
|
|
||||||
|
|
|
||||||
13
src/table.h
13
src/table.h
|
|
@ -38,7 +38,7 @@ class NUT_EXPORT Table : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Table(QObject *tableSet = 0);
|
explicit Table(QObject *parentTableSet = 0);
|
||||||
|
|
||||||
enum Status{
|
enum Status{
|
||||||
NewCreated,
|
NewCreated,
|
||||||
|
|
@ -56,8 +56,10 @@ public:
|
||||||
Status status() const;
|
Status status() const;
|
||||||
void setStatus(const Status &status);
|
void setStatus(const Status &status);
|
||||||
|
|
||||||
TableSetBase *tableSet() const;
|
TableSetBase *parentTableSet() const;
|
||||||
void setTableSet(TableSetBase *tableSet);
|
void setParentTableSet(TableSetBase *parentTableSet);
|
||||||
|
|
||||||
|
TableSetBase *childTableSet(const QString &name) const;
|
||||||
|
|
||||||
QSet<QString> changedProperties() const;
|
QSet<QString> changedProperties() const;
|
||||||
|
|
||||||
|
|
@ -72,9 +74,10 @@ protected:
|
||||||
private:
|
private:
|
||||||
Status _status;
|
Status _status;
|
||||||
QSet<QString> _changedProperties;
|
QSet<QString> _changedProperties;
|
||||||
TableSetBase *_tableSet;
|
//TODO: is this removable?
|
||||||
|
TableSetBase *_parentTableSet;
|
||||||
|
|
||||||
QSet<TableSetBase*> tableSets;
|
QSet<TableSetBase*> childTableSets;
|
||||||
void clear();
|
void clear();
|
||||||
void add(TableSetBase *);
|
void add(TableSetBase *);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,23 @@ bool TableModel::operator !=(const TableModel &t) const
|
||||||
return !(*this == t);
|
return !(*this == t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TableModel::checkClassInfo(const QMetaClassInfo &classInfo,
|
||||||
|
QString &type, QString &name, QString &value)
|
||||||
|
{
|
||||||
|
if (!QString(classInfo.name()).startsWith(__nut_NAME_PERFIX)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
QStringList parts = QString(classInfo.value()).split("\n");
|
||||||
|
if (parts.count() != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
type = parts[0];
|
||||||
|
name = parts[1];
|
||||||
|
value = parts[2];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TableModel::TableModel(int typeId, QString tableName)
|
TableModel::TableModel(int typeId, QString tableName)
|
||||||
{
|
{
|
||||||
//TODO: check that
|
//TODO: check that
|
||||||
|
|
@ -163,20 +180,19 @@ 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 type;
|
||||||
name = name.replace("\"", "");
|
QString name;
|
||||||
|
QString value;
|
||||||
|
|
||||||
name = name.remove(__nut_NAME_PERFIX);
|
if (!checkClassInfo(tableMetaObject->classInfo(j),
|
||||||
|
type, name, value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(name.contains(" ")){
|
if(type == __nut_FIELD){
|
||||||
QStringList parts = name.split(" ");
|
FieldModel *f = new FieldModel;
|
||||||
QString propName = parts.at(1);
|
f->name = name;
|
||||||
|
_fields.append(f);
|
||||||
if(propName == __nut_FIELD){
|
|
||||||
FieldModel *f = new FieldModel;
|
|
||||||
f->name = parts.at(0);
|
|
||||||
_fields.append(f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Browse all fields
|
// Browse all fields
|
||||||
|
|
@ -195,47 +211,48 @@ TableModel::TableModel(int typeId, QString tableName)
|
||||||
|
|
||||||
// Browse class infos
|
// Browse class infos
|
||||||
for(int j = 0; j < tableMetaObject->classInfoCount(); j++){
|
for(int j = 0; j < tableMetaObject->classInfoCount(); j++){
|
||||||
QString name = tableMetaObject->classInfo(j).name();
|
QString type;
|
||||||
QString value = tableMetaObject->classInfo(j).value();
|
QString name;
|
||||||
|
QString value;
|
||||||
|
|
||||||
name = name.replace("\"", "").remove(__nut_NAME_PERFIX);
|
if (!checkClassInfo(tableMetaObject->classInfo(j),
|
||||||
value = value.replace("\"", "");
|
type, name, value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(name.contains(" ")){
|
if(type == __nut_FOREGION_KEY){
|
||||||
QStringList parts = name.split(" ");
|
RelationModel *fk = new RelationModel;
|
||||||
QString propName = parts.at(1);
|
fk->slaveTable = this;
|
||||||
|
fk->localColumn = name + "Id";
|
||||||
|
fk->localProperty = name;
|
||||||
|
fk->foregionColumn = value;
|
||||||
|
fk->masterClassName = value;
|
||||||
|
_foregionKeys.append(fk);
|
||||||
|
}
|
||||||
|
|
||||||
if(propName == __nut_FOREGION_KEY){
|
if(type == __nut_FIELD){
|
||||||
RelationModel *fk = new RelationModel;
|
|
||||||
fk->localColumn = parts.at(0);
|
|
||||||
fk->foregionColumn = value;
|
|
||||||
fk->className = value;
|
|
||||||
_foregionKeys.append(fk);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(propName == __nut_FIELD){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FieldModel *f = field(parts.at(0));
|
|
||||||
if(!f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(propName == __nut_LEN)
|
|
||||||
f->length = value.toInt();
|
|
||||||
else if(propName == __nut_NOT_NULL)
|
|
||||||
f->notNull = true;
|
|
||||||
else if(propName == __nut_DEFAULT_VALUE)
|
|
||||||
f->defaultValue = value;
|
|
||||||
else if(propName == __nut_PRIMARY_KEY)
|
|
||||||
f->isPrimaryKey = true;
|
|
||||||
else if(propName == __nut_AUTO_INCREMENT)
|
|
||||||
f->isAutoIncrement = true;
|
|
||||||
else if(propName == __nut_UNIQUE)
|
|
||||||
f->isUnique = true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FieldModel *f = field(name);
|
||||||
|
if(!f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(type == __nut_LEN)
|
||||||
|
f->length = value.toInt();
|
||||||
|
else if(type == __nut_NOT_NULL)
|
||||||
|
f->notNull = true;
|
||||||
|
else if(type == __nut_DEFAULT_VALUE)
|
||||||
|
f->defaultValue = value;
|
||||||
|
else if(type == __nut_PRIMARY_KEY)
|
||||||
|
f->isPrimaryKey = true;
|
||||||
|
else if(type == __nut_AUTO_INCREMENT)
|
||||||
|
f->isAutoIncrement = true;
|
||||||
|
else if(type == __nut_UNIQUE)
|
||||||
|
f->isUnique = true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!findByTypeId(typeId) && !tableName.isNull())
|
if(!findByTypeId(typeId) && !tableName.isNull())
|
||||||
|
|
@ -355,7 +372,7 @@ QJsonObject TableModel::toJson() const
|
||||||
RelationModel *TableModel::foregionKey(QString otherTable) const
|
RelationModel *TableModel::foregionKey(QString otherTable) const
|
||||||
{
|
{
|
||||||
foreach (RelationModel *fk, _foregionKeys)
|
foreach (RelationModel *fk, _foregionKeys)
|
||||||
if(fk->className == otherTable)
|
if(fk->masterClassName == otherTable)
|
||||||
return fk;
|
return fk;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -65,10 +65,15 @@ struct FieldModel{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RelationModel{
|
struct RelationModel{
|
||||||
QString className;
|
//slave
|
||||||
QString localColumn;
|
QString localColumn;
|
||||||
TableModel *table;
|
QString localProperty;
|
||||||
|
TableModel *slaveTable;
|
||||||
|
//master
|
||||||
QString foregionColumn;
|
QString foregionColumn;
|
||||||
|
TableModel *masterTable;
|
||||||
|
|
||||||
|
QString masterClassName;
|
||||||
};
|
};
|
||||||
class TableModel
|
class TableModel
|
||||||
{
|
{
|
||||||
|
|
@ -117,6 +122,8 @@ private:
|
||||||
QList<FieldModel*> _fields;
|
QList<FieldModel*> _fields;
|
||||||
QList<RelationModel*> _foregionKeys;
|
QList<RelationModel*> _foregionKeys;
|
||||||
static QSet<TableModel*>_allModels;
|
static QSet<TableModel*>_allModels;
|
||||||
|
bool checkClassInfo(const QMetaClassInfo &classInfo,
|
||||||
|
QString &type, QString &name, QString &value);
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(T *t)
|
||||||
_tables.insert(t);
|
_tables.insert(t);
|
||||||
_tablesList.append(t);
|
_tablesList.append(t);
|
||||||
// rows.append(t);
|
// rows.append(t);
|
||||||
t->setTableSet(this);
|
t->setParentTableSet(this);
|
||||||
if(t->status() != Table::FeatchedFromDB)
|
if(t->status() != Table::FeatchedFromDB)
|
||||||
t->setStatus(Table::Added);
|
t->setStatus(Table::Added);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ public:
|
||||||
|
|
||||||
virtual int save(Database *db, bool cleanUp = false);
|
virtual int save(Database *db, bool cleanUp = false);
|
||||||
void clearChilds();
|
void clearChilds();
|
||||||
void add(Table* t);
|
|
||||||
QString childClassName() const;
|
QString childClassName() const;
|
||||||
|
|
||||||
Database *database() const;
|
Database *database() const;
|
||||||
|
|
@ -53,6 +52,12 @@ protected:
|
||||||
Database *_database;
|
Database *_database;
|
||||||
Table *_table;
|
Table *_table;
|
||||||
QString _childClassName;
|
QString _childClassName;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add(Table* t);
|
||||||
|
|
||||||
|
friend class Table;
|
||||||
|
friend class QueryBase;
|
||||||
};
|
};
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -230,4 +230,5 @@ WherePhrase WherePhrase::operator>=(const QVariant &other)
|
||||||
return WherePhrase(this, PhraseData::GreaterEqual, other);
|
return WherePhrase(this, PhraseData::GreaterEqual, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NUT_END_NAMESPACE
|
NUT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,8 @@ class FieldPhrase : public WherePhrase
|
||||||
public:
|
public:
|
||||||
FieldPhrase(const char *className, const char *s);
|
FieldPhrase(const char *className, const char *s);
|
||||||
|
|
||||||
|
WherePhrase operator=(const FieldPhrase<T> &other);
|
||||||
|
|
||||||
WherePhrase operator=(const WherePhrase &other);
|
WherePhrase operator=(const WherePhrase &other);
|
||||||
WherePhrase operator=(const QVariant &other);
|
WherePhrase operator=(const QVariant &other);
|
||||||
WherePhrase operator+(const QVariant &other);
|
WherePhrase operator+(const QVariant &other);
|
||||||
|
|
@ -179,6 +181,13 @@ operator=(const QVariant &other)
|
||||||
return WherePhrase(this, PhraseData::Set, other);
|
return WherePhrase(this, PhraseData::Set, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Q_OUTOFLINE_TEMPLATE WherePhrase
|
||||||
|
FieldPhrase<T>::operator=(const FieldPhrase<T> &other)
|
||||||
|
{
|
||||||
|
return WherePhrase(this, PhraseData::Equal, &other);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Q_OUTOFLINE_TEMPLATE WherePhrase FieldPhrase<T>::
|
Q_OUTOFLINE_TEMPLATE WherePhrase FieldPhrase<T>::
|
||||||
operator=(const WherePhrase &other)
|
operator=(const WherePhrase &other)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include "post.h"
|
#include "post.h"
|
||||||
#include "comment.h"
|
#include "comment.h"
|
||||||
|
|
||||||
|
#define PRINT(x) qDebug() << #x "=" << x;
|
||||||
MainTest::MainTest(QObject *parent) : QObject(parent)
|
MainTest::MainTest(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +47,16 @@ void MainTest::dataScheema()
|
||||||
|
|
||||||
// qDebug() << model.toJson();
|
// qDebug() << model.toJson();
|
||||||
// qDebug() << db.model().toJson();
|
// qDebug() << db.model().toJson();
|
||||||
// QTEST_ASSERT(model == db.model());
|
// QTEST_ASSERT(model == db.model());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainTest::createUser()
|
||||||
|
{
|
||||||
|
user = new User;
|
||||||
|
user->setUsername("admin");
|
||||||
|
user->setPassword("123456");
|
||||||
|
db.users()->append(user);
|
||||||
|
db.saveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainTest::createPost()
|
void MainTest::createPost()
|
||||||
|
|
@ -61,6 +71,7 @@ void MainTest::createPost()
|
||||||
Comment *comment = new Comment;
|
Comment *comment = new Comment;
|
||||||
comment->setMessage("comment #" + QString::number(i));
|
comment->setMessage("comment #" + QString::number(i));
|
||||||
comment->setSaveDate(QDateTime::currentDateTime());
|
comment->setSaveDate(QDateTime::currentDateTime());
|
||||||
|
comment->setAuthorId(user->id());
|
||||||
newPost->comments()->append(comment);
|
newPost->comments()->append(comment);
|
||||||
}
|
}
|
||||||
db.saveChanges();
|
db.saveChanges();
|
||||||
|
|
@ -84,6 +95,7 @@ void MainTest::createPost2()
|
||||||
Comment *comment = new Comment;
|
Comment *comment = new Comment;
|
||||||
comment->setMessage("comment #" + QString::number(i));
|
comment->setMessage("comment #" + QString::number(i));
|
||||||
comment->setSaveDate(QDateTime::currentDateTime());
|
comment->setSaveDate(QDateTime::currentDateTime());
|
||||||
|
comment->setAuthor(user);
|
||||||
comment->setPostId(newPost->id());
|
comment->setPostId(newPost->id());
|
||||||
db.comments()->append(comment);
|
db.comments()->append(comment);
|
||||||
}
|
}
|
||||||
|
|
@ -96,18 +108,16 @@ void MainTest::createPost2()
|
||||||
void MainTest::selectPosts()
|
void MainTest::selectPosts()
|
||||||
{
|
{
|
||||||
auto q = db.posts()->query()
|
auto q = db.posts()->query()
|
||||||
// q->join(Post::commentsTable());
|
->join<Comment>()//Comment::authorIdField() == Post::idField())
|
||||||
// q->join(Post::commentsTable());
|
|
||||||
->join<User>()
|
|
||||||
->join<Comment>()
|
|
||||||
->orderBy(!Post::saveDateField() & Post::bodyField())
|
->orderBy(!Post::saveDateField() & Post::bodyField())
|
||||||
->setWhere(Post::idField() == postId);
|
->setWhere(Post::idField() == postId);
|
||||||
|
|
||||||
auto posts = q->toList();
|
auto posts = q->toList();
|
||||||
qDebug() << "SQL="<<q->sqlCommand();
|
|
||||||
post = posts.at(0);
|
post = posts.at(0);
|
||||||
post->setBody("");
|
post->setBody("");
|
||||||
|
|
||||||
|
PRINT(posts.length());
|
||||||
|
PRINT(posts.at(0)->comments()->length());
|
||||||
QTEST_ASSERT(posts.length() == 1);
|
QTEST_ASSERT(posts.length() == 1);
|
||||||
QTEST_ASSERT(posts.at(0)->comments()->length() == 3);
|
QTEST_ASSERT(posts.at(0)->comments()->length() == 3);
|
||||||
QTEST_ASSERT(posts.at(0)->title() == "post title");
|
QTEST_ASSERT(posts.at(0)->title() == "post title");
|
||||||
|
|
@ -118,12 +128,21 @@ void MainTest::selectPosts()
|
||||||
db.cleanUp();
|
db.cleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainTest::selectFirst()
|
||||||
|
{
|
||||||
|
auto q = db.posts()->query();
|
||||||
|
|
||||||
|
auto posts = q->first();
|
||||||
|
|
||||||
|
qDebug() << q->sqlCommand();
|
||||||
|
QTEST_ASSERT(posts != Q_NULLPTR);
|
||||||
|
}
|
||||||
|
|
||||||
void MainTest::selectPostsWithoutTitle()
|
void MainTest::selectPostsWithoutTitle()
|
||||||
{
|
{
|
||||||
auto q = db.posts()->query();
|
auto q = db.posts()->query();
|
||||||
q->setWhere(Post::titleField().isNull());
|
q->setWhere(Post::titleField().isNull());
|
||||||
auto count = q->count();
|
auto count = q->count();
|
||||||
qDebug() << q->sqlCommand();
|
|
||||||
QTEST_ASSERT(count == 0);
|
QTEST_ASSERT(count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,14 +177,16 @@ void MainTest::testDate()
|
||||||
void MainTest::join()
|
void MainTest::join()
|
||||||
{
|
{
|
||||||
auto q = db.comments()->query()
|
auto q = db.comments()->query()
|
||||||
// ->join(Comment::author())
|
->join<User>()
|
||||||
// ->join(Comment::post())
|
->join<Post>();
|
||||||
->join<Post>()
|
|
||||||
->setWhere(Comment::saveDateField() < QDateTime::currentDateTime().addDays(-1))
|
|
||||||
->orderBy(Comment::saveDateField());
|
|
||||||
|
|
||||||
q->toList();
|
// Comment *comment = q->first();
|
||||||
|
auto comments = q->toList();
|
||||||
|
// Comment *comment = q->toList().first();
|
||||||
qDebug() << q->sqlCommand();
|
qDebug() << q->sqlCommand();
|
||||||
|
QTEST_ASSERT(comments.length());
|
||||||
|
QTEST_ASSERT(comments[0]->author());
|
||||||
|
QTEST_ASSERT(comments[0]->author()->username() == "admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -176,13 +197,6 @@ void MainTest::selectWithInvalidRelation()
|
||||||
q->toList();
|
q->toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainTest::select10NewstPosts()
|
|
||||||
{
|
|
||||||
auto q = db.posts()->query();
|
|
||||||
q->orderBy(!Post::saveDateField());
|
|
||||||
q->toList(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainTest::modifyPost()
|
void MainTest::modifyPost()
|
||||||
{
|
{
|
||||||
auto q = db.posts()->query();
|
auto q = db.posts()->query();
|
||||||
|
|
@ -199,6 +213,7 @@ void MainTest::modifyPost()
|
||||||
->setWhere(Post::idField() == postId);
|
->setWhere(Post::idField() == postId);
|
||||||
|
|
||||||
post = q->first();
|
post = q->first();
|
||||||
|
PRINT(post->title());
|
||||||
QTEST_ASSERT(post->title() == "new name");
|
QTEST_ASSERT(post->title() == "new name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,7 +221,6 @@ void MainTest::emptyDatabase()
|
||||||
{
|
{
|
||||||
auto commentsCount = db.comments()->query()->remove();
|
auto commentsCount = db.comments()->query()->remove();
|
||||||
auto postsCount = db.posts()->query()->remove();
|
auto postsCount = db.posts()->query()->remove();
|
||||||
|
|
||||||
QTEST_ASSERT(postsCount == 3);
|
QTEST_ASSERT(postsCount == 3);
|
||||||
QTEST_ASSERT(commentsCount == 6);
|
QTEST_ASSERT(commentsCount == 6);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@
|
||||||
|
|
||||||
#include "weblogdatabase.h"
|
#include "weblogdatabase.h"
|
||||||
class Post;
|
class Post;
|
||||||
|
class User;
|
||||||
class MainTest : public QObject
|
class MainTest : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
WeblogDatabase db;
|
WeblogDatabase db;
|
||||||
int postId;
|
int postId;
|
||||||
Post *post;
|
Post *post;
|
||||||
|
User *user;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainTest(QObject *parent = 0);
|
explicit MainTest(QObject *parent = 0);
|
||||||
|
|
@ -22,13 +24,15 @@ private slots:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
void dataScheema();
|
void dataScheema();
|
||||||
|
void createUser();
|
||||||
void createPost();
|
void createPost();
|
||||||
void createPost2();
|
void createPost2();
|
||||||
|
void join();
|
||||||
void selectPosts();
|
void selectPosts();
|
||||||
|
void selectFirst();
|
||||||
void selectPostsWithoutTitle();
|
void selectPostsWithoutTitle();
|
||||||
void selectPostIds();
|
void selectPostIds();
|
||||||
void testDate();
|
void testDate();
|
||||||
void join();
|
|
||||||
void selectWithInvalidRelation();
|
void selectWithInvalidRelation();
|
||||||
void select10NewstPosts();
|
void select10NewstPosts();
|
||||||
void modifyPost();
|
void modifyPost();
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ SOURCES += \
|
||||||
../common/comment.cpp \
|
../common/comment.cpp \
|
||||||
../common/post.cpp \
|
../common/post.cpp \
|
||||||
../common/user.cpp \
|
../common/user.cpp \
|
||||||
../common/weblogdatabase.cpp
|
../common/weblogdatabase.cpp \
|
||||||
|
../common/score.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
maintest.h \
|
maintest.h \
|
||||||
|
|
@ -21,4 +22,5 @@ HEADERS += \
|
||||||
../common/comment.h \
|
../common/comment.h \
|
||||||
../common/post.h \
|
../common/post.h \
|
||||||
../common/user.h \
|
../common/user.h \
|
||||||
../common/weblogdatabase.h
|
../common/weblogdatabase.h \
|
||||||
|
../common/score.h
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "comment.h"
|
#include "comment.h"
|
||||||
|
|
||||||
Comment::Comment(QObject *parent) : Table(parent)
|
Comment::Comment(QObject *parent) : Table(parent),
|
||||||
|
m_author(Q_NULLPTR), m_post(Q_NULLPTR)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class Comment : public Table
|
||||||
NUT_FOREGION_KEY(User, int, author, author, setAuthor)
|
NUT_FOREGION_KEY(User, int, author, author, setAuthor)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE explicit Comment(QObject *tableSet = 0);
|
Q_INVOKABLE explicit Comment(QObject *parentTableSet = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Comment*)
|
Q_DECLARE_METATYPE(Comment*)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
#include "post.h"
|
#include "post.h"
|
||||||
#include "comment.h"
|
#include "comment.h"
|
||||||
|
#include "score.h"
|
||||||
#include "tableset.h"
|
#include "tableset.h"
|
||||||
|
|
||||||
Post::Post(QObject *parent) : Table(parent),
|
Post::Post(QObject *parent) : Table(parent),
|
||||||
m_comments(new TableSet<Comment>(this)), m_id(0), m_title("")
|
m_id(0), m_title(""),
|
||||||
|
m_comments(new TableSet<Comment>(this)),
|
||||||
|
m_scores(new TableSet<Score>(this))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using namespace NUT_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Comment;
|
class Comment;
|
||||||
|
class Score;
|
||||||
class Post : public Table
|
class Post : public Table
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -27,9 +28,10 @@ class Post : public Table
|
||||||
NUT_DECLARE_FIELD(QString, body, body, setBody)
|
NUT_DECLARE_FIELD(QString, body, body, setBody)
|
||||||
|
|
||||||
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
||||||
|
NUT_DECLARE_CHILD_TABLE(Score, scores)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE Post(QObject *tableSet = 0);
|
Q_INVOKABLE Post(QObject *parentTableSet = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "score.h"
|
||||||
|
|
||||||
|
Score::Score(QObject *parent) : Nut::Table(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef SCORE_H
|
||||||
|
#define SCORE_H
|
||||||
|
|
||||||
|
#include "table.h"
|
||||||
|
|
||||||
|
class User;
|
||||||
|
class Post;
|
||||||
|
class Score : public Nut::Table
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||||
|
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||||
|
|
||||||
|
NUT_DECLARE_FIELD(int, score, score, setScore)
|
||||||
|
|
||||||
|
NUT_FOREGION_KEY(Post, int, post, post, setPost)
|
||||||
|
NUT_FOREGION_KEY(User, int, user, user, setUser)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE Score(QObject *parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCORE_H
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
#include "comment.h"
|
||||||
|
#include "score.h"
|
||||||
|
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
#include "comment.h"
|
|
||||||
|
|
||||||
User::User(QObject *tableSet) : Table(tableSet),
|
User::User(QObject *tableSet) : Table(tableSet),
|
||||||
m_comments(new TableSet<Comment>(this))
|
m_comments(new TableSet<Comment>(this)),
|
||||||
|
m_scores(new TableSet<Score>(this))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ using namespace NUT_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Comment;
|
class Comment;
|
||||||
|
class Score;
|
||||||
class User : public Nut::Table
|
class User : public Nut::Table
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||||
NUT_DECLARE_FIELD(QUuid, id, id, setId)
|
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||||
|
|
||||||
NUT_NOT_NULL(username)
|
NUT_NOT_NULL(username)
|
||||||
NUT_LEN(username, 50)
|
NUT_LEN(username, 50)
|
||||||
|
|
@ -28,9 +29,10 @@ class User : public Nut::Table
|
||||||
NUT_DECLARE_FIELD(QString, password, password, setPassword)
|
NUT_DECLARE_FIELD(QString, password, password, setPassword)
|
||||||
|
|
||||||
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
||||||
|
NUT_DECLARE_CHILD_TABLE(Score, scores)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE User(QObject *tableSet = 0);
|
Q_INVOKABLE User(QObject *parentTableSet = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(User*)
|
Q_DECLARE_METATYPE(User*)
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
#include "post.h"
|
#include "post.h"
|
||||||
#include "comment.h"
|
#include "comment.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
#include "score.h"
|
||||||
#include "weblogdatabase.h"
|
#include "weblogdatabase.h"
|
||||||
|
|
||||||
WeblogDatabase::WeblogDatabase() : Database(),
|
WeblogDatabase::WeblogDatabase() : Database(),
|
||||||
m_posts(new TableSet<Post>(this)),
|
m_posts(new TableSet<Post>(this)),
|
||||||
m_comments(new TableSet<Comment>(this)),
|
m_comments(new TableSet<Comment>(this)),
|
||||||
m_users(new TableSet<User>(this))
|
m_users(new TableSet<User>(this)),
|
||||||
|
m_scores(new TableSet<Score>(this))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using namespace NUT_NAMESPACE;
|
||||||
class Post;
|
class Post;
|
||||||
class Comment;
|
class Comment;
|
||||||
class User;
|
class User;
|
||||||
|
class Score;
|
||||||
class WeblogDatabase : public Database
|
class WeblogDatabase : public Database
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -19,6 +20,7 @@ class WeblogDatabase : public Database
|
||||||
NUT_DECLARE_TABLE(Post, post)
|
NUT_DECLARE_TABLE(Post, post)
|
||||||
NUT_DECLARE_TABLE(Comment, comment)
|
NUT_DECLARE_TABLE(Comment, comment)
|
||||||
NUT_DECLARE_TABLE(User, user)
|
NUT_DECLARE_TABLE(User, user)
|
||||||
|
NUT_DECLARE_TABLE(Score, score)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WeblogDatabase();
|
WeblogDatabase();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <QtTest>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QSqlError>
|
||||||
|
|
||||||
|
#include "consts.h"
|
||||||
|
|
||||||
|
#include "jointest.h"
|
||||||
|
#include "query.h"
|
||||||
|
#include "tableset.h"
|
||||||
|
#include "tablemodel.h"
|
||||||
|
#include "databasemodel.h"
|
||||||
|
|
||||||
|
#include "user.h"
|
||||||
|
#include "post.h"
|
||||||
|
#include "comment.h"
|
||||||
|
#include "score.h"
|
||||||
|
|
||||||
|
#define PRINT(x) qDebug() << #x "=" << x;
|
||||||
|
JoinTest::JoinTest(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinTest::initTestCase()
|
||||||
|
{
|
||||||
|
qDebug() << "User type id:" << qRegisterMetaType<User*>();
|
||||||
|
qDebug() << "Post type id:" << qRegisterMetaType<Post*>();
|
||||||
|
qDebug() << "Comment type id:" << qRegisterMetaType<Comment*>();
|
||||||
|
qDebug() << "Score type id:" << qRegisterMetaType<Score*>();
|
||||||
|
qDebug() << "DB type id:" << qRegisterMetaType<WeblogDatabase*>();
|
||||||
|
|
||||||
|
db.setDriver(DRIVER);
|
||||||
|
db.setHostName(HOST);
|
||||||
|
db.setDatabaseName("nut_tst_join.db");
|
||||||
|
db.setUserName(USERNAME);
|
||||||
|
db.setPassword(PASSWORD);
|
||||||
|
|
||||||
|
bool ok = db.open();
|
||||||
|
|
||||||
|
// db.comments()->query()->remove();
|
||||||
|
// db.posts()->query()->remove();
|
||||||
|
|
||||||
|
QTEST_ASSERT(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinTest::join()
|
||||||
|
{
|
||||||
|
auto q = db.comments()->query()
|
||||||
|
->join<User>()
|
||||||
|
->join<Post>();
|
||||||
|
|
||||||
|
// Comment *comment = q->first();
|
||||||
|
auto comments = q->toList();
|
||||||
|
// Comment *comment = q->toList().first();
|
||||||
|
// qDebug() << q->sqlCommand();
|
||||||
|
PRINT(comments.length());
|
||||||
|
|
||||||
|
// QTEST_ASSERT(comments.length());
|
||||||
|
// QTEST_ASSERT(comments[0]->author());
|
||||||
|
// QTEST_ASSERT(comments[0]->author()->username() == "admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinTest::join2()
|
||||||
|
{
|
||||||
|
auto q = db.users()->query()
|
||||||
|
->join<Comment>()
|
||||||
|
->join<Score>();
|
||||||
|
|
||||||
|
// Comment *comment = q->first();
|
||||||
|
auto comments = q->toList();
|
||||||
|
// Comment *comment = q->toList().first();
|
||||||
|
// qDebug() << q->sqlCommand();
|
||||||
|
// QTEST_ASSERT(comments.length());
|
||||||
|
// QTEST_ASSERT(comments[0]->author());
|
||||||
|
// QTEST_ASSERT(comments[0]->author()->username() == "admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(JoinTest)
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef JOINTEST_H
|
||||||
|
#define JOINTEST_H
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#include "weblogdatabase.h"
|
||||||
|
|
||||||
|
class JoinTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
WeblogDatabase db;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit JoinTest(QObject *parent = 0);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initTestCase();
|
||||||
|
|
||||||
|
void join();
|
||||||
|
void join2();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JOINTEST_H
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
QT += qml quick testlib sql
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
TARGET = tst_nut
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
CONFIG += warn_on qmltestcase c++11
|
||||||
|
INCLUDEPATH += $$PWD/../../src $$PWD/../common
|
||||||
|
include(../../nut.pri)
|
||||||
|
IMPORTPATH += $$OUT_PWD/../src/imports
|
||||||
|
SOURCES += \
|
||||||
|
jointest.cpp \
|
||||||
|
../common/comment.cpp \
|
||||||
|
../common/post.cpp \
|
||||||
|
../common/user.cpp \
|
||||||
|
../common/weblogdatabase.cpp \
|
||||||
|
../common/score.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
jointest.h \
|
||||||
|
../common/consts.h \
|
||||||
|
../common/comment.h \
|
||||||
|
../common/post.h \
|
||||||
|
../common/user.h \
|
||||||
|
../common/weblogdatabase.h \
|
||||||
|
../common/score.h
|
||||||
Loading…
Reference in New Issue