join progress / pass to home
This commit is contained in:
parent
c5e9d5ec2b
commit
b3fac0763c
|
|
@ -198,7 +198,7 @@ bool DatabasePrivate::getCurrectScheema()
|
|||
}
|
||||
|
||||
if (type == __nut_TABLE)
|
||||
tables.insert(name, type);
|
||||
tables.insert(name, value);
|
||||
|
||||
if (type == __nut_DB_VERSION)
|
||||
currentModel.setVersion(name);
|
||||
|
|
@ -250,7 +250,6 @@ bool DatabasePrivate::checkClassInfo(const QMetaClassInfo &classInfo, QString &t
|
|||
type = parts[0];
|
||||
name = parts[1];
|
||||
value = parts[2];
|
||||
qDebug() << Q_FUNC_INFO << parts;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,16 +70,15 @@ TableModel *DatabaseModel::tableByName(QString tableName) const
|
|||
|
||||
TableModel *DatabaseModel::tableByClassName(QString className) const
|
||||
{
|
||||
QStringList l;
|
||||
for(int i = 0; i < size(); i++){
|
||||
TableModel *s = at(i);
|
||||
|
||||
l.append(s->className());
|
||||
if(s->className() == className)
|
||||
return s;
|
||||
}
|
||||
|
||||
// qWarning("Table with class name '%s' not found in model",
|
||||
// qUtf8Printable(className));
|
||||
Q_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public: \
|
|||
#define NUT_FOREGION_KEY(type, keytype, name, read, write) \
|
||||
Q_PROPERTY(type* name READ read WRITE write) \
|
||||
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
|
||||
NUT_INFO(__nut_FOREGION_KEY, name, type) \
|
||||
NUT_INFO(__nut_FOREGION_KEY, name##Id, type) \
|
||||
type *m_##name; \
|
||||
public: \
|
||||
type *read() const { return m_##name ; } \
|
||||
|
|
|
|||
|
|
@ -140,8 +140,8 @@ QString MySqlGenerator::selectCommand(SqlGeneratorBase::AgregateType t, QString
|
|||
|
||||
if (take != -1 && skip != -1)
|
||||
command.append(QString(" LIMIT %1 OFFSET %2")
|
||||
.arg(skip)
|
||||
.arg(take));
|
||||
.arg(take)
|
||||
.arg(skip));
|
||||
return command;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ QString SqlGeneratorBase::masterDatabaseName(QString databaseName)
|
|||
|
||||
QString SqlGeneratorBase::createTable(TableModel *table)
|
||||
{
|
||||
|
||||
Q_UNUSED(table);
|
||||
return "";
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
|
||||
|
|
@ -95,6 +96,21 @@ QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
|
|||
return "";
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::recordsPhrase(QString className)
|
||||
{
|
||||
TableModel *table = _database->model().tableByClassName(className);
|
||||
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)
|
||||
{
|
||||
return field->name + " " + fieldType(field) + (field->notNull ? " NOT NULL" : "");
|
||||
|
|
@ -181,13 +197,13 @@ QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
|
|||
|
||||
sql = QString("CREATE TABLE %1 \n(%2)").arg(newTable->name()).arg(
|
||||
columnSql.join(",\n"));
|
||||
qDebug() << sql;
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
|
||||
{
|
||||
//TODO: reorder list first!
|
||||
//TODO: make this ungly code better and bugless :-)
|
||||
/*
|
||||
* Known issues:
|
||||
|
|
@ -198,46 +214,50 @@ QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
|
|||
return "";
|
||||
|
||||
if (list.count() == 1)
|
||||
return list.first();
|
||||
return "[" + list.first() + "]";
|
||||
|
||||
DatabaseModel model = _database->model();
|
||||
QStringList clone = list;
|
||||
QString mainTable = clone.takeFirst();
|
||||
QString ret = mainTable;
|
||||
QString ret = "[" + mainTable + "]";
|
||||
|
||||
do {
|
||||
QString table = model.tableByClassName(clone.first())->name();
|
||||
clone.takeFirst();
|
||||
RelationModel *rel = model.relationByTableNames(mainTable, table);
|
||||
if (!clone.count())
|
||||
break;
|
||||
|
||||
QString table = clone.first();// model.tableByClassName(clone.first())->name();
|
||||
RelationModel *rel = model.relationByClassNames(mainTable, clone.first());
|
||||
if (rel) {
|
||||
//mainTable is master of table
|
||||
ret.append(QString(" INNER JOIN %1 ON %4.%2 = %1.%3")
|
||||
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
|
||||
.arg(table)
|
||||
.arg(rel->table->primaryKey())
|
||||
.arg(rel->localColumn)
|
||||
.arg(mainTable));
|
||||
|
||||
if (order != Q_NULLPTR)
|
||||
order->append(table + "." + rel->localColumn);
|
||||
order->append(mainTable + "." + rel->table->primaryKey());
|
||||
|
||||
} else{
|
||||
rel = model.relationByTableNames(table, mainTable);
|
||||
rel = model.relationByClassNames(clone.first(), mainTable);
|
||||
if (rel) {
|
||||
// table is master of mainTable
|
||||
ret.append(QString(" INNER JOIN %1 ON %4.%2 = %1.%3")
|
||||
ret.append(QString(" INNER JOIN [%1] ON %4.%2 = %1.%3")
|
||||
.arg(table)
|
||||
.arg(rel->localColumn)
|
||||
.arg(rel->table->primaryKey())
|
||||
.arg(mainTable));
|
||||
|
||||
if (order != Q_NULLPTR)
|
||||
order->append(table + "." + rel->table->primaryKey());
|
||||
order->append(mainTable + "." + rel->localColumn);
|
||||
|
||||
} else {
|
||||
qInfo("Relation for %s and %s not exists",
|
||||
qPrintable(table), qPrintable(mainTable));
|
||||
}
|
||||
}
|
||||
|
||||
clone.takeFirst();
|
||||
} while (clone.count());
|
||||
|
||||
return ret;
|
||||
|
|
@ -389,6 +409,15 @@ QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
|
|||
|
||||
QStringList joinedOrders;
|
||||
QString select = agregateText(t, agregateArg);
|
||||
|
||||
if (select == "*") {
|
||||
select = "";
|
||||
foreach (QString c, joins) {
|
||||
if (!select.isEmpty())
|
||||
select.append(", ");
|
||||
select.append(recordsPhrase(c));
|
||||
}
|
||||
}
|
||||
QString from = join(joins, &joinedOrders);
|
||||
QString where = createWhere(wheres);
|
||||
QString orderText = joinedOrders.join(", ");
|
||||
|
|
@ -433,7 +462,8 @@ QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
|
|||
void SqlGeneratorBase::replaceTableNames(QString &command)
|
||||
{
|
||||
foreach (TableModel *m, TableModel::allModels())
|
||||
command = command.replace("[" + m->className() + "].", "`" + m->name() + "`.");
|
||||
command = command
|
||||
.replace("[" + m->className() + "]", "`" + m->name() + "`");
|
||||
}
|
||||
|
||||
void SqlGeneratorBase::removeTableNames(QString &command)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ public:
|
|||
|
||||
virtual QString saveRecord(Table *t, QString tableName);
|
||||
|
||||
virtual QString recordsPhrase(QString className);
|
||||
|
||||
virtual QString insertRecord(Table *t, QString tableName);
|
||||
virtual QString updateRecord(Table *t, QString tableName);
|
||||
virtual QString deleteRecord(Table *t, QString tableName);
|
||||
|
|
|
|||
|
|
@ -71,4 +71,19 @@ QString SqliteGenerator::fieldType(FieldModel *field)
|
|||
return dbType;
|
||||
}
|
||||
|
||||
QString SqliteGenerator::selectCommand(SqlGeneratorBase::AgregateType t,
|
||||
QString agregateArg,
|
||||
QList<WherePhrase> &wheres,
|
||||
QList<WherePhrase> &orders,
|
||||
QStringList joins, int skip, int take)
|
||||
{
|
||||
QString command = SqlGeneratorBase::selectCommand(t, agregateArg, 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
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ public:
|
|||
SqliteGenerator(Database *parent = 0);
|
||||
|
||||
QString fieldType(FieldModel *field);
|
||||
|
||||
QString selectCommand(AgregateType t, QString agregateArg,
|
||||
QList<WherePhrase> &wheres,
|
||||
QList<WherePhrase> &orders,
|
||||
QStringList joins, int skip, int take);
|
||||
};
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
62
src/query.h
62
src/query.h
|
|
@ -122,73 +122,99 @@ Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
|
|||
template <class T>
|
||||
Q_OUTOFLINE_TEMPLATE QList<T *> Query<T>::toList(int count)
|
||||
{
|
||||
Q_UNUSED(count);
|
||||
Q_D(Query);
|
||||
QList<T*> result;
|
||||
d->select = "*";
|
||||
|
||||
d->joins.prepend(d->className);
|
||||
|
||||
qDebug() << "JOINS="<< d->joins;
|
||||
|
||||
d->sql = d->database->sqlGenertor()->selectCommand(
|
||||
SqlGeneratorBase::SelectAll, "", d->wheres, d->orderPhrases,
|
||||
d->joins, d->skip, d->take);
|
||||
qDebug() << d->sql;
|
||||
QSqlQuery q = d->database->exec(d->sql);
|
||||
|
||||
struct LevelData{
|
||||
QString key;
|
||||
QString className;
|
||||
QString tableName;
|
||||
QVariant keyValue;
|
||||
int typeId;
|
||||
TableSetBase *tableSet;
|
||||
Table *lastRow;
|
||||
};
|
||||
QVector<LevelData> levels;
|
||||
QList<T*> returnList;
|
||||
foreach (QString className, d->joins) {
|
||||
LevelData data;
|
||||
data.className = className;
|
||||
TableModel *m = d->database->model().tableByClassName(className);
|
||||
if (!m)
|
||||
qFatal("Model '%s' not found!!!", qPrintable(className));
|
||||
data.key = m->primaryKey();
|
||||
if (!m) {
|
||||
qWarning("Model '%s' not found!!!", qPrintable(className));
|
||||
return returnList;
|
||||
}
|
||||
data.key = m->name() + "_" + m->primaryKey();
|
||||
data.typeId = m->typeId();
|
||||
data.keyValue = QVariant();
|
||||
data.tableSet = 0;
|
||||
data.tableName = m->name();
|
||||
levels.append(data);
|
||||
}
|
||||
|
||||
QList<T*> returnList;
|
||||
while (q.next()) {
|
||||
for (int i = 0; i < levels.count(); i++) {
|
||||
LevelData &data = levels[i];
|
||||
if (!data.tableSet || data.keyValue != q.value(data.key)) {
|
||||
if (/*!data.tableSet ||*/ data.keyValue != q.value(data.key)) {
|
||||
data.keyValue = q.value(data.key);
|
||||
|
||||
//create table row
|
||||
Table *childTable;
|
||||
Table *table;
|
||||
if (data.className == d->className) {
|
||||
childTable = new T();
|
||||
returnList.append(dynamic_cast<T*>(childTable));
|
||||
table = new T();
|
||||
table->setTableSet(d->tableSet);
|
||||
returnList.append(dynamic_cast<T*>(table));
|
||||
} else {
|
||||
const QMetaObject *childMetaObject
|
||||
= QMetaType::metaObjectForType(data.typeId);
|
||||
childTable = qobject_cast<Table *>(childMetaObject->newInstance());
|
||||
table = qobject_cast<Table *>(childMetaObject->newInstance());
|
||||
}
|
||||
|
||||
QStringList childFields
|
||||
= d->database->model().tableByClassName(data.className)->fieldsNames();
|
||||
foreach (QString field, childFields)
|
||||
childTable->setProperty(field.toLatin1().data(), q.value(field));
|
||||
table->setProperty(field.toLatin1().data(),
|
||||
q.value(data.tableName + "_" + field));
|
||||
|
||||
table->setStatus(Table::FeatchedFromDB);
|
||||
table->setParent(this);
|
||||
table->clear();
|
||||
|
||||
//set last created row
|
||||
data.lastRow = childTable;
|
||||
data.lastRow = table;
|
||||
if (i < levels.count() - 1) {
|
||||
QSet<TableSetBase *> tableSets = childTable->tableSets;
|
||||
foreach (TableSetBase *ts, tableSets)
|
||||
if (ts->childClassName() == levels[i + 1].className)
|
||||
data.tableSet = ts;
|
||||
// if (data.className == d->className) {
|
||||
// data.tableSet = d->tableSet;
|
||||
// } else
|
||||
{
|
||||
QSet<TableSetBase *> tableSets = table->tableSets;
|
||||
foreach (TableSetBase *ts, tableSets)
|
||||
if (ts->childClassName() == levels[i + 1].className)
|
||||
data.tableSet = ts;
|
||||
|
||||
if (!data.tableSet)
|
||||
qWarning() << "Dataset not found for" << data.className;
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
// if (!table->tableSet())
|
||||
table->setTableSet(levels[i - 1].tableSet);
|
||||
table->setParentTable(levels[i - 1].lastRow);
|
||||
} else {
|
||||
// table->setTableSet(d->tableSet);
|
||||
// data.tableSet = d->tableSet;
|
||||
}
|
||||
if (i)
|
||||
childTable->setTableSet(levels[i - 1].tableSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ int Table::save(Database *db)
|
|||
{
|
||||
QSqlQuery q = db->exec(db->sqlGenertor()->saveRecord(this, db->tableName(metaObject()->className())));
|
||||
|
||||
|
||||
if(status() == Added && isPrimaryKeyAutoIncrement())
|
||||
setProperty(primaryKey().toLatin1().data(), q.lastInsertId());
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,6 @@ bool TableModel::checkClassInfo(const QMetaClassInfo &classInfo,
|
|||
type = parts[0];
|
||||
name = parts[1];
|
||||
value = parts[2];
|
||||
qDebug() << Q_FUNC_INFO << parts;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +189,6 @@ TableModel::TableModel(int typeId, QString tableName)
|
|||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "**********" << type << __nut_FIELD << (type == __nut_FIELD);
|
||||
if(type == __nut_FIELD){
|
||||
FieldModel *f = new FieldModel;
|
||||
f->name = name;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "post.h"
|
||||
#include "comment.h"
|
||||
|
||||
#define PRINT(x)
|
||||
//qDebug() << #x "=" << x;
|
||||
MainTest::MainTest(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
|
@ -70,6 +72,7 @@ void MainTest::createPost()
|
|||
Comment *comment = new Comment;
|
||||
comment->setMessage("comment #" + QString::number(i));
|
||||
comment->setSaveDate(QDateTime::currentDateTime());
|
||||
comment->setAuthorId(user->id());
|
||||
newPost->comments()->append(comment);
|
||||
}
|
||||
db.saveChanges();
|
||||
|
|
@ -106,18 +109,16 @@ void MainTest::createPost2()
|
|||
void MainTest::selectPosts()
|
||||
{
|
||||
auto q = db.posts()->query()
|
||||
// q->join(Post::commentsTable());
|
||||
// q->join(Post::commentsTable());
|
||||
// ->join<User>()
|
||||
->join<Comment>()
|
||||
->orderBy(!Post::saveDateField() & Post::bodyField())
|
||||
->setWhere(Post::idField() == postId);
|
||||
|
||||
auto posts = q->toList();
|
||||
qDebug() << "SQL="<<q->sqlCommand();
|
||||
post = posts.at(0);
|
||||
post->setBody("");
|
||||
|
||||
PRINT(posts.length());
|
||||
PRINT(posts.at(0)->comments()->length());
|
||||
QTEST_ASSERT(posts.length() == 1);
|
||||
QTEST_ASSERT(posts.at(0)->comments()->length() == 3);
|
||||
QTEST_ASSERT(posts.at(0)->title() == "post title");
|
||||
|
|
@ -128,12 +129,18 @@ void MainTest::selectPosts()
|
|||
db.cleanUp();
|
||||
}
|
||||
|
||||
void MainTest::selectFirst()
|
||||
{
|
||||
auto posts = db.posts()->query()
|
||||
->first();
|
||||
QTEST_ASSERT(posts != Q_NULLPTR);
|
||||
}
|
||||
|
||||
void MainTest::selectPostsWithoutTitle()
|
||||
{
|
||||
auto q = db.posts()->query();
|
||||
q->setWhere(Post::titleField().isNull());
|
||||
auto count = q->count();
|
||||
qDebug() << q->sqlCommand();
|
||||
QTEST_ASSERT(count == 0);
|
||||
}
|
||||
|
||||
|
|
@ -169,12 +176,13 @@ void MainTest::join()
|
|||
{
|
||||
auto q = db.comments()->query()
|
||||
->join<User>()
|
||||
->join<Post>()
|
||||
->setWhere(Comment::saveDateField() < QDateTime::currentDateTime().addDays(-1))
|
||||
->orderBy(Comment::saveDateField());
|
||||
->join<Post>();
|
||||
|
||||
q->toList();
|
||||
Comment *comment = q->first();
|
||||
|
||||
// Comment *comment = q->toList().first();
|
||||
qDebug() << q->sqlCommand();
|
||||
QTEST_ASSERT(comment->author()->username() == "admin");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -208,6 +216,7 @@ void MainTest::modifyPost()
|
|||
->setWhere(Post::idField() == postId);
|
||||
|
||||
post = q->first();
|
||||
PRINT(post->title());
|
||||
QTEST_ASSERT(post->title() == "new name");
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +224,6 @@ void MainTest::emptyDatabase()
|
|||
{
|
||||
auto commentsCount = db.comments()->query()->remove();
|
||||
auto postsCount = db.posts()->query()->remove();
|
||||
|
||||
QTEST_ASSERT(postsCount == 3);
|
||||
QTEST_ASSERT(commentsCount == 6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@ private slots:
|
|||
void createPost();
|
||||
void createPost2();
|
||||
void selectPosts();
|
||||
void selectFirst();
|
||||
void join();
|
||||
void selectPostsWithoutTitle();
|
||||
void selectPostIds();
|
||||
void testDate();
|
||||
void join();
|
||||
void selectWithInvalidRelation();
|
||||
void select10NewstPosts();
|
||||
void modifyPost();
|
||||
|
|
|
|||
Loading…
Reference in New Issue