join progress / pass to home

This commit is contained in:
Hamed Masafi 2018-01-11 19:44:29 +03:30
parent c5e9d5ec2b
commit b3fac0763c
13 changed files with 135 additions and 53 deletions

View File

@ -198,7 +198,7 @@ bool DatabasePrivate::getCurrectScheema()
} }
if (type == __nut_TABLE) if (type == __nut_TABLE)
tables.insert(name, type); tables.insert(name, value);
if (type == __nut_DB_VERSION) if (type == __nut_DB_VERSION)
currentModel.setVersion(name); currentModel.setVersion(name);
@ -250,7 +250,6 @@ bool DatabasePrivate::checkClassInfo(const QMetaClassInfo &classInfo, QString &t
type = parts[0]; type = parts[0];
name = parts[1]; name = parts[1];
value = parts[2]; value = parts[2];
qDebug() << Q_FUNC_INFO << parts;
return true; return true;
} }
} }

View File

@ -70,16 +70,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;
} }

View File

@ -71,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) \
NUT_INFO(__nut_FOREGION_KEY, name, type) \ NUT_INFO(__nut_FOREGION_KEY, name##Id, type) \
type *m_##name; \ type *m_##name; \
public: \ public: \
type *read() const { return m_##name ; } \ type *read() const { return m_##name ; } \

View File

@ -140,8 +140,8 @@ QString MySqlGenerator::selectCommand(SqlGeneratorBase::AgregateType t, QString
if (take != -1 && skip != -1) if (take != -1 && skip != -1)
command.append(QString(" LIMIT %1 OFFSET %2") command.append(QString(" LIMIT %1 OFFSET %2")
.arg(skip) .arg(take)
.arg(take)); .arg(skip));
return command; return command;
} }

View File

@ -71,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)
@ -95,6 +96,21 @@ QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
return ""; 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) QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
{ {
return field->name + " " + fieldType(field) + (field->notNull ? " NOT NULL" : ""); 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( sql = QString("CREATE TABLE %1 \n(%2)").arg(newTable->name()).arg(
columnSql.join(",\n")); columnSql.join(",\n"));
qDebug() << sql;
} }
return sql; return sql;
} }
QString SqlGeneratorBase::join(const QStringList &list, QStringList *order) QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
{ {
//TODO: reorder list first!
//TODO: make this ungly code better and bugless :-) //TODO: make this ungly code better and bugless :-)
/* /*
* Known issues: * Known issues:
@ -198,46 +214,50 @@ QString SqlGeneratorBase::join(const QStringList &list, QStringList *order)
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 table = model.tableByClassName(clone.first())->name(); if (!clone.count())
clone.takeFirst(); break;
RelationModel *rel = model.relationByTableNames(mainTable, table);
QString table = clone.first();// model.tableByClassName(clone.first())->name();
RelationModel *rel = model.relationByClassNames(mainTable, clone.first());
if (rel) { if (rel) {
//mainTable is master of table //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(table)
.arg(rel->table->primaryKey()) .arg(rel->table->primaryKey())
.arg(rel->localColumn) .arg(rel->localColumn)
.arg(mainTable)); .arg(mainTable));
if (order != Q_NULLPTR) if (order != Q_NULLPTR)
order->append(table + "." + rel->localColumn); order->append(mainTable + "." + rel->table->primaryKey());
} else{ } else{
rel = model.relationByTableNames(table, mainTable); rel = model.relationByClassNames(clone.first(), mainTable);
if (rel) { if (rel) {
// table is master of mainTable // 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(table)
.arg(rel->localColumn) .arg(rel->localColumn)
.arg(rel->table->primaryKey()) .arg(rel->table->primaryKey())
.arg(mainTable)); .arg(mainTable));
if (order != Q_NULLPTR) if (order != Q_NULLPTR)
order->append(table + "." + rel->table->primaryKey()); order->append(mainTable + "." + rel->localColumn);
} else { } else {
qInfo("Relation for %s and %s not exists", qInfo("Relation for %s and %s not exists",
qPrintable(table), qPrintable(mainTable)); qPrintable(table), qPrintable(mainTable));
} }
} }
clone.takeFirst();
} while (clone.count()); } while (clone.count());
return ret; return ret;
@ -389,6 +409,15 @@ QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
QStringList joinedOrders; QStringList joinedOrders;
QString select = agregateText(t, agregateArg); 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 from = join(joins, &joinedOrders);
QString where = createWhere(wheres); QString where = createWhere(wheres);
QString orderText = joinedOrders.join(", "); QString orderText = joinedOrders.join(", ");
@ -433,7 +462,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)

View File

@ -72,6 +72,8 @@ public:
virtual QString saveRecord(Table *t, QString tableName); virtual QString saveRecord(Table *t, QString tableName);
virtual QString recordsPhrase(QString className);
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);

View File

@ -71,4 +71,19 @@ QString SqliteGenerator::fieldType(FieldModel *field)
return dbType; 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 NUT_END_NAMESPACE

View File

@ -32,6 +32,11 @@ public:
SqliteGenerator(Database *parent = 0); SqliteGenerator(Database *parent = 0);
QString fieldType(FieldModel *field); 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 NUT_END_NAMESPACE

View File

@ -122,73 +122,99 @@ 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*> result;
d->select = "*"; d->select = "*";
d->joins.prepend(d->className); d->joins.prepend(d->className);
qDebug() << "JOINS="<< d->joins;
d->sql = d->database->sqlGenertor()->selectCommand( d->sql = d->database->sqlGenertor()->selectCommand(
SqlGeneratorBase::SelectAll, "", d->wheres, d->orderPhrases, SqlGeneratorBase::SelectAll, "", d->wheres, d->orderPhrases,
d->joins, d->skip, d->take); d->joins, d->skip, d->take);
qDebug() << d->sql;
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
struct LevelData{ struct LevelData{
QString key; QString key;
QString className; QString className;
QString tableName;
QVariant keyValue; QVariant keyValue;
int typeId; int typeId;
TableSetBase *tableSet; TableSetBase *tableSet;
Table *lastRow; Table *lastRow;
}; };
QVector<LevelData> levels; QVector<LevelData> levels;
QList<T*> returnList;
foreach (QString className, d->joins) { foreach (QString className, d->joins) {
LevelData data; LevelData data;
data.className = className; data.className = className;
TableModel *m = d->database->model().tableByClassName(className); TableModel *m = d->database->model().tableByClassName(className);
if (!m) if (!m) {
qFatal("Model '%s' not found!!!", qPrintable(className)); qWarning("Model '%s' not found!!!", qPrintable(className));
data.key = m->primaryKey(); return returnList;
}
data.key = m->name() + "_" + m->primaryKey();
data.typeId = m->typeId(); data.typeId = m->typeId();
data.keyValue = QVariant(); data.keyValue = QVariant();
data.tableSet = 0; data.tableSet = 0;
data.tableName = m->name();
levels.append(data); levels.append(data);
} }
QList<T*> returnList;
while (q.next()) { while (q.next()) {
for (int i = 0; i < levels.count(); i++) { for (int i = 0; i < levels.count(); i++) {
LevelData &data = levels[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 //create table row
Table *childTable; Table *table;
if (data.className == d->className) { if (data.className == d->className) {
childTable = new T(); table = new T();
returnList.append(dynamic_cast<T*>(childTable)); table->setTableSet(d->tableSet);
returnList.append(dynamic_cast<T*>(table));
} else { } else {
const QMetaObject *childMetaObject const QMetaObject *childMetaObject
= QMetaType::metaObjectForType(data.typeId); = QMetaType::metaObjectForType(data.typeId);
childTable = qobject_cast<Table *>(childMetaObject->newInstance()); table = qobject_cast<Table *>(childMetaObject->newInstance());
} }
QStringList childFields QStringList childFields
= d->database->model().tableByClassName(data.className)->fieldsNames(); = d->database->model().tableByClassName(data.className)->fieldsNames();
foreach (QString field, childFields) 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 //set last created row
data.lastRow = childTable; data.lastRow = table;
if (i < levels.count() - 1) { if (i < levels.count() - 1) {
QSet<TableSetBase *> tableSets = childTable->tableSets; // if (data.className == d->className) {
foreach (TableSetBase *ts, tableSets) // data.tableSet = d->tableSet;
if (ts->childClassName() == levels[i + 1].className) // } else
data.tableSet = ts; {
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);
} }
} }
} }

View File

@ -134,7 +134,6 @@ int Table::save(Database *db)
{ {
QSqlQuery q = db->exec(db->sqlGenertor()->saveRecord(this, db->tableName(metaObject()->className()))); QSqlQuery q = db->exec(db->sqlGenertor()->saveRecord(this, db->tableName(metaObject()->className())));
if(status() == Added && isPrimaryKeyAutoIncrement()) if(status() == Added && isPrimaryKeyAutoIncrement())
setProperty(primaryKey().toLatin1().data(), q.lastInsertId()); setProperty(primaryKey().toLatin1().data(), q.lastInsertId());

View File

@ -157,7 +157,6 @@ bool TableModel::checkClassInfo(const QMetaClassInfo &classInfo,
type = parts[0]; type = parts[0];
name = parts[1]; name = parts[1];
value = parts[2]; value = parts[2];
qDebug() << Q_FUNC_INFO << parts;
return true; return true;
} }
} }
@ -190,7 +189,6 @@ TableModel::TableModel(int typeId, QString tableName)
continue; continue;
} }
qDebug() << "**********" << type << __nut_FIELD << (type == __nut_FIELD);
if(type == __nut_FIELD){ if(type == __nut_FIELD){
FieldModel *f = new FieldModel; FieldModel *f = new FieldModel;
f->name = name; f->name = name;

View File

@ -14,6 +14,8 @@
#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)
{ {
} }
@ -70,6 +72,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();
@ -106,18 +109,16 @@ void MainTest::createPost2()
void MainTest::selectPosts() void MainTest::selectPosts()
{ {
auto q = db.posts()->query() auto q = db.posts()->query()
// q->join(Post::commentsTable());
// q->join(Post::commentsTable());
// ->join<User>()
->join<Comment>() ->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");
@ -128,12 +129,18 @@ void MainTest::selectPosts()
db.cleanUp(); db.cleanUp();
} }
void MainTest::selectFirst()
{
auto posts = db.posts()->query()
->first();
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);
} }
@ -169,12 +176,13 @@ void MainTest::join()
{ {
auto q = db.comments()->query() auto q = db.comments()->query()
->join<User>() ->join<User>()
->join<Post>() ->join<Post>();
->setWhere(Comment::saveDateField() < QDateTime::currentDateTime().addDays(-1))
->orderBy(Comment::saveDateField());
q->toList(); Comment *comment = q->first();
// Comment *comment = q->toList().first();
qDebug() << q->sqlCommand(); qDebug() << q->sqlCommand();
QTEST_ASSERT(comment->author()->username() == "admin");
} }
@ -208,6 +216,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");
} }
@ -215,7 +224,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);
} }

View File

@ -28,10 +28,11 @@ private slots:
void createPost(); void createPost();
void createPost2(); void createPost2();
void selectPosts(); void selectPosts();
void selectFirst();
void join();
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();