From 3ca86c7c5923fbde757f26519b50ee38c6d8e01f Mon Sep 17 00:00:00 2001 From: "Schaich, Alonso" Date: Tue, 29 Aug 2023 17:09:17 +0900 Subject: [PATCH] Add Test for ORM --- BookModel.cpp | 161 +++++++++++++++++++++++++++++++++++++++++++ BookModel.hpp | 72 +++++++++++++++++++ CMakeLists.txt | 2 +- PublisherModel.cpp | 155 +++++++++++++++++++++++++++++++++++++++++ PublisherModel.hpp | 65 +++++++++++++++++ QSqlQueryTest.cpp | 8 +++ TinyOrmQueryTest.cpp | 78 +++++++++++++++++++++ TinyOrmQueryTest.hpp | 4 +- 8 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 BookModel.cpp create mode 100644 BookModel.hpp create mode 100644 PublisherModel.cpp create mode 100644 PublisherModel.hpp diff --git a/BookModel.cpp b/BookModel.cpp new file mode 100644 index 0000000..395bc96 --- /dev/null +++ b/BookModel.cpp @@ -0,0 +1,161 @@ +#include + +#include "BookModel.hpp" +#include "PublisherModel.hpp" + +const QString BookModel::g_property_id = "id"; +const QString BookModel::g_property_publisher("publisher"); +const QString BookModel::g_property_author = "author"; +const QString BookModel::g_property_title = "title"; +const QString BookModel::g_property_releaseDate = "released"; +const QString BookModel::g_property_isbn = "isbn"; +const QString BookModel::g_table("books"); + +QStringList BookModel::u_fillable { + g_property_id, + g_property_author, + g_property_title, + g_property_releaseDate, + g_property_isbn +}; + +const bool BookModel::u_snakeAttributes(false); + +BookModel::BookModel(QString author, QString title, QDate releaseDate, QString isbn) + : BookModel() +{ + setAuthor(author); + setTitle(title); + setReleaseDate(releaseDate); + setIsbn(isbn); +} + +BookModel::BookModel() + : Model() + , u_relations(relations()) + , u_table(table()) +{ +} + +BookModel::~BookModel() +{ +} + +BookModel::BookModel(const BookModel &other) + : Model(other) + , u_relations(relations()) + , u_table(table()) +{ +} + +BookModel::BookModel(Orm::Tiny::DontFillDefaultAttributes attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +BookModel::BookModel(const QVector &attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +BookModel::BookModel(std::initializer_list attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +BookModel &BookModel::operator=(const BookModel &other) +{ + Model::operator=(other); + // do not overwrite u_relations and u_table + return *this; +} + +QHash BookModel::relations() const +{ + return { + {PublisherModel::g_table, [](RelationStore& visitor) { visitor(&BookModel::publisher); }} + }; +} + +QString BookModel::table() const +{ + return g_table; +} + +std::unique_ptr> +BookModel::publisher() +{ + return belongsTo(); +} + +void BookModel::createTableCallback(Orm::SchemaNs::Blueprint& table) +{ + table.id(); + table.foreignId(g_property_publisher).nullable().constrained().cascadeOnDelete().cascadeOnUpdate(); + table.string(g_property_author); + table.string(g_property_title); + table.string(g_property_isbn); + table.date(g_property_releaseDate); + table.timestamps(); +} + +void BookModel::createTable() +{ + Orm::Schema::create(g_table, BookModel::createTableCallback); +} + +void BookModel::dropTable() +{ + Orm::Schema::drop(g_table); +} + +qlonglong BookModel::id() const +{ + return getAttribute(g_property_id).toLongLong(); +} +void BookModel::setId(qlonglong id) +{ + setAttribute(g_property_id, id); +} + +QString BookModel::author() const +{ + return getAttribute(g_property_author).toString(); +} +void BookModel::setAuthor(QString author) +{ + setAttribute(g_property_author, author); +} + +QString BookModel::title() const +{ + return getAttribute(g_property_title).toString(); +} +void BookModel::setTitle(QString title) +{ + setAttribute(g_property_title, title); +} + +QString BookModel::isbn() const +{ + return getAttribute(g_property_isbn).toString(); +} +void BookModel::setIsbn(QString isbn) +{ + setAttribute(g_property_isbn, isbn); +} + +QDate BookModel::releaseDate() const +{ + return getAttribute(g_property_releaseDate).toDate(); +} +void BookModel::setReleaseDate(QDate released) +{ + setAttribute(g_property_releaseDate, released); +} diff --git a/BookModel.hpp b/BookModel.hpp new file mode 100644 index 0000000..f4d523f --- /dev/null +++ b/BookModel.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include + +#include "PublisherModel.hpp" + +class PublisherModel; + +class BookModel final : public Orm::Tiny::Model +{ + friend Model; + using Model::Model; + +public: + BookModel(QString author, QString title, QDate releaseDate, QString isbn); + BookModel(); + ~BookModel(); + BookModel(const BookModel &other); + BookModel(Orm::Tiny::DontFillDefaultAttributes); + BookModel(const QVector &attributes); + BookModel(std::initializer_list attributes); + BookModel &operator=(const BookModel &other); + Model &operator=(Model &&) noexcept = delete; + + static void createTable(); + static void dropTable(); + + qlonglong id() const; + void setId(qlonglong id); + + QString author() const; + void setAuthor(QString author); + + QString title() const; + void setTitle(QString title); + + QDate releaseDate() const; + void setReleaseDate(QDate released); + + QString isbn() const; + void setIsbn(QString isbn); + +public: + std::unique_ptr> publisher(); + +private: + using RelationStore = Orm::Tiny::Support::Stores::BaseRelationStore; + + static QStringList u_fillable; + static const bool u_snakeAttributes; + + QHash u_relations; + QString u_table; + +protected: + static void createTableCallback(Orm::SchemaNs::Blueprint& table); + QHash relations() const; + QString table() const; + +public: + static const QString g_property_id; + static const QString g_property_publisher; + static const QString g_property_author; + static const QString g_property_title; + static const QString g_property_releaseDate; + static const QString g_property_isbn; + static const QString g_table; +}; + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index e3c7a37..45ca49b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set_target_properties(QSqlQueryTest PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTI find_package(TinyOrm CONFIG REQUIRED) add_executable(TinyOrmQueryTest) -target_sources(TinyOrmQueryTest PRIVATE TinyOrmQueryTest.cpp) +target_sources(TinyOrmQueryTest PRIVATE BookModel.cpp PublisherModel.cpp TinyOrmQueryTest.cpp) target_link_libraries(TinyOrmQueryTest PRIVATE Qt::Core Qt::Sql Qt::Test TinyOrm::TinyOrm) set_target_properties(TinyOrmQueryTest PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY}) diff --git a/PublisherModel.cpp b/PublisherModel.cpp new file mode 100644 index 0000000..07fe88a --- /dev/null +++ b/PublisherModel.cpp @@ -0,0 +1,155 @@ +#include + +#include "BookModel.hpp" +#include "PublisherModel.hpp" + +const QString PublisherModel::g_property_id("id"); +const QString PublisherModel::g_property_name("name"); +const QString PublisherModel::g_property_founded("founded"); +const QString PublisherModel::g_property_website("website"); +const QString PublisherModel::g_table("publishers"); + +const QVector PublisherModel::u_with { + BookModel::g_table +}; + +const QStringList PublisherModel::u_fillable { + g_property_id, + g_property_name, + g_property_founded, + g_property_website +}; + +const QVector PublisherModel::u_attributes { + { g_property_name, "" }, + { g_property_founded, QDate(1970,1,1).toString(Qt::ISODate) }, + { g_property_website, "" } +}; + +const bool PublisherModel::u_snakeAttributes(false); + +PublisherModel::PublisherModel() + : Model() + , u_relations(relations()) + , u_table(table()) +{ +} +PublisherModel::~PublisherModel() +{ +} + +PublisherModel::PublisherModel(const PublisherModel &other) + : Model(other) + , u_relations(relations()) + , u_table(table()) +{ +} + +PublisherModel::PublisherModel(QString name, QDate founded, QUrl website) + : PublisherModel() +{ + setName(name); + setFounded(founded); + setWebsite(website); +} + +PublisherModel::PublisherModel(Orm::Tiny::DontFillDefaultAttributes attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +PublisherModel::PublisherModel(const QVector &attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +PublisherModel::PublisherModel(std::initializer_list attributes) + : Model(attributes) + , u_relations(relations()) + , u_table(table()) +{ +} + +PublisherModel &PublisherModel::operator=(const PublisherModel &other) { + Model::operator=(other); + // do not overwrite u_relations or u_table + return *this; +} + +void PublisherModel::createTableCallback(Orm::SchemaNs::Blueprint& table) +{ + table.id(); + table.string(g_property_name); + table.date(g_property_founded); + table.string(g_property_website); + table.timestamps(); +} + +void PublisherModel::createTable() +{ + Orm::Schema::create(g_table, PublisherModel::createTableCallback); +} + +void PublisherModel::dropTable() +{ + Orm::Schema::drop(g_table); +} + + +qlonglong PublisherModel::id() const +{ + return getAttribute(g_property_id).toLongLong(); +} +void PublisherModel::setId(qlonglong id) +{ + setAttribute(g_property_id, id); +} + +QString PublisherModel::name() const +{ + return getAttribute(g_property_name).toString(); +} +void PublisherModel::setName(QString name) +{ + setAttribute(g_property_name, name); +} + +QDate PublisherModel::founded() const +{ + return getAttribute(g_property_founded).toDate(); +} +void PublisherModel::setFounded(QDate founded) +{ + setAttribute(g_property_founded, founded); +} + +QUrl PublisherModel::website() const +{ + return getAttribute(g_property_website).toUrl(); +} +void PublisherModel::setWebsite(QUrl website) +{ + setAttribute(g_property_website, website.toString()); +} + +std::unique_ptr> +PublisherModel::books() +{ + return hasMany(BookModel::g_property_publisher); +} + +QHash PublisherModel::relations() const +{ + return { + { BookModel::g_table, [](RelationStore& visitor) { visitor(&PublisherModel::books); } } + }; +} + +QString PublisherModel::table() const +{ + return g_table; +} diff --git a/PublisherModel.hpp b/PublisherModel.hpp new file mode 100644 index 0000000..ab81ffb --- /dev/null +++ b/PublisherModel.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include "BookModel.hpp" + +class BookModel; + +class PublisherModel final : public Orm::Tiny::Model +{ + friend Model; + using Model::Model; + +public: + PublisherModel(QString name, QDate founded, QUrl website); + PublisherModel(); + ~PublisherModel(); + PublisherModel(const PublisherModel &other); + PublisherModel(Orm::Tiny::DontFillDefaultAttributes); + PublisherModel(const QVector &attributes); + PublisherModel(std::initializer_list attributes); + PublisherModel &operator=(const PublisherModel &other); + Model &operator=(Model &&) noexcept = delete; + + + static void createTable(); + static void dropTable(); + + qlonglong id() const; + void setId(qlonglong id); + + QString name() const; + void setName(QString name); + + QDate founded() const; + void setFounded(QDate founded); + + QUrl website() const; + void setWebsite(QUrl website); + +public: + std::unique_ptr> books(); + +private: + static const QVector u_with; + static const QStringList u_fillable; + static const QVector u_attributes; + static const bool u_snakeAttributes; + + using RelationStore = Orm::Tiny::Support::Stores::BaseRelationStore; + QHash u_relations; + QString u_table; + +protected: + static void createTableCallback(Orm::SchemaNs::Blueprint& table); + QHash relations() const; + QString table() const; + +public: + static const QString g_property_id; + static const QString g_property_name; + static const QString g_property_founded; + static const QString g_property_website; + static const QString g_table; +}; diff --git a/QSqlQueryTest.cpp b/QSqlQueryTest.cpp index 52c51cd..863ff3c 100644 --- a/QSqlQueryTest.cpp +++ b/QSqlQueryTest.cpp @@ -50,6 +50,14 @@ void QSqlQueryTest::cleanup() void QSqlQueryTest::helloWorld() { + QSqlQuery query(*this); + query.prepare("INSERT INTO foobar(message) VALUES (:message)"); + query.bindValue(":message", QUrl("www.wikipedia.org").toString()); + bool success = query.exec(); + if (!success) { + qCritical() << query.lastError().text().toStdString(); + } + QVERIFY(success); } QTEST_MAIN(QSqlQueryTest) diff --git a/TinyOrmQueryTest.cpp b/TinyOrmQueryTest.cpp index ec7fae9..39ed3c1 100644 --- a/TinyOrmQueryTest.cpp +++ b/TinyOrmQueryTest.cpp @@ -1,3 +1,6 @@ +#include "BookModel.hpp" +#include "PublisherModel.hpp" + #include "TinyOrmQueryTest.hpp" namespace MyNamespace @@ -49,6 +52,8 @@ namespace MyNamespace { try { Orm::Schema::create("demoTable", demoTable); + PublisherModel::createTable(); + BookModel::createTable(); } catch (const std::exception& ex) { qCritical() << ex.what(); } @@ -56,6 +61,18 @@ namespace MyNamespace void MyTinyTest::cleanup() { + try { + BookModel::dropTable(); + } catch (const std::exception& ex) { + qCritical() << ex.what(); + } + + try { + PublisherModel::dropTable(); + } catch (const std::exception& ex) { + qCritical() << ex.what(); + } + try { Orm::Schema::drop("demoTable"); } catch (const std::exception& ex) { @@ -120,6 +137,67 @@ namespace MyNamespace QVERIFY(exceptionReceived); QCOMPARE(rowCount, 2); } + + void MyTinyTest::ormSimple() + { + qlonglong id(-1); + try { + PublisherModel pub("Chilton Book Company", QDate(1904, 3, 31), QUrl("https://www.cengagegroup.com/")); + pub.save(); + + std::optional readback(PublisherModel::find(pub.id())); + QVERIFY(readback); + + PublisherModel pub2(readback.value()); + QCOMPARE(pub.name(), pub2.name()); + QCOMPARE(pub.founded(), pub2.founded()); + QCOMPARE(pub.website(), pub2.website()); + } catch (const std::exception& ex) { + qCritical() << ex.what(); + QFAIL(ex.what()); + } + } + + void MyTinyTest::ormOneToMany() + { + try { + PublisherModel chilton("Chilton Book Company", QDate(1904, 3, 31), QUrl("https://www.cengagegroup.com/")); + PublisherModel penguin("Penguin Random House", QDate(2013, 7, 1), QUrl("https://penguinrandomhouse.com/")); + PublisherModel bloomsbury("Bloomsbury Publishing", QDate(1986, 9, 26), QUrl("http://bloomsbury.com/")); + chilton.save(); + penguin.save(); + bloomsbury.save(); + + QVector dune{ + BookModel("Frank Herbert", "Dune", QDate(1965, 1, 1), "978-0801950773"), + BookModel("Frank Herbert", "Dune Messiah", QDate(1969, 1, 1), "978-1940884677"), + BookModel("Frank Herbert", "Children of Dune", QDate(1976, 4, 21), "978-1940884677"), + BookModel("Frank Herbert", "God Emperor of Dune", QDate(1981, 5, 1), "978-0399125935"), + BookModel("Frank Herbert", "Heretics of Dune", QDate(1984, 3, 1), "978-0575034235"), + + BookModel("Brian Herbert", "House Attreides", QDate(1999, 10, 5), "978-0553110616"), + BookModel("Brian Herbert", "House Harkonnen", QDate(2000, 10, 3), "978-0553110722"), + BookModel("Brian Herbert", "House Corrino", QDate(2001, 10, 2), "978-0553110845") + }; + QVector harryPotter{ + BookModel("J.K. Rowling", "Harry Potter and the Philosopher's Stone", QDate(1997, 6, 7), "978-0747532699"), + BookModel("J.K. Rowling", "Harry Potter and the Chamber of Secrets", QDate(1998, 7, 2), "978-0747538493"), + BookModel("J.K. Rowling", "Harry Potter and the Prisoner of Azkaban", QDate(1999, 7, 8), "978-0747542155"), + BookModel("J.K. Rowling", "Harry Potter and the Goblet of Fire", QDate(2000, 7, 8), "978-0747546245"), + BookModel("J.K. Rowling", "Harry Potter and the Order of the Phoenix", QDate(2003, 6, 21), "978-0747551003"), + BookModel("J.K. Rowling", "Harry Potter and the Half-Blood Prince", QDate(2005, 7, 16), "978-0747581086"), + BookModel("J.K. Rowling", "Harry Potter and the Deathly Hallows", QDate(2007, 7, 21), "978-0747591054") + }; + + chilton.books()->save(dune[0]); + penguin.books()->saveMany(QVector(dune.constBegin()+1, dune.constEnd())); + bloomsbury.books()->saveMany(harryPotter); + } + catch (const std::exception& ex) { + qCritical() << ex.what(); + QFAIL(ex.what()); + } + } } QTEST_MAIN(MyNamespace::MyTinyTest); diff --git a/TinyOrmQueryTest.hpp b/TinyOrmQueryTest.hpp index 975da10..61497b7 100644 --- a/TinyOrmQueryTest.hpp +++ b/TinyOrmQueryTest.hpp @@ -27,7 +27,9 @@ namespace MyNamespace void helloWorld(); void invalidInsert(); - + void ormSimple(); + void ormOneToMany(); + private: std::shared_ptr m_db; };