From 0198f6d022c5527df8b03d442ec8cf85cff89c8f Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 4 Aug 2025 22:15:23 +0500 Subject: [PATCH 01/12] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20=D0=B8=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D1=8B=D1=85=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 160 +++++++++++++++++----------------- src/model/author_s.h | 45 +++------- src/model/book_s.h | 69 +++++++++++---- src/model/genre_s.h | 28 ++++++ src/model/model_global.h | 3 + src/model/series_s.h | 28 ++++++ src/restapi/restapiserver.cpp | 31 +++++-- 7 files changed, 226 insertions(+), 138 deletions(-) create mode 100644 src/model/genre_s.h create mode 100644 src/model/series_s.h diff --git a/src/main.cpp b/src/main.cpp index 247ddbd..b4a639e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,11 +8,11 @@ #include /* Опыты с odb */ +#include // create_database #include // Должен быть здесь #include #include // Должен быть здесь #include -#include // create_database #include #include @@ -22,79 +22,79 @@ void fillBooksBD(uDBase& db) try { QVector> authors = { - SH::create("George", "Orwell", 142), - SH::create("J.K.", "Rowling", 56), - SH::create("J.R.R.", "Tolkien", 81), - SH::create("Leo", "Tolstoy", 189), - SH::create("Fyodor", "Dostoevsky", 174), - SH::create("Mark", "Twain", 183), - SH::create("Charles", "Dickens", 208), - SH::create("Virginia", "Woolf", 134), - SH::create("Ernest", "Hemingway", 122), - SH::create("Gabriel", "García Márquez", 98), - SH::create("Franz", "Kafka", 100), - SH::create("Harper", "Lee", 64), - SH::create("William", "Shakespeare", 459), - SH::create("Oscar", "Wilde", 155), - SH::create("Aldous", "Huxley", 123), - SH::create("Jane", "Austen", 210), - SH::create("John", "Steinbeck", 116), - SH::create("Agatha", "Christie", 124), - SH::create("Isaac", "Asimov", 105) + SH::create("George Orwell", "en"), + SH::create("J.K. Rowling", "en"), + SH::create("J.R.R. Tolkien", "en"), + SH::create("Leo Tolstoy", "ru"), + SH::create("Fyodor Dostoevsky", "ru"), + SH::create("Mark Twain", "en"), + SH::create("Charles Dickens", "en"), + SH::create("Virginia Woolf", "en"), + SH::create("Ernest Hemingway", "en"), + SH::create("Gabriel García Márquez", "en"), + SH::create("Franz Kafka", "de"), + SH::create("Harper Lee", "en"), + SH::create("William Shakespeare", "en"), + SH::create("Oscar Wilde", "en"), + SH::create("Aldous Huxley", "en"), + SH::create("Jane Austen", "en"), + SH::create("John Steinbeck", "en"), + SH::create("Agatha Christie", "en"), + SH::create("Isaac Asimov", "ru"), }; // Список книг QVector books = { - Book_S("1984", authors[0], 1949), - Book_S("Harry Potter and the Philosopher's Stone", authors[1], 1997), - Book_S("The Hobbit", authors[2], 1937), - Book_S("War and Peace", authors[3], 1869), - Book_S("Crime and Punishment", authors[4], 1866), - Book_S("Adventures of Huckleberry Finn", authors[5], 1884), - Book_S("A Tale of Two Cities", authors[6], 1859), - Book_S("Mrs. Dalloway", authors[7], 1925), - Book_S("The Old Man and the Sea", authors[8], 1952), - Book_S("One Hundred Years of Solitude", authors[9], 1967), - Book_S("The Trial", authors[10], 1925), - Book_S("To Kill a Mockingbird", authors[11], 1960), - Book_S("Macbeth", authors[12], 1606), - Book_S("The Picture of Dorian Gray", authors[13], 1890), - Book_S("Brave New World", authors[14], 1932), - Book_S("Pride and Prejudice", authors[15], 1813), - Book_S("The Brothers Karamazov", authors[4], 1880), - Book_S("The Grapes of Wrath", authors[16], 1939), - Book_S("Murder on the Orient Express", authors[17], 1934), - Book_S("I, Robot", authors[18], 1950), - Book_S("Animal Farm", authors[0], 1945), - Book_S("Harry Potter and the Chamber of Secrets", authors[1], 1998), - Book_S("The Lord of the Rings: The Fellowship of the Ring", authors[2], 1954), - Book_S("Anna Karenina", authors[3], 1878), - Book_S("The Idiot", authors[4], 1869), - Book_S("The Adventures of Tom Sawyer", authors[5], 1876), - Book_S("Oliver Twist", authors[6], 1837), - Book_S("To the Lighthouse", authors[7], 1927), - Book_S("For Whom the Bell Tolls", authors[8], 1940), - Book_S("Love in the Time of Cholera", authors[9], 1985), - Book_S("The Metamorphosis", authors[10], 1915), - Book_S("Go Set a Watchman", authors[11], 2015), - Book_S("King Lear", authors[12], 1605), - Book_S("The Importance of Being Earnest", authors[13], 1895), - Book_S("Brave New World Revisited", authors[14], 1958), - Book_S("Emma", authors[15], 1815), - Book_S("The Double", authors[4], 1846), - Book_S("Of Mice and Men", authors[16], 1937), - Book_S("And Then There Were None", authors[17], 1939), - Book_S("The Foundation Trilogy", authors[18], 1951), - Book_S("Down and Out in Paris and London", authors[0], 1933), - Book_S("Harry Potter and the Prisoner of Azkaban", authors[1], 1999), - Book_S("The Lord of the Rings: The Two Towers", authors[2], 1954), - Book_S("War and Peace", authors[3], 1869), - Book_S("The Brothers Karamazov", authors[4], 1880), - Book_S("The Prince and the Pauper", authors[5], 1881), - Book_S("David Copperfield", authors[6], 1850), - Book_S("The Waves", authors[7], 1931), - Book_S("A Farewell to Arms", authors[8], 1929), - Book_S("Chronicle of a Death Foretold", authors[9], 1981) + Book_S({ .author = authors[0], .title = "1984" }), + Book_S({ .author = authors[1], .title = "Harry Potter and the Philosopher's Stone" }), + Book_S({ .author = authors[2], .title = "The Hobbit" }), + Book_S({ .author = authors[3], .title = "War and Peace" }), + Book_S({ .author = authors[4], .title = "Crime and Punishment" }), + Book_S({ .author = authors[5], .title = "Adventures of Huckleberry Finn" }), + Book_S({ .author = authors[6], .title = "A Tale of Two Cities" }), + Book_S({ .author = authors[7], .title = "Mrs. Dalloway" }), + Book_S({ .author = authors[8], .title = "The Old Man and the Sea" }), + Book_S({ .author = authors[9], .title = "One Hundred Years of Solitude" }), + Book_S({ .author = authors[10], .title = "The Trial" }), + Book_S({ .author = authors[11], .title = "To Kill a Mockingbird" }), + Book_S({ .author = authors[12], .title = "Macbeth" }), + Book_S({ .author = authors[13], .title = "The Picture of Dorian Gray" }), + Book_S({ .author = authors[14], .title = "Brave New World" }), + Book_S({ .author = authors[15], .title = "Pride and Prejudice" }), + Book_S({ .author = authors[4], .title = "The Brothers Karamazov" }), + Book_S({ .author = authors[16], .title = "The Grapes of Wrath" }), + Book_S({ .author = authors[17], .title = "Murder on the Orient Express" }), + Book_S({ .author = authors[18], .title = "I, Robot" }), + Book_S({ .author = authors[0], .title = "Animal Farm" }), + Book_S({ .author = authors[1], .title = "Harry Potter and the Chamber of Secrets" }), + Book_S({ .author = authors[2], .title = "The Lord of the Rings: The Fellowship of the Ring" }), + Book_S({ .author = authors[3], .title = "Anna Karenina" }), + Book_S({ .author = authors[4], .title = "The Idiot" }), + Book_S({ .author = authors[5], .title = "The Adventures of Tom Sawyer" }), + Book_S({ .author = authors[6], .title = "Oliver Twist" }), + Book_S({ .author = authors[7], .title = "To the Lighthouse" }), + Book_S({ .author = authors[8], .title = "For Whom the Bell Tolls" }), + Book_S({ .author = authors[9], .title = "Love in the Time of Cholera" }), + Book_S({ .author = authors[10], .title = "The Metamorphosis" }), + Book_S({ .author = authors[11], .title = "Go Set a Watchman" }), + Book_S({ .author = authors[12], .title = "King Lear" }), + Book_S({ .author = authors[13], .title = "The Importance of Being Earnest" }), + Book_S({ .author = authors[14], .title = "Brave New World Revisited" }), + Book_S({ .author = authors[15], .title = "Emma" }), + Book_S({ .author = authors[4], .title = "The Double" }), + Book_S({ .author = authors[16], .title = "Of Mice and Men" }), + Book_S({ .author = authors[17], .title = "And Then There Were None" }), + Book_S({ .author = authors[18], .title = "The Foundation Trilogy" }), + Book_S({ .author = authors[0], .title = "Down and Out in Paris and London" }), + Book_S({ .author = authors[1], .title = "Harry Potter and the Prisoner of Azkaban" }), + Book_S({ .author = authors[2], .title = "The Lord of the Rings: The Two Towers" }), + Book_S({ .author = authors[3], .title = "War and Peace" }), + Book_S({ .author = authors[4], .title = "The Brothers Karamazov" }), + Book_S({ .author = authors[5], .title = "The Prince and the Pauper" }), + Book_S({ .author = authors[6], .title = "David Copperfield" }), + Book_S({ .author = authors[7], .title = "The Waves" }), + Book_S({ .author = authors[8], .title = "A Farewell to Arms" }), + Book_S({ .author = authors[9], .title = "Chronicle of a Death Foretold" }), }; // Сохранение авторов в базу данных @@ -132,16 +132,16 @@ int main(int argc, char* argv[]) fillBooksBD(db); // Сохранение дополнителньых авторов в базу данных - { - auto authors = fillAuthorDB(); - odb::core::transaction t(db->begin()); - for (auto& author : authors) - { - SH tempAuthor = SH::create(author.first, author.last, author.age); - db->persist(tempAuthor); - } - t.commit(); - } + // { + // auto authors = fillAuthorDB(); + // odb::core::transaction t(db->begin()); + // for (auto& author : authors) + // { + // SH tempAuthor = SH::create(author., author.last, author.age); + // db->persist(tempAuthor); + // } + // t.commit(); + // } RestApiServer server(*db); server.start(8080); diff --git a/src/model/author_s.h b/src/model/author_s.h index bb9ea34..4113b11 100644 --- a/src/model/author_s.h +++ b/src/model/author_s.h @@ -1,40 +1,28 @@ -// file : hello/person.hxx -// copyright : not copyrighted - public domain - #ifndef AUTHOR_S_H #define AUTHOR_S_H #include "model_global.h" -#include - -#include -#include -#include - #pragma db object class MODEL_EXPORT Author_S { public: Author_S() = default; - Author_S(const QString& firstN, - const QString& lastN, - const unsigned short age) : - m_firstName(firstN), - m_lastName(lastN), - m_age(age) - { - } + Author_S(const QString& fullName, + const QString& langCode) : + m_fullName(fullName), + m_langCode(langCode) + {} - unsigned long long id() const { return m_id; } - QString firstName() const { return m_firstName; } - QString lastName() const { return m_lastName; } - unsigned short age() const { return m_age; } + quint64 id() const { return m_id; } + void setId(quint64 newId) { m_id = newId; } - QString full_name() const { return m_firstName + " " + m_lastName; } + QString fullName() const { return m_fullName; } + void setFullName(const QString& newFullName) { m_fullName = newFullName; } - void age(unsigned short age) { m_age = age; } + QString langCode() const { return m_langCode; } + void setLangCode(const QString& newLangCode) { m_langCode = newLangCode; } private: friend class odb::access; @@ -43,9 +31,8 @@ private: #pragma db id auto quint64 m_id; - QString m_firstName; - QString m_lastName; - quint64 m_age; + QString m_fullName; + QString m_langCode; }; #pragma db view object(Author_S) @@ -53,12 +40,6 @@ struct person_stat { #pragma db column("count(" + Author_S::m_id + ")") std::size_t count; - -#pragma db column("min(" + Author_S::m_age + ")") - unsigned short min_age; - -#pragma db column("max(" + Author_S::m_age + ")") - unsigned short max_age; }; #endif // AUTHOR_S_H diff --git a/src/model/book_s.h b/src/model/book_s.h index 8a82ded..659cb35 100644 --- a/src/model/book_s.h +++ b/src/model/book_s.h @@ -1,37 +1,64 @@ -// file : hello/person.hxx -// copyright : not copyrighted - public domain - #ifndef BOOK_S_H #define BOOK_S_H #include "model_global.h" -#include -#include -#include -#include +#include #include "author_s.h" +#include "genre_s.h" +#include "series_s.h" + +struct Book_SZ +{ + SH author; + QString title; + SH series; + quint8 year; + SH genre; + QDateTime lastModified = QDateTime::currentDateTime(); + QString lang; +}; #pragma db object class MODEL_EXPORT Book_S { public: Book_S() = default; - - Book_S(const QString& name, - const SH& author, - const int year) + Book_S(const Book_SZ& book) { - m_author = author; - m_name = name; - m_year = year; - }; + m_author = book.author; + m_title = book.title; + m_series = book.series; + m_year = book.year; + m_genre = book.genre; + m_lastModified = book.lastModified; + m_lang = book.lang; + } + + quint64 id() const { return m_id; } + void setId(const quint64& newId) { m_id = newId; } - unsigned long long id() const { return m_id; } SH author() const { return m_author; } - QString name() const { return m_name; } - int year() const { return m_year; } + void setAuthor(const SH& newAuthor) { m_author = newAuthor; } + + QString title() const { return m_title; } + void setTitle(const QString& newTitle) { m_title = newTitle; } + + SH series() const { return m_series; } + void setSeries(const SH& newSeries) { m_series = newSeries; } + + quint8 year() const { return m_year; } + void setYear(const quint8& newYear) { m_year = newYear; } + + SH genre() const { return m_genre; } + void setGenre(const SH& newGenre) { m_genre = newGenre; } + + QDateTime lastModified() const { return m_lastModified; } + void setLastModified(const QDateTime& newLastModified) { m_lastModified = newLastModified; } + + QString lang() const { return m_lang; } + void setLang(const QString& newLang) { m_lang = newLang; } private: friend class odb::access; @@ -41,8 +68,12 @@ private: quint64 m_id; SH m_author; - QString m_name; + QString m_title; + SH m_series; quint8 m_year; + SH m_genre; + QDateTime m_lastModified; + QString m_lang; }; // #pragma db view object(Book_S) object(Author_S = author:Book_S::m_author) diff --git a/src/model/genre_s.h b/src/model/genre_s.h new file mode 100644 index 0000000..a577c15 --- /dev/null +++ b/src/model/genre_s.h @@ -0,0 +1,28 @@ +#ifndef GENRE_H +#define GENRE_H + +#include "model_global.h" + +#pragma db object +class MODEL_EXPORT Genre_S +{ +public: + Genre_S() = default; + + quint64 id() const { return m_id; } + void setId(const quint64& newId) { m_id = newId; } + + QString name() const { return m_name; } + void setName(const QString& newName) { m_name = newName; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; + + QString m_name; +}; + +#endif // GENRE_H diff --git a/src/model/model_global.h b/src/model/model_global.h index c01f3b5..ee08f08 100644 --- a/src/model/model_global.h +++ b/src/model/model_global.h @@ -9,4 +9,7 @@ #define MODEL_EXPORT Q_DECL_IMPORT #endif +#include +#include + #endif // MODEL_GLOBAL_H diff --git a/src/model/series_s.h b/src/model/series_s.h new file mode 100644 index 0000000..59ac95f --- /dev/null +++ b/src/model/series_s.h @@ -0,0 +1,28 @@ +#ifndef SERIES_H +#define SERIES_H + +#include "model_global.h" + +#pragma db object +class MODEL_EXPORT Series_S +{ +public: + Series_S() = default; + + quint64 id() const { return m_id; } + void setId(const quint64& newId) { m_id = newId; } + + QString serName() const { return m_serName; } + void setSerName(const QString& newSerName) { m_serName = newSerName; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; + + QString m_serName; +}; + +#endif // SERIES_H diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index b9820e2..4298e65 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -79,9 +79,18 @@ QByteArray RestApiServer::processRequest(const QString& request) { QJsonObject j; j["id"] = QString::number(book.id()); - j["name"] = book.name(); - j["author"] = book.author()->full_name(); + + QJsonObject author; + author["id"] = QString::number(book.author()->id()); + author["fullName"] = book.author()->fullName(); + author["langCode"] = book.author()->langCode(); + j["author"] = author; + // j["series"] = book.series()->serName(); + // j["genre"] = book.genre()->name(); + j["title"] = book.title(); j["year"] = book.year(); + j["lastModified"] = book.lastModified().toString(); + j["lang"] = book.lang(); jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); @@ -103,9 +112,18 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(book.id()); - j["title"] = book.name(); - j["author"] = book.author()->full_name(); + + QJsonObject author; + author["id"] = QString::number(book.author()->id()); + author["fullName"] = book.author()->fullName(); + author["langCode"] = book.author()->langCode(); + j["author"] = author; + // j["series"] = book.series()->serName(); + // j["genre"] = book.genre()->name(); + j["title"] = book.title(); j["year"] = book.year(); + j["lastModified"] = book.lastModified().toString(); + j["lang"] = book.lang(); jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); @@ -126,9 +144,8 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(author.id()); - j["first"] = author.firstName(); - j["last"] = author.lastName(); - j["age"] = author.age(); + j["fullName"] = author.fullName(); + j["langCode"] = author.langCode(); jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); -- 2.49.1 From 96bdf1e5e8dcf814b518dce80caa1fc1255d1170 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 5 Aug 2025 00:06:02 +0500 Subject: [PATCH 02/12] =?UTF-8?q?=D0=97=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20?= =?UTF-8?q?=D0=B2=20=D0=91=D0=94=20=D0=BC=D0=BD=D0=BE=D0=B3=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BA=D0=BE=20=D0=BC=D0=BD=D0=BE=D0=B3=D0=B8=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/database.qbs | 3 + src/database/database_utils.cpp | 98 +++++++++-------- src/database/database_utils.h | 15 +-- src/main.cpp | 179 +++++++++++++------------------- src/model/author_book_s.h | 46 ++++++++ src/model/author_s.h | 6 +- src/model/book_s.h | 7 +- src/model/model.qbs | 3 +- src/restapi/restapiserver.cpp | 62 +++++------ 9 files changed, 217 insertions(+), 202 deletions(-) create mode 100644 src/model/author_book_s.h diff --git a/src/database/database.qbs b/src/database/database.qbs index c1e4a3e..48a25ac 100644 --- a/src/database/database.qbs +++ b/src/database/database.qbs @@ -18,6 +18,9 @@ PSLibrary { Depends { name: "odb.gen" } Depends { name: "rdbase" } + Depends { name: "model" } + + Depends { name: "redkit_gen" } odb.gen.databases: "sqlite" cpp.cxxLanguageVersion: "c++17" diff --git a/src/database/database_utils.cpp b/src/database/database_utils.cpp index 0081295..305a107 100644 --- a/src/database/database_utils.cpp +++ b/src/database/database_utils.cpp @@ -1,57 +1,55 @@ #include "database_utils.h" -#include - -namespace +void addBook(oDBase& db, const QString title, const QVector& authors) { - -// Функция для генерации случайной строки (имени или фамилии) -QString generate_random_string(const QVector& pool) -{ - static std::random_device rd; - static std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, pool.size() - 1); - return pool[dis(gen)]; -} - -// Функция для генерации случайного года -int generate_random_year(int min_year = 1900, int max_year = 2020) -{ - static std::random_device rd; - static std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(min_year, max_year); - return dis(gen); -} - -} // namespace - -QVector fillAuthorDB() -{ - QVector first_names = { - "John", "Jane", "Alex", "Chris", "Robert", "Emily", "James", "Linda", "David", "Sarah", - "Michael", "Elizabeth", "Daniel", "Samantha", "William", "Olivia", "Ethan", "Sophia", "Joshua", "Charlotte", - "Daniel", "Grace", "Benjamin", "Isabella", "Matthew", "Victoria", "Henry", "Abigail", "Samuel", "Megan", - "Lucas", "Lily", "Andrew", "Madison", "Jackson", "Chloe", "Aiden", "Amelia", "Thomas", "Natalie", - "Ryan", "Zoe", "Jack", "Harper", "Elijah", "Ava", "Isaac", "Mia", "Caleb", "Ella" - }; - QVector last_names = { - "Doe", "Smith", "Johnson", "Williams", "Jones", "Brown", "Davis", "Miller", "Wilson", "Moore", - "Taylor", "Anderson", "Thomas", "Jackson", "White", "Harris", "Martin", "Thompson", "Garcia", "Martinez", - "Roberts", "Clark", "Lewis", "Walker", "Young", "Allen", "King", "Wright", "Scott", "Adams", - "Baker", "Gonzalez", "Nelson", "Carter", "Mitchell", "Perez", "Robinson", "Hughes", "Flores", "Cook", - "Rogers", "Gutierrez", "Ramirez", "Diaz", "Perez", "Ross", "Sanders", "Price", "Howard", "Cooper" - }; - - QVector vecTest; - - for (int i = 0; i < 50; ++i) + odb::transaction t(db.begin()); + try { - QString first_name = generate_random_string(first_names); - QString last_name = generate_random_string(last_names); - int birth_year = generate_random_year(1900, 2000); + // 1. Создаем/получаем книгу + auto books = db.query(odb::query::title == title); + SH book; - vecTest.push_back({ first_name, last_name, birth_year }); + if (books.empty()) + { + book = SH::create(); + book->setTitle(title); + + db.persist(book); + } + else + { + book = books.begin().load(); // Берем первую найденную книгу + } + + // 2. Обрабатываем авторов + for (const auto& name : authors) + { + auto authors = db.query(odb::query::fullName == name); + SH author = authors.empty() ? SH::create() : authors.begin().load(); + + if (authors.empty()) + { + author->setFullName(name); + db.persist(author); + } + + // Проверяем и создаем связь + + auto links = db.query( + odb::query::author->id == author->id() + && odb::query::book->id == book->id()); + + if (links.empty()) + { + db.persist(SH::create(author, book)); + } + } + + t.commit(); + } + catch (...) + { + t.rollback(); + throw; } - - return vecTest; } diff --git a/src/database/database_utils.h b/src/database/database_utils.h index a4f227a..67bcb6e 100644 --- a/src/database/database_utils.h +++ b/src/database/database_utils.h @@ -1,3 +1,4 @@ +#include #include #include @@ -27,11 +28,11 @@ using oDBase = odb::sqlite::database; using uDBase = U; -struct testData -{ - QString first; - QString last; - int age; -}; +#include +#include +#include +#include +#include +#include -QVector DATABASE_EXPORT fillAuthorDB(); +void DATABASE_EXPORT addBook(oDBase& db, const QString title, const QVector& authors); diff --git a/src/main.cpp b/src/main.cpp index b4a639e..769cba3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,11 +8,8 @@ #include /* Опыты с odb */ -#include // create_database -#include // Должен быть здесь -#include -#include // Должен быть здесь -#include +#include // create_database +#include #include #include @@ -21,97 +18,81 @@ void fillBooksBD(uDBase& db) { try { - QVector> authors = { - SH::create("George Orwell", "en"), - SH::create("J.K. Rowling", "en"), - SH::create("J.R.R. Tolkien", "en"), - SH::create("Leo Tolstoy", "ru"), - SH::create("Fyodor Dostoevsky", "ru"), - SH::create("Mark Twain", "en"), - SH::create("Charles Dickens", "en"), - SH::create("Virginia Woolf", "en"), - SH::create("Ernest Hemingway", "en"), - SH::create("Gabriel García Márquez", "en"), - SH::create("Franz Kafka", "de"), - SH::create("Harper Lee", "en"), - SH::create("William Shakespeare", "en"), - SH::create("Oscar Wilde", "en"), - SH::create("Aldous Huxley", "en"), - SH::create("Jane Austen", "en"), - SH::create("John Steinbeck", "en"), - SH::create("Agatha Christie", "en"), - SH::create("Isaac Asimov", "ru"), + QVector authors = { + Author_S("George Orwell", "en"), + Author_S("J.K. Rowling", "en"), + Author_S("J.R.R. Tolkien", "en"), + Author_S("Leo Tolstoy", "ru"), + Author_S("Fyodor Dostoevsky", "ru"), + Author_S("Mark Twain", "en"), + Author_S("Charles Dickens", "en"), + Author_S("Virginia Woolf", "en"), + Author_S("Ernest Hemingway", "en"), + Author_S("Gabriel García Márquez", "en"), + Author_S("Franz Kafka", "de"), + Author_S("Harper Lee", "en"), + Author_S("William Shakespeare", "en"), + Author_S("Oscar Wilde", "en"), + Author_S("Aldous Huxley", "en"), + Author_S("Jane Austen", "en"), + Author_S("John Steinbeck", "en"), + Author_S("Agatha Christie", "en"), + Author_S("Isaac Asimov", "ru"), }; - // Список книг - QVector books = { - Book_S({ .author = authors[0], .title = "1984" }), - Book_S({ .author = authors[1], .title = "Harry Potter and the Philosopher's Stone" }), - Book_S({ .author = authors[2], .title = "The Hobbit" }), - Book_S({ .author = authors[3], .title = "War and Peace" }), - Book_S({ .author = authors[4], .title = "Crime and Punishment" }), - Book_S({ .author = authors[5], .title = "Adventures of Huckleberry Finn" }), - Book_S({ .author = authors[6], .title = "A Tale of Two Cities" }), - Book_S({ .author = authors[7], .title = "Mrs. Dalloway" }), - Book_S({ .author = authors[8], .title = "The Old Man and the Sea" }), - Book_S({ .author = authors[9], .title = "One Hundred Years of Solitude" }), - Book_S({ .author = authors[10], .title = "The Trial" }), - Book_S({ .author = authors[11], .title = "To Kill a Mockingbird" }), - Book_S({ .author = authors[12], .title = "Macbeth" }), - Book_S({ .author = authors[13], .title = "The Picture of Dorian Gray" }), - Book_S({ .author = authors[14], .title = "Brave New World" }), - Book_S({ .author = authors[15], .title = "Pride and Prejudice" }), - Book_S({ .author = authors[4], .title = "The Brothers Karamazov" }), - Book_S({ .author = authors[16], .title = "The Grapes of Wrath" }), - Book_S({ .author = authors[17], .title = "Murder on the Orient Express" }), - Book_S({ .author = authors[18], .title = "I, Robot" }), - Book_S({ .author = authors[0], .title = "Animal Farm" }), - Book_S({ .author = authors[1], .title = "Harry Potter and the Chamber of Secrets" }), - Book_S({ .author = authors[2], .title = "The Lord of the Rings: The Fellowship of the Ring" }), - Book_S({ .author = authors[3], .title = "Anna Karenina" }), - Book_S({ .author = authors[4], .title = "The Idiot" }), - Book_S({ .author = authors[5], .title = "The Adventures of Tom Sawyer" }), - Book_S({ .author = authors[6], .title = "Oliver Twist" }), - Book_S({ .author = authors[7], .title = "To the Lighthouse" }), - Book_S({ .author = authors[8], .title = "For Whom the Bell Tolls" }), - Book_S({ .author = authors[9], .title = "Love in the Time of Cholera" }), - Book_S({ .author = authors[10], .title = "The Metamorphosis" }), - Book_S({ .author = authors[11], .title = "Go Set a Watchman" }), - Book_S({ .author = authors[12], .title = "King Lear" }), - Book_S({ .author = authors[13], .title = "The Importance of Being Earnest" }), - Book_S({ .author = authors[14], .title = "Brave New World Revisited" }), - Book_S({ .author = authors[15], .title = "Emma" }), - Book_S({ .author = authors[4], .title = "The Double" }), - Book_S({ .author = authors[16], .title = "Of Mice and Men" }), - Book_S({ .author = authors[17], .title = "And Then There Were None" }), - Book_S({ .author = authors[18], .title = "The Foundation Trilogy" }), - Book_S({ .author = authors[0], .title = "Down and Out in Paris and London" }), - Book_S({ .author = authors[1], .title = "Harry Potter and the Prisoner of Azkaban" }), - Book_S({ .author = authors[2], .title = "The Lord of the Rings: The Two Towers" }), - Book_S({ .author = authors[3], .title = "War and Peace" }), - Book_S({ .author = authors[4], .title = "The Brothers Karamazov" }), - Book_S({ .author = authors[5], .title = "The Prince and the Pauper" }), - Book_S({ .author = authors[6], .title = "David Copperfield" }), - Book_S({ .author = authors[7], .title = "The Waves" }), - Book_S({ .author = authors[8], .title = "A Farewell to Arms" }), - Book_S({ .author = authors[9], .title = "Chronicle of a Death Foretold" }), - }; + addBook(*db, "1984", { authors[0].fullName() }); + addBook(*db, "Harry Potter and the Philosopher's Stone", { authors[1].fullName() }); + addBook(*db, "The Hobbit", { authors[2].fullName() }); + addBook(*db, "War and Peace", { authors[3].fullName() }); + addBook(*db, "Crime and Punishment", { authors[4].fullName() }); + addBook(*db, "Adventures of Huckleberry Finn", { authors[5].fullName() }); + addBook(*db, "A Tale of Two Cities", { authors[6].fullName() }); + addBook(*db, "Mrs. Dalloway", { authors[7].fullName() }); + addBook(*db, "The Old Man and the Sea", { authors[8].fullName() }); + addBook(*db, "One Hundred Years of Solitude", { authors[9].fullName() }); + addBook(*db, "The Trial", { authors[10].fullName() }); + addBook(*db, "To Kill a Mockingbird", { authors[11].fullName() }); + addBook(*db, "Macbeth", { authors[12].fullName() }); + addBook(*db, "The Picture of Dorian Gray", { authors[13].fullName() }); + addBook(*db, "Brave New World", { authors[14].fullName() }); + addBook(*db, "Pride and Prejudice", { authors[15].fullName() }); + addBook(*db, "The Brothers Karamazov", { authors[4].fullName() }); + addBook(*db, "The Grapes of Wrath", { authors[16].fullName() }); + addBook(*db, "Murder on the Orient Express", { authors[17].fullName() }); + addBook(*db, "I, Robot", { authors[18].fullName() }); + addBook(*db, "Animal Farm", { authors[0].fullName() }); + addBook(*db, "Harry Potter and the Chamber of Secrets", { authors[1].fullName() }); + addBook(*db, "The Lord of the Rings: The Fellowship of the Ring", { authors[2].fullName() }); + addBook(*db, "Anna Karenina", { authors[3].fullName() }); + addBook(*db, "The Idiot", { authors[4].fullName() }); + addBook(*db, "The Adventures of Tom Sawyer", { authors[5].fullName() }); + addBook(*db, "Oliver Twist", { authors[6].fullName() }); + addBook(*db, "To the Lighthouse", { authors[7].fullName() }); + addBook(*db, "For Whom the Bell Tolls", { authors[8].fullName() }); + addBook(*db, "Love in the Time of Cholera", { authors[9].fullName() }); + addBook(*db, "The Metamorphosis", { authors[10].fullName() }); + addBook(*db, "Go Set a Watchman", { authors[11].fullName() }); + addBook(*db, "King Lear", { authors[12].fullName() }); + addBook(*db, "The Importance of Being Earnest", { authors[13].fullName() }); + addBook(*db, "Brave New World Revisited", { authors[14].fullName() }); + addBook(*db, "Emma", { authors[15].fullName() }); + addBook(*db, "The Double", { authors[4].fullName() }); + addBook(*db, "Of Mice and Men", { authors[16].fullName() }); + addBook(*db, "And Then There Were None", { authors[17].fullName() }); + addBook(*db, "The Foundation Trilogy", { authors[18].fullName() }); + addBook(*db, "Down and Out in Paris and London", { authors[0].fullName() }); + addBook(*db, "Harry Potter and the Prisoner of Azkaban", { authors[1].fullName() }); + addBook(*db, "The Lord of the Rings: The Two Towers", { authors[2].fullName() }); + addBook(*db, "War and Peace", { authors[3].fullName() }); + addBook(*db, "The Brothers Karamazov", { authors[4].fullName() }); + addBook(*db, "The Prince and the Pauper", { authors[5].fullName() }); + addBook(*db, "David Copperfield", { authors[6].fullName() }); + addBook(*db, "The Waves", { authors[7].fullName() }); + addBook(*db, "A Farewell to Arms", { authors[8].fullName() }); + addBook(*db, "Chronicle of a Death Foretold", { authors[9].fullName() }); - // Сохранение авторов в базу данных - { - odb::core::transaction t(db->begin()); - for (auto& author : authors) - db->persist(author); - t.commit(); - } - - // Сохранение книг в базу данных - { - odb::core::transaction t(db->begin()); - for (auto& book : books) - db->persist(book); - t.commit(); - } + addBook(*db, "1984", { "George Orwell" }); + addBook(*db, "Harry Potter and the Philosopher's Stone", { "J.K. Rowling" }); std::cout << "Test data added successfully." << std::endl; } @@ -131,18 +112,6 @@ int main(int argc, char* argv[]) // TODO Как-то нужно выполнять лишь раз fillBooksBD(db); - // Сохранение дополнителньых авторов в базу данных - // { - // auto authors = fillAuthorDB(); - // odb::core::transaction t(db->begin()); - // for (auto& author : authors) - // { - // SH tempAuthor = SH::create(author., author.last, author.age); - // db->persist(tempAuthor); - // } - // t.commit(); - // } - RestApiServer server(*db); server.start(8080); diff --git a/src/model/author_book_s.h b/src/model/author_book_s.h new file mode 100644 index 0000000..32a90ae --- /dev/null +++ b/src/model/author_book_s.h @@ -0,0 +1,46 @@ +#ifndef AUTHOR_BOOK_H +#define AUTHOR_BOOK_H + +#include "model_global.h" + +#include "author_s.h" +#include "book_s.h" + +#pragma db object +class MODEL_EXPORT AuthorBook_S +{ +private: + AuthorBook_S() = default; + +public: + AuthorBook_S(SH author, + SH book) : + m_author(author), + m_book(book) {} + + quint64 id() const { return m_id; } + void setId(quint64 newId) { m_id = newId; } + + SH author() const { return m_author; } + void setAuthor(const SH& newAuthor) { m_author = newAuthor; } + + SH book() const { return m_book; } + void setBook(const SH& newBook) { m_book = newBook; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; + +#pragma db not_null + SH m_author; + +#pragma db not_null + SH m_book; + +#pragma db index("author_book_unique") member(m_author) member(m_book) unique +}; + +#endif // AUTHOR_BOOK_H diff --git a/src/model/author_s.h b/src/model/author_s.h index 4113b11..bef4022 100644 --- a/src/model/author_s.h +++ b/src/model/author_s.h @@ -3,12 +3,14 @@ #include "model_global.h" +// @JsonSerializer +class Author_S; + #pragma db object class MODEL_EXPORT Author_S { public: Author_S() = default; - Author_S(const QString& fullName, const QString& langCode) : m_fullName(fullName), @@ -27,7 +29,7 @@ public: private: friend class odb::access; -private: +public: // for Redkit-gen #pragma db id auto quint64 m_id; diff --git a/src/model/book_s.h b/src/model/book_s.h index 659cb35..3a09af6 100644 --- a/src/model/book_s.h +++ b/src/model/book_s.h @@ -11,7 +11,6 @@ struct Book_SZ { - SH author; QString title; SH series; quint8 year; @@ -27,7 +26,6 @@ public: Book_S() = default; Book_S(const Book_SZ& book) { - m_author = book.author; m_title = book.title; m_series = book.series; m_year = book.year; @@ -39,9 +37,6 @@ public: quint64 id() const { return m_id; } void setId(const quint64& newId) { m_id = newId; } - SH author() const { return m_author; } - void setAuthor(const SH& newAuthor) { m_author = newAuthor; } - QString title() const { return m_title; } void setTitle(const QString& newTitle) { m_title = newTitle; } @@ -63,11 +58,11 @@ public: private: friend class odb::access; +// public: // for Redkit-gen private: #pragma db id auto quint64 m_id; - SH m_author; QString m_title; SH m_series; quint8 m_year; diff --git a/src/model/model.qbs b/src/model/model.qbs index fbd8c8d..9e0d2ab 100644 --- a/src/model/model.qbs +++ b/src/model/model.qbs @@ -20,7 +20,8 @@ PSLibrary { Depends { name: "rdbase" } Depends { name: "redkit_gen" } - redkit_gen.includeModules: ["JsonSerializer"] + redkit_gen.includeModules: [redkit_gen.module.JsonSerializer, + redkit_gen.module.SettingsSerializer,] odb.gen.databases: "sqlite" cpp.cxxLanguageVersion: "c++17" diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 4298e65..59a11bc 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -64,7 +64,7 @@ QByteArray RestApiServer::processRequest(const QString& request) if (request.startsWith("GET /books/author/")) { QString author = request.section(' ', 1, 1).section('/', 3, 3).replace("%20", " "); - quint64 ageReq = author.toInt(); + // quint64 ageReq = author.toInt(); QStringList nameParts = author.split(' '); QString firstName = nameParts.size() > 0 ? nameParts[0] : ""; @@ -72,27 +72,27 @@ QByteArray RestApiServer::processRequest(const QString& request) odb::transaction t(m_db.begin()); - auto books = m_db.query(odb::query::author->id == ageReq); + // auto books = m_db.query(odb::query::author->id == ageReq); QJsonArray jArray; - for (const auto& book : books) - { - QJsonObject j; - j["id"] = QString::number(book.id()); + // for (const auto& book : books) + // { + // QJsonObject j; + // j["id"] = QString::number(book.id()); - QJsonObject author; - author["id"] = QString::number(book.author()->id()); - author["fullName"] = book.author()->fullName(); - author["langCode"] = book.author()->langCode(); - j["author"] = author; - // j["series"] = book.series()->serName(); - // j["genre"] = book.genre()->name(); - j["title"] = book.title(); - j["year"] = book.year(); - j["lastModified"] = book.lastModified().toString(); - j["lang"] = book.lang(); - jArray.push_back(j); - } + // QJsonObject author; + // author["id"] = QString::number(book.author()->id()); + // author["fullName"] = book.author()->fullName(); + // author["langCode"] = book.author()->langCode(); + // j["author"] = author; + // // j["series"] = book.series()->serName(); + // // j["genre"] = book.genre()->name(); + // j["title"] = book.title(); + // j["year"] = book.year(); + // j["lastModified"] = book.lastModified().toString(); + // j["lang"] = book.lang(); + // jArray.push_back(j); + // } auto jDoc = QJsonDocument(jArray); t.commit(); @@ -113,18 +113,18 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(book.id()); - QJsonObject author; - author["id"] = QString::number(book.author()->id()); - author["fullName"] = book.author()->fullName(); - author["langCode"] = book.author()->langCode(); - j["author"] = author; - // j["series"] = book.series()->serName(); - // j["genre"] = book.genre()->name(); - j["title"] = book.title(); - j["year"] = book.year(); - j["lastModified"] = book.lastModified().toString(); - j["lang"] = book.lang(); - jArray.push_back(j); + // QJsonObject author; + // author["id"] = QString::number(book.author()->id()); + // author["fullName"] = book.author()->fullName(); + // author["langCode"] = book.author()->langCode(); + // j["author"] = author; + // // j["series"] = book.series()->serName(); + // // j["genre"] = book.genre()->name(); + // j["title"] = book.title(); + // j["year"] = book.year(); + // j["lastModified"] = book.lastModified().toString(); + // j["lang"] = book.lang(); + // jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); t.commit(); -- 2.49.1 From 8cb56837f5424182353d32081739b09e8daee7a3 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 5 Aug 2025 00:09:46 +0500 Subject: [PATCH 03/12] =?UTF-8?q?=D0=9F=D0=B0=D1=80=D0=B0=20=D0=BA=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=BC=D0=BD=D1=8B=D1=85=20=D0=BA=D0=BD=D0=B8?= =?UTF-8?q?=D0=B6=D0=B5=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 769cba3..971d54c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,8 @@ void fillBooksBD(uDBase& db) Author_S("Isaac Asimov", "ru"), }; + addBook(*db, "Очень странная книжка", { "Автор 1", "Автор 2", "Авторк 3" }); + addBook(*db, "1984", { authors[0].fullName() }); addBook(*db, "Harry Potter and the Philosopher's Stone", { authors[1].fullName() }); addBook(*db, "The Hobbit", { authors[2].fullName() }); @@ -94,6 +96,8 @@ void fillBooksBD(uDBase& db) addBook(*db, "1984", { "George Orwell" }); addBook(*db, "Harry Potter and the Philosopher's Stone", { "J.K. Rowling" }); + addBook(*db, "Очень странная книжка 2", { "Автор 4", "Авторк 3" }); + std::cout << "Test data added successfully." << std::endl; } catch (const odb::exception& e) -- 2.49.1 From 89b43f5aad387c6d57a3b5774c805948359ddcd4 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 5 Aug 2025 09:33:05 +0500 Subject: [PATCH 04/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D0=B0?= =?UTF-8?q?=20Settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/database_utils.h | 12 ++++++------ src/model/{ => books}/author_book_s.h | 2 +- src/model/{ => books}/author_s.h | 2 +- src/model/{ => books}/book_s.h | 2 +- src/model/{ => books}/genre_s.h | 2 +- src/model/{ => books}/series_s.h | 2 +- src/model/model.qbs | 9 +++++++++ src/model/settings/settings.h | 23 +++++++++++++++++++++++ src/restapi/restapiserver.cpp | 8 ++++---- 9 files changed, 47 insertions(+), 15 deletions(-) rename src/model/{ => books}/author_book_s.h (96%) rename src/model/{ => books}/author_s.h (96%) rename src/model/{ => books}/book_s.h (98%) rename src/model/{ => books}/genre_s.h (93%) rename src/model/{ => books}/series_s.h (93%) create mode 100644 src/model/settings/settings.h diff --git a/src/database/database_utils.h b/src/database/database_utils.h index 67bcb6e..5dccabe 100644 --- a/src/database/database_utils.h +++ b/src/database/database_utils.h @@ -28,11 +28,11 @@ using oDBase = odb::sqlite::database; using uDBase = U; -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include void DATABASE_EXPORT addBook(oDBase& db, const QString title, const QVector& authors); diff --git a/src/model/author_book_s.h b/src/model/books/author_book_s.h similarity index 96% rename from src/model/author_book_s.h rename to src/model/books/author_book_s.h index 32a90ae..a098dcc 100644 --- a/src/model/author_book_s.h +++ b/src/model/books/author_book_s.h @@ -1,7 +1,7 @@ #ifndef AUTHOR_BOOK_H #define AUTHOR_BOOK_H -#include "model_global.h" +#include #include "author_s.h" #include "book_s.h" diff --git a/src/model/author_s.h b/src/model/books/author_s.h similarity index 96% rename from src/model/author_s.h rename to src/model/books/author_s.h index bef4022..e8d6355 100644 --- a/src/model/author_s.h +++ b/src/model/books/author_s.h @@ -1,7 +1,7 @@ #ifndef AUTHOR_S_H #define AUTHOR_S_H -#include "model_global.h" +#include // @JsonSerializer class Author_S; diff --git a/src/model/book_s.h b/src/model/books/book_s.h similarity index 98% rename from src/model/book_s.h rename to src/model/books/book_s.h index 3a09af6..ee83309 100644 --- a/src/model/book_s.h +++ b/src/model/books/book_s.h @@ -1,7 +1,7 @@ #ifndef BOOK_S_H #define BOOK_S_H -#include "model_global.h" +#include #include diff --git a/src/model/genre_s.h b/src/model/books/genre_s.h similarity index 93% rename from src/model/genre_s.h rename to src/model/books/genre_s.h index a577c15..9b6651f 100644 --- a/src/model/genre_s.h +++ b/src/model/books/genre_s.h @@ -1,7 +1,7 @@ #ifndef GENRE_H #define GENRE_H -#include "model_global.h" +#include #pragma db object class MODEL_EXPORT Genre_S diff --git a/src/model/series_s.h b/src/model/books/series_s.h similarity index 93% rename from src/model/series_s.h rename to src/model/books/series_s.h index 59ac95f..62b2c91 100644 --- a/src/model/series_s.h +++ b/src/model/books/series_s.h @@ -1,7 +1,7 @@ #ifndef SERIES_H #define SERIES_H -#include "model_global.h" +#include #pragma db object class MODEL_EXPORT Series_S diff --git a/src/model/model.qbs b/src/model/model.qbs index 9e0d2ab..40e34f2 100644 --- a/src/model/model.qbs +++ b/src/model/model.qbs @@ -26,12 +26,21 @@ PSLibrary { odb.gen.databases: "sqlite" cpp.cxxLanguageVersion: "c++17" + Group { + id: headers + name: "headers" + files: [ + "model_global.h", + ] + } + Group { id: odbs name: "odb" files: [ "**/*.h", ] + excludeFiles: headers.files fileTags: ["hpp", "odbxx", "rgen"] } diff --git a/src/model/settings/settings.h b/src/model/settings/settings.h new file mode 100644 index 0000000..3ab49e5 --- /dev/null +++ b/src/model/settings/settings.h @@ -0,0 +1,23 @@ +#ifndef SETTINGS_S_H +#define SETTINGS_S_H + +#include + +#pragma db object +class MODEL_EXPORT Settings_S +{ +public: + Settings_S() = default; + + quint64 id() const { return m_id; } + void setId(const quint64& newId) { m_id = newId; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; +}; + +#endif // SETTINGS_S_H diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 59a11bc..7d11978 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -5,10 +5,10 @@ #include #include -#include // Должен быть здесь -#include -#include // Должен быть здесь -#include +#include // Должен быть здесь +#include +#include // Должен быть здесь +#include #include #include -- 2.49.1 From 34fcabc04e328c58ce65f6d3fe24c22b80917312 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 9 Aug 2025 16:03:39 +0500 Subject: [PATCH 05/12] =?UTF-8?q?=D0=9F=D0=B0=D1=80=D1=81=D0=B8=D0=BC=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8E=20?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=BD=D0=B8=D0=B3=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 3 ++ external_libs/quazip.qbs | 34 ++++++++++++++ project.qbs | 1 + redkitty | 2 +- src/cpp-opds.qbs | 3 ++ src/fb2extractor.cpp | 79 +++++++++++++++++++++++++++++++++ src/fb2extractor.h | 26 +++++++++++ src/main.cpp | 95 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 external_libs/quazip.qbs create mode 100644 src/fb2extractor.cpp create mode 100644 src/fb2extractor.h diff --git a/.gitmodules b/.gitmodules index 4254dc4..7186484 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "redkitty"] path = redkitty url = git@gitea.redkit-lab.work:redkit-lab/redkitty.git +[submodule "external_libs/quazip"] + path = external_libs/quazip + url = https://github.com/stachenov/quazip.git diff --git a/external_libs/quazip.qbs b/external_libs/quazip.qbs new file mode 100644 index 0000000..bf7ce29 --- /dev/null +++ b/external_libs/quazip.qbs @@ -0,0 +1,34 @@ +import qbs + +PSLibrary { + name: "quazip" + + property string quazipPath: path + "/quazip" // Путь к исходникам QuaZip + property string noname: { + console.error("noname" + exportedIncludePaths) + return "noname" + } + + Depends { name: "zlib" } + + Group { + name: "h" + id: qh + files: [ + quazipPath + "/quazip/*.h", + ] + } + + Group { + name: "cpp" + files: [ + quazipPath + "/quazip/*.cpp", + quazipPath + "/quazip/*.c" + ] + } + + // Export { + // Depends { name:"cpp" } + // cpp.includePaths: qh + // } +} diff --git a/project.qbs b/project.qbs index fee6594..72e9161 100644 --- a/project.qbs +++ b/project.qbs @@ -17,5 +17,6 @@ Project { "src/database/database.qbs", "src/model/model.qbs", "src/restapi/restapi.qbs", + "external_libs/quazip.qbs", ] } diff --git a/redkitty b/redkitty index 2316dde..47579f9 160000 --- a/redkitty +++ b/redkitty @@ -1 +1 @@ -Subproject commit 2316ddea7250c3d828a7c4a45f49ea8bc100448b +Subproject commit 47579f9e2e5e2973e1bbf260565563380b53e849 diff --git a/src/cpp-opds.qbs b/src/cpp-opds.qbs index f1b969f..572fa67 100644 --- a/src/cpp-opds.qbs +++ b/src/cpp-opds.qbs @@ -22,12 +22,15 @@ PSApplication { Depends { name: "redkit_gen" } Depends { name: "rdbase" } Depends { name: "model" } + Depends { name: "quazip" } cpp.cxxLanguageVersion: "c++20" Group { name: "cpp" files: [ + "fb2extractor.cpp", + "fb2extractor.h", "main.cpp", ] } diff --git a/src/fb2extractor.cpp b/src/fb2extractor.cpp new file mode 100644 index 0000000..87b0156 --- /dev/null +++ b/src/fb2extractor.cpp @@ -0,0 +1,79 @@ +#include "fb2extractor.h" + +// FB2Extractor::FB2Extractor() {} + +Fb2Metadata parseFb2Metadata(QXmlStreamReader &sr) +{ + Fb2Metadata meta; + QString currentElement; + bool inTitleInfo = false; + bool inAuthor = false; + QString currentAuthor; + + while (!sr.atEnd()) + { + switch (sr.readNext()) + { + case QXmlStreamReader::StartElement: + currentElement = sr.name().toString(); + + if (currentElement == "title-info") + { + inTitleInfo = true; + } + else if (inTitleInfo) + { + if (currentElement == "book-title") + { + meta.title = sr.readElementText(); + } + else if (currentElement == "genre") + { + meta.genres << sr.readElementText(); + } + else if (currentElement == "author") + { + inAuthor = true; + currentAuthor.clear(); + } + else if (inAuthor && (currentElement == "first-name" || currentElement == "last-name" || currentElement == "middle-name")) + { + currentAuthor += sr.readElementText() + " "; + } + } + break; + + case QXmlStreamReader::EndElement: + if (sr.name().toString() == "title-info") + { + inTitleInfo = false; + } + else if (sr.name().toString() == "author" && inAuthor) + { + meta.authors << currentAuthor.trimmed(); + inAuthor = false; + } + break; + + case QXmlStreamReader::Characters: + // Обработка текста уже делается в readElementText() + break; + + default: + break; + } + + // Прерываем парсинг, если нашли все метаданные + if (!meta.title.isEmpty() && !meta.authors.isEmpty() && !meta.genres.isEmpty()) + { + break; + } + } + + if (sr.hasError()) + { + qWarning() << "XML parsing error:" << sr.errorString(); + } + + return meta; +} diff --git a/src/fb2extractor.h b/src/fb2extractor.h new file mode 100644 index 0000000..20c0ffd --- /dev/null +++ b/src/fb2extractor.h @@ -0,0 +1,26 @@ +#ifndef FB2EXTRACTOR_H +#define FB2EXTRACTOR_H + +#include +#include +#include + +#include +#include + +// class FB2Extractor +// { +// public: +// FB2Extractor(); +// }; + +struct Fb2Metadata +{ + QString title; + QStringList authors; + QStringList genres; +}; + +Fb2Metadata parseFb2Metadata(QXmlStreamReader& sr); + +#endif // FB2EXTRACTOR_H diff --git a/src/main.cpp b/src/main.cpp index 971d54c..8ded449 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -14,6 +15,69 @@ #include +#include "fb2extractor.h" + +QMap readFb2MetadataFromZip(const QString& zipPath) +{ + QMap metadata; + QuaZip zip(zipPath); + + if (!zip.open(QuaZip::mdUnzip)) + { + qWarning() << "Failed to open ZIP archive"; + return metadata; + } + + int count = 0; + for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) + { + ++count; + + qWarning() << "*********" << count << "*********"; + + // Получение информации о файле + QuaZipFileInfo fileInfo; + if (zip.getCurrentFileInfo(&fileInfo)) + { + qDebug() << "File:" << fileInfo.name + << "Size:" << fileInfo.uncompressedSize << "bytes" + << "Compressed:" << fileInfo.compressedSize << "bytes" + << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); + } + + QString fb2FileName = zip.getCurrentFileName(); + + if (fb2FileName.isEmpty()) + { + qWarning() << "No FB2 file found in archive"; + zip.close(); + return metadata; + } + + // Читаем FB2 файл из архива + // qWarning() << "Читаем FB2 файл из архива" << fb2FileName; + QuaZipFile fb2File(&zip); + bool isOpen = fb2File.open(QIODevice::ReadOnly); + int zipError = fb2File.getZipError(); + if (!isOpen || zipError != UNZ_OK) + { + qWarning() << "Failed to open FB2 file in archive"; + zip.close(); + return metadata; + } + + // Парсим XML метаданные + QXmlStreamReader fXmlBook(&fb2File); + const auto data = parseFb2Metadata(fXmlBook); + + qWarning() << data.title << data.authors << data.genres; + + qWarning() << "*********" << count << "*********"; + } + + return metadata; +} + void fillBooksBD(uDBase& db) { try @@ -119,6 +183,36 @@ int main(int argc, char* argv[]) RestApiServer server(*db); server.start(8080); + // QString zipArzh = "f.fb2-631519-634744.zip"; + QString zipArzh = "/home/alex/repos/exp/cpp-opds/f.fb2-631519-634744.zip"; + + const auto books = readFb2MetadataFromZip(zipArzh); + qWarning() << " books.count()" << books.count(); + + // QuaZip zip(zipArzh); + // if (!zip.open(QuaZip::mdUnzip)) + // { + // qWarning() << "Failed to open archive"; + // } + // else + // { + // qWarning() << "Total files:" << zip.getEntriesCount(); + + // for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) + // { + // QuaZipFileInfo fileInfo; + // if (zip.getCurrentFileInfo(&fileInfo)) + // { + // qDebug() << "File:" << fileInfo.name + // << "Size:" << fileInfo.uncompressedSize << "bytes" + // << "Compressed:" << fileInfo.compressedSize << "bytes" + // << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); + // } + // } + // } + + // zip.close(); + // Set up code that uses the Qt event loop here. // Call a.quit() or a.exit() to quit the application. // A not very useful example would be including @@ -130,5 +224,6 @@ int main(int argc, char* argv[]) // If you do not need a running Qt event loop, remove the call // to a.exec() or use the Non-Qt Plain C++ Application template. + qWarning() << "S EXIT"; return a.exec(); } -- 2.49.1 From d01c789b066d98f26dddb73fd40c5730fb0719ff Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 9 Aug 2025 18:31:55 +0500 Subject: [PATCH 06/12] =?UTF-8?q?=D0=9D=D0=B5=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=87=D0=B0=D1=8F=20wip=D0=BB=D1=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cpp-opds.qbs | 3 +- src/database/database.qbs | 1 - src/fb2extractor.h | 26 --------- src/main.cpp | 99 ++++++++++++++------------------ src/{ => utils}/fb2extractor.cpp | 38 ++++++++---- src/utils/fb2extractor.h | 36 ++++++++++++ src/utils/utils.qbs | 22 +++++++ src/utils/utils_global.h | 12 ++++ src/utils/zipwrapper.cpp | 60 +++++++++++++++++++ src/utils/zipwrapper.h | 29 ++++++++++ 10 files changed, 230 insertions(+), 96 deletions(-) delete mode 100644 src/fb2extractor.h rename src/{ => utils}/fb2extractor.cpp (67%) create mode 100644 src/utils/fb2extractor.h create mode 100644 src/utils/utils.qbs create mode 100644 src/utils/utils_global.h create mode 100644 src/utils/zipwrapper.cpp create mode 100644 src/utils/zipwrapper.h diff --git a/src/cpp-opds.qbs b/src/cpp-opds.qbs index 572fa67..ecf85a1 100644 --- a/src/cpp-opds.qbs +++ b/src/cpp-opds.qbs @@ -23,14 +23,13 @@ PSApplication { Depends { name: "rdbase" } Depends { name: "model" } Depends { name: "quazip" } + Depends { name: "utils" } cpp.cxxLanguageVersion: "c++20" Group { name: "cpp" files: [ - "fb2extractor.cpp", - "fb2extractor.h", "main.cpp", ] } diff --git a/src/database/database.qbs b/src/database/database.qbs index 48a25ac..3cdc49d 100644 --- a/src/database/database.qbs +++ b/src/database/database.qbs @@ -11,7 +11,6 @@ PSLibrary { "DATABASE_SQLITE", "DATABASE_LIBRARY" ] - consoleApplication: true Depends { name: "Qt"; submodules: [ "core", "network" ] } Depends { name: "cpp" } diff --git a/src/fb2extractor.h b/src/fb2extractor.h deleted file mode 100644 index 20c0ffd..0000000 --- a/src/fb2extractor.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FB2EXTRACTOR_H -#define FB2EXTRACTOR_H - -#include -#include -#include - -#include -#include - -// class FB2Extractor -// { -// public: -// FB2Extractor(); -// }; - -struct Fb2Metadata -{ - QString title; - QStringList authors; - QStringList genres; -}; - -Fb2Metadata parseFb2Metadata(QXmlStreamReader& sr); - -#endif // FB2EXTRACTOR_H diff --git a/src/main.cpp b/src/main.cpp index 8ded449..088a307 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,8 @@ #include -#include "fb2extractor.h" +#include +#include QMap readFb2MetadataFromZip(const QString& zipPath) { @@ -36,43 +37,43 @@ QMap readFb2MetadataFromZip(const QString& zipPath) qWarning() << "*********" << count << "*********"; // Получение информации о файле - QuaZipFileInfo fileInfo; - if (zip.getCurrentFileInfo(&fileInfo)) - { - qDebug() << "File:" << fileInfo.name - << "Size:" << fileInfo.uncompressedSize << "bytes" - << "Compressed:" << fileInfo.compressedSize << "bytes" - << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); - } + // QuaZipFileInfo fileInfo; + // if (zip.getCurrentFileInfo(&fileInfo)) + // { + // qDebug() << "File:" << fileInfo.name + // << "Size:" << fileInfo.uncompressedSize << "bytes" + // << "Compressed:" << fileInfo.compressedSize << "bytes" + // << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); + // } QString fb2FileName = zip.getCurrentFileName(); + qWarning() << fb2FileName; + // if (fb2FileName.isEmpty()) + // { + // qWarning() << "No FB2 file found in archive"; + // zip.close(); + // return metadata; + // } - if (fb2FileName.isEmpty()) - { - qWarning() << "No FB2 file found in archive"; - zip.close(); - return metadata; - } - - // Читаем FB2 файл из архива - // qWarning() << "Читаем FB2 файл из архива" << fb2FileName; + // // Читаем FB2 файл из архива + // // qWarning() << "Читаем FB2 файл из архива" << fb2FileName; QuaZipFile fb2File(&zip); - bool isOpen = fb2File.open(QIODevice::ReadOnly); - int zipError = fb2File.getZipError(); - if (!isOpen || zipError != UNZ_OK) - { - qWarning() << "Failed to open FB2 file in archive"; - zip.close(); - return metadata; - } + // bool isOpen = fb2File.open(QIODevice::ReadOnly); + // int zipError = fb2File.getZipError(); + // if (!isOpen || zipError != UNZ_OK) + // { + // qWarning() << "Failed to open FB2 file in archive"; + // zip.close(); + // return metadata; + // } - // Парсим XML метаданные - QXmlStreamReader fXmlBook(&fb2File); - const auto data = parseFb2Metadata(fXmlBook); + // // Парсим XML метаданные + // QXmlStreamReader fXmlBook(&fb2File); + // const auto data = parseFb2Metadata(fXmlBook); - qWarning() << data.title << data.authors << data.genres; + // qWarning() << data.title << data.authors << data.genres; - qWarning() << "*********" << count << "*********"; + // qWarning() << "*********" << count << "*********"; } return metadata; @@ -187,31 +188,19 @@ int main(int argc, char* argv[]) QString zipArzh = "/home/alex/repos/exp/cpp-opds/f.fb2-631519-634744.zip"; const auto books = readFb2MetadataFromZip(zipArzh); - qWarning() << " books.count()" << books.count(); + // qWarning() << " books.count()" << books.count(); - // QuaZip zip(zipArzh); - // if (!zip.open(QuaZip::mdUnzip)) - // { - // qWarning() << "Failed to open archive"; - // } - // else - // { - // qWarning() << "Total files:" << zip.getEntriesCount(); - - // for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) - // { - // QuaZipFileInfo fileInfo; - // if (zip.getCurrentFileInfo(&fileInfo)) - // { - // qDebug() << "File:" << fileInfo.name - // << "Size:" << fileInfo.uncompressedSize << "bytes" - // << "Compressed:" << fileInfo.compressedSize << "bytes" - // << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); - // } - // } - // } - - // zip.close(); + auto z = ZipWrapper(zipArzh); + for (const auto& filename : z.getFiles()) + { + if (filename.endsWith(".fb2")) + { + auto zf = z.getFile(filename).data(); + auto fb2File = FB2Extractor(*zf); + const auto book = fb2File.parse(); + // qWarning() << book.title; + } + } // Set up code that uses the Qt event loop here. // Call a.quit() or a.exit() to quit the application. diff --git a/src/fb2extractor.cpp b/src/utils/fb2extractor.cpp similarity index 67% rename from src/fb2extractor.cpp rename to src/utils/fb2extractor.cpp index 87b0156..da59847 100644 --- a/src/fb2extractor.cpp +++ b/src/utils/fb2extractor.cpp @@ -1,21 +1,35 @@ #include "fb2extractor.h" -// FB2Extractor::FB2Extractor() {} +// FB2Extractor::FB2Extractor() +// { +// } -Fb2Metadata parseFb2Metadata(QXmlStreamReader &sr) +FB2Extractor::FB2Extractor(QuaZipFile& file) : + m_file(&file) { +} + +FB2Extractor::~FB2Extractor() +{ + m_file.close(); +} + +Fb2Metadata FB2Extractor::parse() +{ + QXmlStreamReader xmlData(&m_file); + Fb2Metadata meta; QString currentElement; bool inTitleInfo = false; bool inAuthor = false; QString currentAuthor; - while (!sr.atEnd()) + while (!xmlData.atEnd()) { - switch (sr.readNext()) + switch (xmlData.readNext()) { case QXmlStreamReader::StartElement: - currentElement = sr.name().toString(); + currentElement = xmlData.name().toString(); if (currentElement == "title-info") { @@ -25,11 +39,11 @@ Fb2Metadata parseFb2Metadata(QXmlStreamReader &sr) { if (currentElement == "book-title") { - meta.title = sr.readElementText(); + meta.title = xmlData.readElementText(); } else if (currentElement == "genre") { - meta.genres << sr.readElementText(); + meta.genres << xmlData.readElementText(); } else if (currentElement == "author") { @@ -38,17 +52,17 @@ Fb2Metadata parseFb2Metadata(QXmlStreamReader &sr) } else if (inAuthor && (currentElement == "first-name" || currentElement == "last-name" || currentElement == "middle-name")) { - currentAuthor += sr.readElementText() + " "; + currentAuthor += xmlData.readElementText() + " "; } } break; case QXmlStreamReader::EndElement: - if (sr.name().toString() == "title-info") + if (xmlData.name().toString() == "title-info") { inTitleInfo = false; } - else if (sr.name().toString() == "author" && inAuthor) + else if (xmlData.name().toString() == "author" && inAuthor) { meta.authors << currentAuthor.trimmed(); inAuthor = false; @@ -70,9 +84,9 @@ Fb2Metadata parseFb2Metadata(QXmlStreamReader &sr) } } - if (sr.hasError()) + if (xmlData.hasError()) { - qWarning() << "XML parsing error:" << sr.errorString(); + qWarning() << "XML parsing error:" << xmlData.errorString(); } return meta; diff --git a/src/utils/fb2extractor.h b/src/utils/fb2extractor.h new file mode 100644 index 0000000..9b33a83 --- /dev/null +++ b/src/utils/fb2extractor.h @@ -0,0 +1,36 @@ +#ifndef FB2EXTRACTOR_H +#define FB2EXTRACTOR_H + +#include "utils_global.h" + +#include +#include +#include + +#include + +struct Fb2Metadata +{ + QString title; // Название книги + QStringList authors; // Авторы + QStringList genres; // Жанры +}; + +Fb2Metadata UTILS_EXPORT parseFb2Metadata(QXmlStreamReader& sr); + +class UTILS_EXPORT FB2Extractor +{ +public: + FB2Extractor(QuaZipFile& file); + ~FB2Extractor(); + + /*! + * \brief Распарсить инфу из содержимого + */ + Fb2Metadata parse(); + +private: + QuaZipFile m_file; +}; + +#endif // FB2EXTRACTOR_H diff --git a/src/utils/utils.qbs b/src/utils/utils.qbs new file mode 100644 index 0000000..fced4a7 --- /dev/null +++ b/src/utils/utils.qbs @@ -0,0 +1,22 @@ +/*! + \qmltype cpp-opds + \inherits Project + \brief Описание +*/ +PSLibrary { + name: "utils" + cpp.defines: [ + "UTILS_LIBRARY" + ] + + Depends { name: "Qt"; submodules: [ "core" ] } + Depends { name: "quazip" } + + Group { + name: "cpp" + files: [ + "**/*.h", + "**/*.cpp", + ] + } +} diff --git a/src/utils/utils_global.h b/src/utils/utils_global.h new file mode 100644 index 0000000..7daa3fb --- /dev/null +++ b/src/utils/utils_global.h @@ -0,0 +1,12 @@ +#ifndef UTILS_GLOBAL_H +#define UTILS_GLOBAL_H + +#include + +#if defined(UTILS_LIBRARY) +#define UTILS_EXPORT Q_DECL_EXPORT +#else +#define UTILS_EXPORT Q_DECL_IMPORT +#endif + +#endif // UTILS_GLOBAL_H diff --git a/src/utils/zipwrapper.cpp b/src/utils/zipwrapper.cpp new file mode 100644 index 0000000..0822709 --- /dev/null +++ b/src/utils/zipwrapper.cpp @@ -0,0 +1,60 @@ +#include "zipwrapper.h" + +#include +#include + +// zipwrapper.cpp +#include "zipwrapper.h" + +#include + +ZipWrapper::ZipWrapper(const QString& zipFilePath) : + m_zip(new QuaZip(zipFilePath)) +{ + if (!m_zip->open(QuaZip::mdUnzip)) + { + qWarning() << "Failed to open archive:" << zipFilePath + << "Error:" << m_zip->getZipError(); + } +} + +ZipWrapper::~ZipWrapper() +{ + if (isOpen()) + { + m_zip->close(); + } +} + +QStringList ZipWrapper::getFiles() +{ + if (!isOpen()) + return {}; + return m_zip->getFileNameList(); +} + +QSharedPointer ZipWrapper::getFile(const QString& filename) +{ + QSharedPointer file(new QuaZipFile(m_zip.data())); + + if (!file->open(QIODevice::ReadOnly)) + { + qWarning() << "Failed to open file:" << filename + << "Error:" << file->getZipError(); + return nullptr; + } + + for (bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile()) + if (m_zip->getCurrentFileName() == filename) + { + auto shqzf = QSharedPointer(new QuaZipFile(m_zip.data())); + return shqzf; + }; + + return file; +} + +bool ZipWrapper::isOpen() const +{ + return m_zip && m_zip->isOpen(); +} diff --git a/src/utils/zipwrapper.h b/src/utils/zipwrapper.h new file mode 100644 index 0000000..72c5dca --- /dev/null +++ b/src/utils/zipwrapper.h @@ -0,0 +1,29 @@ +// zipwrapper.h +#ifndef ZIPWRAPPER_H +#define ZIPWRAPPER_H + +#include "utils_global.h" + +#include +#include +#include +#include + +class QuaZip; +class QuaZipFile; + +class UTILS_EXPORT ZipWrapper +{ +public: + explicit ZipWrapper(const QString& zipFilePath); + ~ZipWrapper(); + + QStringList getFiles(); + QSharedPointer getFile(const QString& filename); + bool isOpen() const; + +private: + QSharedPointer m_zip; +}; + +#endif // ZIPWRAPPER_H -- 2.49.1 From c151fdd8d11cd0f0dac8be6242b1d1fe64c7450a Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 9 Aug 2025 18:32:04 +0500 Subject: [PATCH 07/12] =?UTF-8?q?=D0=BD=D0=B0=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/project.qbs b/project.qbs index 72e9161..90f6a06 100644 --- a/project.qbs +++ b/project.qbs @@ -17,6 +17,7 @@ Project { "src/database/database.qbs", "src/model/model.qbs", "src/restapi/restapi.qbs", + "src/utils/utils.qbs", "external_libs/quazip.qbs", ] } -- 2.49.1 From 4568ef65db0f06554b703364a3491bb1c73d43e3 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 9 Aug 2025 20:49:04 +0500 Subject: [PATCH 08/12] =?UTF-8?q?=D0=9E=D0=9D=D0=9E=20=D0=A0=D0=90=D0=91?= =?UTF-8?q?=D0=9E=D0=A2=D0=90=D0=95=D0=A2=20=D1=85=D0=BE=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B8=20=D1=81=D1=82=D1=80=D1=91=D0=BC=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 82 +++--------------- src/restapi/restapiserver.cpp | 9 +- src/utils/fb2extractor.cpp | 8 ++ src/utils/fb2extractor.h | 6 +- src/utils/zipwrapper.cpp | 152 ++++++++++++++++++++++++++-------- src/utils/zipwrapper.h | 24 +++--- 6 files changed, 155 insertions(+), 126 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 088a307..3524cce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,67 +18,6 @@ #include #include -QMap readFb2MetadataFromZip(const QString& zipPath) -{ - QMap metadata; - QuaZip zip(zipPath); - - if (!zip.open(QuaZip::mdUnzip)) - { - qWarning() << "Failed to open ZIP archive"; - return metadata; - } - - int count = 0; - for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) - { - ++count; - - qWarning() << "*********" << count << "*********"; - - // Получение информации о файле - // QuaZipFileInfo fileInfo; - // if (zip.getCurrentFileInfo(&fileInfo)) - // { - // qDebug() << "File:" << fileInfo.name - // << "Size:" << fileInfo.uncompressedSize << "bytes" - // << "Compressed:" << fileInfo.compressedSize << "bytes" - // << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); - // } - - QString fb2FileName = zip.getCurrentFileName(); - qWarning() << fb2FileName; - // if (fb2FileName.isEmpty()) - // { - // qWarning() << "No FB2 file found in archive"; - // zip.close(); - // return metadata; - // } - - // // Читаем FB2 файл из архива - // // qWarning() << "Читаем FB2 файл из архива" << fb2FileName; - QuaZipFile fb2File(&zip); - // bool isOpen = fb2File.open(QIODevice::ReadOnly); - // int zipError = fb2File.getZipError(); - // if (!isOpen || zipError != UNZ_OK) - // { - // qWarning() << "Failed to open FB2 file in archive"; - // zip.close(); - // return metadata; - // } - - // // Парсим XML метаданные - // QXmlStreamReader fXmlBook(&fb2File); - // const auto data = parseFb2Metadata(fXmlBook); - - // qWarning() << data.title << data.authors << data.genres; - - // qWarning() << "*********" << count << "*********"; - } - - return metadata; -} - void fillBooksBD(uDBase& db) { try @@ -184,21 +123,20 @@ int main(int argc, char* argv[]) RestApiServer server(*db); server.start(8080); - // QString zipArzh = "f.fb2-631519-634744.zip"; QString zipArzh = "/home/alex/repos/exp/cpp-opds/f.fb2-631519-634744.zip"; - const auto books = readFb2MetadataFromZip(zipArzh); - // qWarning() << " books.count()" << books.count(); - auto z = ZipWrapper(zipArzh); - for (const auto& filename : z.getFiles()) + const auto books = z.work(); + + for (const auto& book : books) { - if (filename.endsWith(".fb2")) + try { - auto zf = z.getFile(filename).data(); - auto fb2File = FB2Extractor(*zf); - const auto book = fb2File.parse(); - // qWarning() << book.title; + addBook(*db, book.title, book.authors); + } + catch (const odb::exception& e) + { + std::cerr << "Error adding test data: " << e.what() << std::endl; } } @@ -213,6 +151,6 @@ int main(int argc, char* argv[]) // If you do not need a running Qt event loop, remove the call // to a.exec() or use the Non-Qt Plain C++ Application template. - qWarning() << "S EXIT"; + // qWarning() << "S EXIT"; return a.exec(); } diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 7d11978..88b4662 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -112,19 +112,18 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(book.id()); - // QJsonObject author; // author["id"] = QString::number(book.author()->id()); // author["fullName"] = book.author()->fullName(); // author["langCode"] = book.author()->langCode(); // j["author"] = author; - // // j["series"] = book.series()->serName(); - // // j["genre"] = book.genre()->name(); - // j["title"] = book.title(); + // j["series"] = book.series()->serName(); + // j["genre"] = book.genre()->name(); + j["title"] = book.title(); // j["year"] = book.year(); // j["lastModified"] = book.lastModified().toString(); // j["lang"] = book.lang(); - // jArray.push_back(j); + jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); t.commit(); diff --git a/src/utils/fb2extractor.cpp b/src/utils/fb2extractor.cpp index da59847..72ddb61 100644 --- a/src/utils/fb2extractor.cpp +++ b/src/utils/fb2extractor.cpp @@ -16,6 +16,14 @@ FB2Extractor::~FB2Extractor() Fb2Metadata FB2Extractor::parse() { + bool isOpen = m_file.open(QIODevice::ReadOnly); + // int zipError = fb2File.getZipError(); + if (!isOpen) + { + qWarning() << "file in extractor is not open"; + return {}; + } + QXmlStreamReader xmlData(&m_file); Fb2Metadata meta; diff --git a/src/utils/fb2extractor.h b/src/utils/fb2extractor.h index 9b33a83..8966acb 100644 --- a/src/utils/fb2extractor.h +++ b/src/utils/fb2extractor.h @@ -11,9 +11,9 @@ struct Fb2Metadata { - QString title; // Название книги - QStringList authors; // Авторы - QStringList genres; // Жанры + QString title; // Название книги + QVector authors; // Авторы + QStringList genres; // Жанры }; Fb2Metadata UTILS_EXPORT parseFb2Metadata(QXmlStreamReader& sr); diff --git a/src/utils/zipwrapper.cpp b/src/utils/zipwrapper.cpp index 0822709..c8460c4 100644 --- a/src/utils/zipwrapper.cpp +++ b/src/utils/zipwrapper.cpp @@ -1,60 +1,142 @@ #include "zipwrapper.h" -#include +#include "fb2extractor.h" + #include -// zipwrapper.cpp -#include "zipwrapper.h" +namespace +{ +Fb2Metadata parse(QuaZipFile& m_file) +{ + bool isOpen = m_file.open(QIODevice::ReadOnly); + // int zipError = fb2File.getZipError(); + if (!isOpen) + { + qWarning() << "file in extractor is not open"; + return {}; + } -#include + QXmlStreamReader xmlData(&m_file); + + Fb2Metadata meta; + QString currentElement; + bool inTitleInfo = false; + bool inAuthor = false; + QString currentAuthor; + + while (!xmlData.atEnd()) + { + switch (xmlData.readNext()) + { + case QXmlStreamReader::StartElement: + currentElement = xmlData.name().toString(); + + if (currentElement == "title-info") + { + inTitleInfo = true; + } + else if (inTitleInfo) + { + if (currentElement == "book-title") + { + meta.title = xmlData.readElementText(); + } + else if (currentElement == "genre") + { + meta.genres << xmlData.readElementText(); + } + else if (currentElement == "author") + { + inAuthor = true; + currentAuthor.clear(); + } + else if (inAuthor && (currentElement == "first-name" || currentElement == "last-name" || currentElement == "middle-name")) + { + currentAuthor += xmlData.readElementText() + " "; + } + } + break; + + case QXmlStreamReader::EndElement: + if (xmlData.name().toString() == "title-info") + { + inTitleInfo = false; + } + else if (xmlData.name().toString() == "author" && inAuthor) + { + meta.authors << currentAuthor.trimmed(); + inAuthor = false; + } + break; + + case QXmlStreamReader::Characters: + // Обработка текста уже делается в readElementText() + break; + + default: + break; + } + + // Прерываем парсинг, если нашли все метаданные + if (!meta.title.isEmpty() && !meta.authors.isEmpty() && !meta.genres.isEmpty()) + { + break; + } + } + + if (xmlData.hasError()) + { + qWarning() << "XML parsing error:" << xmlData.errorString(); + } + + return meta; +} + +} // namespace ZipWrapper::ZipWrapper(const QString& zipFilePath) : - m_zip(new QuaZip(zipFilePath)) + m_zip(zipFilePath) { - if (!m_zip->open(QuaZip::mdUnzip)) - { - qWarning() << "Failed to open archive:" << zipFilePath - << "Error:" << m_zip->getZipError(); - } + m_zip.open(QuaZip::mdUnzip); + isOpen(); } ZipWrapper::~ZipWrapper() { - if (isOpen()) - { - m_zip->close(); - } + // В любом случае закрываем архив + m_zip.close(); } -QStringList ZipWrapper::getFiles() +QVector ZipWrapper::work() { if (!isOpen()) return {}; - return m_zip->getFileNameList(); -} -QSharedPointer ZipWrapper::getFile(const QString& filename) -{ - QSharedPointer file(new QuaZipFile(m_zip.data())); - - if (!file->open(QIODevice::ReadOnly)) + // int i = 0; + QVector parsedBooks; + for (bool more = m_zip.goToFirstFile(); more; more = m_zip.goToNextFile()) { - qWarning() << "Failed to open file:" << filename - << "Error:" << file->getZipError(); - return nullptr; + // ++i; + if (m_zip.getCurrentFileName().endsWith(".fb2")) + { + QuaZipFile fb2File(&m_zip); + + auto fb2Extr = parse(fb2File); + // qWarning() << i << ":" << fb2Extr.title << fb2Extr.authors << fb2Extr.genres; + parsedBooks.push_back(fb2Extr); + } + else + qWarning() << "Неизвестный файл" << &m_zip; } - for (bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile()) - if (m_zip->getCurrentFileName() == filename) - { - auto shqzf = QSharedPointer(new QuaZipFile(m_zip.data())); - return shqzf; - }; - - return file; + return parsedBooks; } -bool ZipWrapper::isOpen() const +bool ZipWrapper::isOpen() { - return m_zip && m_zip->isOpen(); + if (m_zip.isOpen()) + return true; + + qWarning() << "Не удалось открыть архив:" << m_zip.getZipName(); + return false; } diff --git a/src/utils/zipwrapper.h b/src/utils/zipwrapper.h index 72c5dca..9052812 100644 --- a/src/utils/zipwrapper.h +++ b/src/utils/zipwrapper.h @@ -1,29 +1,31 @@ -// zipwrapper.h #ifndef ZIPWRAPPER_H #define ZIPWRAPPER_H #include "utils_global.h" -#include +#include #include -#include -#include +#include -class QuaZip; -class QuaZipFile; + + +#include +#include // TODO для совместимости. Временно + +#include "fb2extractor.h" class UTILS_EXPORT ZipWrapper { public: - explicit ZipWrapper(const QString& zipFilePath); + ZipWrapper(const QString& zipFilePath); ~ZipWrapper(); - QStringList getFiles(); - QSharedPointer getFile(const QString& filename); - bool isOpen() const; + QVector work(); private: - QSharedPointer m_zip; + bool isOpen(); + + QuaZip m_zip; }; #endif // ZIPWRAPPER_H -- 2.49.1 From b993116e094e23fd6903af94ec7f0b2f9c71b4a8 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 9 Aug 2025 22:18:32 +0500 Subject: [PATCH 09/12] =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=B2?= =?UTF-8?q?=20=D0=91=D0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project.qbs | 2 + src/model/books/book_s.h | 2 +- src/repository/bookrepository.cpp | 89 ++++++++++++++++++++++++++++++ src/repository/bookrepository.h | 40 ++++++++++++++ src/repository/repository.qbs | 33 +++++++++++ src/repository/repository_global.h | 12 ++++ src/restapi/restapi.qbs | 1 + src/restapi/restapiserver.cpp | 82 +++++++++++++-------------- src/utils/zipwrapper.h | 2 - 9 files changed, 217 insertions(+), 46 deletions(-) create mode 100644 src/repository/bookrepository.cpp create mode 100644 src/repository/bookrepository.h create mode 100644 src/repository/repository.qbs create mode 100644 src/repository/repository_global.h diff --git a/project.qbs b/project.qbs index 90f6a06..c36f82f 100644 --- a/project.qbs +++ b/project.qbs @@ -18,6 +18,8 @@ Project { "src/model/model.qbs", "src/restapi/restapi.qbs", "src/utils/utils.qbs", + "src/repository/repository.qbs", + "external_libs/quazip.qbs", ] } diff --git a/src/model/books/book_s.h b/src/model/books/book_s.h index ee83309..9622e5e 100644 --- a/src/model/books/book_s.h +++ b/src/model/books/book_s.h @@ -58,7 +58,7 @@ public: private: friend class odb::access; -// public: // for Redkit-gen + // public: // for Redkit-gen private: #pragma db id auto quint64 m_id; diff --git a/src/repository/bookrepository.cpp b/src/repository/bookrepository.cpp new file mode 100644 index 0000000..1e8778e --- /dev/null +++ b/src/repository/bookrepository.cpp @@ -0,0 +1,89 @@ +#include "bookrepository.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace repository +{ + +BookRepository::BookRepository(odb::core::database& db) : + m_db(db) +{} + +QVector BookRepository::findAll() +{ + odb::transaction t(m_db.begin()); + odb::result res(m_db.query()); + + QVector books; + + for (auto it = res.begin(); it != res.end(); ++it) + { + const auto& book = *it; + books.push_back(book); + } + + t.commit(); + + return books; +} + +Book_S BookRepository::findById(int id) +{ + odb::transaction t(m_db.begin()); + odb::result res(m_db.query(odb::query::id == id)); + + Book_S book; + res.value(book); + + t.commit(); + + return book; +} + +// void BookRepository::save(const Book_S& book) +// { +// } + +void BookRepository::remove(int id) +{ + odb::transaction t(m_db.begin()); + odb::result res(m_db.query(odb::query::id == id)); + res.one().reset(); + t.commit(); +} + +QVector BookRepository::findByAuthor(const QString& author) +{ + odb::transaction t(m_db.begin()); + auto author_s = m_db.query(odb::query::fullName == author).one(); + + QVector books; + + using ABQuery = odb::query; + using ABResult = odb::result; + ABResult abResult(m_db.query(ABQuery::author == author_s->id())); + + for (const AuthorBook_S& ab : abResult) + { + // Загружаем каждую книгу по ID + SH book(m_db.load(ab.book()->id())); + books.push_back(*book.data()); + } + + t.commit(); + + return books; +} + +} // namespace repository diff --git a/src/repository/bookrepository.h b/src/repository/bookrepository.h new file mode 100644 index 0000000..8b620c7 --- /dev/null +++ b/src/repository/bookrepository.h @@ -0,0 +1,40 @@ +#ifndef BOOKREPOSITORY_H +#define BOOKREPOSITORY_H + +#include "repository_global.h" + +#include + +#include +#include + +namespace repository +{ + +class REPOSITORY_EXPORT BookRepository +{ +public: + BookRepository(odb::core::database& db); + + // Получить все книги + QVector findAll(); + + // Найти книгу по ID + Book_S findById(int id); + + // Сохранить книгу (создать или обновить) + // void save(const Book_S& book); + + // Удалить книгу + void remove(int id); + + // Найти книги по автору + QVector findByAuthor(const QString& author); + +private: + odb::core::database& m_db; +}; + +} // namespace repository + +#endif // BOOKREPOSITORY_H diff --git a/src/repository/repository.qbs b/src/repository/repository.qbs new file mode 100644 index 0000000..f7649c8 --- /dev/null +++ b/src/repository/repository.qbs @@ -0,0 +1,33 @@ +/*! + \qmltype cpp-opds + \inherits Project + \brief Описание +*/ +PSLibrary { + name: "repository" + cpp.defines: [ + "REPOSITORY_LIBRARY" + ] + + Depends { name: "Qt"; submodules: [ "core" ] } + Depends { name: "model" } + + Depends { name: "rdbase" } + Depends { name: "odb.gen" } + Depends { name: "database" } + + Group { + name: "cpp" + files: [ + "**/*.h", + "**/*.cpp", + ] + } + + cpp.dynamicLibraries: [ + "odb-sqlite", + "odb-qt", + "odb", + "sqlite3" + ] +} diff --git a/src/repository/repository_global.h b/src/repository/repository_global.h new file mode 100644 index 0000000..b2eeb4b --- /dev/null +++ b/src/repository/repository_global.h @@ -0,0 +1,12 @@ +#ifndef REPOSITORY_GLOBAL_H +#define REPOSITORY_GLOBAL_H + +#include + +#if defined(REPOSITORY_LIBRARY) +#define REPOSITORY_EXPORT Q_DECL_EXPORT +#else +#define REPOSITORY_EXPORT Q_DECL_IMPORT +#endif + +#endif // REPOSITORY_GLOBAL_H diff --git a/src/restapi/restapi.qbs b/src/restapi/restapi.qbs index 046ae13..8bb41ac 100644 --- a/src/restapi/restapi.qbs +++ b/src/restapi/restapi.qbs @@ -19,6 +19,7 @@ WPSLibrary { Depends { name: "redkit_gen" } Depends { name: "rdbase" } Depends { name: "model" } + Depends { name: "repository" } cpp.cxxLanguageVersion: "c++20" diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 88b4662..24ebb60 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -10,6 +10,8 @@ #include // Должен быть здесь #include +#include + #include #include #include @@ -63,70 +65,64 @@ QByteArray RestApiServer::processRequest(const QString& request) if (request.startsWith("GET /books/author/")) { + repository::BookRepository b(m_db); + QString author = request.section(' ', 1, 1).section('/', 3, 3).replace("%20", " "); - // quint64 ageReq = author.toInt(); - - QStringList nameParts = author.split(' '); - QString firstName = nameParts.size() > 0 ? nameParts[0] : ""; - QString lastName = nameParts.size() > 1 ? nameParts[1] : ""; - - odb::transaction t(m_db.begin()); - - // auto books = m_db.query(odb::query::author->id == ageReq); + qWarning() << author; + auto books = b.findByAuthor(author); QJsonArray jArray; - // for (const auto& book : books) - // { - // QJsonObject j; - // j["id"] = QString::number(book.id()); + for (const auto& book : books) + { + QJsonObject j; + j["id"] = QString::number(book.id()); - // QJsonObject author; - // author["id"] = QString::number(book.author()->id()); - // author["fullName"] = book.author()->fullName(); - // author["langCode"] = book.author()->langCode(); - // j["author"] = author; - // // j["series"] = book.series()->serName(); - // // j["genre"] = book.genre()->name(); - // j["title"] = book.title(); - // j["year"] = book.year(); - // j["lastModified"] = book.lastModified().toString(); - // j["lang"] = book.lang(); - // jArray.push_back(j); - // } + j["title"] = book.title(); + + jArray.push_back(j); + } auto jDoc = QJsonDocument(jArray); - t.commit(); + return "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + jDoc.toJson(QJsonDocument::Indented); + } + + if (request.startsWith("GET /books/id")) + { + repository::BookRepository b(m_db); + + QString book_id = request.section(' ', 1, 1).section('/', 3, 3).replace("%20", " "); + qWarning() << book_id; + + auto book = b.findById(book_id.toInt()); + + QJsonObject j; + j["id"] = QString::number(book.id()); + QJsonObject author; + // // // author["id"] = QString::number(book.author()->id()); + // // // author["fullName"] = book.author()->fullName(); + // // // author["langCode"] = book.author()->langCode(); + j["author"] = author; + j["title"] = book.title(); + + auto jDoc = QJsonDocument(j); return "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + jDoc.toJson(QJsonDocument::Indented); } if (request.startsWith("GET /books")) { - odb::transaction t(m_db.begin()); - odb::result res(m_db.query()); + repository::BookRepository b(m_db); QJsonArray jArray; - for (auto it = res.begin(); it != res.end(); ++it) + for (const auto& book : b.findAll()) { - const auto& book = *it; - QJsonObject j; j["id"] = QString::number(book.id()); - // QJsonObject author; - // author["id"] = QString::number(book.author()->id()); - // author["fullName"] = book.author()->fullName(); - // author["langCode"] = book.author()->langCode(); - // j["author"] = author; - // j["series"] = book.series()->serName(); - // j["genre"] = book.genre()->name(); j["title"] = book.title(); - // j["year"] = book.year(); - // j["lastModified"] = book.lastModified().toString(); - // j["lang"] = book.lang(); + jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); - t.commit(); return "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + jDoc.toJson(QJsonDocument::Indented); } diff --git a/src/utils/zipwrapper.h b/src/utils/zipwrapper.h index 9052812..fdfcf09 100644 --- a/src/utils/zipwrapper.h +++ b/src/utils/zipwrapper.h @@ -7,8 +7,6 @@ #include #include - - #include #include // TODO для совместимости. Временно -- 2.49.1 From 78b01bc0b17fb226d174f4a0b27e8c6f4763dc97 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 10 Aug 2025 10:44:39 +0500 Subject: [PATCH 10/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D0=BC=20=D1=82=D0=B0=D0=BA=20=D0=B6=D0=B5=20=D0=B2?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D0=B2=D1=8F=D0=B7?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=83=D1=8E=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 2 +- src/repository/authorrepository.cpp | 81 +++++++++++++++++++++++++++++ src/repository/authorrepository.h | 41 +++++++++++++++ src/repository/bookrepository.cpp | 13 +++-- src/repository/bookrepository.h | 3 +- src/restapi/restapiserver.cpp | 51 ++++++++++++++---- 6 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 src/repository/authorrepository.cpp create mode 100644 src/repository/authorrepository.h diff --git a/src/main.cpp b/src/main.cpp index 3524cce..68626cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,7 +118,7 @@ int main(int argc, char* argv[]) uDBase db(openDB(dbPath)); // TODO Как-то нужно выполнять лишь раз - fillBooksBD(db); + // fillBooksBD(db); RestApiServer server(*db); server.start(8080); diff --git a/src/repository/authorrepository.cpp b/src/repository/authorrepository.cpp new file mode 100644 index 0000000..f28bc09 --- /dev/null +++ b/src/repository/authorrepository.cpp @@ -0,0 +1,81 @@ +#include "authorrepository.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace repository +{ + +AuthorRepository::AuthorRepository(odb::core::database& db) : + m_db(db) +{} + +QVector AuthorRepository::findAll() +{ + odb::transaction t(m_db.begin()); + odb::result res(m_db.query()); + + QVector authors; + + for (auto it = res.begin(); it != res.end(); ++it) + { + const auto& author = *it; + authors.push_back(author); + } + + t.commit(); + + return authors; +} + +Author_S AuthorRepository::findById(int id) +{ + odb::transaction t(m_db.begin()); + odb::result res(m_db.query(odb::query::id == id)); + + Author_S author; + res.value(author); + + t.commit(); + + return author; +} + +QVector AuthorRepository::findByBook(const int& bookId) +{ + odb::transaction t(m_db.begin()); + + QVector authors; + + using ABQuery = odb::query; + using ABResult = odb::result; + ABResult abResult(m_db.query(ABQuery::book == bookId)); + + for (const AuthorBook_S& ab : abResult) + { + // Загружаем каждую книгу по ID + SH author(m_db.load(ab.author()->id())); + authors.push_back(*author.data()); + } + t.commit(); + + return authors; +} + +QVector AuthorRepository::findByBook(const QString& book_name) +{ + odb::transaction t(m_db.begin()); + auto book_s = m_db.query(odb::query::title == book_name).one(); + + return findByBook(book_s->id()); +} + +} // namespace repository diff --git a/src/repository/authorrepository.h b/src/repository/authorrepository.h new file mode 100644 index 0000000..76c8454 --- /dev/null +++ b/src/repository/authorrepository.h @@ -0,0 +1,41 @@ +#ifndef AUTHORREPOSITORY_H +#define AUTHORREPOSITORY_H + +#include "repository_global.h" + +#include + +#include +#include + +namespace repository +{ + +class REPOSITORY_EXPORT AuthorRepository +{ +public: + AuthorRepository(odb::core::database& db); + + // Получить всех авторов + QVector findAll(); + + // Найти автора по id + Author_S findById(int id); + + // Сохранить книгу (создать или обновить) + // void save(const Book_S& book); + + // Удалить автора + // void remove(int id); + + // Найти авторов по книге + QVector findByBook(const int& book_id); + QVector findByBook(const QString& bookName); + +private: + odb::core::database& m_db; +}; + +} // namespace repository + +#endif // AUTHORREPOSITORY_H diff --git a/src/repository/bookrepository.cpp b/src/repository/bookrepository.cpp index 1e8778e..af7ddee 100644 --- a/src/repository/bookrepository.cpp +++ b/src/repository/bookrepository.cpp @@ -63,16 +63,15 @@ void BookRepository::remove(int id) t.commit(); } -QVector BookRepository::findByAuthor(const QString& author) +QVector BookRepository::findByAuthor(const int& authorId) { odb::transaction t(m_db.begin()); - auto author_s = m_db.query(odb::query::fullName == author).one(); QVector books; using ABQuery = odb::query; using ABResult = odb::result; - ABResult abResult(m_db.query(ABQuery::author == author_s->id())); + ABResult abResult(m_db.query(ABQuery::author == authorId)); for (const AuthorBook_S& ab : abResult) { @@ -86,4 +85,12 @@ QVector BookRepository::findByAuthor(const QString& author) return books; } +QVector BookRepository::findByAuthor(const QString& author) +{ + odb::transaction t(m_db.begin()); + auto author_s = m_db.query(odb::query::fullName == author).one(); + + return findByAuthor(author_s->id()); +} + } // namespace repository diff --git a/src/repository/bookrepository.h b/src/repository/bookrepository.h index 8b620c7..f1918b8 100644 --- a/src/repository/bookrepository.h +++ b/src/repository/bookrepository.h @@ -29,7 +29,8 @@ public: void remove(int id); // Найти книги по автору - QVector findByAuthor(const QString& author); + QVector findByAuthor(const QString& authorName); + QVector findByAuthor(const int& authorId); private: odb::core::database& m_db; diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 24ebb60..b84c4a2 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -10,6 +10,7 @@ #include // Должен быть здесь #include +#include #include #include @@ -76,7 +77,6 @@ QByteArray RestApiServer::processRequest(const QString& request) { QJsonObject j; j["id"] = QString::number(book.id()); - j["title"] = book.title(); jArray.push_back(j); @@ -97,11 +97,19 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(book.id()); - QJsonObject author; - // // // author["id"] = QString::number(book.author()->id()); - // // // author["fullName"] = book.author()->fullName(); - // // // author["langCode"] = book.author()->langCode(); - j["author"] = author; + QJsonArray authors; + + repository::AuthorRepository a(m_db); + + for (const auto& author : a.findByBook(book.id())) + { + QJsonObject jj; + jj["id"] = QString::number(author.id()); + jj["fullName"] = author.fullName(); + authors.push_back(jj); + } + + j["authors"] = authors; j["title"] = book.title(); auto jDoc = QJsonDocument(j); @@ -120,6 +128,17 @@ QByteArray RestApiServer::processRequest(const QString& request) j["id"] = QString::number(book.id()); j["title"] = book.title(); + QJsonArray authors; + repository::AuthorRepository a(m_db); + for (const auto& author : a.findByBook(book.id())) + { + QJsonObject jj; + jj["id"] = QString::number(author.id()); + jj["fullName"] = author.fullName(); + authors.push_back(jj); + } + j["authors"] = authors; + jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); @@ -127,10 +146,10 @@ QByteArray RestApiServer::processRequest(const QString& request) return "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + jDoc.toJson(QJsonDocument::Indented); } - if (request.startsWith("GET /author")) + if (request.startsWith("GET /authors")) { - odb::transaction t(m_db.begin()); - odb::result res(m_db.query()); + repository::AuthorRepository a(m_db); + auto res = a.findAll(); QJsonArray jArray; for (auto it = res.begin(); it != res.end(); ++it) @@ -140,11 +159,21 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(author.id()); j["fullName"] = author.fullName(); - j["langCode"] = author.langCode(); + + QJsonArray books; + repository::BookRepository b(m_db); + for (const auto& book : b.findByAuthor(author.id())) + { + QJsonObject jj; + jj["id"] = QString::number(book.id()); + jj["title"] = book.title(); + books.push_back(jj); + } + j["books"] = books; + jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); - t.commit(); return "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + jDoc.toJson(QJsonDocument::Indented); } -- 2.49.1 From b4fa718be67da9982b7351d4ec7b3c50b1e08e32 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 10 Aug 2025 12:08:49 +0500 Subject: [PATCH 11/12] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=B2=D0=B0=D0=BB=D0=B8=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85?= =?UTF-8?q?=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 38 ++++++++++++------------- src/model/books/author_s.h | 12 ++------ src/model/books/book_s.h | 48 -------------------------------- src/model/books/genre_book_s.h | 45 ++++++++++++++++++++++++++++++ src/model/books/manutomanybase.h | 10 +++++++ src/model/books/series_book_s.h | 45 ++++++++++++++++++++++++++++++ src/model/books/series_s.h | 4 +-- 7 files changed, 124 insertions(+), 78 deletions(-) create mode 100644 src/model/books/genre_book_s.h create mode 100644 src/model/books/manutomanybase.h create mode 100644 src/model/books/series_book_s.h diff --git a/src/main.cpp b/src/main.cpp index 68626cb..6c61dee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,25 +23,25 @@ void fillBooksBD(uDBase& db) try { QVector authors = { - Author_S("George Orwell", "en"), - Author_S("J.K. Rowling", "en"), - Author_S("J.R.R. Tolkien", "en"), - Author_S("Leo Tolstoy", "ru"), - Author_S("Fyodor Dostoevsky", "ru"), - Author_S("Mark Twain", "en"), - Author_S("Charles Dickens", "en"), - Author_S("Virginia Woolf", "en"), - Author_S("Ernest Hemingway", "en"), - Author_S("Gabriel García Márquez", "en"), - Author_S("Franz Kafka", "de"), - Author_S("Harper Lee", "en"), - Author_S("William Shakespeare", "en"), - Author_S("Oscar Wilde", "en"), - Author_S("Aldous Huxley", "en"), - Author_S("Jane Austen", "en"), - Author_S("John Steinbeck", "en"), - Author_S("Agatha Christie", "en"), - Author_S("Isaac Asimov", "ru"), + Author_S("George Orwell"), + Author_S("J.K. Rowling"), + Author_S("J.R.R. Tolkien"), + Author_S("Leo Tolstoy"), + Author_S("Fyodor Dostoevsky"), + Author_S("Mark Twain"), + Author_S("Charles Dickens"), + Author_S("Virginia Woolf"), + Author_S("Ernest Hemingway"), + Author_S("Gabriel García Márquez"), + Author_S("Franz Kafka"), + Author_S("Harper Lee"), + Author_S("William Shakespeare"), + Author_S("Oscar Wilde"), + Author_S("Aldous Huxley"), + Author_S("Jane Austen"), + Author_S("John Steinbeck"), + Author_S("Agatha Christie"), + Author_S("Isaac Asimov"), }; addBook(*db, "Очень странная книжка", { "Автор 1", "Автор 2", "Авторк 3" }); diff --git a/src/model/books/author_s.h b/src/model/books/author_s.h index e8d6355..1cd5d3c 100644 --- a/src/model/books/author_s.h +++ b/src/model/books/author_s.h @@ -3,19 +3,13 @@ #include -// @JsonSerializer -class Author_S; - #pragma db object class MODEL_EXPORT Author_S { public: Author_S() = default; - Author_S(const QString& fullName, - const QString& langCode) : - m_fullName(fullName), - m_langCode(langCode) - {} + Author_S(const QString& fullName) : + m_fullName(fullName) {} quint64 id() const { return m_id; } void setId(quint64 newId) { m_id = newId; } @@ -29,7 +23,7 @@ public: private: friend class odb::access; -public: // for Redkit-gen +private: #pragma db id auto quint64 m_id; diff --git a/src/model/books/book_s.h b/src/model/books/book_s.h index 9622e5e..47d4cf9 100644 --- a/src/model/books/book_s.h +++ b/src/model/books/book_s.h @@ -5,34 +5,11 @@ #include -#include "author_s.h" -#include "genre_s.h" -#include "series_s.h" - -struct Book_SZ -{ - QString title; - SH series; - quint8 year; - SH genre; - QDateTime lastModified = QDateTime::currentDateTime(); - QString lang; -}; - #pragma db object class MODEL_EXPORT Book_S { public: Book_S() = default; - Book_S(const Book_SZ& book) - { - m_title = book.title; - m_series = book.series; - m_year = book.year; - m_genre = book.genre; - m_lastModified = book.lastModified; - m_lang = book.lang; - } quint64 id() const { return m_id; } void setId(const quint64& newId) { m_id = newId; } @@ -40,15 +17,9 @@ public: QString title() const { return m_title; } void setTitle(const QString& newTitle) { m_title = newTitle; } - SH series() const { return m_series; } - void setSeries(const SH& newSeries) { m_series = newSeries; } - quint8 year() const { return m_year; } void setYear(const quint8& newYear) { m_year = newYear; } - SH genre() const { return m_genre; } - void setGenre(const SH& newGenre) { m_genre = newGenre; } - QDateTime lastModified() const { return m_lastModified; } void setLastModified(const QDateTime& newLastModified) { m_lastModified = newLastModified; } @@ -58,33 +29,14 @@ public: private: friend class odb::access; - // public: // for Redkit-gen private: #pragma db id auto quint64 m_id; QString m_title; - SH m_series; quint8 m_year; - SH m_genre; QDateTime m_lastModified; QString m_lang; }; -// #pragma db view object(Book_S) object(Author_S = author:Book_S::m_author) -// struct BookByAuthorView -// { -// #pragma db column(Book_S::m_id) -// quint64 book_id; - -// #pragma db column(Book_S::m_name) -// QString book_name; - -// #pragma db column(Book_S::m_year) -// qint8 year; - -// #pragma db column(Author_S::m_first + " " + Author_S::m_last) -// QString author_full_name; -// }; - #endif // BOOK_S_H diff --git a/src/model/books/genre_book_s.h b/src/model/books/genre_book_s.h new file mode 100644 index 0000000..e04bbc7 --- /dev/null +++ b/src/model/books/genre_book_s.h @@ -0,0 +1,45 @@ +#ifndef GENRE_BOOK_S_H +#define GENRE_BOOK_S_H + +#include + +#include "book_s.h" +#include "genre_s.h" + +#pragma db object +class GenreBook_S +{ +private: + GenreBook_S() = default; + +public: + GenreBook_S(const SH& genreId, const SH& bookId) : + m_genreId(genreId), + m_bookId(bookId) {} + + quint64 id() const { return m_id; } + void setId(quint64 newId) { m_id = newId; } + + SH genreId() const { return m_genreId; } + void setGenreId(const SH& newGenreId) { m_genreId = newGenreId; } + + SH bookId() const { return m_bookId; } + void setBookId(const SH& newBookId) { m_bookId = newBookId; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; + +#pragma db not_null + SH m_genreId; + +#pragma db not_null + SH m_bookId; + +#pragma db index("genre_book_unique") member(m_genreId) member(m_bookId) unique +}; + +#endif // GENRE_BOOK_S_H diff --git a/src/model/books/manutomanybase.h b/src/model/books/manutomanybase.h new file mode 100644 index 0000000..c894e70 --- /dev/null +++ b/src/model/books/manutomanybase.h @@ -0,0 +1,10 @@ +#ifndef MANUTOMANYBASE_H +#define MANUTOMANYBASE_H + +class ManuToManyBase +{ +public: + ManuToManyBase(); +}; + +#endif // MANUTOMANYBASE_H diff --git a/src/model/books/series_book_s.h b/src/model/books/series_book_s.h new file mode 100644 index 0000000..96ca570 --- /dev/null +++ b/src/model/books/series_book_s.h @@ -0,0 +1,45 @@ +#ifndef SERIES_BOOK_S_H +#define SERIES_BOOK_S_H + +#include + +#include "book_s.h" +#include "series_s.h" + +#pragma db object +class MODEL_EXPORT SeriesBook_S +{ +private: + SeriesBook_S() = default; + +public: + SeriesBook_S(const SH& serieId, const SH& bookId) : + m_serieId(serieId), + m_bookId(bookId) {} + + quint64 id() const { return m_id; } + void setId(quint64 newId) { m_id = newId; } + + SH serieId() const { return m_serieId; } + void setSerieId(const SH& newSerieId) { m_serieId = newSerieId; } + + SH bookId() const { return m_bookId; } + void setBookId(const SH& newBookId) { m_bookId = newBookId; } + +private: + friend class odb::access; + +private: +#pragma db id auto + quint64 m_id; + +#pragma db not_null + SH m_serieId; + +#pragma db not_null + SH m_bookId; + +#pragma db index("series_book_unique") member(m_serieId) member(m_bookId) unique +}; + +#endif // SERIES_BOOK_S_H diff --git a/src/model/books/series_s.h b/src/model/books/series_s.h index 62b2c91..83e92d2 100644 --- a/src/model/books/series_s.h +++ b/src/model/books/series_s.h @@ -12,8 +12,8 @@ public: quint64 id() const { return m_id; } void setId(const quint64& newId) { m_id = newId; } - QString serName() const { return m_serName; } - void setSerName(const QString& newSerName) { m_serName = newSerName; } + QString name() const { return m_serName; } + void setName(const QString& newSerName) { m_serName = newSerName; } private: friend class odb::access; -- 2.49.1 From 7406bcec21ada807dd3b8bfe626ef7e5b8a02eec Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 10 Aug 2025 15:30:56 +0500 Subject: [PATCH 12/12] =?UTF-8?q?=D0=A3=D0=BF=D1=80=D0=BE=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0?= =?UTF-8?q?=20=D0=BA=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=BC=20=D1=82=D0=B0?= =?UTF-8?q?=D0=B1=D0=BB=D0=B8=D1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/model/books/author_book_s.h | 1 + src/model/books/author_s.h | 1 + src/model/books/book_s.h | 1 + src/model/books/genre_book_s.h | 1 + src/model/books/genre_s.h | 1 + src/model/books/series_book_s.h | 1 + src/model/books/series_s.h | 1 + 7 files changed, 7 insertions(+) diff --git a/src/model/books/author_book_s.h b/src/model/books/author_book_s.h index a098dcc..ea131d3 100644 --- a/src/model/books/author_book_s.h +++ b/src/model/books/author_book_s.h @@ -31,6 +31,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/author_s.h b/src/model/books/author_s.h index 1cd5d3c..5912262 100644 --- a/src/model/books/author_s.h +++ b/src/model/books/author_s.h @@ -24,6 +24,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/book_s.h b/src/model/books/book_s.h index 47d4cf9..194c5a1 100644 --- a/src/model/books/book_s.h +++ b/src/model/books/book_s.h @@ -30,6 +30,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/genre_book_s.h b/src/model/books/genre_book_s.h index e04bbc7..9607e3d 100644 --- a/src/model/books/genre_book_s.h +++ b/src/model/books/genre_book_s.h @@ -30,6 +30,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/genre_s.h b/src/model/books/genre_s.h index 9b6651f..0e4d95c 100644 --- a/src/model/books/genre_s.h +++ b/src/model/books/genre_s.h @@ -19,6 +19,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/series_book_s.h b/src/model/books/series_book_s.h index 96ca570..9ef4c0f 100644 --- a/src/model/books/series_book_s.h +++ b/src/model/books/series_book_s.h @@ -30,6 +30,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; diff --git a/src/model/books/series_s.h b/src/model/books/series_s.h index 83e92d2..0df4634 100644 --- a/src/model/books/series_s.h +++ b/src/model/books/series_s.h @@ -19,6 +19,7 @@ private: friend class odb::access; private: +public: #pragma db id auto quint64 m_id; -- 2.49.1