From 424ecf76837f013d374237c3fcfad4dc44390d2a Mon Sep 17 00:00:00 2001 From: Hamed Masafi Date: Wed, 27 Jan 2021 18:20:31 +0330 Subject: [PATCH] Qproperty (#118) * initial commit * new property schema ok --- .gitmodules | 3 + 3rdparty/serializer | 1 + src/nut/config/nut_macros.h | 13 +++- src/nut/core/core.pri | 2 + src/nut/core/propertysignalmapper.cpp | 73 ++++++++++++++++++++ src/nut/core/propertysignalmapper.h | 49 +++++++++++++ src/nut/core/table.cpp | 12 ++++ src/nut/core/table.h | 5 ++ src/nut/core/tableset.h | 19 +++++ tests/auto/auto.pro | 1 + tests/auto/common/comment.cpp | 57 +++++++++++++++ tests/auto/common/comment.h | 35 ++++++++-- tests/auto/common/post.cpp | 70 +++++++++++++++++++ tests/auto/common/post.h | 38 ++++++++-- tests/auto/common/user.cpp | 42 +++++++++++ tests/auto/common/user.h | 28 +++++++- tests/auto/tst_basic/tst_basic.cpp | 8 +-- tests/auto/tst_properties/sampledatabase.cpp | 8 +++ tests/auto/tst_properties/sampledatabase.h | 17 +++++ tests/auto/tst_properties/sampletable.cpp | 48 +++++++++++++ tests/auto/tst_properties/sampletable.h | 40 +++++++++++ tests/auto/tst_properties/tst_properties.cpp | 69 ++++++++++++++++++ tests/auto/tst_properties/tst_properties.h | 26 +++++++ tests/auto/tst_properties/tst_properties.pro | 19 +++++ 24 files changed, 666 insertions(+), 17 deletions(-) create mode 160000 3rdparty/serializer create mode 100644 src/nut/core/propertysignalmapper.cpp create mode 100644 src/nut/core/propertysignalmapper.h create mode 100644 tests/auto/tst_properties/sampledatabase.cpp create mode 100644 tests/auto/tst_properties/sampledatabase.h create mode 100644 tests/auto/tst_properties/sampletable.cpp create mode 100644 tests/auto/tst_properties/sampletable.h create mode 100644 tests/auto/tst_properties/tst_properties.cpp create mode 100644 tests/auto/tst_properties/tst_properties.h create mode 100644 tests/auto/tst_properties/tst_properties.pro diff --git a/.gitmodules b/.gitmodules index 8251c1c..bb74164 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "src/nut/3rdparty/serializer"] path = src/nut/3rdparty/serializer url = https://github.com/HamedMasafi/Serializer.git +[submodule "3rdparty/serializer"] + path = 3rdparty/serializer + url = https://github.com/HamedMasafi/Serializer.git diff --git a/3rdparty/serializer b/3rdparty/serializer new file mode 160000 index 0000000..0e794d6 --- /dev/null +++ b/3rdparty/serializer @@ -0,0 +1 @@ +Subproject commit 0e794d6317595d077e95e8a06f1f3a8c92543b05 diff --git a/src/nut/config/nut_macros.h b/src/nut/config/nut_macros.h index 52cd802..80e8758 100644 --- a/src/nut/config/nut_macros.h +++ b/src/nut/config/nut_macros.h @@ -28,6 +28,17 @@ private: //Table +#define NUT_FIELD(type, name) \ + private: \ + NUT_INFO(__nut_FIELD, name, 0) \ + public: \ + static NUT_WRAP_NAMESPACE(FieldPhrase)& name ## Field(){ \ + static NUT_WRAP_NAMESPACE(FieldPhrase) f = \ + NUT_WRAP_NAMESPACE(FieldPhrase) \ + (staticMetaObject.className(), #name); \ + return f; \ + } + #define NUT_DECLARE_FIELD(type, name, read, write) \ Q_PROPERTY(type name READ read WRITE write) \ NUT_INFO(__nut_FIELD, name, 0) \ @@ -113,7 +124,7 @@ public slots: \ return m_##n; \ } -#define NUT_FIELD(name) NUT_INFO(__nut_FIELD, name, 0) +//#define NUT_FIELD(name) NUT_INFO(__nut_FIELD, name, 0) #define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0) \ public: \ QVariant primaryValue() const override { \ diff --git a/src/nut/core/core.pri b/src/nut/core/core.pri index aa46c3e..3092946 100644 --- a/src/nut/core/core.pri +++ b/src/nut/core/core.pri @@ -8,6 +8,7 @@ HEADERS += \ $$PWD/changelogtable.h \ $$PWD/database.h \ $$PWD/database_p.h \ + $$PWD/propertysignalmapper.h \ $$PWD/query.h \ $$PWD/table.h \ $$PWD/table_p.h \ @@ -18,6 +19,7 @@ SOURCES += \ $$PWD/bulkinserter.cpp \ $$PWD/changelogtable.cpp \ $$PWD/database.cpp \ + $$PWD/propertysignalmapper.cpp \ $$PWD/query.cpp \ $$PWD/table.cpp \ $$PWD/tableset.cpp diff --git a/src/nut/core/propertysignalmapper.cpp b/src/nut/core/propertysignalmapper.cpp new file mode 100644 index 0000000..2b82cda --- /dev/null +++ b/src/nut/core/propertysignalmapper.cpp @@ -0,0 +1,73 @@ +/************************************************************************** +** +** This file is part of Nut project. +** https://github.com/HamedMasafi/Nut +** +** Nut is free software: you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** Nut is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with Nut. If not, see . +** +**************************************************************************/ + +#include "propertysignalmapper.h" +#include "table.h" + +NUT_BEGIN_NAMESPACE + +QMap PropertySignalMapper::_data; + +void PropertySignalMapper::map(Table *obj) +{ + if (obj->_is_signals_mapped) + return; + ClassData *d; + const QMetaObject *mo = obj->metaObject(); + auto className = QString::fromUtf8(mo->className()); + + if (_data.contains(className)) { + d = _data.value(className); + + for (auto &p: d->properties) + QObject::connect(obj, p.notifySignal(), obj, d->propertyChanged); + + } else { + d = new ClassData; + d->propertyChanged = mo->method(mo->indexOfSlot("propertyChanged()")); + + for (int i = 0; i < mo->propertyCount(); ++i) { + QMetaProperty p = mo->property(i); + if (!strcmp(p.name(), "objectName")) + continue; + + if (p.hasNotifySignal()) { + d->signalMaps.insert(QLatin1String(p.notifySignal().name()), + QLatin1String(p.name())); + d->properties.append(p); + QObject::connect(obj, p.notifySignal(), obj, d->propertyChanged); + } + } + + _data.insert(className, d); + } + + obj->_is_signals_mapped = true; +} + +QString PropertySignalMapper::changedProperty(QObject *obj, int senderSignalIndex) +{ + return _data.value(QString::fromUtf8(obj->metaObject()->className())) + ->signalMaps.value( + QString::fromUtf8(obj->metaObject()->method(senderSignalIndex).name()) + ); +} + +NUT_END_NAMESPACE diff --git a/src/nut/core/propertysignalmapper.h b/src/nut/core/propertysignalmapper.h new file mode 100644 index 0000000..ea2dfac --- /dev/null +++ b/src/nut/core/propertysignalmapper.h @@ -0,0 +1,49 @@ +/************************************************************************** +** +** This file is part of Nut project. +** https://github.com/HamedMasafi/Nut +** +** Nut is free software: you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** Nut is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with Nut. If not, see . +** +**************************************************************************/ + +#ifndef PROPERTYSIGNALMAPPER_H +#define PROPERTYSIGNALMAPPER_H + +#include + +#include +#include + +NUT_BEGIN_NAMESPACE + +class Table; +class PropertySignalMapper +{ + struct ClassData + { + QMetaMethod propertyChanged; + QList properties; + QMap signalMaps; + }; + static QMap _data; + +public: + static void map(Table *obj); + static QString changedProperty(QObject *obj, int senderSignalIndex); +}; + +NUT_END_NAMESPACE + +#endif // PROPERTYSIGNALMAPPER_H diff --git a/src/nut/core/table.cpp b/src/nut/core/table.cpp index 866c5c9..3b6571e 100644 --- a/src/nut/core/table.cpp +++ b/src/nut/core/table.cpp @@ -28,6 +28,7 @@ #include "databasemodel.h" #include "abstractsqlgenerator.h" #include "abstracttableset.h" +#include "propertysignalmapper.h" NUT_BEGIN_NAMESPACE @@ -149,6 +150,17 @@ bool Table::setParentTable(Table *master, TableModel *masterModel, TableModel *m return false; } +void Table::propertyChanged() +{ + auto pname = PropertySignalMapper::changedProperty(this, senderSignalIndex()); + propertyChanged(pname); +} + +void Table::init() +{ + PropertySignalMapper::map(this); +} + AbstractTableSet *Table::parentTableSet() const { //Q_D(const Table); diff --git a/src/nut/core/table.h b/src/nut/core/table.h index 55e1051..740b799 100644 --- a/src/nut/core/table.h +++ b/src/nut/core/table.h @@ -72,11 +72,15 @@ public: signals: public slots: + void propertyChanged(); protected: + void init(); void propertyChanged(const QString &propName); private: + bool _is_signals_mapped{false}; + void setModel(TableModel *model); // TableModel *myModel; // Status _status; @@ -94,6 +98,7 @@ private: template friend class TableSet; friend class AbstractTableSet; + friend class PropertySignalMapper; }; NUT_END_NAMESPACE diff --git a/src/nut/core/tableset.h b/src/nut/core/tableset.h index bd0450c..67508a7 100644 --- a/src/nut/core/tableset.h +++ b/src/nut/core/tableset.h @@ -54,6 +54,10 @@ public: explicit TableSet(Database *parent); explicit TableSet(Table *parent); +#ifndef NUT_RAW_POINTER + void append(T *t); + void append(QList t); +#endif void append(Row t); void append(RowList t); void remove(Row t); @@ -113,6 +117,21 @@ Q_OUTOFLINE_TEMPLATE Row TableSet::operator[](int i) const return at(i); } +#ifndef NUT_RAW_POINTER +template +Q_OUTOFLINE_TEMPLATE void TableSet::append(T *t) +{ + append(QSharedPointer(t)); +} + +template +Q_OUTOFLINE_TEMPLATE void TableSet::append(QList t) +{ + for (auto &table: t) + append(table); +} +#endif + template Q_OUTOFLINE_TEMPLATE void TableSet::append(Row t) { diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index f3d4077..3bca532 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -5,6 +5,7 @@ SUBDIRS += \ tst_benckmark \ tst_datatypes \ tst_phrases \ + tst_properties \ tst_quuid \ tst_generators \ tst_upgrades \ diff --git a/tests/auto/common/comment.cpp b/tests/auto/common/comment.cpp index 59b2e0d..e7933d3 100644 --- a/tests/auto/common/comment.cpp +++ b/tests/auto/common/comment.cpp @@ -4,7 +4,64 @@ Comment::Comment(QObject *parent) : Table(parent) { + init(); +} +int Comment::id() const +{ + return m_id; +} + +QString Comment::message() const +{ + return m_message; +} + +QDateTime Comment::saveDate() const +{ + return m_saveDate; +} + +qreal Comment::point() const +{ + return m_point; +} + +void Comment::setId(int id) +{ + if (m_id == id) + return; + + m_id = id; + emit idChanged(m_id); +} + +void Comment::setMessage(QString message) +{ + if (m_message == message) + return; + + m_message = message; + emit messageChanged(m_message); +} + +void Comment::setSaveDate(QDateTime saveDate) +{ + if (m_saveDate == saveDate) + return; + + m_saveDate = saveDate; + emit saveDateChanged(m_saveDate); +} + +void Comment::setPoint(qreal point) +{ + qWarning("Floating point comparison needs context sanity check"); + if (qFuzzyCompare(m_point, point)) + return; + + m_point = point; + emit pointChanged(m_point); } NUT_FOREIGN_KEY_IMPLEMENT(Comment, Post, int, post, post, setPost) diff --git a/tests/auto/common/comment.h b/tests/auto/common/comment.h index 52ab829..d443ebd 100644 --- a/tests/auto/common/comment.h +++ b/tests/auto/common/comment.h @@ -15,17 +15,44 @@ class Comment : public Table { Q_OBJECT + Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) + Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged) + Q_PROPERTY(QDateTime saveDate READ saveDate WRITE setSaveDate NOTIFY saveDateChanged) + Q_PROPERTY(qreal point READ point WRITE setPoint NOTIFY pointChanged) + NUT_PRIMARY_AUTO_INCREMENT(id) - NUT_DECLARE_FIELD(int, id, id, setId) - NUT_DECLARE_FIELD(QString, message, message, setMessage) - NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate) - NUT_DECLARE_FIELD(qreal, point, point, setPoint) + NUT_FIELD(int, id) + NUT_FIELD(QString, message) + NUT_FIELD(QDateTime, saveDate) + NUT_FIELD(qreal, point) NUT_FOREIGN_KEY_DECLARE(Post, int, post, post, setPost) NUT_FOREIGN_KEY_DECLARE(User, int, author, author, setAuthor) + int m_id; + QString m_message; + QDateTime m_saveDate; + qreal m_point; + public: Q_INVOKABLE explicit Comment(QObject *parentTableSet = nullptr); + + int id() const; + QString message() const; + QDateTime saveDate() const; + qreal point() const; + +public slots: + void setId(int id); + void setMessage(QString message); + void setSaveDate(QDateTime saveDate); + void setPoint(qreal point); + +signals: + void idChanged(int id); + void messageChanged(QString message); + void saveDateChanged(QDateTime saveDate); + void pointChanged(qreal point); }; Q_DECLARE_METATYPE(Comment*) diff --git a/tests/auto/common/post.cpp b/tests/auto/common/post.cpp index 9aa932a..bd47943 100644 --- a/tests/auto/common/post.cpp +++ b/tests/auto/common/post.cpp @@ -8,7 +8,77 @@ Post::Post(QObject *parent) : Table(parent), m_comments(new TableSet(this)), m_scores(new TableSet(this)) { + init(); +} +int Post::id() const +{ + return m_id; +} + +QString Post::title() const +{ + return m_title; +} + +QDateTime Post::saveDate() const +{ + return m_saveDate; +} + +QString Post::body() const +{ + return m_body; +} + +bool Post::isPublic() const +{ + return m_isPublic; +} + +void Post::setId(int id) +{ + if (m_id == id) + return; + + m_id = id; + emit idChanged(m_id); +} + +void Post::setTitle(QString title) +{ + if (m_title == title) + return; + + m_title = title; + emit titleChanged(m_title); +} + +void Post::setSaveDate(QDateTime saveDate) +{ + if (m_saveDate == saveDate) + return; + + m_saveDate = saveDate; + emit saveDateChanged(m_saveDate); +} + +void Post::setBody(QString body) +{ + if (m_body == body) + return; + + m_body = body; + emit bodyChanged(m_body); +} + +void Post::setPublic(bool isPublic) +{ + if (m_isPublic == isPublic) + return; + + m_isPublic = isPublic; + emit isPublicChanged(m_isPublic); } NUT_IMPLEMENT_CHILD_TABLE(Post, Comment, comments) diff --git a/tests/auto/common/post.h b/tests/auto/common/post.h index 9112c27..92d6a26 100644 --- a/tests/auto/common/post.h +++ b/tests/auto/common/post.h @@ -17,27 +17,55 @@ class Post : public Table { Q_OBJECT + Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_PROPERTY(QDateTime saveDate READ saveDate WRITE setSaveDate NOTIFY saveDateChanged) + Q_PROPERTY(QString body READ body WRITE setBody NOTIFY bodyChanged) + Q_PROPERTY(bool isPublic READ isPublic WRITE setPublic NOTIFY isPublicChanged) + NUT_PRIMARY_AUTO_INCREMENT(id) - NUT_DECLARE_FIELD(int, id, id, setId) + NUT_FIELD(int, id) NUT_NOT_NULL(title) NUT_LEN(title, 50) - NUT_DECLARE_FIELD(QString, title, title, setTitle) + NUT_FIELD(QString, title) - NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate) + NUT_FIELD(QDateTime, saveDate) - NUT_DECLARE_FIELD(QString, body, body, setBody) - NUT_DECLARE_FIELD(bool, isPublic, isPublic, setPublic) + NUT_FIELD(QString, body) + NUT_FIELD(bool, isPublic) NUT_DECLARE_CHILD_TABLE(Comment, comments) NUT_DECLARE_CHILD_TABLE(Score, scores) + int m_id; + QString m_title; + QDateTime m_saveDate; + QString m_body; + bool m_isPublic; + public: Q_INVOKABLE Post(QObject *parentTableSet = nullptr); + int id() const; + QString title() const; + QDateTime saveDate() const; + QString body() const; + bool isPublic() const; + signals: + void idChanged(int id); + void titleChanged(QString title); + void saveDateChanged(QDateTime saveDate); + void bodyChanged(QString body); + void isPublicChanged(bool isPublic); public slots: + void setId(int id); + void setTitle(QString title); + void setSaveDate(QDateTime saveDate); + void setBody(QString body); + void setPublic(bool isPublic); }; Q_DECLARE_METATYPE(Post*) diff --git a/tests/auto/common/user.cpp b/tests/auto/common/user.cpp index b2ee974..d5b12d1 100644 --- a/tests/auto/common/user.cpp +++ b/tests/auto/common/user.cpp @@ -7,7 +7,49 @@ User::User(QObject *tableSet) : Table(tableSet), m_comments(new TableSet(this)), m_scores(new TableSet(this)) { + init(); +} +int User::id() const +{ + return m_id; +} + +QString User::username() const +{ + return m_username; +} + +QString User::password() const +{ + return m_password; +} + +void User::setId(int id) +{ + if (m_id == id) + return; + + m_id = id; + emit idChanged(m_id); +} + +void User::setUsername(QString username) +{ + if (m_username == username) + return; + + m_username = username; + emit usernameChanged(m_username); +} + +void User::setPassword(QString password) +{ + if (m_password == password) + return; + + m_password = password; + emit passwordChanged(m_password); } NUT_IMPLEMENT_CHILD_TABLE(User, Comment, comments) diff --git a/tests/auto/common/user.h b/tests/auto/common/user.h index 1f617fe..f004a63 100644 --- a/tests/auto/common/user.h +++ b/tests/auto/common/user.h @@ -17,22 +17,44 @@ class User : public Nut::Table { Q_OBJECT + Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) + Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged) + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) + NUT_PRIMARY_AUTO_INCREMENT(id) - NUT_DECLARE_FIELD(int, id, id, setId) + NUT_FIELD(int, id) NUT_NOT_NULL(username) NUT_LEN(username, 50) - NUT_DECLARE_FIELD(QString, username, username, setUsername) + NUT_FIELD(QString, username) NUT_NOT_NULL(password) NUT_LEN(password, 50) - NUT_DECLARE_FIELD(QString, password, password, setPassword) + NUT_FIELD(QString, password) NUT_DECLARE_CHILD_TABLE(Comment, comments) NUT_DECLARE_CHILD_TABLE(Score, scores) + int m_id; + QString m_username; + QString m_password; + public: Q_INVOKABLE User(QObject *parentTableSet = nullptr); + + int id() const; + QString username() const; + QString password() const; + +public slots: + void setId(int id); + void setUsername(QString username); + void setPassword(QString password); + +signals: + void idChanged(int id); + void usernameChanged(QString username); + void passwordChanged(QString password); }; Q_DECLARE_METATYPE(User*) diff --git a/tests/auto/tst_basic/tst_basic.cpp b/tests/auto/tst_basic/tst_basic.cpp index 4ea84e8..62ebb63 100644 --- a/tests/auto/tst_basic/tst_basic.cpp +++ b/tests/auto/tst_basic/tst_basic.cpp @@ -139,16 +139,16 @@ void BasicTest::updatePostOnTheFly() void BasicTest::selectPublicts() { - auto q = db.posts()->query() + auto publinPostsCount = db.posts()->query() .where(Post::isPublicField()) .count(); - auto q2 = db.posts()->query() + auto nonPublicPostsCount = db.posts()->query() .where(!Post::isPublicField()) .count(); - QCOMPARE(q, 1); - QCOMPARE(q2, 1); + QCOMPARE(publinPostsCount, 1); + QCOMPARE(nonPublicPostsCount, 1); } void BasicTest::selectPosts() diff --git a/tests/auto/tst_properties/sampledatabase.cpp b/tests/auto/tst_properties/sampledatabase.cpp new file mode 100644 index 0000000..86f5c2d --- /dev/null +++ b/tests/auto/tst_properties/sampledatabase.cpp @@ -0,0 +1,8 @@ +#include "sampledatabase.h" +#include "sampletable.h" + +SampleDataBase::SampleDataBase() : Nut::Database() + , m_items(new Nut::TableSet(this)) +{ + +} diff --git a/tests/auto/tst_properties/sampledatabase.h b/tests/auto/tst_properties/sampledatabase.h new file mode 100644 index 0000000..90ca262 --- /dev/null +++ b/tests/auto/tst_properties/sampledatabase.h @@ -0,0 +1,17 @@ +#ifndef SAMPLEDATABASE_H +#define SAMPLEDATABASE_H + +#include + +class SampleTable; +class SampleDataBase : public Nut::Database +{ + Q_OBJECT + NUT_DB_VERSION(1) + NUT_DECLARE_TABLE(SampleTable, items) + +public: + SampleDataBase(); +}; + +#endif // SAMPLEDATABASE_H diff --git a/tests/auto/tst_properties/sampletable.cpp b/tests/auto/tst_properties/sampletable.cpp new file mode 100644 index 0000000..d378553 --- /dev/null +++ b/tests/auto/tst_properties/sampletable.cpp @@ -0,0 +1,48 @@ +#include "sampletable.h" + +SampleTable::SampleTable(QObject *parent) : Nut::Table(parent) +{ + init(); +} + +int SampleTable::id() const +{ + return m_id; +} + +QString SampleTable::name() const +{ + return m_name; +} + +QString SampleTable::lastName() const +{ + return m_lastName; +} + +void SampleTable::setId(int id) +{ + if (m_id == id) + return; + + m_id = id; + emit idChanged(m_id); +} + +void SampleTable::setName(QString name) +{ + if (m_name == name) + return; + + m_name = name; + emit nameChanged(m_name); +} + +void SampleTable::setLastName(QString lastName) +{ + if (m_lastName == lastName) + return; + + m_lastName = lastName; + emit lastNameChanged(m_lastName); +} diff --git a/tests/auto/tst_properties/sampletable.h b/tests/auto/tst_properties/sampletable.h new file mode 100644 index 0000000..d77693a --- /dev/null +++ b/tests/auto/tst_properties/sampletable.h @@ -0,0 +1,40 @@ +#ifndef SAMPLETABLE_H +#define SAMPLETABLE_H + +#include + +class SampleTable : public Nut::Table +{ + Q_OBJECT + Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY lastNameChanged) + + int m_id; + QString m_name; + QString m_lastName; + + NUT_PRIMARY_KEY(id) + NUT_FIELD(int, id) + NUT_FIELD(QString, name) + NUT_FIELD(QString, lastName) + +public: + explicit SampleTable(QObject *parent = nullptr); + + int id() const; + QString name() const; + QString lastName() const; + +public slots: + void setId(int id); + void setName(QString name); + void setLastName(QString lastName); + +signals: + void idChanged(int id); + void nameChanged(QString name); + void lastNameChanged(QString lastName); +}; + +#endif // SAMPLETABLE_H diff --git a/tests/auto/tst_properties/tst_properties.cpp b/tests/auto/tst_properties/tst_properties.cpp new file mode 100644 index 0000000..e197280 --- /dev/null +++ b/tests/auto/tst_properties/tst_properties.cpp @@ -0,0 +1,69 @@ +#include +#include "tst_properties.h" +#include "sampledatabase.h" +#include "sampletable.h" +#include "../common/consts.h" +#include + +PropertiesTest::PropertiesTest(QObject *parent) : QObject(parent) +{ +} + +void PropertiesTest::initTestCase() +{ + + REGISTER(SampleTable); + REGISTER(SampleDataBase); + + db.setDriver(DRIVER); + db.setHostName(HOST); + db.setDatabaseName(DATABASE); + db.setUserName(USERNAME); + db.setPassword(PASSWORD); + + bool ok = db.open(); + QVERIFY(ok); + + db.items()->query().remove(); +} + +void PropertiesTest::insert() +{ + auto s = new SampleTable; + s->setId(1); + s->setName("hamed"); + s->setLastName("masafi"); + db.items()->append(s); + auto c = db.saveChanges(); + QCOMPARE(c, 1); +} + +void PropertiesTest::select() +{ + auto item = db.items()->query() + .first(); + QCOMPARE(item->name(), "hamed"); +} + +void PropertiesTest::parallelUpdate() +{ + auto item1 = db.items()->query() + .first(); + { + auto item2 = db.items()->query() + .first(); + + item2->setLastName("masafi 2"); + db.saveChanges(); + } + item1->setName("hamed 2"); + db.saveChanges(); + + auto item = db.items()->query() + .first(); + + QCOMPARE(item->name(), "hamed 2"); + QCOMPARE(item->lastName(), "masafi 2"); +} + +QTEST_MAIN(PropertiesTest) diff --git a/tests/auto/tst_properties/tst_properties.h b/tests/auto/tst_properties/tst_properties.h new file mode 100644 index 0000000..52d39d5 --- /dev/null +++ b/tests/auto/tst_properties/tst_properties.h @@ -0,0 +1,26 @@ +#ifndef TST_PROPERTIES_H +#define TST_PROPERTIES_H + +#include +#include + +#include "sampledatabase.h" + +class PropertiesTest : public QObject +{ + Q_OBJECT + SampleDataBase db; + +public: + explicit PropertiesTest(QObject *parent = nullptr); + +signals: + +private slots: + void initTestCase(); + void insert(); + void select(); + void parallelUpdate(); +}; + +#endif // TST_PROPERTIES_H diff --git a/tests/auto/tst_properties/tst_properties.pro b/tests/auto/tst_properties/tst_properties.pro new file mode 100644 index 0000000..59933c5 --- /dev/null +++ b/tests/auto/tst_properties/tst_properties.pro @@ -0,0 +1,19 @@ +QT += testlib sql + +TARGET = tst_basic +TEMPLATE = app + +CONFIG += warn_on c++11 + +include(../common/nut-lib.pri) + +SOURCES += \ + sampledatabase.cpp \ + sampletable.cpp \ + tst_properties.cpp + +HEADERS += \ + sampledatabase.h \ + sampletable.h \ + tst_properties.h +