~aleteoryx/muditaos

88939f8209c7d80252a49cce9fda48ce9384f17e — PrzeBrudny 5 years ago a59fe8f
[EGD-4070] Messages listView sync db queries refactored to full async. (#837)

49 files changed, 675 insertions(+), 417 deletions(-)

M module-apps/application-messages/ApplicationMessages.cpp
M module-apps/application-messages/CMakeLists.txt
M module-apps/application-messages/models/BaseThreadsRecordModel.cpp
M module-apps/application-messages/models/BaseThreadsRecordModel.hpp
R module-apps/application-messages/{widgets => models}/SMSTemplateModel.cpp
R module-apps/application-messages/{widgets => models}/SMSTemplateModel.hpp
M module-apps/application-messages/models/SMSThreadModel.cpp
M module-apps/application-messages/models/SMSThreadModel.hpp
M module-apps/application-messages/models/ThreadsModel.cpp
M module-apps/application-messages/models/ThreadsModel.hpp
M module-apps/application-messages/models/ThreadsSearchResultsModel.cpp
M module-apps/application-messages/models/ThreadsSearchResultsModel.hpp
M module-apps/application-messages/widgets/SMSTemplateItem.hpp
M module-apps/application-messages/widgets/ThreadItem.cpp
M module-apps/application-messages/widgets/ThreadItem.hpp
M module-apps/application-messages/windows/MessagesMainWindow.cpp
M module-apps/application-messages/windows/SMSTemplatesWindow.hpp
M module-apps/application-messages/windows/SMSThreadViewWindow.cpp
M module-apps/application-messages/windows/SMSThreadViewWindow.hpp
M module-apps/application-messages/windows/SearchResults.cpp
M module-db/CMakeLists.txt
M module-db/Interface/ContactRecord.cpp
M module-db/Interface/ContactRecord.hpp
M module-db/Interface/SMSRecord.cpp
M module-db/Interface/SMSRecord.hpp
M module-db/Interface/SMSTemplateRecord.cpp
M module-db/Interface/SMSTemplateRecord.hpp
M module-db/Interface/ThreadRecord.cpp
M module-db/Interface/ThreadRecord.hpp
M module-db/Tables/Record.hpp
M module-db/Tables/ThreadsTable.cpp
M module-db/queries/messages/sms/QuerySMSGetForList.cpp
M module-db/queries/messages/sms/QuerySMSGetForList.hpp
A module-db/queries/messages/templates/QuerySMSTemplateGetForList.cpp
A module-db/queries/messages/templates/QuerySMSTemplateGetForList.hpp
M module-db/queries/messages/threads/QueryThreadMarkAsRead.cpp
M module-db/queries/messages/threads/QueryThreadMarkAsRead.hpp
M module-db/queries/messages/threads/QueryThreadsGet.cpp
M module-db/queries/messages/threads/QueryThreadsGet.hpp
A module-db/queries/messages/threads/QueryThreadsGetForList.cpp
A module-db/queries/messages/threads/QueryThreadsGetForList.hpp
R module-db/queries/messages/threads/{QueryThreadsSearch => QueryThreadsSearchForList}.cpp
R module-db/queries/messages/threads/{QueryThreadsSearch => QueryThreadsSearchForList}.hpp
M module-db/queries/phonebook/QueryContactGetByID.cpp
M module-db/queries/phonebook/QueryContactGetByID.hpp
M module-db/tests/QueryInterface.cpp
M module-db/tests/ThreadRecord_tests.cpp
M module-services/service-desktop/endpoints/DBHelper.hpp
M module-services/service-desktop/endpoints/messages/MessageHelper.cpp
M module-apps/application-messages/ApplicationMessages.cpp => module-apps/application-messages/ApplicationMessages.cpp +3 -3
@@ 158,7 158,7 @@ namespace app

    bool ApplicationMessages::markSmsThreadAsRead(const uint32_t id)
    {
        using namespace db::query::smsthread;
        using namespace db::query;
        LOG_DEBUG("markSmsThreadAsRead");
        DBServiceAPI::GetQuery(
            this, db::Interface::Name::SMSThread, std::make_unique<MarkAsRead>(id, MarkAsRead::Read::True));


@@ 167,8 167,8 @@ namespace app

    bool ApplicationMessages::markSmsThreadAsUnread(const uint32_t id)
    {
        using namespace db::query::smsthread;
        LOG_DEBUG("markSmsThreadAsRead");
        using namespace db::query;
        LOG_DEBUG("markSmsThreadAsUnRead");
        DBServiceAPI::GetQuery(
            this, db::Interface::Name::SMSThread, std::make_unique<MarkAsRead>(id, MarkAsRead::Read::False));
        return true;

M module-apps/application-messages/CMakeLists.txt => module-apps/application-messages/CMakeLists.txt +1 -1
@@ 15,7 15,7 @@ target_sources( ${PROJECT_NAME}
    PRIVATE
        "ApplicationMessages.cpp"
        "widgets/ThreadItem.cpp"
        "widgets/SMSTemplateModel.cpp"
        "models/SMSTemplateModel.cpp"
        "widgets/SMSTemplateItem.cpp"
        "widgets/SMSInputWidget.cpp"
        "widgets/SMSOutputWidget.cpp"

M module-apps/application-messages/models/BaseThreadsRecordModel.cpp => module-apps/application-messages/models/BaseThreadsRecordModel.cpp +1 -2
@@ 12,11 12,10 @@ BaseThreadsRecordModel::BaseThreadsRecordModel(app::Application *app) : Database

unsigned int BaseThreadsRecordModel::requestRecordsCount()
{
    recordsCount = DBServiceAPI::ThreadGetCount(application);
    return recordsCount;
}

bool BaseThreadsRecordModel::updateRecords(std::vector<ThreadRecord> records)
bool BaseThreadsRecordModel::updateRecords(std::vector<ThreadListStruct> records)
{
    DatabaseModel::updateRecords(std::move(records));
    list->onProviderDataUpdate();

M module-apps/application-messages/models/BaseThreadsRecordModel.hpp => module-apps/application-messages/models/BaseThreadsRecordModel.hpp +16 -2
@@ 10,15 10,29 @@
#include "Interface/ThreadRecord.hpp"

#include <vector>
#include <module-db/Interface/ContactRecord.hpp>

class BaseThreadsRecordModel : public app::DatabaseModel<ThreadRecord>, public gui::ListItemProvider
struct ThreadListStruct
{
    std::shared_ptr<ThreadRecord> thread;
    std::shared_ptr<ContactRecord> contact;
    std::shared_ptr<utils::PhoneNumber::View> number;

    ThreadListStruct(std::shared_ptr<ThreadRecord> thread,
                     std::shared_ptr<ContactRecord> contact,
                     std::shared_ptr<utils::PhoneNumber::View> number)
        : thread(thread), contact(contact), number(number)
    {}
};

class BaseThreadsRecordModel : public app::DatabaseModel<ThreadListStruct>, public gui::ListItemProvider
{
  public:
    BaseThreadsRecordModel() = delete;
    BaseThreadsRecordModel(app::Application *app);

    unsigned int requestRecordsCount() override;
    bool updateRecords(std::vector<ThreadRecord> records) override;
    bool updateRecords(std::vector<ThreadListStruct> records) override;
    void requestRecords(const uint32_t offset, const uint32_t limit) override;

    app::Application *getApplication(void)

R module-apps/application-messages/widgets/SMSTemplateModel.cpp => module-apps/application-messages/models/SMSTemplateModel.cpp +27 -11
@@ 2,29 2,20 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SMSTemplateModel.hpp"
#include "SMSTemplateItem.hpp"
#include "ListView.hpp"
#include "application-messages/data/SMSdata.hpp"
#include "application-messages/data/MessagesStyle.hpp"
#include "application-messages/widgets/SMSTemplateItem.hpp"
#include "application-messages/ApplicationMessages.hpp"
#include <service-db/api/DBServiceAPI.hpp>
#include <module-db/queries/messages/templates/QuerySMSTemplateGetForList.hpp>

SMSTemplateModel::SMSTemplateModel(app::Application *app) : DatabaseModel(app)
{}

unsigned int SMSTemplateModel::requestRecordsCount()
{
    recordsCount = DBServiceAPI::SMSTemplateGetCount(application);
    LOG_DEBUG("SMSTemplateGetCount %" PRIu32, recordsCount);

    return recordsCount;
}

void SMSTemplateModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    DBServiceAPI::SMSTemplateGetLimitOffset(application, offset, limit);
}

bool SMSTemplateModel::updateRecords(std::vector<SMSTemplateRecord> records)
{
    if (DatabaseModel::updateRecords(std::move(records))) {


@@ 61,3 52,28 @@ gui::ListItem *SMSTemplateModel::getItem(gui::Order order)

    return item;
}

void SMSTemplateModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    auto query = std::make_unique<db::query::SMSTemplateGetForList>(offset, limit);
    query->setQueryListener(
        db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
    DBServiceAPI::GetQuery(application, db::Interface::Name::SMSTemplate, std::move(query));
}

auto SMSTemplateModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
{
    auto msgResponse = dynamic_cast<db::query::SMSTemplateGetForListResult *>(queryResult);
    assert(msgResponse != nullptr);

    // If list record count has changed we need to rebuild list.
    if (recordsCount != (msgResponse->getCount())) {
        recordsCount = msgResponse->getCount();
        list->rebuildList(style::listview::RebuildType::Full, 0, true);
        return false;
    }

    auto records = msgResponse->getResults();

    return this->updateRecords(std::move(records));
}

R module-apps/application-messages/widgets/SMSTemplateModel.hpp => module-apps/application-messages/models/SMSTemplateModel.hpp +2 -0
@@ 22,4 22,6 @@ class SMSTemplateModel : public app::DatabaseModel<SMSTemplateRecord>, public gu

    unsigned int getMinimalItemHeight() const override;
    gui::ListItem *getItem(gui::Order order) override;

    auto handleQueryResponse(db::QueryResult *queryResult) -> bool;
};

M module-apps/application-messages/models/SMSThreadModel.cpp => module-apps/application-messages/models/SMSThreadModel.cpp +3 -1
@@ 51,7 51,7 @@ unsigned int SMSThreadModel::requestRecordsCount()

void SMSThreadModel::requestRecords(uint32_t offset, uint32_t limit)
{
    auto query = std::make_unique<db::query::SMSGetForList>(smsThreadID, offset, limit);
    auto query = std::make_unique<db::query::SMSGetForList>(smsThreadID, offset, limit, numberID);
    query->setQueryListener(
        db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
    DBServiceAPI::GetQuery(application, db::Interface::Name::SMS, std::move(query));


@@ 88,6 88,8 @@ auto SMSThreadModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
        smsInput->displayDraftMessage();
    }

    number = std::make_unique<utils::PhoneNumber::View>(msgResponse->getNumber());

    return this->updateRecords(std::move(records_data));
}


M module-apps/application-messages/models/SMSThreadModel.hpp => module-apps/application-messages/models/SMSThreadModel.hpp +1 -0
@@ 15,6 15,7 @@ class SMSThreadModel : public app::DatabaseModel<SMSRecord>, public gui::ListIte
    unsigned int smsThreadID      = 0;
    gui::SMSInputWidget *smsInput = nullptr;
    std::unique_ptr<utils::PhoneNumber::View> number;
    unsigned int numberID = DB_ID_NONE;

    SMSThreadModel(app::Application *app);
    ~SMSThreadModel() override;

M module-apps/application-messages/models/ThreadsModel.cpp => module-apps/application-messages/models/ThreadsModel.cpp +33 -10
@@ 5,6 5,7 @@
#include "InputEvent.hpp"
#include "OptionWindow.hpp"
#include "OptionsWindow.hpp"
#include "ListView.hpp"
#include "application-messages/data/SMSdata.hpp"
#include "application-messages/data/MessagesStyle.hpp"
#include "application-messages/widgets/ThreadItem.hpp"


@@ 12,6 13,7 @@
#include "log/log.hpp"
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-db/queries/messages/threads/QueryThreadsGet.hpp>
#include <module-db/queries/messages/threads/QueryThreadsGetForList.hpp>

ThreadsModel::ThreadsModel(app::Application *app) : BaseThreadsRecordModel(app)
{}


@@ 23,19 25,21 @@ auto ThreadsModel::getMinimalItemHeight() const -> unsigned int

auto ThreadsModel::getItem(gui::Order order) -> gui::ListItem *
{
    std::shared_ptr<ThreadRecord> thread = getRecord(order);
    std::shared_ptr<ThreadListStruct> threadStruct = getRecord(order);

    if (thread.get() == nullptr) {
    if (!threadStruct) {
        return nullptr;
    }

    auto item               = gui::ThreadItem::makeThreadItem(this, thread);
    item->activatedCallback = [this, thread](gui::Item &item) {
    auto item = gui::ThreadItem::makeThreadItem(threadStruct);

    item->activatedCallback = [this, threadStruct](gui::Item &item) {
        LOG_INFO("ThreadItem ActivatedCallback");
        if (application) {
            const auto &threadItem = static_cast<gui::ThreadItem &>(item);
            application->switchWindow(gui::name::window::thread_view,
                                      std::make_unique<SMSThreadData>(thread, threadItem.getThreadName()));
            application->switchWindow(
                gui::name::window::thread_view,
                std::make_unique<SMSThreadData>(threadStruct->thread, threadItem.getThreadName()));
        }
        else {
            LOG_ERROR("No application!");


@@ 61,7 65,7 @@ auto ThreadsModel::getItem(gui::Order order) -> gui::ListItem *

void ThreadsModel::requestRecords(uint32_t offset, uint32_t limit)
{
    auto query = std::make_unique<db::query::ThreadsGet>(offset, limit);
    auto query = std::make_unique<db::query::ThreadsGetForList>(offset, limit);
    query->setQueryListener(
        db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
    DBServiceAPI::GetQuery(getApplication(), db::Interface::Name::SMSThread, std::move(query));


@@ 69,10 73,29 @@ void ThreadsModel::requestRecords(uint32_t offset, uint32_t limit)

auto ThreadsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
{
    auto msgResponse = dynamic_cast<db::query::ThreadsGetResults *>(queryResult);
    auto msgResponse = dynamic_cast<db::query::ThreadsGetForListResults *>(queryResult);
    assert(msgResponse != nullptr);

    auto records_data = msgResponse->getResults();
    auto records      = std::vector<ThreadRecord>(records_data.begin(), records_data.end());
    // If list record count has changed we need to rebuild list.
    if (recordsCount != (msgResponse->getCount())) {
        recordsCount = msgResponse->getCount();
        list->rebuildList(style::listview::RebuildType::Full, 0, true);
        return false;
    }

    auto threads  = msgResponse->getResults();
    auto contacts = msgResponse->getContacts();
    auto numbers  = msgResponse->getNumbers();

    std::vector<ThreadListStruct> records;

    assert(threads.size() == contacts.size() && threads.size() == numbers.size());

    for (unsigned int i = 0; i < threads.size(); i++) {
        records.emplace_back(std::make_shared<ThreadRecord>(threads[i]),
                             std::make_shared<ContactRecord>(contacts[i]),
                             std::make_shared<utils::PhoneNumber::View>(numbers[i]));
    }

    return this->updateRecords(std::move(records));
}

M module-apps/application-messages/models/ThreadsModel.hpp => module-apps/application-messages/models/ThreadsModel.hpp +1 -0
@@ 3,6 3,7 @@

#pragma once

#include <module-db/Interface/ContactRecord.hpp>
#include "BaseThreadsRecordModel.hpp"

class ThreadsModel : public BaseThreadsRecordModel

M module-apps/application-messages/models/ThreadsSearchResultsModel.cpp => module-apps/application-messages/models/ThreadsSearchResultsModel.cpp +26 -25
@@ 7,7 7,7 @@
#include "application-messages/widgets/SearchResultsItem.hpp"

#include "service-db/api/DBServiceAPI.hpp"
#include <module-db/queries/messages/threads/QueryThreadsSearch.hpp>
#include <module-db/queries/messages/threads/QueryThreadsSearchForList.hpp>
#include <module-apps/application-messages/ApplicationMessages.hpp>
#include "application-messages/data/MessagesStyle.hpp"



@@ 24,23 24,18 @@ namespace gui::model

    auto ThreadsSearchResultsModel::getItem(gui::Order order) -> gui::ListItem *
    {
        std::shared_ptr<ThreadListStruct> threadStruct = getRecord(order);

        std::shared_ptr<ThreadRecord> thread = getRecord(order);

        if (thread.get() == nullptr) {
        if (threadStruct == nullptr) {
            return nullptr;
        }

        auto ret = new gui::SearchResultsItem();
        {
            auto contactRec = DBServiceAPI::ContactGetByID(getApplication(), thread->contactID);
            auto cont       = contactRec->front();
            ret->setContact(cont.getFormattedName());
        }
        ret->setTimestamp(utils::time::DateTime(thread->date));
        {
            ret->setContact(threadStruct->contact->getFormattedName());
            ret->setTimestamp(utils::time::DateTime(threadStruct->thread->date));
            // The only thing that differs with ThreadModel actually - here show what was found
            ret->setPreview(thread->snippet);
            ret->setPreview(threadStruct->thread->snippet);
        }

        return ret;


@@ 48,36 43,42 @@ namespace gui::model

    void ThreadsSearchResultsModel::requestRecords(uint32_t offset, uint32_t limit)
    {
        if (std::string(search_value).compare("") != 0) {
            auto query = std::make_unique<db::query::ThreadsSearch>(search_value, offset, limit);
        if (std::string(textToSearch).compare("") != 0) {
            auto query = std::make_unique<db::query::ThreadsSearchForList>(textToSearch, offset, limit);
            query->setQueryListener(
                db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
            DBServiceAPI::GetQuery(getApplication(), db::Interface::Name::SMSThread, std::move(query));
        }
    }

    void ThreadsSearchResultsModel::setSearchValue(const UTF8 &search_value)
    void ThreadsSearchResultsModel::setSearchValue(const UTF8 &value)
    {
        this->search_value = search_value;
        this->textToSearch = value;
    }

    auto ThreadsSearchResultsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
    {
        auto msgResponse = dynamic_cast<db::query::ThreadsSearchResult *>(queryResult);
        auto msgResponse = dynamic_cast<db::query::ThreadsSearchResultForList *>(queryResult);
        assert(msgResponse != nullptr);

        auto records_data = msgResponse->getResults();
        auto records      = std::vector<ThreadRecord>(records_data.begin(), records_data.end());
        // If list record count has changed we need to rebuild list.
        if (recordsCount != (msgResponse->getCount())) {
            recordsCount = msgResponse->getCount();
            list->rebuildList(style::listview::RebuildType::Full, 0, true);
            return false;
        }

        if (msgResponse->getMax() == 0) {
        auto threads  = msgResponse->getResults();
        auto contacts = msgResponse->getContacts();

            auto app = dynamic_cast<app::ApplicationMessages *>(application);
            assert(app);
            return app->searchEmpty();
        }
        std::vector<ThreadListStruct> records;

        assert(threads.size() == contacts.size());

        assert(list);
        list->setElementsCount(msgResponse->getMax());
        for (unsigned int i = 0; i < threads.size(); i++) {
            records.emplace_back(
                std::make_shared<ThreadRecord>(threads[i]), std::make_shared<ContactRecord>(contacts[i]), nullptr);
        }

        return this->updateRecords(std::move(records));
    }

M module-apps/application-messages/models/ThreadsSearchResultsModel.hpp => module-apps/application-messages/models/ThreadsSearchResultsModel.hpp +1 -1
@@ 11,7 11,7 @@ namespace gui::model

    class ThreadsSearchResultsModel : public BaseThreadsRecordModel
    {
        UTF8 search_value;
        UTF8 textToSearch;

      public:
        ThreadsSearchResultsModel(app::Application *app);

M module-apps/application-messages/widgets/SMSTemplateItem.hpp => module-apps/application-messages/widgets/SMSTemplateItem.hpp +1 -2
@@ 3,8 3,7 @@

#pragma once

#include "SMSTemplateModel.hpp"

#include <Interface/SMSTemplateRecord.hpp>
#include <Label.hpp>
#include <Image.hpp>
#include <ListItem.hpp>

M module-apps/application-messages/widgets/ThreadItem.cpp => module-apps/application-messages/widgets/ThreadItem.cpp +17 -32
@@ 11,18 11,13 @@

namespace gui
{
    ThreadItem *ThreadItem::makeThreadItem(ThreadsModel *model, std::shared_ptr<ThreadRecord> thread)
    ThreadItem *ThreadItem::makeThreadItem(const std::shared_ptr<ThreadListStruct> &threadStruct)
    {
        ThreadItem *threadItem = thread->isUnread() ? new ThreadItemNotRead(model) : new ThreadItem(model);
        threadItem->setThreadItem(thread);
        ThreadItem *threadItem = threadStruct->thread->isUnread() ? new ThreadItemNotRead() : new ThreadItem();
        threadItem->setThreadItem(threadStruct);
        return threadItem;
    }

    ThreadItem::ThreadItem(ThreadsModel *model)
    {
        this->model = model;
    }

    auto ThreadItem::getThreadName() const -> UTF8
    {
        std::ostringstream name;


@@ 36,7 31,7 @@ namespace gui
    void ThreadItem::setPreview()
    {
        UTF8 prefix;
        switch (thread->type) {
        switch (threadStruct->thread->type) {
        case SMSType::DRAFT:
            prefix = utils::localize.get("app_messages_thread_draft");
            break;


@@ 50,36 45,27 @@ namespace gui
        default:
            break;
        }
        preview->setText(prefix + thread->snippet);
        preview->setText(prefix + threadStruct->thread->snippet);
    }

    void ThreadItem::setThreadItem(std::shared_ptr<ThreadRecord> _thread)
    void ThreadItem::setThreadItem(std::shared_ptr<ThreadListStruct> _threadStruct)
    {
        thread = std::move(_thread);
        if (model != nullptr) {
            const auto &contact = getContactRecord();
            setContactName(contact, getNumberImportance(contact));
        }
        threadStruct = std::move(_threadStruct);

        timestamp->setText(utils::time::DateTime(thread->date));
        setContactName(getNumberImportance());
        timestamp->setText(utils::time::DateTime(threadStruct->thread->date));
        setPreview();
    }

    auto ThreadItem::getContactRecord() -> ContactRecord
    {
        auto contactRec = DBServiceAPI::ContactGetByIDWithTemporary(model->getApplication(), thread->contactID);
        return contactRec->front();
    }

    auto ThreadItem::getNumberImportance(const ContactRecord &contact) -> std::optional<long>
    auto ThreadItem::getNumberImportance() -> std::optional<long>
    {
        if (contact.numbers.size() < 2) {
        if (threadStruct->contact->numbers.size() < 2) {
            // At least two phone numbers are needed to indicate a number importance.
            return std::nullopt;
        }

        const auto numberRec     = DBServiceAPI::GetNumberById(model->getApplication(), thread->numberID);
        const auto &phoneNumbers = contact.numbers;
        const auto numberRec     = threadStruct->number;
        const auto &phoneNumbers = threadStruct->contact->numbers;

        const auto it = std::find_if(phoneNumbers.begin(), phoneNumbers.end(), [&numberRec](const auto &phoneNumber) {
            return phoneNumber.number == *numberRec;


@@ 91,15 77,15 @@ namespace gui
        return std::distance(phoneNumbers.begin(), it) + 1;
    }

    void ThreadItem::setContactName(const ContactRecord &contactInfo, std::optional<long int> numberImportance)
    void ThreadItem::setContactName(std::optional<long int> numberImportance)
    {
        contact->setText(contactInfo.getFormattedName());
        contact->setText(threadStruct->contact->getFormattedName());
        if (numberImportance.has_value()) {
            displayNumberImportance(numberImportance.value());
        }
    }

    ThreadItemWithIndicator::ThreadItemWithIndicator(ThreadsModel *model, const UTF8 &indicatorName) : ThreadItem(model)
    ThreadItemWithIndicator::ThreadItemWithIndicator(const UTF8 &indicatorName) : ThreadItem()
    {
        indicator = new gui::Image(this, 0, 0, indicatorName);
    }


@@ 118,7 104,6 @@ namespace gui
                                   indicator->getSize(gui::Axis::Y) / 2); // align with text
    }

    ThreadItemNotRead::ThreadItemNotRead(ThreadsModel *model)
        : ThreadItemWithIndicator(model, ThreadItemNotRead::indicatorName)
    ThreadItemNotRead::ThreadItemNotRead() : ThreadItemWithIndicator(ThreadItemNotRead::indicatorName)
    {}
} /*namespace gui*/

M module-apps/application-messages/widgets/ThreadItem.hpp => module-apps/application-messages/widgets/ThreadItem.hpp +10 -12
@@ 12,28 12,26 @@ namespace gui

    class ThreadItem : public BaseThreadItem
    {
        ThreadsModel *model = nullptr;
        std::shared_ptr<ThreadRecord> thread;
        std::shared_ptr<ThreadListStruct> threadStruct;

        auto getContactRecord() -> ContactRecord;
        auto getNumberImportance(const ContactRecord &contact) -> std::optional<long int>;
        auto getNumberImportance() -> std::optional<long int>;

        void setPreview();
        void setContactName(const ContactRecord &contactInfo, std::optional<long int> numberImportance = std::nullopt);
        void setContactName(std::optional<long int> numberImportance = std::nullopt);

      public:
        explicit ThreadItem(ThreadsModel *model);
        ThreadItem() = default;

        void setThreadItem(std::shared_ptr<ThreadRecord> _thread);
        void setThreadItem(std::shared_ptr<ThreadListStruct> _threadStruct);

        auto getThreadName() const -> UTF8;
        [[nodiscard]] auto getThreadName() const -> UTF8;

        std::shared_ptr<ThreadRecord> getThreadItem()
        {
            return thread;
            return threadStruct->thread;
        }

        static ThreadItem *makeThreadItem(ThreadsModel *model, std::shared_ptr<ThreadRecord> thread);
        static ThreadItem *makeThreadItem(const std::shared_ptr<ThreadListStruct> &threadStruct);
    };

    class ThreadItemWithIndicator : public ThreadItem


@@ 43,7 41,7 @@ namespace gui
        void onDimensionChangedBottom(const BoundingBox &oldDim, const BoundingBox &newDim) override;

      public:
        ThreadItemWithIndicator(ThreadsModel *model, const UTF8 &indicatorName);
        ThreadItemWithIndicator(const UTF8 &indicatorName);
    };

    class ThreadItemNotRead : public ThreadItemWithIndicator


@@ 51,7 49,7 @@ namespace gui
        static const inline UTF8 indicatorName = "dot_12px_hard_alpha_W_M";

      public:
        ThreadItemNotRead(ThreadsModel *model);
        ThreadItemNotRead();
    };

} /*namespace gui*/

M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +1 -1
@@ 53,6 53,7 @@ namespace gui
                                 msgThreadStyle::listHeight,
                                 threadsModel);
        list->setScrollTopMargin(style::margins::small);
        list->rebuildList();

        bottomBar->setActive(BottomBar::Side::LEFT, true);
        bottomBar->setActive(BottomBar::Side::CENTER, true);


@@ 129,7 130,6 @@ namespace gui
        }
        else {
            emptyListIcon->setVisible(false);
            list->rebuildList(style::listview::RebuildType::InPlace);
        }

        DBServiceAPI::GetQuery(application,

M module-apps/application-messages/windows/SMSTemplatesWindow.hpp => module-apps/application-messages/windows/SMSTemplatesWindow.hpp +1 -1
@@ 3,7 3,7 @@

#pragma once

#include "application-messages/widgets/SMSTemplateModel.hpp"
#include "application-messages/models/SMSTemplateModel.hpp"
#include "application-messages/data/SMSdata.hpp"

#include <AppWindow.hpp>

M module-apps/application-messages/windows/SMSThreadViewWindow.cpp => module-apps/application-messages/windows/SMSThreadViewWindow.cpp +22 -10
@@ 13,6 13,8 @@
#include <TextBubble.hpp>
#include <service-db/api/DBServiceAPI.hpp>
#include <service-db/messages/DBNotificationMessage.hpp>
#include <module-db/queries/phonebook/QueryContactGetByID.hpp>

#include <log/log.hpp>
#include <Style.hpp>



@@ 64,15 66,8 @@ namespace gui
        {
            auto pdata = dynamic_cast<SMSThreadData *>(data);
            if (pdata) {
                LOG_INFO("We have it! %" PRIu32, pdata->thread->ID);
                auto ret = DBServiceAPI::ContactGetByIDWithTemporary(application, pdata->thread->contactID);
                contact  = std::make_shared<ContactRecord>(ret->front());
                // should be name number for now - easier to handle
                setTitle(pdata->threadName.value_or(ret->front().getFormattedName()));
                auto retNumber = DBServiceAPI::GetNumberById(application, pdata->thread->numberID, numberIdTimeout);
                assert(retNumber != nullptr);
                smsModel->number = std::move(retNumber);
                LOG_INFO("Phonenumber for thread: %s", smsModel->number->getFormatted().c_str());
                LOG_INFO("Thread data received: %" PRIu32, pdata->thread->ID);
                requestContactName(pdata->thread->contactID);

                // Mark thread as Read
                if (pdata->thread->isUnread()) {


@@ 82,7 77,7 @@ namespace gui
                        app->markSmsThreadAsRead(pdata->thread->ID);
                    }
                }

                smsModel->numberID    = pdata->thread->numberID;
                smsModel->smsThreadID = pdata->thread->ID;
                smsList->rebuildList();
            }


@@ 126,4 121,21 @@ namespace gui
        return false;
    }

    auto SMSThreadViewWindow::requestContactName(unsigned int contactID) -> void
    {
        auto query = std::make_unique<db::query::ContactGetByID>(contactID, true);
        query->setQueryListener(db::QueryCallback::fromFunction(
            [this](auto response) { return handleContactNameQueryResponse(response); }));
        DBServiceAPI::GetQuery(application, db::Interface::Name::Contact, std::move(query));
    }

    auto SMSThreadViewWindow::handleContactNameQueryResponse(db::QueryResult *queryResult) -> bool
    {
        auto msgResponse = dynamic_cast<db::query::ContactGetByIDResult *>(queryResult);
        assert(msgResponse != nullptr);

        setTitle(msgResponse->getResult().getFormattedName());

        return false;
    }
} /* namespace gui */

M module-apps/application-messages/windows/SMSThreadViewWindow.hpp => module-apps/application-messages/windows/SMSThreadViewWindow.hpp +6 -11
@@ 18,27 18,22 @@ namespace gui
    class SMSThreadViewWindow : public AppWindow
    {
      private:
        std::shared_ptr<SMSThreadModel> smsModel = nullptr;
        gui::ListView *smsList                   = nullptr;
        std::shared_ptr<SMSThreadModel> smsModel;
        gui::ListView *smsList = nullptr;

        std::shared_ptr<ContactRecord> contact;

        inline static const std::uint32_t numberIdTimeout = 1000;
        auto requestContactName(unsigned int ContactID) -> void;
        auto handleContactNameQueryResponse(db::QueryResult *) -> bool;

      public:
        SMSThreadViewWindow(app::Application *app);
        explicit SMSThreadViewWindow(app::Application *app);
        ~SMSThreadViewWindow() override;

        virtual ~SMSThreadViewWindow();
        // virtual methods
        bool onInput(const InputEvent &inputEvent) override;

        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void onClose() override;

        bool onDatabaseMessage(sys::Message *msgl) override;
        void rebuild() override;
        void buildInterface() override;

        void destroyInterface() override;
    };


M module-apps/application-messages/windows/SearchResults.cpp => module-apps/application-messages/windows/SearchResults.cpp +1 -1
@@ 8,7 8,7 @@
#include "module-apps/application-messages/data/MessagesStyle.hpp"
#include "messages/DBThreadMessage.hpp"
#include "messages/QueryMessage.hpp"
#include "queries/messages/threads/QueryThreadsSearch.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include "service-db/messages/DBMessage.hpp"
#include <i18/i18.hpp>


M module-db/CMakeLists.txt => module-db/CMakeLists.txt +3 -1
@@ 75,11 75,13 @@ set(SOURCES
        queries/messages/templates/QuerySMSTemplateAdd.cpp
        queries/messages/templates/QuerySMSTemplateGetByID.cpp
        queries/messages/templates/QuerySMSTemplateGet.cpp
        queries/messages/templates/QuerySMSTemplateGetForList.cpp
        queries/messages/templates/QuerySMSTemplateGetCount.cpp
        queries/messages/templates/QuerySMSTemplateRemove.cpp
        queries/messages/templates/QuerySMSTemplateUpdate.cpp
        queries/messages/threads/QueryThreadsSearch.cpp
        queries/messages/threads/QueryThreadsSearchForList.cpp
        queries/messages/threads/QueryThreadsGet.cpp
        queries/messages/threads/QueryThreadsGetForList.cpp
        queries/messages/threads/QueryThreadGetByID.cpp
        queries/messages/threads/QueryThreadGetByNumber.cpp
        queries/messages/threads/QueryThreadGetByContactID.cpp

M module-db/Interface/ContactRecord.cpp => module-db/Interface/ContactRecord.cpp +16 -2
@@ 219,11 219,20 @@ auto ContactRecordInterface::getLetterMapQuery(std::shared_ptr<db::Query> query)
auto ContactRecordInterface::getByIDQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>
{
    auto readQuery = static_cast<db::query::ContactGetByID *>(query.get());
    auto record    = ContactRecordInterface::GetByID(readQuery->getID());
    auto response  = std::make_unique<db::query::ContactGetByIDResult>(record);
    ContactRecord record;

    if (readQuery->getWithTemporary()) {
        record = ContactRecordInterface::GetByIdWithTemporary(readQuery->getID());
    }
    else {
        record = ContactRecordInterface::GetByID(readQuery->getID());
    }

    auto response = std::make_unique<db::query::ContactGetByIDResult>(record);
    response->setRequestQuery(query);
    return response;
}

auto ContactRecordInterface::getSizeQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>
{
    auto textFilter = dynamic_cast<const db::query::TextFilter *>(query.get());


@@ 279,6 288,11 @@ auto ContactRecordInterface::getSizeQuery(std::shared_ptr<db::Query> query) -> s
    return response;
}

auto ContactRecordInterface::getForListQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>
{
    return nullptr;
}

auto ContactRecordInterface::addQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>
{
    auto addQuery = dynamic_cast<db::query::ContactAdd *>(query.get());

M module-db/Interface/ContactRecord.hpp => module-db/Interface/ContactRecord.hpp +1 -0
@@ 234,6 234,7 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco

    const std::uint32_t favouritesGroupId;
    auto getQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;
    auto getForListQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;
    auto getLetterMapQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;

    auto getByIDQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;

M module-db/Interface/SMSRecord.cpp => module-db/Interface/SMSRecord.cpp +31 -123
@@ 17,18 17,12 @@
#include "queries/messages/sms/QuerySMSGetByThreadID.hpp"
#include "queries/messages/sms/QuerySMSGetCountByThreadID.hpp"
#include "queries/messages/sms/QuerySMSGetLastByThreadID.hpp"
#include <queries/messages/sms/QuerySMSGetForList.hpp>

#include <log/log.hpp>

#include <PhoneNumber.hpp>
#include <optional>
#include <module-db/queries/messages/sms/QuerySMSGetForList.hpp>

SMSRecord::SMSRecord(const SMSTableRow &w, const utils::PhoneNumber::View &num)
    : date(w.date), dateSent(w.dateSent), errorCode(w.errorCode), body(w.body), type(w.type), threadID(w.threadID),
      contactID(w.contactID), number(num)
{
    this->ID = w.ID;
}

SMSRecordInterface::SMSRecordInterface(SmsDB *smsDb, ContactsDB *contactsDb) : smsDB(smsDb), contactsDB(contactsDb)
{}


@@ 363,77 357,44 @@ std::unique_ptr<db::query::SMSSearchByTypeResult> SMSRecordInterface::runQueryIm
    return std::make_unique<db::query::SMSSearchByTypeResult>(db_result.first, *records);
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::getByIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetByID *>(query.get());
    auto sms              = smsDB->sms.getById(localQuery->id);
    SMSRecord record;

    record.body      = sms.body;
    record.contactID = sms.contactID;
    record.date      = sms.date;
    record.dateSent  = sms.dateSent;
    record.errorCode = sms.errorCode;
    record.threadID  = sms.threadID;
    record.type      = sms.type;
    record.ID        = sms.ID;
    auto response    = std::make_unique<db::query::SMSGetByIDResult>(record);

    auto response = std::make_unique<db::query::SMSGetByIDResult>(sms);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::getByContactIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByContactIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetByContactID *>(query.get());
    auto smsVector        = smsDB->sms.getByContactId(localQuery->contactId);
    std::vector<SMSRecord> recordVector;
    for (auto sms : smsVector) {
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        recordVector.emplace_back(record);
    }
    auto recordVector     = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());

    auto response = std::make_unique<db::query::SMSGetByContactIDResult>(recordVector);
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByTextQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByTextQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetByText *>(query.get());
    auto smsVector        = smsDB->sms.getByText(localQuery->text);
    std::vector<SMSRecord> recordVector;
    for (auto sms : smsVector) {
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        recordVector.emplace_back(record);
    }
    auto recordVector     = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());

    auto response = std::make_unique<db::query::SMSGetByTextResult>(recordVector);
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountQuery(const std::shared_ptr<db::Query> &query)
{
    auto response = std::make_unique<db::query::SMSGetCountResult>(smsDB->sms.count());
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountByThreadIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountByThreadIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetCountByThreadID *>(query.get());
    auto response         = std::make_unique<db::query::SMSGetCountByThreadIDResult>(


@@ 442,7 403,7 @@ std::unique_ptr<db::QueryResult> SMSRecordInterface::getCountByThreadIDQuery(std
    return response;
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::addQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::addQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSAdd *>(query.get());
    auto record           = localQuery->record;


@@ 454,7 415,7 @@ std::unique_ptr<db::QueryResult> SMSRecordInterface::addQuery(std::shared_ptr<db
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::removeQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::removeQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSRemove *>(query.get());
    auto ret              = RemoveByID(localQuery->id);


@@ 462,7 423,7 @@ std::unique_ptr<db::QueryResult> SMSRecordInterface::removeQuery(std::shared_ptr
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::updateQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::updateQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSUpdate *>(query.get());
    auto ret              = Update(localQuery->record);


@@ 470,107 431,54 @@ std::unique_ptr<db::QueryResult> SMSRecordInterface::updateQuery(std::shared_ptr
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::getQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGet *>(query.get());

    auto smsVector = smsDB->sms.getLimitOffset(localQuery->getOffset(), localQuery->getLimit());
    std::vector<SMSRecord> recordVector;
    for (auto sms : smsVector) {
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        recordVector.emplace_back(record);
    }
    auto smsVector    = smsDB->sms.getLimitOffset(localQuery->getOffset(), localQuery->getLimit());
    auto recordVector = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());

    auto response = std::make_unique<db::query::SMSGetResult>(recordVector);
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByThreadIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getByThreadIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetByThreadID *>(query.get());
    auto smsVector        = smsDB->sms.getByThreadId(localQuery->threadId, localQuery->offset, localQuery->limit);
    std::vector<SMSRecord> recordVector;
    for (auto sms : smsVector) {
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        recordVector.emplace_back(record);
    }
    auto recordVector     = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());

    auto response = std::make_unique<db::query::SMSGetByThreadIDResult>(recordVector);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::getForListQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getForListQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetForList *>(query.get());
    auto smsVector =
        smsDB->sms.getByThreadIdWithoutDraftWithEmptyInput(localQuery->threadId, localQuery->offset, localQuery->limit);
    std::vector<SMSRecord> recordVector;
    for (auto sms : smsVector) {
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        recordVector.emplace_back(record);
    }

    auto count = smsDB->sms.countWithoutDraftsByThreadId(localQuery->threadId);
    auto draft = smsDB->sms.getDraftByThreadId(localQuery->threadId);

    SMSRecord record;
    record.body      = draft.body;
    record.contactID = draft.contactID;
    record.date      = draft.date;
    record.dateSent  = draft.dateSent;
    record.errorCode = draft.errorCode;
    record.threadID  = draft.threadID;
    record.type      = draft.type;
    record.ID        = draft.ID;

    auto response = std::make_unique<db::query::SMSGetForListResult>(recordVector, count, record);

    auto recordVector = std::vector<SMSRecord>(smsVector.begin(), smsVector.end());
    auto count        = smsDB->sms.countWithoutDraftsByThreadId(localQuery->threadId);
    auto draft        = smsDB->sms.getDraftByThreadId(localQuery->threadId);

    auto number = ContactRecordInterface(contactsDB).GetNumberById(localQuery->contactID);

    auto response = std::make_unique<db::query::SMSGetForListResult>(recordVector, count, draft, number);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::getLastByThreadIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::getLastByThreadIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSGetLastByThreadID *>(query.get());
    const auto &result    = smsDB->sms.getByThreadId(localQuery->threadId, 0, 0);
    std::optional<SMSRecord> lastRecord;
    if (!result.empty()) {
        const auto &sms = result.back();
        SMSRecord record;
        record.body      = sms.body;
        record.contactID = sms.contactID;
        record.date      = sms.date;
        record.dateSent  = sms.dateSent;
        record.errorCode = sms.errorCode;
        record.threadID  = sms.threadID;
        record.type      = sms.type;
        record.ID        = sms.ID;
        lastRecord       = record;
        lastRecord = result.back();
    }

    auto response = std::make_unique<db::query::SMSGetLastByThreadIDResult>(lastRecord);
    response->setRequestQuery(query);
    return response;

M module-db/Interface/SMSRecord.hpp => module-db/Interface/SMSRecord.hpp +20 -13
@@ 32,7 32,14 @@ struct SMSRecord : public Record
    utils::PhoneNumber::View number;

    SMSRecord() = default;
    SMSRecord(const SMSTableRow &, const utils::PhoneNumber::View &);
    SMSRecord(const SMSTableRow &w)
        : Record(w.ID), date(w.date), dateSent(w.dateSent), errorCode(w.errorCode), body(w.body), type(w.type),
          threadID(w.threadID), contactID(w.contactID)
    {}
    SMSRecord(const SMSTableRow &w, const utils::PhoneNumber::View &num)
        : Record(w.ID), date(w.date), dateSent(w.dateSent), errorCode(w.errorCode), body(w.body), type(w.type),
          threadID(w.threadID), contactID(w.contactID), number(num)
    {}
};

enum class SMSRecordField


@@ 72,16 79,16 @@ class SMSRecordInterface : public RecordInterface<SMSRecord, SMSRecordField>

    static void UpdateThreadSummary(ThreadRecord &threadToUpdate, const SMSRecord &rec);
    std::unique_ptr<db::query::SMSSearchByTypeResult> runQueryImpl(const db::query::SMSSearchByType *query);
    std::unique_ptr<db::QueryResult> getByIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getByContactIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getByTextQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getCountQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> addQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> removeQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> updateQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getByThreadIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getForListQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getCountByThreadIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getLastByThreadIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getByIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getByContactIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getByTextQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getCountQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> addQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> removeQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> updateQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getByThreadIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getForListQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getCountByThreadIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getLastByThreadIDQuery(const std::shared_ptr<db::Query> &query);
};

M module-db/Interface/SMSTemplateRecord.cpp => module-db/Interface/SMSTemplateRecord.cpp +27 -15
@@ 8,6 8,7 @@
#include "queries/messages/templates/QuerySMSTemplateGetCount.hpp"
#include "queries/messages/templates/QuerySMSTemplateRemove.hpp"
#include "queries/messages/templates/QuerySMSTemplateUpdate.hpp"
#include <queries/messages/templates/QuerySMSTemplateGetForList.hpp>

#include <log/log.hpp>



@@ 91,6 92,9 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::runQuery(std::share
    else if (typeid(*query) == typeid(db::query::SMSTemplateGet)) {
        return getQuery(query);
    }
    else if (typeid(*query) == typeid(db::query::SMSTemplateGetForList)) {
        return getForListQuery(query);
    }
    else if (typeid(*query) == typeid(db::query::SMSTemplateGetCount)) {
        return getCountQuery(query);
    }


@@ 108,7 112,7 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::runQuery(std::share
    }
}

std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getByIDQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getByIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto local_query = static_cast<const db::query::SMSTemplateGetByID *>(query.get());
    auto smsTemplate       = smsDB->templates.getById(local_query->id);


@@ 117,29 121,37 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getByIDQuery(std::s
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateGet *>(query.get());
    auto dbResult         = smsDB->templates.getLimitOffset(localQuery->offset, localQuery->limit);
    std::vector<SMSTemplateRecord> recordVector;
    for (auto SMStemplate : dbResult) {
        SMSTemplateRecord record;
        record.ID                 = SMStemplate.ID;
        record.text               = SMStemplate.text;
        record.lastUsageTimestamp = SMStemplate.lastUsageTimestamp;
        recordVector.emplace_back(record);
    }
    auto response = std::make_unique<db::query::SMSTemplateGetResult>(std::move(recordVector));

    auto recordVector = std::vector<SMSTemplateRecord>(dbResult.begin(), dbResult.end());
    auto response     = std::make_unique<db::query::SMSTemplateGetResult>(std::move(recordVector));
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getForListQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateGetForList *>(query.get());
    auto dbResult         = smsDB->templates.getLimitOffset(localQuery->offset, localQuery->limit);

    auto recordVector = std::vector<SMSTemplateRecord>(dbResult.begin(), dbResult.end());
    auto count        = smsDB->templates.count();

    auto response = std::make_unique<db::query::SMSTemplateGetForListResult>(std::move(recordVector), count);
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getCountQuery(std::shared_ptr<db::Query> query)

std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::getCountQuery(const std::shared_ptr<db::Query> &query)
{
    auto response = std::make_unique<db::query::SMSTemplateGetCountResult>(smsDB->templates.count());
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::addQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::addQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateAdd *>(query.get());
    auto ret              = SMSTemplateRecordInterface::Add(localQuery->rec);


@@ 147,7 159,7 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::addQuery(std::share
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::removeQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::removeQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateRemove *>(query.get());
    auto ret              = smsDB->templates.removeById(localQuery->id);


@@ 155,7 167,7 @@ std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::removeQuery(std::sh
    response->setRequestQuery(query);
    return response;
}
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::updateQuery(std::shared_ptr<db::Query> query)
std::unique_ptr<db::QueryResult> SMSTemplateRecordInterface::updateQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::SMSTemplateAdd *>(query.get());
    auto ret              = SMSTemplateRecordInterface::Update(localQuery->rec);

M module-db/Interface/SMSTemplateRecord.hpp => module-db/Interface/SMSTemplateRecord.hpp +7 -6
@@ 48,10 48,11 @@ class SMSTemplateRecordInterface : public RecordInterface<SMSTemplateRecord, SMS

  private:
    SmsDB *smsDB = nullptr;
    std::unique_ptr<db::QueryResult> getByIDQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getCountQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> addQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> removeQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> updateQuery(std::shared_ptr<db::Query> query);
    std::unique_ptr<db::QueryResult> getByIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getForListQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getCountQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> addQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> removeQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> updateQuery(const std::shared_ptr<db::Query> &query);
};

M module-db/Interface/ThreadRecord.cpp => module-db/Interface/ThreadRecord.cpp +123 -51
@@ 10,6 10,8 @@
#include <queries/messages/threads/QueryThreadGetByContactID.hpp>
#include <queries/messages/threads/QueryThreadRemove.hpp>
#include <queries/messages/threads/QueryThreadsGet.hpp>
#include <queries/messages/threads/QueryThreadsGetForList.hpp>
#include <queries/messages/threads/QueryThreadsSearchForList.hpp>

#include <cassert>
#include <log/log.hpp>


@@ 164,71 166,141 @@ ThreadRecord ThreadRecordInterface::GetByNumber(const utils::PhoneNumber::View &

std::unique_ptr<db::QueryResult> ThreadRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (const auto localQuery = dynamic_cast<const db::query::ThreadsSearch *>(query.get())) {
        auto dbResult = smsDB->threads.getBySMSQuery(localQuery->text, localQuery->startingPosition, localQuery->depth);

        auto response = std::make_unique<db::query::ThreadsSearchResult>(dbResult.first, dbResult.second);
        response->setRequestQuery(query);
        return response;
    if (typeid(*query) == typeid(db::query::ThreadsSearchForList)) {
        return threadSearchForListQuery(query);
    }

    if (const auto localQuery = dynamic_cast<const db::query::ThreadsGet *>(query.get())) {
        auto dbResult = smsDB->threads.getLimitOffset(localQuery->offset, localQuery->limit);

        auto response = std::make_unique<db::query::ThreadsGetResults>(dbResult);
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::MarkAsRead)) {
        return markAsReadQuery(query);
    }

    if (const auto local_query = dynamic_cast<const db::query::smsthread::MarkAsRead *>(query.get())) {
        auto response = runQueryImpl(local_query);
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::ThreadsGet)) {
        return threadsGetQuery(query);
    }

    if (const auto local_query = dynamic_cast<const db::query::ThreadGetByID *>(query.get())) {
        const auto ret = GetByID(local_query->id);
        auto response  = std::make_unique<db::query::ThreadGetByIDResult>(
            ret.isValid() ? std::optional<ThreadRecord>{ret} : std::nullopt);
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::ThreadsGetForList)) {
        return threadsGetForListQuery(query);
    }

    if (const auto local_query = dynamic_cast<const db::query::ThreadGetByNumber *>(query.get())) {
        auto response = std::make_unique<db::query::ThreadGetByNumberResult>(GetByNumber(local_query->getNumber()));
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::ThreadGetByID)) {
        return threadGetByIDQuery(query);
    }

    if (const auto local_query = dynamic_cast<const db::query::ThreadGetByContactID *>(query.get())) {
        const auto thread = GetByContact(local_query->id);
        auto response     = std::make_unique<db::query::ThreadGetByContactIDResult>(
            thread.isValid() ? std::optional<ThreadRecord>(thread) : std::nullopt);
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::ThreadGetByNumber)) {
        return threadGetByNumberQuery(query);
    }

    if (const auto local_query = dynamic_cast<const db::query::ThreadRemove *>(query.get())) {
        const auto ret = RemoveByID(local_query->id);
        auto response  = std::make_unique<db::query::ThreadRemoveResult>(ret);
        response->setRequestQuery(query);
        return response;
    else if (typeid(*query) == typeid(db::query::ThreadGetByContactID)) {
        return threadGetByContactIDQuery(query);
    }
    else if (typeid(*query) == typeid(db::query::ThreadRemove)) {
        return threadRemoveQuery(query);
    }

    return nullptr;
}

std::unique_ptr<db::query::smsthread::MarkAsReadResult> ThreadRecordInterface::runQueryImpl(
    const db::query::smsthread::MarkAsRead *query)
std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadSearchForListQuery(
    const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadsSearchForList *>(query.get());
    auto dbResult = smsDB->threads.getBySMSQuery(localQuery->textToSearch, localQuery->offset, localQuery->limit);

    auto records = std::vector<ThreadRecord>(dbResult.second.begin(), dbResult.second.end());
    auto count   = dbResult.first;

    std::vector<ContactRecord> contacts;

    for (const auto &record : records) {
        contacts.push_back(ContactRecordInterface(contactsDB).GetByIdWithTemporary(record.contactID));
    }

    auto response = std::make_unique<db::query::ThreadsSearchResultForList>(records, contacts, count);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::markAsReadQuery(const std::shared_ptr<db::Query> &query)
{
    using namespace db::query::smsthread;
    auto ret = false;
    const auto localQuery = static_cast<const db::query::MarkAsRead *>(query.get());
    auto record           = GetByID(localQuery->id);
    auto ret              = false;

    auto record = GetByID(query->id);
    if (record.isValid()) {
        LOG_FATAL("query-read %d", static_cast<int>(query->read));
        record.unreadMsgCount = query->read == MarkAsRead::Read::True ? 0 : 1;
        LOG_FATAL("query-read %d", static_cast<int>(localQuery->read));
        record.unreadMsgCount = localQuery->read == db::query::MarkAsRead::Read::True ? 0 : 1;
        ret                   = Update(record);
    }
    return std::make_unique<MarkAsReadResult>(ret);

    return std::make_unique<db::query::MarkAsReadResult>(ret);
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadsGetQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadsGet *>(query.get());

    auto dbResult = smsDB->threads.getLimitOffset(localQuery->offset, localQuery->limit);
    auto records  = std::vector<ThreadRecord>(dbResult.begin(), dbResult.end());

    auto response = std::make_unique<db::query::ThreadsGetResults>(records);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadsGetForListQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadsGetForList *>(query.get());

    auto dbResult = smsDB->threads.getLimitOffset(localQuery->offset, localQuery->limit);
    auto records  = std::vector<ThreadRecord>(dbResult.begin(), dbResult.end());

    std::vector<ContactRecord> contacts;
    std::vector<utils::PhoneNumber::View> numbers;

    for (const auto &record : records) {
        contacts.push_back(ContactRecordInterface(contactsDB).GetByIdWithTemporary(record.contactID));
        numbers.push_back(ContactRecordInterface(contactsDB).GetNumberById(record.numberID));
    }

    auto count = smsDB->threads.count();

    auto response = std::make_unique<db::query::ThreadsGetForListResults>(records, contacts, numbers, count);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadGetByIDQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadGetByID *>(query.get());

    const auto ret = GetByID(localQuery->id);
    auto response  = std::make_unique<db::query::ThreadGetByIDResult>(ret.isValid() ? std::optional<ThreadRecord>{ret}
                                                                                   : std::nullopt);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadGetByNumberQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadGetByNumber *>(query.get());

    auto response = std::make_unique<db::query::ThreadGetByNumberResult>(GetByNumber(localQuery->getNumber()));
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadGetByContactIDQuery(
    const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadGetByContactID *>(query.get());

    const auto thread = GetByContact(localQuery->id);
    auto response     = std::make_unique<db::query::ThreadGetByContactIDResult>(
        thread.isValid() ? std::optional<ThreadRecord>(thread) : std::nullopt);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadRemoveQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<const db::query::ThreadRemove *>(query.get());

    const auto ret = RemoveByID(localQuery->id);
    auto response  = std::make_unique<db::query::ThreadRemoveResult>(ret);
    response->setRequestQuery(query);
    return response;
}

M module-db/Interface/ThreadRecord.hpp => module-db/Interface/ThreadRecord.hpp +11 -7
@@ 7,7 7,6 @@
#include "module-db/Databases/SmsDB.hpp"
#include "module-db/Databases/ContactsDB.hpp"
#include "module-db/Common/Common.hpp"
#include "module-db/queries/messages/threads/QueryThreadsSearch.hpp"
#include "module-db/queries/messages/threads/QueryThreadMarkAsRead.hpp"
#include <PhoneNumber.hpp>



@@ 26,11 25,9 @@ struct ThreadRecord : Record

    ThreadRecord() = default;
    ThreadRecord(const ThreadsTableRow &rec)
        : date(rec.date), msgCount(rec.msgCount), unreadMsgCount(rec.unreadMsgCount), snippet(rec.snippet),
          type(rec.type), contactID(rec.contactID), numberID(rec.numberID)
    {
        ID = rec.ID;
    }
        : Record(rec.ID), date(rec.date), msgCount(rec.msgCount), unreadMsgCount(rec.unreadMsgCount),
          snippet(rec.snippet), type(rec.type), contactID(rec.contactID), numberID(rec.numberID)
    {}

    bool isUnread() const
    {


@@ 76,5 73,12 @@ class ThreadRecordInterface : public RecordInterface<ThreadRecord, ThreadRecordF
    /// for now implementation between Interface <-> Database
    /// it would only make sense to pass Query from Inteface to multiple databases to get all data we are interested in
    /// or better split it to smaller entities... this could be done with any db high level interface -  left as it is
    std::unique_ptr<db::query::smsthread::MarkAsReadResult> runQueryImpl(const db::query::smsthread::MarkAsRead *query);
    std::unique_ptr<db::QueryResult> threadSearchForListQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> markAsReadQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadsGetQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadsGetForListQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadGetByIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadGetByNumberQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadGetByContactIDQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> threadRemoveQuery(const std::shared_ptr<db::Query> &query);
};

M module-db/Tables/Record.hpp => module-db/Tables/Record.hpp +3 -0
@@ 12,6 12,9 @@ struct Record
{
    uint32_t ID = DB_ID_NONE;

    Record() = default;
    Record(uint32_t ID) : ID(ID){};

    bool isValid() const
    {
        auto result = ID != DB_ID_NONE;

M module-db/Tables/ThreadsTable.cpp => module-db/Tables/ThreadsTable.cpp +8 -11
@@ 199,23 199,20 @@ std::pair<uint32_t, std::vector<ThreadsTableRow>> ThreadsTable::getBySMSQuery(st
    auto ret       = std::pair<uint32_t, std::vector<ThreadsTableRow>>{0, {}};
    auto count_ret = db->query("SELECT COUNT (*) from sms WHERE sms.body like \'%%%q%%\'", text.c_str());
    ret.first      = count_ret == nullptr ? 0 : (*count_ret)[0].getUInt32();

    if (ret.first != 0) {
        auto retQuery =
            db->query("SELECT * from sms WHERE sms.body like \'%%%q%%\' ORDER BY date DESC LIMIT %lu OFFSET %lu;",
                      text.c_str(),
                      limit,
                      offset);
        do {
            ret.second.push_back(ThreadsTableRow{
                {.ID = (*retQuery)[0].getUInt32()},
                .date           = (*retQuery)[3].getUInt32(),
                .msgCount       = 0,
                .unreadMsgCount = 0,
                .contactID      = (*retQuery)[2].getUInt32(),
                .snippet        = (*retQuery)[6].getString(),
                .type           = static_cast<SMSType>((*retQuery)[7].getUInt32()),
            });
        } while (retQuery->nextRow());

        if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
            ret.second = {};
        }
        else {
            fillRetQuery(ret.second, retQuery);
        }
    }
    else {
        ret.second = {};

M module-db/queries/messages/sms/QuerySMSGetForList.cpp => module-db/queries/messages/sms/QuerySMSGetForList.cpp +11 -4
@@ 7,8 7,8 @@

namespace db::query
{
    SMSGetForList::SMSGetForList(unsigned int threadId, unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), threadId(threadId), offset(offset), limit(limit)
    SMSGetForList::SMSGetForList(unsigned int threadId, unsigned int offset, unsigned int limit, unsigned int contactID)
        : Query(Query::Type::Read), threadId(threadId), offset(offset), limit(limit), contactID(contactID)
    {}

    auto SMSGetForList::debugInfo() const -> std::string


@@ 16,8 16,11 @@ namespace db::query
        return "SMSGetForList";
    }

    SMSGetForListResult::SMSGetForListResult(std::vector<SMSRecord> result, unsigned int count, SMSRecord draft)
        : result(std::move(result)), count(count), draft(std::move(draft))
    SMSGetForListResult::SMSGetForListResult(std::vector<SMSRecord> result,
                                             unsigned int count,
                                             SMSRecord draft,
                                             const utils::PhoneNumber::View &number)
        : result(std::move(result)), count(count), draft(std::move(draft)), number(number)
    {}
    auto SMSGetForListResult::getResults() const -> std::vector<SMSRecord>
    {


@@ 31,6 34,10 @@ namespace db::query
    {
        return draft;
    }
    auto SMSGetForListResult::getNumber() const -> utils::PhoneNumber::View
    {
        return number;
    }
    auto SMSGetForListResult::debugInfo() const -> std::string
    {
        return "SMSGetForListResult";

M module-db/queries/messages/sms/QuerySMSGetForList.hpp => module-db/queries/messages/sms/QuerySMSGetForList.hpp +11 -5
@@ 13,11 13,12 @@ namespace db::query
    class SMSGetForList : public Query
    {
      public:
        unsigned int threadId = DB_ID_NONE;
        unsigned int offset   = 0;
        unsigned int limit    = 0;
        unsigned int threadId  = DB_ID_NONE;
        unsigned int offset    = 0;
        unsigned int limit     = 0;
        unsigned int contactID = 0;

        SMSGetForList(unsigned int id, unsigned int offset = 0, unsigned int limit = 0);
        SMSGetForList(unsigned int id, unsigned int offset = 0, unsigned int limit = 0, unsigned int contactID = 0);
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };



@@ 26,12 27,17 @@ namespace db::query
        std::vector<SMSRecord> result;
        unsigned int count = 0;
        SMSRecord draft;
        utils::PhoneNumber::View number;

      public:
        SMSGetForListResult(std::vector<SMSRecord> result, unsigned int count, SMSRecord draft);
        SMSGetForListResult(std::vector<SMSRecord> result,
                            unsigned int count,
                            SMSRecord draft,
                            const utils::PhoneNumber::View &number);
        [[nodiscard]] auto getResults() const -> std::vector<SMSRecord>;
        [[nodiscard]] auto getCount() const -> unsigned int;
        [[nodiscard]] auto getDraft() const -> SMSRecord;
        [[nodiscard]] auto getNumber() const -> utils::PhoneNumber::View;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };


A module-db/queries/messages/templates/QuerySMSTemplateGetForList.cpp => module-db/queries/messages/templates/QuerySMSTemplateGetForList.cpp +34 -0
@@ 0,0 1,34 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuerySMSTemplateGetForList.hpp"

#include <utility>

namespace db::query
{
    SMSTemplateGetForList::SMSTemplateGetForList(unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), offset(offset), limit(limit)
    {}

    auto SMSTemplateGetForList::debugInfo() const -> std::string
    {
        return "SMSTemplateGetForList";
    }

    SMSTemplateGetForListResult::SMSTemplateGetForListResult(std::vector<SMSTemplateRecord> result, unsigned int count)
        : result(std::move(result)), count(count)
    {}
    auto SMSTemplateGetForListResult::getResults() const -> std::vector<SMSTemplateRecord>
    {
        return result;
    }
    auto SMSTemplateGetForListResult::getCount() const -> unsigned int
    {
        return count;
    }
    auto SMSTemplateGetForListResult::debugInfo() const -> std::string
    {
        return "SMSTemplateGetForListResult";
    }
} // namespace db::query

A module-db/queries/messages/templates/QuerySMSTemplateGetForList.hpp => module-db/queries/messages/templates/QuerySMSTemplateGetForList.hpp +36 -0
@@ 0,0 1,36 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Common/Query.hpp>
#include <string>
#include <Interface/SMSTemplateRecord.hpp>

namespace db::query
{

    class SMSTemplateGetForList : public Query
    {
      public:
        unsigned int offset = 0;
        unsigned int limit  = 0;

        SMSTemplateGetForList(unsigned int offset = 0, unsigned int limit = 0);
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class SMSTemplateGetForListResult : public QueryResult
    {
        std::vector<SMSTemplateRecord> result;
        unsigned int count = 0;

      public:
        SMSTemplateGetForListResult(std::vector<SMSTemplateRecord> result, unsigned int count);

        [[nodiscard]] auto getResults() const -> std::vector<SMSTemplateRecord>;
        [[nodiscard]] auto getCount() const -> unsigned int;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

} // namespace db::query

M module-db/queries/messages/threads/QueryThreadMarkAsRead.cpp => module-db/queries/messages/threads/QueryThreadMarkAsRead.cpp +2 -2
@@ 3,7 3,7 @@

#include "QueryThreadMarkAsRead.hpp"

namespace db::query::smsthread
namespace db::query
{
    MarkAsRead::MarkAsRead(uint32_t id, Read read) : Query(Query::Type::Update), read(read), id(id)
    {}


@@ 25,4 25,4 @@ namespace db::query::smsthread
    {
        return "MarkAsReadResult";
    }
} // namespace db::query::smsthread
} // namespace db::query

M module-db/queries/messages/threads/QueryThreadMarkAsRead.hpp => module-db/queries/messages/threads/QueryThreadMarkAsRead.hpp +2 -2
@@ 6,7 6,7 @@
#include <Common/Query.hpp>
#include <string>

namespace db::query::smsthread
namespace db::query
{
    class MarkAsRead : public Query
    {


@@ 34,4 34,4 @@ namespace db::query::smsthread
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

} // namespace db::query::smsthread
} // namespace db::query

M module-db/queries/messages/threads/QueryThreadsGet.cpp => module-db/queries/messages/threads/QueryThreadsGet.cpp +2 -2
@@ 16,10 16,10 @@ namespace db::query
        return "SMSThreadsGet";
    }

    ThreadsGetResults::ThreadsGetResults(std::vector<ThreadsTableRow> result_rows) : results(std::move(result_rows))
    ThreadsGetResults::ThreadsGetResults(std::vector<ThreadRecord> result_rows) : results(std::move(result_rows))
    {}

    auto ThreadsGetResults::getResults() const -> std::vector<ThreadsTableRow>
    auto ThreadsGetResults::getResults() const -> std::vector<ThreadRecord>
    {
        return results;
    }

M module-db/queries/messages/threads/QueryThreadsGet.hpp => module-db/queries/messages/threads/QueryThreadsGet.hpp +4 -3
@@ 4,6 4,7 @@
#pragma once

#include <Tables/ThreadsTable.hpp>
#include "Interface/ThreadRecord.hpp"
#include <Common/Query.hpp>
#include <string>



@@ 22,11 23,11 @@ namespace db::query

    class ThreadsGetResults : public QueryResult
    {
        std::vector<ThreadsTableRow> results;
        std::vector<ThreadRecord> results;

      public:
        ThreadsGetResults(std::vector<ThreadsTableRow> result_rows);
        [[nodiscard]] auto getResults() const -> std::vector<ThreadsTableRow>;
        ThreadsGetResults(std::vector<ThreadRecord> result_rows);
        [[nodiscard]] auto getResults() const -> std::vector<ThreadRecord>;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };


A module-db/queries/messages/threads/QueryThreadsGetForList.cpp => module-db/queries/messages/threads/QueryThreadsGetForList.cpp +45 -0
@@ 0,0 1,45 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <Tables/ThreadsTable.hpp>
#include <utility>
#include "QueryThreadsGetForList.hpp"

namespace db::query
{
    ThreadsGetForList::ThreadsGetForList(unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), offset(offset), limit(limit)
    {}
    auto ThreadsGetForList::debugInfo() const -> std::string
    {
        return "SMSThreadsGetForList";
    }

    ThreadsGetForListResults::ThreadsGetForListResults(std::vector<ThreadRecord> results,
                                                       std::vector<ContactRecord> contacts,
                                                       std::vector<utils::PhoneNumber::View> numbers,
                                                       unsigned int count)
        : results(std::move(results)), contacts(std::move(contacts)), numbers(std::move(numbers)), count(count)
    {}
    auto ThreadsGetForListResults::getResults() const -> std::vector<ThreadRecord>
    {
        return results;
    }
    auto ThreadsGetForListResults::getContacts() const -> std::vector<ContactRecord>
    {
        return contacts;
    }
    auto ThreadsGetForListResults::getNumbers() const -> std::vector<utils::PhoneNumber::View>
    {
        return numbers;
    }
    auto ThreadsGetForListResults::getCount() const -> unsigned int
    {
        return count;
    }
    auto ThreadsGetForListResults::debugInfo() const -> std::string
    {
        return "SMSThreadsGetForListResults";
    }

} // namespace db::query

A module-db/queries/messages/threads/QueryThreadsGetForList.hpp => module-db/queries/messages/threads/QueryThreadsGetForList.hpp +43 -0
@@ 0,0 1,43 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Interface/ThreadRecord.hpp>
#include <Interface/ContactRecord.hpp>
#include <Common/Query.hpp>
#include <string>

namespace db::query
{

    class ThreadsGetForList : public Query
    {
      public:
        unsigned int offset;
        unsigned int limit;
        ThreadsGetForList(unsigned int offset, unsigned int limit);

        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class ThreadsGetForListResults : public QueryResult
    {
        std::vector<ThreadRecord> results;
        std::vector<ContactRecord> contacts;
        std::vector<utils::PhoneNumber::View> numbers;
        unsigned int count = 0;

      public:
        ThreadsGetForListResults(std::vector<ThreadRecord> result,
                                 std::vector<ContactRecord> contacts,
                                 std::vector<utils::PhoneNumber::View> numbers,
                                 unsigned int count);
        [[nodiscard]] auto getResults() const -> std::vector<ThreadRecord>;
        [[nodiscard]] auto getContacts() const -> std::vector<ContactRecord>;
        [[nodiscard]] auto getNumbers() const -> std::vector<utils::PhoneNumber::View>;
        [[nodiscard]] auto getCount() const -> unsigned int;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

}; // namespace db::query

R module-db/queries/messages/threads/QueryThreadsSearch.cpp => module-db/queries/messages/threads/QueryThreadsSearchForList.cpp +19 -11
@@ 1,35 1,43 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SMSTable.hpp"
#include "QueryThreadsSearch.hpp"
#include "QueryThreadsSearchForList.hpp"

#include <utility>

namespace db::query
{
    ThreadsSearch::ThreadsSearch(std::string text_to_search, unsigned int starting_position, unsigned int depth)
        : Query(Query::Type::Read), text(text_to_search), startingPosition(starting_position), depth(depth)
    ThreadsSearchForList::ThreadsSearchForList(std::string textToSearch, unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), textToSearch(std::move(textToSearch)), offset(offset), limit(limit)
    {}

    auto ThreadsSearch::debugInfo() const -> std::string
    auto ThreadsSearchForList::debugInfo() const -> std::string
    {
        return "SMSSearch";
    }

    ThreadsSearchResult::ThreadsSearchResult(unsigned int results_max_depth, std::vector<ThreadsTableRow> result_rows)
        : results_max_depth(results_max_depth), results(result_rows)
    ThreadsSearchResultForList::ThreadsSearchResultForList(std::vector<ThreadRecord> results,
                                                           std::vector<ContactRecord> contacts,
                                                           unsigned int count)
        : results(std::move(results)), contacts(std::move(contacts)), count(count)
    {}

    auto ThreadsSearchResult::getMax() const -> unsigned int
    auto ThreadsSearchResultForList::getCount() const -> unsigned int
    {
        return results_max_depth;
        return count;
    }

    auto ThreadsSearchResult::getResults() const -> std::vector<ThreadsTableRow>
    auto ThreadsSearchResultForList::getResults() const -> std::vector<ThreadRecord>
    {
        return results;
    }

    [[nodiscard]] auto ThreadsSearchResult::debugInfo() const -> std::string
    auto ThreadsSearchResultForList::getContacts() const -> std::vector<ContactRecord>
    {
        return contacts;
    }

    [[nodiscard]] auto ThreadsSearchResultForList::debugInfo() const -> std::string
    {
        return "SMSSearchResult";
    }

R module-db/queries/messages/threads/QueryThreadsSearch.hpp => module-db/queries/messages/threads/QueryThreadsSearchForList.hpp +17 -12
@@ 3,33 3,38 @@

#pragma once

#include <Tables/ThreadsTable.hpp>
#include <Interface/ThreadRecord.hpp>
#include <Interface/ContactRecord.hpp>
#include <Common/Query.hpp>
#include <string>

namespace db::query
{
    /// implements search for SMS by text
    class ThreadsSearch : public Query
    class ThreadsSearchForList : public Query
    {
      public:
        std::string text;
        unsigned int startingPosition;
        unsigned int depth;
        ThreadsSearch(std::string text_to_search, unsigned int starting_position, unsigned int depth);
        std::string textToSearch;
        unsigned int offset;
        unsigned int limit;
        ThreadsSearchForList(std::string textToSearch, unsigned int offset, unsigned int limit);

        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

    class ThreadsSearchResult : public QueryResult
    class ThreadsSearchResultForList : public QueryResult
    {
        unsigned int results_max_depth = 0;
        std::vector<ThreadsTableRow> results;
        std::vector<ThreadRecord> results;
        std::vector<ContactRecord> contacts;
        unsigned int count = 0;

      public:
        ThreadsSearchResult(unsigned int results_max_depth, std::vector<ThreadsTableRow> result_rows);
        [[nodiscard]] auto getMax() const -> unsigned int;
        [[nodiscard]] auto getResults() const -> std::vector<ThreadsTableRow>;
        ThreadsSearchResultForList(std::vector<ThreadRecord> result,
                                   std::vector<ContactRecord> contacts,
                                   unsigned int count);
        [[nodiscard]] auto getCount() const -> unsigned int;
        [[nodiscard]] auto getResults() const -> std::vector<ThreadRecord>;
        [[nodiscard]] auto getContacts() const -> std::vector<ContactRecord>;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };


M module-db/queries/phonebook/QueryContactGetByID.cpp => module-db/queries/phonebook/QueryContactGetByID.cpp +2 -1
@@ 7,7 7,8 @@

using namespace db::query;

ContactGetByID::ContactGetByID(unsigned int id) : Query(Query::Type::Read), id(id)
ContactGetByID::ContactGetByID(unsigned int id, bool withTemporary)
    : Query(Query::Type::Read), id(id), withTemporary(withTemporary)
{}

ContactGetByIDResult::ContactGetByIDResult(const ContactRecord &record) : record(std::move(record))

M module-db/queries/phonebook/QueryContactGetByID.hpp => module-db/queries/phonebook/QueryContactGetByID.hpp +6 -1
@@ 16,15 16,20 @@ namespace db::query
    class ContactGetByID : public Query
    {
      public:
        ContactGetByID(unsigned int id);
        ContactGetByID(unsigned int id, bool withTemporary = false);
        [[nodiscard]] auto debugInfo() const -> std::string override;
        auto getID() -> unsigned int
        {
            return id;
        }
        auto getWithTemporary() -> bool
        {
            return withTemporary;
        }

      private:
        unsigned int id;
        bool withTemporary = false;
    };

    class ContactGetByIDResult : public QueryResult

M module-db/tests/QueryInterface.cpp => module-db/tests/QueryInterface.cpp +3 -3
@@ 9,7 9,7 @@
#include "Databases/SmsDB.hpp"
#include "SMSRecord.hpp"
#include "ThreadRecord.hpp"
#include "queries/messages/threads/QueryThreadsSearch.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include "queries/messages/sms/QuerySMSAdd.hpp"
#include "queries/messages/sms/QuerySMSRemove.hpp"
#include "queries/messages/sms/QuerySMSUpdate.hpp"


@@ 51,7 51,7 @@ TEST_CASE("Query interface")
        REQUIRE(smsInterface->runQuery(std::make_shared<db::TestQuery>()) == nullptr);
    }

    auto query = std::make_shared<db::query::ThreadsSearch>("a", 0, 10);
    auto query = std::make_shared<db::query::ThreadsSearchForList>("a", 0, 10);

    SECTION("known query, wrong interface")
    {


@@ 62,7 62,7 @@ TEST_CASE("Query interface")
    SECTION("proper result returned")
    {
        auto result = threadInterface->runQuery(query);
        REQUIRE(dynamic_cast<db::query::ThreadsSearchResult *>(result.get()));
        REQUIRE(dynamic_cast<db::query::ThreadsSearchResultForList *>(result.get()));
    }

    SECTION("Endpoint callback test")

M module-db/tests/ThreadRecord_tests.cpp => module-db/tests/ThreadRecord_tests.cpp +9 -11
@@ 10,7 10,7 @@
#include "Interface/SMSRecord.hpp"
#include "Interface/ThreadRecord.hpp"
#include "queries/messages/threads/QueryThreadMarkAsRead.hpp"
#include "queries/messages/threads/QueryThreadsSearch.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include "queries/messages/threads/QueryThreadGetByID.hpp"
#include "queries/messages/threads/QueryThreadGetByContactID.hpp"
#include "queries/messages/threads/QueryThreadGetByNumber.hpp"


@@ 180,10 180,9 @@ TEST_CASE("Thread Record tests")
        REQUIRE(rec.isUnread());

        {
            auto query =
                std::make_shared<db::query::smsthread::MarkAsRead>(3, db::query::smsthread::MarkAsRead::Read::True);
            auto query  = std::make_shared<db::query::MarkAsRead>(3, db::query::MarkAsRead::Read::True);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::smsthread::MarkAsReadResult *>(ret.get());
            auto result = dynamic_cast<db::query::MarkAsReadResult *>(ret.get());
            REQUIRE(result != nullptr);
            REQUIRE(result->getResult());
            rec = threadRecordInterface1.GetByID(3);


@@ 191,10 190,9 @@ TEST_CASE("Thread Record tests")
        }

        {
            auto query =
                std::make_shared<db::query::smsthread::MarkAsRead>(3, db::query::smsthread::MarkAsRead::Read::False);
            auto query  = std::make_shared<db::query::MarkAsRead>(3, db::query::MarkAsRead::Read::False);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::smsthread::MarkAsReadResult *>(ret.get());
            auto result = dynamic_cast<db::query::MarkAsReadResult *>(ret.get());
            REQUIRE(result != nullptr);
            REQUIRE(result->getResult());
            rec = threadRecordInterface1.GetByID(3);


@@ 222,18 220,18 @@ TEST_CASE("Thread Record tests")
        REQUIRE(smsRecInterface.Add(recordIN));

        {
            auto query  = std::make_shared<db::query::ThreadsSearch>("A", 0, 10);
            auto query  = std::make_shared<db::query::ThreadsSearchForList>("A", 0, 10);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::ThreadsSearchResult *>(ret.get());
            auto result = dynamic_cast<db::query::ThreadsSearchResultForList *>(ret.get());
            REQUIRE(result != nullptr);
            auto results = result->getResults();
            REQUIRE(results.size() == 2);
        }

        {
            auto query  = std::make_shared<db::query::ThreadsSearch>("O", 0, 10);
            auto query  = std::make_shared<db::query::ThreadsSearchForList>("O", 0, 10);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::ThreadsSearchResult *>(ret.get());
            auto result = dynamic_cast<db::query::ThreadsSearchResultForList *>(ret.get());
            REQUIRE(result != nullptr);
            auto results = result->getResults();
            REQUIRE(results.size() == 1);

M module-services/service-desktop/endpoints/DBHelper.hpp => module-services/service-desktop/endpoints/DBHelper.hpp +1 -1
@@ 7,7 7,7 @@
#include "Context.hpp"
#include "ParserFSM.hpp"
#include "messages/QueryMessage.hpp"
#include "queries/messages/threads/QueryThreadsSearch.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include <Service/Common.hpp>
#include <Service/Service.hpp>
#include "Endpoint.hpp"

M module-services/service-desktop/endpoints/messages/MessageHelper.cpp => module-services/service-desktop/endpoints/messages/MessageHelper.cpp +4 -4
@@ 16,7 16,7 @@
#include "queries/messages/sms/QuerySMSGetByID.hpp"
#include "queries/messages/sms/QuerySMSGetByText.hpp"
#include "queries/messages/sms/QuerySMSGetCount.hpp"
#include "queries/messages/threads/QueryThreadsSearch.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include "queries/messages/sms/QuerySMSRemove.hpp"
#include "queries/messages/templates/QuerySMSTemplateGet.hpp"
#include "queries/messages/templates/QuerySMSTemplateRemove.hpp"


@@ 434,15 434,15 @@ auto MessageHelper::updateDBEntry(Context &context) -> sys::ReturnCodes

auto MessageHelper::updateSMS(Context &context) -> sys::ReturnCodes
{
    using namespace db::query::smsthread;
    using namespace db::query;

    auto query = std::make_unique<db::query::smsthread::MarkAsRead>(
    auto query = std::make_unique<db::query::MarkAsRead>(
        context.getBody()[json::messages::threadID].int_value(),
        (context.getBody()[json::messages::isUnread].bool_value() ? MarkAsRead::Read::False : MarkAsRead::Read::True));

    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSResult = dynamic_cast<db::query::smsthread::MarkAsReadResult *>(result)) {
            if (auto SMSResult = dynamic_cast<db::query::MarkAsReadResult *>(result)) {

                context.setResponseStatus(SMSResult->getResult() ? http::Code::OK : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());