Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions src/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,14 @@ public: \
propertyChanged(#name); \
}

#define NUT_FOREIGN_KEY(type, keytype, name, read, write) \
Q_PROPERTY(Nut::Row<type> name READ read WRITE write) \
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
NUT_INFO(__nut_FOREIGN_KEY, name, type) \
Nut::Row<type> m_##name; \
public slots: \
Nut::Row<type> read() const { return m_##name ; } \
Q_INVOKABLE void write(Nut::Row<type> name){ \
m_##name = name; \
}

#define NUT_FOREIGN_KEY_DECLARE(type, keytype, name, read, write) \
NUT_INFO(__nut_FIELD, name##Id, 0) \
NUT_INFO(__nut_FOREIGN_KEY, name, type) \
Nut::Row<type> m_##name; \
keytype m_##name##Id; \
Q_PROPERTY(Nut::Row<type> name READ read WRITE write) \
Q_PROPERTY(keytype name##Id READ read##Id WRITE write##Id) \
Q_PROPERTY(Nut::Row<Table> _##name READ _##read WRITE _##write) \
public: \
Nut::Row<type> read() const; \
keytype read##Id() const; \
Expand All @@ -109,9 +99,11 @@ public: \
(staticMetaObject.className(), #name); \
return f; \
} \
public slots: \
void write(Nut::Row<type> name); \
void write##Id(keytype name##Id);
void write##Id(keytype name##Id); \
private: \
Nut::Row<Table> _##read() const; \
void _##write(Nut::Row<Table> name);

#define NUT_FOREIGN_KEY_IMPLEMENT(class, type, keytype, name, read, write) \
\
Expand All @@ -132,6 +124,13 @@ public slots: \
m_##name##Id = name##Id; \
m_##name = nullptr; \
propertyChanged(QT_STRINGIFY2(name##Id)); \
} \
Nut::Row<Table> class::_##read() const { return m_##name ; } \
\
void class::_##write(Nut::Row<Table> name) { \
propertyChanged(QT_STRINGIFY2(keyname)); \
m_##name = qSharedPointerCast< type >( name );\
m_##name##Id = m_##name->primaryValue().value<keytype>(); \
}


Expand Down
92 changes: 64 additions & 28 deletions src/query.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ template <class T>
Q_DECLARE_PRIVATE(Query)

bool m_autoDelete;
// level is basically a table object which is affected by the query
struct LevelData{
QList<int> masters;
QList<int> slaves;
QList<QString> masterFields;
QString keyFiledname;
QVariant lastKeyValue;
TableModel *table = nullptr;
Row<Table> lastRow;
};

public:
explicit Query(Database *database, TableSetBase *tableSet, bool autoDelete);
Expand Down Expand Up @@ -107,6 +117,9 @@ template <class T>

//debug purpose
QString sqlCommand() const;

private:
void fillRowProperties(Row<Table> row, LevelData &currentLevel, QSqlQuery &q);
};

template<typename T>
Expand Down Expand Up @@ -166,6 +179,32 @@ Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
delete d;
}

template<class T>
Q_OUTOFLINE_TEMPLATE void Query<T>::fillRowProperties(Row<Table> row, LevelData &currentLevel, QSqlQuery &q)
{
Q_D(Query);
QList<FieldModel*> childFields = currentLevel.table->fields();
foreach (FieldModel *field, childFields) {
// go through all fields of the current level assign value to them
if (!d->fieldPhrase.data.isEmpty()) {
bool found = false;
for (auto fieldP : d->fieldPhrase.data) {
if (fieldP->fieldName == field->name
&& fieldP->className == d->className) {
found = true;
break;
}
}
if (!found)
continue;
}
row->setProperty(field->name.toLatin1().data(),
d->database->sqlGenertor()->unescapeValue(
field->type, q.value(currentLevel.table->name() + "." + field->name)
));
}
}

template <class T>
Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
{
Expand All @@ -189,15 +228,6 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
foreach (RelationModel *rel, d->relations)
relatedTables << rel->slaveTable << rel->masterTable;

struct LevelData{
QList<int> masters;
QList<int> slaves;
QList<QString> masterFields;
QString keyFiledname;
QVariant lastKeyValue;
TableModel *table;
Row<Table> lastRow;
};
QVector<LevelData> levels;
QSet<QString> importedTables;
auto add_table = [&](int i, TableModel* table) {
Expand Down Expand Up @@ -232,21 +262,15 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)

levels.append(data);
};

// Always add the reference to the query's base table as first item
add_table(0, d->database->model().tableByName(d->tableName));
for (int i = 0; i < d->relations.count(); ++i) {
RelationModel *rel = d->relations[i];
add_table(i, rel->masterTable);
add_table(i, rel->slaveTable);
}

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)
Expand Down Expand Up @@ -290,15 +314,17 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
//create table row
Row<Table> row;
if (data.table->className() == d->className) {
// create a row for the current table
row = Nut::create<T>();
#ifdef NUT_SHARED_POINTER
returnList.append(row.objectCast<T>());
#else
returnList.append(dynamic_cast<T*>(table));
#endif
d->tableSet->add(row);

fillRowProperties(row, data, q);
} else {
// create row for a related table
Table *table;
const QMetaObject *childMetaObject
= QMetaType::metaObjectForType(data.table->typeId());
Expand All @@ -308,19 +334,29 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
qFatal("Could not create instance of %s",
qPrintable(data.table->name()));
row = createFrom(table);
// fill up the fields of the related row before attaching to the parent
// because the parent's setter would overwrite the parent's foreign key
// with default initialized primary key of the current (related one)
fillRowProperties(row, data, q);
if (levels[0].lastRow) {
// assign the current row (belongs to a joined table) to the query's base table
foreach (RelationModel *rel, d->relations) {
if (rel->slaveTable->className() == levels[0].table->className()
&& rel->masterTable->className() == data.table->className()) {
// relation found -> assign the row to the query's base table proper field
QString propertyName = "_" + rel->localProperty;
levels[0].lastRow.data()->setProperty(
propertyName.toUtf8().constData(),
QVariant::fromValue(row));
break;
}
}
}
}

QList<FieldModel*> childFields = data.table->fields();
foreach (FieldModel *field, childFields)
row->setProperty(field->name.toLatin1().data(),
d->database->sqlGenertor()->unescapeValue(
field->type,
q.value(data.table->name() + "." + field->name)));

for (int i = 0; i < data.masters.count(); ++i) {
int master = data.masters[i];
auto tableset = levels[master].lastRow.data()->childTableSet(
data.table->className());
auto tableset = levels[master].lastRow.data()->childTableSet(data.table->className());
tableset->add(row);
}

Expand Down
4 changes: 3 additions & 1 deletion src/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ NUT_BEGIN_NAMESPACE

Table::Table(QObject *parent) : QObject(parent),
d(new TablePrivate)
{ }
{
qRegisterMetaType<Nut::Row<Table>>("Nut::Row<Table>");
}

Table::~Table()
{
Expand Down
2 changes: 2 additions & 0 deletions src/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,6 @@ public slots:

NUT_END_NAMESPACE

Q_DECLARE_METATYPE(Nut::Row<Nut::Table>)

#endif // TABLE_H
19 changes: 9 additions & 10 deletions test/tst_basic/tst_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,17 +227,16 @@ void BasicTest::testDate()

void BasicTest::join()
{
// TIC();
// auto q = db.comments()->query()
// ->join<User>()
// ->join<Post>();

// auto comments = q->toList();
TIC();
auto q = db.comments()->query()
->join<User>()
->join<Post>();

// TOC();
// QTEST_ASSERT(comments.length());
// QTEST_ASSERT(comments[0]->author());
// QTEST_ASSERT(comments[0]->author()->username() == "admin");
auto comments = q->toList();
TOC();
QTEST_ASSERT(comments.length());
QTEST_ASSERT(comments[0]->author());
QTEST_ASSERT(comments[0]->author()->username() == "admin");
}


Expand Down