From b9bd4372e797c041bd14391706cd66887aed18bd Mon Sep 17 00:00:00 2001 From: Mati Date: Tue, 28 May 2019 13:27:54 +0200 Subject: [PATCH] Refactor, Added ContactsTable --- module-db/CMakeLists.txt | 4 + module-db/Common/Common.hpp | 9 ++ module-db/Database/Database.hpp | 1 - module-db/Databases/ContactsDB.cpp | 29 +++++ module-db/Databases/ContactsDB.hpp | 33 +++++ module-db/Databases/SmsDB.cpp | 32 +++++ module-db/Databases/SmsDB.hpp | 37 ++++++ module-db/Tables/ContactsTable.cpp | 158 ++++++++++++++++++++++++ module-db/Tables/ContactsTable.hpp | 84 +++++++++++++ module-db/Tables/SMSTable.cpp | 58 +++++++-- module-db/Tables/SMSTable.hpp | 12 +- module-db/Tables/Table.hpp | 16 +-- module-db/Tables/ThreadsTable.cpp | 71 ++++++++--- module-db/Tables/ThreadsTable.hpp | 12 +- module-db/tests/CMakeLists.txt | 1 + module-db/tests/ContactsTable_tests.cpp | 113 +++++++++++++++++ module-db/tests/SMSTable_tests.cpp | 60 +++++---- module-db/tests/ThreadsTable_tests.cpp | 57 +++++---- 18 files changed, 691 insertions(+), 96 deletions(-) create mode 100644 module-db/Databases/ContactsDB.cpp create mode 100644 module-db/Databases/ContactsDB.hpp create mode 100644 module-db/Databases/SmsDB.cpp create mode 100644 module-db/Databases/SmsDB.hpp create mode 100644 module-db/Tables/ContactsTable.cpp create mode 100644 module-db/Tables/ContactsTable.hpp create mode 100644 module-db/tests/ContactsTable_tests.cpp diff --git a/module-db/CMakeLists.txt b/module-db/CMakeLists.txt index 964e1995f..3019c4af7 100644 --- a/module-db/CMakeLists.txt +++ b/module-db/CMakeLists.txt @@ -28,9 +28,13 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Database/sqlite3.c ${CMAKE_CURRENT_SOURCE_DIR}/Database/sqlite3vfs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Databases/ContactsDB.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Databases/SmsDB.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Tables/Table.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Tables/SMSTable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Tables/ThreadsTable.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Tables/ContactsTable.cpp ) diff --git a/module-db/Common/Common.hpp b/module-db/Common/Common.hpp index a403d4223..cd9cdc2ce 100644 --- a/module-db/Common/Common.hpp +++ b/module-db/Common/Common.hpp @@ -24,4 +24,13 @@ enum class SMSType { ALL = 0xFF }; +/** + * Types of contacts + */ +enum class ContactType { + USER = 1, + MESSAGE, + PHONE +}; + #endif //PUREPHONE_COMMON_HPP diff --git a/module-db/Database/Database.hpp b/module-db/Database/Database.hpp index d8a47242d..20956059c 100644 --- a/module-db/Database/Database.hpp +++ b/module-db/Database/Database.hpp @@ -51,7 +51,6 @@ private: protected: sqlite3 *dbConnection; const char* dbName; - }; diff --git a/module-db/Databases/ContactsDB.cpp b/module-db/Databases/ContactsDB.cpp new file mode 100644 index 000000000..75cc6fae3 --- /dev/null +++ b/module-db/Databases/ContactsDB.cpp @@ -0,0 +1,29 @@ + +/* + * @file ContactsDB.cpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#include "ContactsDB.hpp" + +const char *ContactsDB::dbName = "contacts.db"; + + +ContactsDB::ContactsDB(): + Database(dbName), + contacts(this){ + + if(contacts.Create() == false) return; + + + isInitialized = true; +} + +ContactsDB::~ContactsDB() { + +} \ No newline at end of file diff --git a/module-db/Databases/ContactsDB.hpp b/module-db/Databases/ContactsDB.hpp new file mode 100644 index 000000000..59ccca24a --- /dev/null +++ b/module-db/Databases/ContactsDB.hpp @@ -0,0 +1,33 @@ + +/* + * @file ContactsDB.hpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#ifndef PUREPHONE_CONTACTSDB_HPP +#define PUREPHONE_CONTACTSDB_HPP + +#include "Database/Database.hpp" +#include "../Tables/ContactsTable.hpp" + +class ContactsDB : public Database { +public: + ContactsDB(); + ~ContactsDB(); + + static const char* GetDBName(){return dbName;} + + ContactsTable contacts; + +private: + bool isInitialized; + static const char *dbName; +}; + + +#endif //PUREPHONE_CONTACTSDB_HPP diff --git a/module-db/Databases/SmsDB.cpp b/module-db/Databases/SmsDB.cpp new file mode 100644 index 000000000..8e58024ba --- /dev/null +++ b/module-db/Databases/SmsDB.cpp @@ -0,0 +1,32 @@ + +/* + * @file SmsDB.cpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#include "SmsDB.hpp" + + +const char *SmsDB::dbName = "sms.db"; + +SmsDB::SmsDB() : + Database(dbName), + sms(this), + threads(this), + isInitialized(false){ + + if(sms.Create() == false) return; + if(threads.Create() == false) return; + + isInitialized = true; + +} + +SmsDB::~SmsDB() { + +} \ No newline at end of file diff --git a/module-db/Databases/SmsDB.hpp b/module-db/Databases/SmsDB.hpp new file mode 100644 index 000000000..1634c8aee --- /dev/null +++ b/module-db/Databases/SmsDB.hpp @@ -0,0 +1,37 @@ + +/* + * @file SmsDB.hpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#ifndef PUREPHONE_SMSDB_HPP +#define PUREPHONE_SMSDB_HPP + +#include "Database/Database.hpp" +#include "../Tables/SMSTable.hpp" +#include "../Tables/ThreadsTable.hpp" + +class SmsDB : public Database { +public: + SmsDB(); + ~SmsDB(); + + SMSTable sms; + ThreadsTable threads; + + static const char* GetDBName(){return dbName;} + +private: + + bool isInitialized; + + static const char *dbName; +}; + + +#endif //PUREPHONE_SMSDB_HPP diff --git a/module-db/Tables/ContactsTable.cpp b/module-db/Tables/ContactsTable.cpp new file mode 100644 index 000000000..5e5683d4e --- /dev/null +++ b/module-db/Tables/ContactsTable.cpp @@ -0,0 +1,158 @@ + +/* + * @file ContactsTable.cpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#include "ContactsTable.hpp" + + +ContactsTable::ContactsTable(Database* db):db(db){ +} + +ContactsTable::~ContactsTable() { + +} + +bool ContactsTable::Create() { + return db->Execute(createTableQuery); +} + +bool ContactsTable::Add(ContactsTableRow entry) { + return db->Execute( + "insert into contacts (name_id, numbers_id, ring_id, address_ids, type, whitelist, blacklist, favourites, speeddial ) VALUES (%lu, '%s', %lu, '%s', %lu, %lu, %lu, %lu, %lu);", + entry.nameID, + entry.numbersID.c_str(), + entry.ringID, + entry.addressIDs.c_str(), + entry.type, + entry.isOnWhitelist, + entry.isOnBlacklist, + entry.isOnFavourites, + entry.speedDial + ); +} + +bool ContactsTable::RemoveByID(uint32_t id) { + return db->Execute("DELETE FROM contacts where _id = %u;", id); +} + +bool ContactsTable::Update(ContactsTableRow entry) { + return db->Execute( + "UPDATE contacts SET name_id = %lu, numbers_id = '%s' ,ring_id = %lu, address_ids = '%s', type = %lu, whitelist = %lu, blacklist = %lu, favourites = %lu, speeddial = %lu WHERE _id=%lu;", + entry.nameID, + entry.numbersID.c_str(), + entry.ringID, + entry.addressIDs.c_str(), + entry.type, + entry.isOnWhitelist, + entry.isOnBlacklist, + entry.isOnFavourites, + entry.speedDial, + entry.ID + ); +} + +ContactsTableRow ContactsTable::GetByID(uint32_t id) { + auto retQuery = db->Query("SELECT * FROM contacts WHERE _id= %u;", id); + + if (retQuery->GetRowCount() == 0) { + return ContactsTableRow(); + } + + return ContactsTableRow{(*retQuery)[0].GetUInt32(), // ID + (*retQuery)[1].GetUInt32(), // nameID + (*retQuery)[2].GetString(), // numbersID + (*retQuery)[3].GetUInt32(), // ringID + (*retQuery)[4].GetString(), // addressID + static_cast((*retQuery)[5].GetUInt32()), // type + (*retQuery)[6].GetBool(), // is on whitelist + (*retQuery)[7].GetBool(), // is on blacklist + (*retQuery)[8].GetBool(), // is on favourites + (*retQuery)[9].GetUInt32(), // speed dial key + }; +} + +std::vector ContactsTable::GetLimitOffset(uint32_t offset, uint32_t limit) { + auto retQuery = db->Query("SELECT * from contacts ORDER BY name_id LIMIT %lu OFFSET %lu;", + limit, + offset); + + if (retQuery->GetRowCount() == 0) { + return std::vector(); + } + + std::vector ret; + + do { + ret.push_back(ContactsTableRow{(*retQuery)[0].GetUInt32(), // ID + (*retQuery)[1].GetUInt32(), // nameID + (*retQuery)[2].GetString(), // numbersID + (*retQuery)[3].GetUInt32(), // ringID + (*retQuery)[4].GetString(), // addressID + static_cast((*retQuery)[5].GetUInt32()), // type + (*retQuery)[6].GetBool(), // is on whitelist + (*retQuery)[7].GetBool(), // is on blacklist + (*retQuery)[8].GetBool(), // is on favourites + (*retQuery)[9].GetUInt32(), // speed dial key + }); + } while (retQuery->NextRow()); + + return ret; +} + +std::vector ContactsTable::GetLimitOffsetByFieldID(uint32_t offset, uint32_t limit, const char *field, + uint32_t id) { + auto retQuery = db->Query("SELECT * from contacts WHERE %s=%lu ORDER BY name_id LIMIT %lu OFFSET %lu;", + field, + id, + limit, + offset); + + if (retQuery->GetRowCount() == 0) { + return std::vector(); + } + + std::vector ret; + + do { + ret.push_back(ContactsTableRow{(*retQuery)[0].GetUInt32(), // ID + (*retQuery)[1].GetUInt32(), // nameID + (*retQuery)[2].GetString(), // numbersID + (*retQuery)[3].GetUInt32(), // ringID + (*retQuery)[4].GetString(), // addressID + static_cast((*retQuery)[5].GetUInt32()), // type + (*retQuery)[6].GetBool(), // is on whitelist + (*retQuery)[7].GetBool(), // is on blacklist + (*retQuery)[8].GetBool(), // is on favourites + (*retQuery)[9].GetUInt32(), // speed dial key + }); + } while (retQuery->NextRow()); + + return ret; +} + +uint32_t ContactsTable::GetCount() { + auto queryRet = db->Query("SELECT COUNT(*) FROM contacts;"); + + if (queryRet->GetRowCount() == 0) { + return 0; + } + + return uint32_t{(*queryRet)[0].GetUInt32()}; +} + +uint32_t ContactsTable::GetCountByFieldID(const char *field, uint32_t id) { + auto queryRet = db->Query("SELECT COUNT(*) FROM contacts WHERE %s=%lu;",field,id); + + if ((queryRet == nullptr) || (queryRet->GetRowCount() == 0)) { + return 0; + } + + return uint32_t{(*queryRet)[0].GetUInt32()}; +} \ No newline at end of file diff --git a/module-db/Tables/ContactsTable.hpp b/module-db/Tables/ContactsTable.hpp new file mode 100644 index 000000000..f8e80a1ff --- /dev/null +++ b/module-db/Tables/ContactsTable.hpp @@ -0,0 +1,84 @@ + +/* + * @file ContactsTable.hpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#ifndef PUREPHONE_CONTACTSTABLE_HPP +#define PUREPHONE_CONTACTSTABLE_HPP + + +#include +#include "Table.hpp" +#include "Database/Database.hpp" +#include "utf8/UTF8.hpp" +#include "Common/Common.hpp" + +struct ContactsTableRow { + uint32_t ID; + uint32_t nameID; + std::string numbersID; + uint32_t ringID; + std::string addressIDs; + ContactType type; + bool isOnWhitelist; + bool isOnBlacklist; + bool isOnFavourites; + uint32_t speedDial; +}; + + +class ContactsTable : public Table { +public: + + ContactsTable(Database* db); + + ~ContactsTable(); + + bool Create() override final; + + bool Add(ContactsTableRow entry) override final; + + bool RemoveByID(uint32_t id) override final; + + bool Update(ContactsTableRow entry) override final; + + ContactsTableRow GetByID(uint32_t id) override final; + + std::vector GetLimitOffset(uint32_t offset, uint32_t limit) override final; + + std::vector + GetLimitOffsetByFieldID(uint32_t offset, uint32_t limit, const char *field, uint32_t id) override final; + + uint32_t GetCount() override final; + + uint32_t GetCountByFieldID(const char *field, uint32_t id) override final; + +private: + + const char *createTableQuery = + "CREATE TABLE IF NOT EXISTS contacts(" + "_id INTEGER PRIMARY KEY," + "name_id INTEGER," + "numbers_id TEXT NOT NULL," + "ring_id INTEGER," + "address_ids TEXT NOT NULL," + "type INTEGER," + "whitelist INTEGER," + "blacklist INTEGER," + "favourites INTEGER," + "speeddial INTEGER," + "FOREIGN KEY(name_id) REFERENCES contact_names(_id) FOREIGN KEY(ring_id) REFERENCES contact_ring(_id)" + ");"; + + Database* db; + +}; + + +#endif //PUREPHONE_CONTACTSTABLE_HPP diff --git a/module-db/Tables/SMSTable.cpp b/module-db/Tables/SMSTable.cpp index 0feac54ef..dfe50770c 100644 --- a/module-db/Tables/SMSTable.cpp +++ b/module-db/Tables/SMSTable.cpp @@ -12,17 +12,19 @@ #include "SMSTable.hpp" -SMSTable::SMSTable() : - Table(dbName) { - isInitialized = db.Execute(createTableQuery); +SMSTable::SMSTable(Database* db): db(db){ } SMSTable::~SMSTable() { } +bool SMSTable::Create() { + return db->Execute(createTableQuery); +} + bool SMSTable::Add(SMSTableRow entry) { - return db.Execute( + return db->Execute( "INSERT INTO sms ( thread_id,contact_id, date, date_send, error_code, body, read, type ) VALUES (%lu,%lu,%lu,%lu,0,'%s',%d,%d);", entry.threadID, entry.contactID, @@ -35,12 +37,12 @@ bool SMSTable::Add(SMSTableRow entry) { } bool SMSTable::RemoveByID(uint32_t id) { - return db.Execute("DELETE FROM sms where _id = %u;", id); + return db->Execute("DELETE FROM sms where _id = %u;", id); } bool SMSTable::Update(SMSTableRow entry) { - return db.Execute( + return db->Execute( "UPDATE sms SET thread_id = %lu, contact_id = %lu ,date = %lu, date_send = %lu, error_code = 0, body = '%s', read = %d, type =%d WHERE _id=%lu;", entry.threadID, entry.contactID, @@ -54,7 +56,7 @@ bool SMSTable::Update(SMSTableRow entry) { } SMSTableRow SMSTable::GetByID(uint32_t id) { - auto retQuery = db.Query("SELECT * FROM sms WHERE _id= %u;", id); + auto retQuery = db->Query("SELECT * FROM sms WHERE _id= %u;", id); if (retQuery->GetRowCount() == 0) { return SMSTableRow(); @@ -74,7 +76,36 @@ SMSTableRow SMSTable::GetByID(uint32_t id) { std::vector SMSTable::GetLimitOffset(uint32_t offset, uint32_t limit) { - auto retQuery = db.Query("SELECT * from sms ORDER BY date LIMIT %lu OFFSET %lu;", + auto retQuery = db->Query("SELECT * from sms ORDER BY date LIMIT %lu OFFSET %lu;", + limit, + offset); + + if (retQuery->GetRowCount() == 0) { + return std::vector(); + } + + std::vector ret; + + do { + ret.push_back(SMSTableRow{(*retQuery)[0].GetUInt32(), // ID + (*retQuery)[1].GetUInt32(), // threadID + (*retQuery)[2].GetUInt32(), // contactID + (*retQuery)[3].GetUInt32(), // date + (*retQuery)[4].GetUInt32(), // dateSent + (*retQuery)[5].GetUInt32(), // errorCode + (*retQuery)[6].GetString(), // body + (*retQuery)[7].GetBool(), // isRead + static_cast((*retQuery)[8].GetUInt32()), // type + }); + } while (retQuery->NextRow()); + + return ret; +} + +std::vector SMSTable::GetLimitOffsetByFieldID(uint32_t offset, uint32_t limit, const char *field, uint32_t id) { + auto retQuery = db->Query("SELECT * from sms WHERE %s=%lu ORDER BY date LIMIT %lu OFFSET %lu;", + field, + id, limit, offset); @@ -101,7 +132,7 @@ std::vector SMSTable::GetLimitOffset(uint32_t offset, uint32_t limi } uint32_t SMSTable::GetCount() { - auto queryRet = db.Query("SELECT COUNT(*) FROM SMS;"); + auto queryRet = db->Query("SELECT COUNT(*) FROM SMS;"); if (queryRet->GetRowCount() == 0) { return 0; @@ -110,5 +141,12 @@ uint32_t SMSTable::GetCount() { return uint32_t{(*queryRet)[0].GetUInt32()}; } +uint32_t SMSTable::GetCountByFieldID(const char *field, uint32_t id) { + auto queryRet = db->Query("SELECT COUNT(*) FROM sms WHERE %s=%lu;",field,id); -const char *SMSTable::dbName = "sms.db"; \ No newline at end of file + if ((queryRet == nullptr) || (queryRet->GetRowCount() == 0)) { + return 0; + } + + return uint32_t{(*queryRet)[0].GetUInt32()}; +} diff --git a/module-db/Tables/SMSTable.hpp b/module-db/Tables/SMSTable.hpp index 2f1c9e808..e710d9df2 100644 --- a/module-db/Tables/SMSTable.hpp +++ b/module-db/Tables/SMSTable.hpp @@ -33,20 +33,20 @@ struct SMSTableRow{ class SMSTable : public Table { public: - SMSTable(); + SMSTable(Database* db); ~SMSTable(); + bool Create() override final; bool Add(SMSTableRow entry) override final; bool RemoveByID(uint32_t id) override final; bool Update(SMSTableRow entry) override final; SMSTableRow GetByID(uint32_t id) override final; - std::vector GetLimitOffset(uint32_t offset,uint32_t limit); + std::vector GetLimitOffset(uint32_t offset,uint32_t limit) override final; + std::vector GetLimitOffsetByFieldID(uint32_t offset,uint32_t limit,const char* field,uint32_t id) override final; uint32_t GetCount() override final; + uint32_t GetCountByFieldID(const char* field,uint32_t id) override final; - static const char* GetDBName(){ - return dbName; - } private: const char* createTableQuery = @@ -62,7 +62,7 @@ private: "type INTEGER," "FOREIGN KEY(thread_id) REFERENCES threads(_id) ON DELETE CASCADE );"; - static const char* dbName; + Database* db; }; diff --git a/module-db/Tables/Table.hpp b/module-db/Tables/Table.hpp index fdf317f3d..78b0f8ad0 100644 --- a/module-db/Tables/Table.hpp +++ b/module-db/Tables/Table.hpp @@ -19,29 +19,21 @@ template class Table { - bool IsInitialized(){return isInitialized;} - protected: - Table(const char* name): - db(name), - isInitialized(false){ - - } + Table(){} ~Table(){} + virtual bool Create() = 0; virtual bool Add(T entry) = 0; virtual bool RemoveByID(uint32_t id) = 0; virtual bool Update(T entry) = 0; virtual T GetByID(uint32_t id) = 0; virtual std::vector GetLimitOffset(uint32_t offset,uint32_t limit) = 0; + virtual std::vector GetLimitOffsetByFieldID(uint32_t offset,uint32_t limit,const char* field,uint32_t id) = 0; virtual uint32_t GetCount() = 0; - - - Database db; - - bool isInitialized; + virtual uint32_t GetCountByFieldID(const char* field,uint32_t id) = 0; }; diff --git a/module-db/Tables/ThreadsTable.cpp b/module-db/Tables/ThreadsTable.cpp index 674bc6507..608d088d4 100644 --- a/module-db/Tables/ThreadsTable.cpp +++ b/module-db/Tables/ThreadsTable.cpp @@ -12,24 +12,27 @@ #include "ThreadsTable.hpp" -ThreadsTable::ThreadsTable() : - Table(dbName) { - // Create necessary tables - isInitialized |= db.Execute(createTableQuery); - isInitialized |= db.Execute(createTableThreadsCounterQuery); - isInitialized |= db.Execute(threadsCounterInsertionQuery); - isInitialized |= db.Execute(threadInsertTriggerQuery); - isInitialized |= db.Execute(threadRemoveTriggerQuery); - +ThreadsTable::ThreadsTable(Database* db):db(db){ } ThreadsTable::~ThreadsTable() { } +bool ThreadsTable::Create() { + // Create necessary tables + if(db->Execute(createTableQuery) == false) return false; + if(db->Execute(createTableThreadsCounterQuery)) return false; + if(db->Execute(threadsCounterInsertionQuery)) return false; + if(db->Execute(threadInsertTriggerQuery)) return false; + if(db->Execute(threadRemoveTriggerQuery)) return false; + + return true; +} + bool ThreadsTable::Add(ThreadsTableRow entry) { - return db.Execute( + return db->Execute( "INSERT INTO threads ( date, msg_count, read, contact_id, snippet, last_dir ) VALUES ( %lu, 0, 0, %lu, '%s', %lu );", entry.date, entry.contactID, @@ -39,11 +42,11 @@ bool ThreadsTable::Add(ThreadsTableRow entry) { } bool ThreadsTable::RemoveByID(uint32_t id) { - return db.Execute("DELETE FROM threads where _id = %u;", id); + return db->Execute("DELETE FROM threads where _id = %u;", id); } bool ThreadsTable::Update(ThreadsTableRow entry) { - return db.Execute( + return db->Execute( "UPDATE threads SET date = %lu, msg_count = %lu ,read = %lu, contact_id = %lu, snippet = '%s', last_dir = %lu WHERE _id=%lu;", entry.date, entry.msgCount, @@ -56,7 +59,7 @@ bool ThreadsTable::Update(ThreadsTableRow entry) { } ThreadsTableRow ThreadsTable::GetByID(uint32_t id) { - auto retQuery = db.Query("SELECT * FROM threads WHERE _id= %u;", id); + auto retQuery = db->Query("SELECT * FROM threads WHERE _id= %u;", id); if (retQuery->GetRowCount() == 0) { return ThreadsTableRow(); @@ -74,7 +77,7 @@ ThreadsTableRow ThreadsTable::GetByID(uint32_t id) { std::vector ThreadsTable::GetLimitOffset(uint32_t offset, uint32_t limit) { - auto retQuery = db.Query("SELECT * from threads ORDER BY date LIMIT %lu OFFSET %lu;", + auto retQuery = db->Query("SELECT * from threads ORDER BY date LIMIT %lu OFFSET %lu;", limit, offset); @@ -98,8 +101,37 @@ std::vector ThreadsTable::GetLimitOffset(uint32_t offset, uint3 return ret; } +std::vector ThreadsTable::GetLimitOffsetByFieldID(uint32_t offset, uint32_t limit, const char *field, + uint32_t id) { + auto retQuery = db->Query("SELECT * from threads WHERE %s=%lu ORDER BY date LIMIT %lu OFFSET %lu;", + field, + id, + limit, + offset); + + if (retQuery->GetRowCount() == 0) { + return std::vector(); + } + + std::vector ret; + + do { + ret.push_back(ThreadsTableRow{(*retQuery)[0].GetUInt32(), // ID + (*retQuery)[1].GetUInt32(), // date + (*retQuery)[2].GetUInt32(), // msgCount + (*retQuery)[3].GetUInt32(), // msgRead + (*retQuery)[4].GetUInt32(), // contactID + (*retQuery)[5].GetString(), // snippet + static_cast((*retQuery)[6].GetUInt32()), // type/last-dir + }); + } while (retQuery->NextRow()); + + return ret; + +} + uint32_t ThreadsTable::GetCount() { - auto queryRet = db.Query("SELECT COUNT(*) FROM threads;"); + auto queryRet = db->Query("SELECT COUNT(*) FROM threads;"); if (queryRet->GetRowCount() == 0) { return 0; @@ -108,5 +140,12 @@ uint32_t ThreadsTable::GetCount() { return uint32_t{(*queryRet)[0].GetUInt32()}; } +uint32_t ThreadsTable::GetCountByFieldID(const char *field, uint32_t id) { + auto queryRet = db->Query("SELECT COUNT(*) FROM threads WHERE %s=%u;",field,id); -const char *ThreadsTable::dbName = "threads.db"; \ No newline at end of file + if ((queryRet == nullptr) || (queryRet->GetRowCount() == 0)) { + return 0; + } + + return uint32_t{(*queryRet)[0].GetUInt32()}; +} diff --git a/module-db/Tables/ThreadsTable.hpp b/module-db/Tables/ThreadsTable.hpp index 482809741..c34e9fca8 100644 --- a/module-db/Tables/ThreadsTable.hpp +++ b/module-db/Tables/ThreadsTable.hpp @@ -30,20 +30,20 @@ struct ThreadsTableRow{ class ThreadsTable : public Table { public: - ThreadsTable(); + ThreadsTable(Database* db); ~ThreadsTable(); + bool Create() override final; bool Add(ThreadsTableRow entry) override final; bool RemoveByID(uint32_t id) override final; bool Update(ThreadsTableRow entry) override final; ThreadsTableRow GetByID(uint32_t id) override final; - std::vector GetLimitOffset(uint32_t offset,uint32_t limit); + std::vector GetLimitOffset(uint32_t offset,uint32_t limit) override final; + std::vector GetLimitOffsetByFieldID(uint32_t offset,uint32_t limit,const char* field,uint32_t id) override final; uint32_t GetCount() override final; + uint32_t GetCountByFieldID(const char* field,uint32_t id) override final; - static const char* GetDBName(){ - return dbName; - } private: const char* createTableQuery = @@ -66,7 +66,7 @@ private: const char* threadInsertTriggerQuery = "CREATE TRIGGER IF NOT EXISTS on_thread_insert AFTER INSERT ON threads BEGIN UPDATE threads_count SET count=count+1 WHERE _id=1; END"; const char* threadRemoveTriggerQuery = "CREATE TRIGGER IF NOT EXISTS on_thread_remove AFTER DELETE ON threads BEGIN UPDATE threads_count SET count=count-1 WHERE _id=1; END"; - static const char* dbName; + Database* db; }; diff --git a/module-db/tests/CMakeLists.txt b/module-db/tests/CMakeLists.txt index 60e9cf58c..d724d3f30 100644 --- a/module-db/tests/CMakeLists.txt +++ b/module-db/tests/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable( ${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/tests-main.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/SMSTable_tests.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ThreadsTable_tests.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ContactsTable_tests.cpp" ) target_link_libraries( ${PROJECT_NAME} PRIVATE module-db ) diff --git a/module-db/tests/ContactsTable_tests.cpp b/module-db/tests/ContactsTable_tests.cpp new file mode 100644 index 000000000..744f0529b --- /dev/null +++ b/module-db/tests/ContactsTable_tests.cpp @@ -0,0 +1,113 @@ + +/* + * @file ContactsTable_tests.cpp + * @author Mateusz Piesta (mateusz.piesta@mudita.com) + * @date 28.05.19 + * @brief + * @copyright Copyright (C) 2019 mudita.com + * @details + */ + + +#include "vfs.hpp" + +#include "catch.hpp" + +#include +#include +#include +#include + +#include + +#include "../Database/Database.hpp" +#include "../Databases/ContactsDB.hpp" + +#include "Tables/ContactsTable.hpp" + +TEST_CASE("Contacts Table tests") +{ + Database::Initialize(); + + vfs.remove(ContactsDB::GetDBName()); + + ContactsDB contactsdb; + + ContactsTableRow testRow1 = {.ID=0, + .nameID=0, + .numbersID="0 1 2 3 4", + .ringID=0, + .addressIDs="5 6 7 8", + .type=ContactType ::PHONE, + .isOnWhitelist=true, + .isOnBlacklist=true, + .isOnFavourites=false, + .speedDial = 666 + + }; + + // Add 4 elements into table + REQUIRE(contactsdb.contacts.Add(testRow1)); + REQUIRE(contactsdb.contacts.Add(testRow1)); + REQUIRE(contactsdb.contacts.Add(testRow1)); + REQUIRE(contactsdb.contacts.Add(testRow1)); + + // Table should have 4 elements + REQUIRE(contactsdb.contacts.GetCount() == 4); + + // Update existing element in table + testRow1.ID = 4; + testRow1.speedDial = 777; + REQUIRE(contactsdb.contacts.Update(testRow1)); + + // Get table row using valid ID & check if it was updated + auto sms = contactsdb.contacts.GetByID(4); + REQUIRE(sms.speedDial == testRow1.speedDial); + + // Get table row using invalid ID(should return empty contactsdb.contactsRow) + auto smsFailed = contactsdb.contacts.GetByID(100); + REQUIRE(smsFailed.speedDial == 0); + + // Get table rows using valid offset/limit parameters + auto retOffsetLimit = contactsdb.contacts.GetLimitOffset(0,4); + REQUIRE(retOffsetLimit.size() == 4); + + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(contactsdb.contacts.GetLimitOffsetByFieldID(0,4,"type", static_cast(ContactType::PHONE)).size() == 4); + + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(contactsdb.contacts.GetLimitOffsetByFieldID(0,4,"type", static_cast(ContactType::USER)).size() == 0); + + // Get table rows using invalid limit parameters(should return 4 elements instead of 100) + auto retOffsetLimitBigger = contactsdb.contacts.GetLimitOffset(0,100); + REQUIRE(retOffsetLimitBigger.size() == 4); + + // Get table rows using invalid offset/limit parameters(should return empty object) + auto retOffsetLimitFailed = contactsdb.contacts.GetLimitOffset(5,4); + REQUIRE(retOffsetLimitFailed.size() == 0); + + // Get count of elements by field's ID + REQUIRE(contactsdb.contacts.GetCountByFieldID("ring_id",0) == 4); + + // Get count of elements by invalid field's ID + REQUIRE(contactsdb.contacts.GetCountByFieldID("invalid_field",0) == 0); + + + REQUIRE(contactsdb.contacts.RemoveByID(2)); + + // Table should have now 3 elements + REQUIRE(contactsdb.contacts.GetCount() == 3); + + // Remove non existing element + REQUIRE(contactsdb.contacts.RemoveByID(100)); + + // Remove all elements from table + REQUIRE(contactsdb.contacts.RemoveByID(1)); + REQUIRE(contactsdb.contacts.RemoveByID(3)); + REQUIRE(contactsdb.contacts.RemoveByID(4)); + + // Table should be empty now + REQUIRE(contactsdb.contacts.GetCount() == 0); + + Database::Deinitialize(); +} \ No newline at end of file diff --git a/module-db/tests/SMSTable_tests.cpp b/module-db/tests/SMSTable_tests.cpp index ef87f271c..4b524dddb 100644 --- a/module-db/tests/SMSTable_tests.cpp +++ b/module-db/tests/SMSTable_tests.cpp @@ -1,6 +1,6 @@ /* - * @file SMSTable_tests.cpp + * @file smsdb.sms_tests.cpp * @author Mateusz Piesta (mateusz.piesta@mudita.com) * @date 28.05.19 * @brief @@ -21,6 +21,7 @@ #include #include "../Database/Database.hpp" +#include "../Databases/SmsDB.hpp" #include "Tables/SMSTable.hpp" @@ -28,9 +29,9 @@ TEST_CASE("SMS Table tests") { Database::Initialize(); - vfs.remove(SMSTable::GetDBName()); + vfs.remove(SmsDB::GetDBName()); - SMSTable smstable; + SmsDB smsdb; SMSTableRow testRow1 = {.ID=0, .threadID=0, @@ -45,54 +46,67 @@ TEST_CASE("SMS Table tests") }; // Add 4 elements into table - REQUIRE(smstable.Add(testRow1)); - REQUIRE(smstable.Add(testRow1)); - REQUIRE(smstable.Add(testRow1)); - REQUIRE(smstable.Add(testRow1)); + REQUIRE(smsdb.sms.Add(testRow1)); + REQUIRE(smsdb.sms.Add(testRow1)); + REQUIRE(smsdb.sms.Add(testRow1)); + REQUIRE(smsdb.sms.Add(testRow1)); // Table should have 4 elements - REQUIRE(smstable.GetCount() == 4); + REQUIRE(smsdb.sms.GetCount() == 4); // Update existing element in table testRow1.ID = 4; testRow1.body = "Updated Test SMS message "; - REQUIRE(smstable.Update(testRow1)); + REQUIRE(smsdb.sms.Update(testRow1)); // Get table row using valid ID & check if it was updated - auto sms = smstable.GetByID(4); + auto sms = smsdb.sms.GetByID(4); REQUIRE(sms.body == testRow1.body); - // Get table row using invalid ID(should return empty SMSTableRow) - auto smsFailed = smstable.GetByID(100); + // Get table row using invalid ID(should return empty smsdb.smsRow) + auto smsFailed = smsdb.sms.GetByID(100); REQUIRE(smsFailed.body == ""); // Get table rows using valid offset/limit parameters - auto retOffsetLimit = smstable.GetLimitOffset(0,4); + auto retOffsetLimit = smsdb.sms.GetLimitOffset(0,4); REQUIRE(retOffsetLimit.size() == 4); + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(smsdb.sms.GetLimitOffsetByFieldID(0,4,"type", static_cast(SMSType::INBOX)).size() == 4); + + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(smsdb.sms.GetLimitOffsetByFieldID(0,4,"type", static_cast(SMSType::ALL)).size() == 0); + // Get table rows using invalid limit parameters(should return 4 elements instead of 100) - auto retOffsetLimitBigger = smstable.GetLimitOffset(0,100); + auto retOffsetLimitBigger = smsdb.sms.GetLimitOffset(0,100); REQUIRE(retOffsetLimitBigger.size() == 4); // Get table rows using invalid offset/limit parameters(should return empty object) - auto retOffsetLimitFailed = smstable.GetLimitOffset(5,4); + auto retOffsetLimitFailed = smsdb.sms.GetLimitOffset(5,4); REQUIRE(retOffsetLimitFailed.size() == 0); - REQUIRE(smstable.RemoveByID(2)); + // Get count of elements by field's ID + REQUIRE(smsdb.sms.GetCountByFieldID("thread_id",0) == 4); + + // Get count of elements by invalid field's ID + REQUIRE(smsdb.sms.GetCountByFieldID("invalid_field",0) == 0); + + + REQUIRE(smsdb.sms.RemoveByID(2)); // Table should have now 3 elements - REQUIRE(smstable.GetCount() == 3); + REQUIRE(smsdb.sms.GetCount() == 3); // Remove non existing element - REQUIRE(smstable.RemoveByID(100)); + REQUIRE(smsdb.sms.RemoveByID(100)); // Remove all elements from table - REQUIRE(smstable.RemoveByID(1)); - REQUIRE(smstable.RemoveByID(3)); - REQUIRE(smstable.RemoveByID(4)); + REQUIRE(smsdb.sms.RemoveByID(1)); + REQUIRE(smsdb.sms.RemoveByID(3)); + REQUIRE(smsdb.sms.RemoveByID(4)); - // Table should have be empty now - REQUIRE(smstable.GetCount() == 0); + // Table should be empty now + REQUIRE(smsdb.sms.GetCount() == 0); Database::Deinitialize(); } \ No newline at end of file diff --git a/module-db/tests/ThreadsTable_tests.cpp b/module-db/tests/ThreadsTable_tests.cpp index 16d094134..3cf63b69c 100644 --- a/module-db/tests/ThreadsTable_tests.cpp +++ b/module-db/tests/ThreadsTable_tests.cpp @@ -21,6 +21,7 @@ #include #include "../Database/Database.hpp" +#include "../Databases/SmsDB.hpp" #include "Tables/ThreadsTable.hpp" @@ -28,9 +29,9 @@ TEST_CASE("Threads Table tests") { Database::Initialize(); - vfs.remove(ThreadsTable::GetDBName()); - - ThreadsTable threadstable; + vfs.remove(SmsDB::GetDBName()); + + SmsDB smsdb; ThreadsTableRow testRow1 = {.ID=0, .date=0, @@ -43,54 +44,66 @@ TEST_CASE("Threads Table tests") }; // Add 4 elements into table - REQUIRE(threadstable.Add(testRow1)); - REQUIRE(threadstable.Add(testRow1)); - REQUIRE(threadstable.Add(testRow1)); - REQUIRE(threadstable.Add(testRow1)); + REQUIRE(smsdb.threads.Add(testRow1)); + REQUIRE(smsdb.threads.Add(testRow1)); + REQUIRE(smsdb.threads.Add(testRow1)); + REQUIRE(smsdb.threads.Add(testRow1)); // Table should have 4 elements - REQUIRE(threadstable.GetCount() == 4); + REQUIRE(smsdb.threads.GetCount() == 4); // Update existing element in table testRow1.ID = 4; testRow1.snippet = "Updated Test snippet"; - REQUIRE(threadstable.Update(testRow1)); + REQUIRE(smsdb.threads.Update(testRow1)); // Get table row using valid ID & check if it was updated - auto thread = threadstable.GetByID(4); + auto thread = smsdb.threads.GetByID(4); REQUIRE(thread.snippet == testRow1.snippet); // Get table row using invalid ID(should return empty SMSTableRow) - auto threadFailed = threadstable.GetByID(100); + auto threadFailed = smsdb.threads.GetByID(100); REQUIRE(threadFailed.snippet == ""); // Get table rows using valid offset/limit parameters - auto retOffsetLimit = threadstable.GetLimitOffset(0,4); + auto retOffsetLimit = smsdb.threads.GetLimitOffset(0,4); REQUIRE(retOffsetLimit.size() == 4); // Get table rows using invalid limit parameters(should return 4 elements instead of 100) - auto retOffsetLimitBigger = threadstable.GetLimitOffset(0,100); + auto retOffsetLimitBigger = smsdb.threads.GetLimitOffset(0,100); REQUIRE(retOffsetLimitBigger.size() == 4); // Get table rows using invalid offset/limit parameters(should return empty object) - auto retOffsetLimitFailed = threadstable.GetLimitOffset(5,4); + auto retOffsetLimitFailed = smsdb.threads.GetLimitOffset(5,4); REQUIRE(retOffsetLimitFailed.size() == 0); - REQUIRE(threadstable.RemoveByID(2)); + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(smsdb.threads.GetLimitOffsetByFieldID(0,4,"msg_count",0).size() == 4); + + // Get table rows using valid offset/limit parameters and specific field's ID + REQUIRE(smsdb.threads.GetLimitOffsetByFieldID(0,4,"contact_id",5).size() == 0); + + // Get count of elements by field's ID + REQUIRE(smsdb.threads.GetCountByFieldID("contact_id",0) == 4); + + // Get count of elements by invalid field's ID + REQUIRE(smsdb.threads.GetCountByFieldID("invalid_field",0) == 0); + + REQUIRE(smsdb.threads.RemoveByID(2)); // Table should have now 3 elements - REQUIRE(threadstable.GetCount() == 3); + REQUIRE(smsdb.threads.GetCount() == 3); // Remove non existing element - REQUIRE(threadstable.RemoveByID(100)); + REQUIRE(smsdb.threads.RemoveByID(100)); // Remove all elements from table - REQUIRE(threadstable.RemoveByID(1)); - REQUIRE(threadstable.RemoveByID(3)); - REQUIRE(threadstable.RemoveByID(4)); + REQUIRE(smsdb.threads.RemoveByID(1)); + REQUIRE(smsdb.threads.RemoveByID(3)); + REQUIRE(smsdb.threads.RemoveByID(4)); - // Table should have be empty now - REQUIRE(threadstable.GetCount() == 0); + // Table should be empty now + REQUIRE(smsdb.threads.GetCount() == 0); Database::Deinitialize(); } \ No newline at end of file