~aleteoryx/muditaos

885fe1083abcf3a39e12d75b6ba0b179b36de0ee — Marcin Smoczyński 5 years ago 258ef22
db: improve query handling

Introduce a new way to handle query responses allowing to deal with
races:
 - bind reponse with request,
 - handle responses with an observer-like interface.

Signed-off-by: Marcin Smoczyński <smoczynski.marcin@gmail.com>
32 files changed, 182 insertions(+), 115 deletions(-)

M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-messages/windows/SearchResults.cpp
M module-apps/application-phonebook/ApplicationPhonebook.cpp
M module-apps/application-phonebook/models/PhonebookModel.cpp
M module-apps/application-phonebook/models/PhonebookModel.hpp
M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp
M module-apps/application-phonebook/windows/PhonebookMainWindow.hpp
M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp
M module-apps/application-phonebook/windows/PhonebookSearchResults.hpp
M module-db/CMakeLists.txt
A module-db/Common/Query.cpp
M module-db/Common/Query.hpp
M module-db/Interface/BaseInterface.hpp
M module-db/Interface/CalllogRecord.cpp
M module-db/Interface/CalllogRecord.hpp
M module-db/Interface/ContactRecord.cpp
M module-db/Interface/ContactRecord.hpp
M module-db/Interface/NotificationsRecord.cpp
M module-db/Interface/NotificationsRecord.hpp
M module-db/Interface/Record.cpp
M module-db/Interface/SMSRecord.cpp
M module-db/Interface/SMSRecord.hpp
M module-db/Interface/ThreadRecord.cpp
M module-db/Interface/ThreadRecord.hpp
M module-db/tests/CalllogRecord_tests.cpp
M module-db/tests/NotificationsRecord_tests.cpp
M module-db/tests/QueryInterface.cpp
M module-db/tests/ThreadRecord_tests.cpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-db/ServiceDB.cpp
M module-services/service-db/messages/QueryMessage.cpp
M module-services/service-db/messages/QueryMessage.hpp
M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +2 -1
@@ 51,7 51,8 @@ namespace app
        // handle database response
        if (resp != nullptr) {
            if (auto msg = dynamic_cast<db::QueryResponse *>(resp)) {
                if (auto response = dynamic_cast<db::query::notifications::GetAllResult *>(msg->getResult())) {
                auto result = msg->getResult();
                if (auto response = dynamic_cast<db::query::notifications::GetAllResult *>(result.get())) {
                    handled = handle(response);
                }
            }

M module-apps/application-messages/windows/SearchResults.cpp => module-apps/application-messages/windows/SearchResults.cpp +2 -1
@@ 58,7 58,8 @@ namespace gui
    bool SearchResults::onDatabaseMessage(sys::Message *msgl)
    {
        if (auto msg = dynamic_cast<db::QueryResponse *>(msgl)) {
            if (auto response = dynamic_cast<db::query::SMSSearchResult *>(msg->getResult())) {
            auto result = msg->getResult();
            if (auto response = dynamic_cast<db::query::SMSSearchResult *>(result.get())) {
                return listViewUpdate(response);
            }
        }

M module-apps/application-phonebook/ApplicationPhonebook.cpp => module-apps/application-phonebook/ApplicationPhonebook.cpp +5 -1
@@ 1,5 1,6 @@
#include "ApplicationPhonebook.hpp"
#include "Dialog.hpp"
#include "messages/QueryMessage.hpp"
#include "models/PhonebookModel.hpp"
#include "windows/PhonebookContact.hpp"
#include "windows/PhonebookContactDetails.hpp"


@@ 38,7 39,10 @@ namespace app
            handled = true;
            switch (resp->responseTo) {
            case MessageType::DBQuery: {
                if (getCurrentWindow()->onDatabaseMessage(resp)) {
                auto queryResponse = dynamic_cast<db::QueryResponse *>(resp);
                assert(queryResponse);

                if (queryResponse->getResult()->handle()) {
                    refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
                }
            } break;

M module-apps/application-phonebook/models/PhonebookModel.cpp => module-apps/application-phonebook/models/PhonebookModel.cpp +17 -3
@@ 3,6 3,7 @@
#include "ListView.hpp"
#include "PhonebookModel.hpp"

#include <Common/Query.hpp>
#include <messages/QueryMessage.hpp>
#include <queries/phonebook/QueryContactGet.hpp>
#include <queries/RecordQuery.hpp>


@@ 11,6 12,7 @@
#include "UiCommonActions.hpp"

#include <string>
#include <utility>

const static std::uint32_t phonebookModelTimeout = 1000;



@@ 31,7 33,8 @@ void PhonebookModel::requestRecordsCount()
        auto queryResponse = dynamic_cast<db::QueryResponse *>(msg.get());
        assert(queryResponse != nullptr);

        auto countResult = dynamic_cast<db::query::RecordsSizeQueryResult *>(queryResponse->getResult());
        auto countResultResponse = queryResponse->getResult();
        auto countResult         = dynamic_cast<db::query::RecordsSizeQueryResult *>(countResultResponse.get());
        assert(countResult != nullptr);

        recordsCount = countResult->getSize();


@@ 40,8 43,9 @@ void PhonebookModel::requestRecordsCount()

void PhonebookModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    DBServiceAPI::GetQuery(
        application, db::Interface::Name::Contact, std::make_unique<db::query::ContactGet>(offset, limit, queryFilter));
    auto query = std::make_unique<db::query::ContactGet>(offset, limit, queryFilter);
    query->setQueryListener(this);
    DBServiceAPI::GetQuery(application, db::Interface::Name::Contact, std::move(query));
}

auto PhonebookModel::updateRecords(std::unique_ptr<std::vector<ContactRecord>> records,


@@ 116,3 120,13 @@ auto PhonebookModel::getFilter() const -> const std::string &
{
    return queryFilter;
}

auto PhonebookModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
{
    auto contactsResponse = dynamic_cast<db::query::ContactGetResult *>(queryResult);
    assert(contactsResponse != nullptr);

    auto records = std::make_unique<std::vector<ContactRecord>>(contactsResponse->getRecords());

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

M module-apps/application-phonebook/models/PhonebookModel.hpp => module-apps/application-phonebook/models/PhonebookModel.hpp +5 -1
@@ 5,6 5,7 @@
#include "application-phonebook/data/PhonebookStyle.hpp"
#include "application-phonebook/widgets/PhonebookItem.hpp"
#include "Application.hpp"
#include "Common/Query.hpp"
#include "DatabaseModel.hpp"
#include "Interface/ContactRecord.hpp"
#include "ListItemProvider.hpp"


@@ 12,7 13,7 @@

#include <string>

class PhonebookModel : public app::DatabaseModel<ContactRecord>, public gui::ListItemProvider
class PhonebookModel : public app::DatabaseModel<ContactRecord>, public gui::ListItemProvider, public db::QueryListener
{
  private:
    std::string queryFilter;


@@ 33,6 34,9 @@ class PhonebookModel : public app::DatabaseModel<ContactRecord>, public gui::Lis
    [[nodiscard]] auto getMinimalItemHeight() const -> unsigned int override;
    auto getItem(gui::Order order) -> gui::ListItem * override;

    // virtual method for db::QueryListener
    auto handleQueryResponse(db::QueryResult *) -> bool override;

    [[nodiscard]] auto getItemCount() const -> int override
    {
        return recordsCount;

M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp => module-apps/application-phonebook/windows/PhonebookMainWindow.cpp +0 -21
@@ 134,27 134,6 @@ namespace gui
        return AppWindow::onInput(inputEvent);
    }

    bool PhonebookMainWindow::onDatabaseMessage(sys::Message *msgl)
    {
        auto respMsg = dynamic_cast<sys::ResponseMessage *>(msgl);

        assert(respMsg != nullptr);
        assert(respMsg->responseTo == MessageType::DBQuery);

        auto queryResponse = dynamic_cast<db::QueryResponse *>(respMsg);
        if (queryResponse == nullptr) {
            LOG_ERROR("Unexpected message.");
            return false;
        }

        auto contactsResponse = dynamic_cast<db::query::ContactGetResult *>(queryResponse->getResult());
        assert(contactsResponse != nullptr);

        auto records = std::make_unique<std::vector<ContactRecord>>(contactsResponse->getRecords());

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

    bool PhonebookMainWindow::isSearchRequested() const
    {
        return requestedSearch;

M module-apps/application-phonebook/windows/PhonebookMainWindow.hpp => module-apps/application-phonebook/windows/PhonebookMainWindow.hpp +0 -1
@@ 28,7 28,6 @@ namespace gui
        // virtual methods
        bool onInput(const InputEvent &inputEvent) override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        bool onDatabaseMessage(sys::Message *msgl) override;

        void rebuild() override;
        void buildInterface() override;

M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp => module-apps/application-phonebook/windows/PhonebookSearchResults.cpp +0 -20
@@ 116,24 116,4 @@ namespace gui
        return true;
    }

    bool PhonebookSearchResults::onDatabaseMessage(sys::Message *msgl)
    {
        auto respMsg = dynamic_cast<sys::ResponseMessage *>(msgl);

        assert(respMsg != nullptr);
        assert(respMsg->responseTo == MessageType::DBQuery);

        auto queryResponse = dynamic_cast<db::QueryResponse *>(respMsg);
        if (queryResponse == nullptr) {
            LOG_ERROR("Unexpected message.");
            return false;
        }

        auto contactsResponse = dynamic_cast<db::query::ContactGetResult *>(queryResponse->getResult());
        assert(contactsResponse != nullptr);

        auto records = std::make_unique<std::vector<ContactRecord>>(contactsResponse->getRecords());

        return searchResultsModel->updateRecords(std::move(records));
    }
} /* namespace gui */

M module-apps/application-phonebook/windows/PhonebookSearchResults.hpp => module-apps/application-phonebook/windows/PhonebookSearchResults.hpp +0 -1
@@ 22,7 22,6 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        bool onDatabaseMessage(sys::Message *msgl) override;
    };

} /* namespace gui */

M module-db/CMakeLists.txt => module-db/CMakeLists.txt +2 -0
@@ 8,6 8,8 @@ include(thirdparty)
set (SQLITE3_SOURCE Database/sqlite3.c)

set(SOURCES
        Common/Query.cpp

        Database/Field.cpp
        Database/QueryResult.cpp
        Database/Database.cpp

A module-db/Common/Query.cpp => module-db/Common/Query.cpp +41 -0
@@ 0,0 1,41 @@
#include "Query.hpp"

#include <memory>
#include <utility>

using namespace db;

Query::Query(Type type, QueryListener *listener) : type(type), listener(listener)
{}

QueryListener *Query::getQueryListener() const noexcept
{
    return listener;
}

void Query::setQueryListener(QueryListener *queryListener) noexcept
{
    listener = queryListener;
}

QueryResult::QueryResult(std::shared_ptr<Query> requestQuery) : requestQuery(std::move(requestQuery))
{}

void QueryResult::setRequestQuery(std::shared_ptr<Query> requestQueryToSet)
{
    requestQuery = requestQueryToSet;
}

std::shared_ptr<Query> QueryResult::getRequestQuery() const noexcept
{
    return requestQuery;
}

bool QueryResult::handle()
{
    if (requestQuery == nullptr || requestQuery->getQueryListener() == nullptr) {
        throw std::runtime_error("No listener to handle query");
    }

    return requestQuery->getQueryListener()->handleQueryResponse(this);
}

M module-db/Common/Query.hpp => module-db/Common/Query.hpp +29 -3
@@ 1,9 1,18 @@
#pragma once

#include <memory>
#include <string>

namespace db
{
    class QueryResult;

    class QueryListener
    {
      public:
        virtual bool handleQueryResponse(QueryResult *) = 0;
    };

    /// virtual query input interface
    class Query
    {


@@ 16,20 25,37 @@ namespace db
            Delete
        };

        Query(Type type) : type(type)
        {}
        Query() = delete;
        Query(Type type, QueryListener *listener = nullptr);
        virtual ~Query() = default;

        QueryListener *getQueryListener() const noexcept;
        void setQueryListener(QueryListener *queryListener) noexcept;

        const Type type;

        [[nodiscard]] virtual auto debugInfo() const -> std::string = 0;

      private:
        QueryListener *listener = nullptr;
    };

    /// virtual query output (result) interface
    class QueryResult
    {
      public:
        virtual ~QueryResult()                                      = default;
        QueryResult(std::shared_ptr<Query> requestQuery = nullptr);
        virtual ~QueryResult() = default;

        void setRequestQuery(std::shared_ptr<Query> requestQueryToSet);
        std::shared_ptr<Query> getRequestQuery() const noexcept;

        virtual bool handle();

        [[nodiscard]] virtual auto debugInfo() const -> std::string = 0;

      protected:
        std::shared_ptr<Query> requestQuery;
    };

} // namespace db

M module-db/Interface/BaseInterface.hpp => module-db/Interface/BaseInterface.hpp +1 -1
@@ 11,7 11,7 @@ namespace db
    class Interface
    {
      public:
        virtual std::unique_ptr<db::QueryResult> runQuery(const db::Query *query);
        virtual std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query);

        enum class Name
        {

M module-db/Interface/CalllogRecord.cpp => module-db/Interface/CalllogRecord.cpp +2 -2
@@ 202,9 202,9 @@ bool CalllogRecordInterface::SetAllRead()
    return calllogDB->calls.SetAllRead();
}

std::unique_ptr<db::QueryResult> CalllogRecordInterface::runQuery(const db::Query *query)
std::unique_ptr<db::QueryResult> CalllogRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (const auto local_query = dynamic_cast<const db::query::calllog::SetAllRead *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::calllog::SetAllRead *>(query.get())) {
        return runQueryImpl(local_query);
    }
    return nullptr;

M module-db/Interface/CalllogRecord.hpp => module-db/Interface/CalllogRecord.hpp +1 -1
@@ 63,7 63,7 @@ class CalllogRecordInterface : public RecordInterface<CalllogRecord, CalllogReco

    uint32_t GetLastID();

    std::unique_ptr<db::QueryResult> runQuery(const db::Query *query) override;
    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;

  private:
    CalllogDB *calllogDB   = nullptr;

M module-db/Interface/ContactRecord.cpp => module-db/Interface/ContactRecord.cpp +10 -6
@@ 130,14 130,14 @@ bool ContactRecordInterface::RemoveByID(uint32_t id)
    return true;
}

std::unique_ptr<db::QueryResult> ContactRecordInterface::runQuery(const db::Query *query)
std::unique_ptr<db::QueryResult> ContactRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (query->type != db::Query::Type::Read) {
        LOG_WARN("Received unhandled query type: %lu", static_cast<unsigned long int>(query->type));
        return nullptr;
    }

    auto textFilter = dynamic_cast<const db::query::TextFilter *>(query);
    auto textFilter = dynamic_cast<const db::query::TextFilter *>(query.get());
    assert(query != nullptr);
    bool searchByNumber = false;
    if (textFilter->isFilterPresent() && utils::is_number(textFilter->getFilterData())) {


@@ 146,7 146,7 @@ std::unique_ptr<db::QueryResult> ContactRecordInterface::runQuery(const db::Quer
    }

    if (typeid(*query) == typeid(db::query::ContactGet)) {
        auto readQuery = static_cast<const db::query::ContactGet *>(query);
        auto readQuery = static_cast<const db::query::ContactGet *>(query.get());
        LOG_DEBUG("Contact read query, filter: \"%s\", offset=%lu, limit=%lu",
                  readQuery->getFilterData().c_str(),
                  static_cast<unsigned long>(readQuery->getOffset()),


@@ 158,10 158,12 @@ std::unique_ptr<db::QueryResult> ContactRecordInterface::runQuery(const db::Quer
        std::vector<ContactRecord> result(ids.size());
        std::transform(std::begin(ids), std::end(ids), std::begin(result), [this](uint32_t id) { return GetByID(id); });

        return std::make_unique<db::query::ContactGetResult>(result);
        auto response = std::make_unique<db::query::ContactGetResult>(result);
        response->setRequestQuery(query);
        return response;
    }
    else if (typeid(*query) == typeid(db::query::ContactGetSize)) {
        auto countQuery = static_cast<const db::query::ContactGetSize *>(query);
        auto countQuery = static_cast<const db::query::ContactGetSize *>(query.get());
        LOG_DEBUG("Contact count query, filter: \"%s\"", countQuery->getFilterData().c_str());

        std::size_t count = 0;


@@ 177,7 179,9 @@ std::unique_ptr<db::QueryResult> ContactRecordInterface::runQuery(const db::Quer

        LOG_DEBUG("Contact count query result: %lu", static_cast<unsigned long>(count));

        return std::make_unique<db::query::RecordsSizeQueryResult>(count);
        auto response = std::make_unique<db::query::RecordsSizeQueryResult>(count);
        response->setRequestQuery(query);
        return response;
    }
    else {
        LOG_ERROR("Unexpected query type.");

M module-db/Interface/ContactRecord.hpp => module-db/Interface/ContactRecord.hpp +1 -1
@@ 165,7 165,7 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
                                                       const char *alternativeName,
                                                       const char *number);

    std::unique_ptr<db::QueryResult> runQuery(const db::Query *query) override;
    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;

  private:
    ContactsDB *contactDB;

M module-db/Interface/NotificationsRecord.cpp => module-db/Interface/NotificationsRecord.cpp +5 -5
@@ 126,18 126,18 @@ NotificationsRecord NotificationsRecordInterface::GetByKey(NotificationsRecord::
    return notificationsDb->notifications.GetByKey(static_cast<uint32_t>(key));
}

std::unique_ptr<db::QueryResult> NotificationsRecordInterface::runQuery(const db::Query *query)
std::unique_ptr<db::QueryResult> NotificationsRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (const auto local_query = dynamic_cast<const db::query::notifications::Get *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::notifications::Get *>(query.get())) {
        return runQueryImpl(local_query);
    }
    if (const auto local_query = dynamic_cast<const db::query::notifications::Increment *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::notifications::Increment *>(query.get())) {
        return runQueryImpl(local_query);
    }
    if (const auto local_query = dynamic_cast<const db::query::notifications::Clear *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::notifications::Clear *>(query.get())) {
        return runQueryImpl(local_query);
    }
    if (const auto local_query = dynamic_cast<const db::query::notifications::GetAll *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::notifications::GetAll *>(query.get())) {
        return runQueryImpl(local_query);
    }
    return nullptr;

M module-db/Interface/NotificationsRecord.hpp => module-db/Interface/NotificationsRecord.hpp +1 -1
@@ 72,7 72,7 @@ class NotificationsRecordInterface : public RecordInterface<NotificationsRecord,

    NotificationsRecord GetByKey(NotificationsRecord::Key key);

    std::unique_ptr<db::QueryResult> runQuery(const db::Query *query) override;
    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;

  private:
    NotificationsDB *notificationsDb = nullptr;

M module-db/Interface/Record.cpp => module-db/Interface/Record.cpp +1 -1
@@ 5,7 5,7 @@
namespace db
{

    std::unique_ptr<QueryResult> Interface::runQuery(const Query *query)
    std::unique_ptr<QueryResult> Interface::runQuery(std::shared_ptr<db::Query> query)
    {
        LOG_DEBUG("Query not handled! debugInfo: %s", query ? query->debugInfo().c_str() : "empty");
        return nullptr;

M module-db/Interface/SMSRecord.cpp => module-db/Interface/SMSRecord.cpp +2 -2
@@ 286,9 286,9 @@ SMSRecord SMSRecordInterface::GetByID(uint32_t id)
    return SMSRecord{sms, number};
}

std::unique_ptr<db::QueryResult> SMSRecordInterface::runQuery(const db::Query *query)
std::unique_ptr<db::QueryResult> SMSRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (const auto local_query = dynamic_cast<const db::query::SMSSearchByType *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::SMSSearchByType *>(query.get())) {
        return runQueryImpl(local_query);
    }
    return nullptr;

M module-db/Interface/SMSRecord.hpp => module-db/Interface/SMSRecord.hpp +3 -3
@@ 56,12 56,12 @@ class SMSRecordInterface : public RecordInterface<SMSRecord, SMSRecordField>
                                                                  SMSRecordField field,
                                                                  const char *str) override final;

    std::unique_ptr<db::QueryResult> runQuery(const db::Query *query) override;
    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;

  private:
    static const uint32_t snippetLength = 45;
    SmsDB *smsDB                 = nullptr;
    ContactsDB *contactsDB       = nullptr;
    SmsDB *smsDB                        = nullptr;
    ContactsDB *contactsDB              = nullptr;

    std::unique_ptr<db::query::SMSSearchByTypeResult> runQueryImpl(const db::query::SMSSearchByType *query);


M module-db/Interface/ThreadRecord.cpp => module-db/Interface/ThreadRecord.cpp +3 -3
@@ 120,12 120,12 @@ ThreadRecord ThreadRecordInterface::GetByContact(uint32_t contact_id)
    return ThreadRecord(ret[0]);
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::runQuery(const db::Query *query)
std::unique_ptr<db::QueryResult> ThreadRecordInterface::runQuery(std::shared_ptr<db::Query> query)
{
    if (const auto local_query = dynamic_cast<const db::query::SMSSearch *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::SMSSearch *>(query.get())) {
        return runQueryImpl(local_query);
    }
    if (const auto local_query = dynamic_cast<const db::query::smsthread::MarkAsRead *>(query)) {
    if (const auto local_query = dynamic_cast<const db::query::smsthread::MarkAsRead *>(query.get())) {
        return runQueryImpl(local_query);
    }
    return nullptr;

M module-db/Interface/ThreadRecord.hpp => module-db/Interface/ThreadRecord.hpp +1 -1
@@ 60,7 60,7 @@ class ThreadRecordInterface : public RecordInterface<ThreadRecord, ThreadRecordF
                                                                     ThreadRecordField field,
                                                                     const char *str) override final;

    std::unique_ptr<db::QueryResult> runQuery(const db::Query *query) override;
    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;

  private:
    SmsDB *smsDB           = nullptr;

M module-db/tests/CalllogRecord_tests.cpp => module-db/tests/CalllogRecord_tests.cpp +2 -2
@@ 173,8 173,8 @@ TEST_CASE("Calllog Record tests")
        REQUIRE(calllogRecordInterface.GetCount(EntryState::UNREAD) == 4);
        REQUIRE(calllogRecordInterface.GetCount(EntryState::READ) == 0);

        db::query::calllog::SetAllRead query;
        auto ret    = calllogRecordInterface.runQuery(&query);
        auto query  = std::make_shared<db::query::calllog::SetAllRead>();
        auto ret    = calllogRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::calllog::SetAllReadResult *>(ret.get());
        REQUIRE(result != nullptr);
        REQUIRE(result->ret == true);

M module-db/tests/NotificationsRecord_tests.cpp => module-db/tests/NotificationsRecord_tests.cpp +8 -8
@@ 161,8 161,8 @@ TEST_CASE("Notifications Record tests")
    }

    auto getByKey = [&](NotificationsRecord::Key key, uint32_t val) {
        db::query::notifications::Get query{key};
        auto ret    = notificationsRecordInterface.runQuery(&query);
        auto query  = std::make_shared<db::query::notifications::Get>(key);
        auto ret    = notificationsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::notifications::GetResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto record = result->getResult();


@@ 172,16 172,16 @@ TEST_CASE("Notifications Record tests")
    };

    auto incrementByKey = [&](NotificationsRecord::Key key) {
        db::query::notifications::Increment query{key};
        auto ret    = notificationsRecordInterface.runQuery(&query);
        auto query  = std::make_shared<db::query::notifications::Increment>(key);
        auto ret    = notificationsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::notifications::IncrementResult *>(ret.get());
        REQUIRE(result != nullptr);
        REQUIRE(result->getResult());
    };

    auto clearByKey = [&](NotificationsRecord::Key key) {
        db::query::notifications::Clear query{key};
        auto ret    = notificationsRecordInterface.runQuery(&query);
        auto query  = std::make_shared<db::query::notifications::Clear>(key);
        auto ret    = notificationsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::notifications::ClearResult *>(ret.get());
        REQUIRE(result != nullptr);
        REQUIRE(result->getResult());


@@ 225,8 225,8 @@ TEST_CASE("Notifications Record tests")

    SECTION("Get All via query")
    {
        db::query::notifications::GetAll query;
        auto ret    = notificationsRecordInterface.runQuery(&query);
        auto query  = std::make_shared<db::query::notifications::GetAll>();
        auto ret    = notificationsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::notifications::GetAllResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();

M module-db/tests/QueryInterface.cpp => module-db/tests/QueryInterface.cpp +4 -4
@@ 40,20 40,20 @@ TEST_CASE("Query interface")

    SECTION("unknown query -> no results")
    {
        REQUIRE(smsInterface->runQuery(std::make_unique<db::TestQuery>().get()) == nullptr);
        REQUIRE(smsInterface->runQuery(std::make_shared<db::TestQuery>()) == nullptr);
    }

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

    SECTION("known query, wrong interface")
    {
        auto result = smsInterface->runQuery(query.get());
        auto result = smsInterface->runQuery(query);
        REQUIRE(result == nullptr);
    }

    SECTION("proper result returned")
    {
        auto result = threadInterface->runQuery(query.get());
        auto result = threadInterface->runQuery(query);
        REQUIRE(dynamic_cast<db::query::SMSSearchResult *>(result.get()));
    }
}

M module-db/tests/ThreadRecord_tests.cpp => module-db/tests/ThreadRecord_tests.cpp +12 -11
@@ 120,8 120,9 @@ TEST_CASE("Thread Record tests")
        REQUIRE(rec.isUnread());

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


@@ 130,8 131,9 @@ TEST_CASE("Thread Record tests")
        }

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


@@ 148,17 150,16 @@ TEST_CASE("Thread Record tests")
        recordIN.dateSent  = 987654321;
        recordIN.errorCode = 0;
        recordIN.number    = utils::PhoneNumber("+48600123456", utils::country::Id::UNKNOWN).getView();
        ;
        recordIN.body = "Ala";
        recordIN.type = SMSType ::DRAFT;
        recordIN.body      = "Ala";
        recordIN.type      = SMSType ::DRAFT;

        REQUIRE(smsRecInterface.Add(recordIN));
        recordIN.body = "Ola";
        REQUIRE(smsRecInterface.Add(recordIN));

        {
            db::query::SMSSearch query{"A", 0, 10};
            auto ret    = threadRecordInterface1.runQuery(&query);
            auto query  = std::make_shared<db::query::SMSSearch>("A", 0, 10);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::SMSSearchResult *>(ret.get());
            REQUIRE(result != nullptr);
            auto results = result->getResults();


@@ 166,8 167,8 @@ TEST_CASE("Thread Record tests")
        }

        {
            db::query::SMSSearch query{"O", 0, 10};
            auto ret    = threadRecordInterface1.runQuery(&query);
            auto query  = std::make_shared<db::query::SMSSearch>("O", 0, 10);
            auto ret    = threadRecordInterface1.runQuery(query);
            auto result = dynamic_cast<db::query::SMSSearchResult *>(ret.get());
            REQUIRE(result != nullptr);
            auto results = result->getResults();

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +2 -1
@@ 878,7 878,8 @@ sys::Message_t ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, sys:
    bool responseHandled = false;
    if (resp != nullptr) {
        if (auto msg = dynamic_cast<db::QueryResponse *>(resp)) {
            if (auto response = dynamic_cast<db::query::SMSSearchByTypeResult *>(msg->getResult())) {
            auto result = msg->getResult();
            if (auto response = dynamic_cast<db::query::SMSSearchByTypeResult *>(result.get())) {
                responseHandled = handle(response);
            }
        }

M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +5 -3
@@ 546,9 546,11 @@ sys::Message_t ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::Respo
        assert(msg);
        db::Interface *interface = getInterface(msg->getInterface());
        assert(interface != nullptr);
        auto result = interface->runQuery(msg->getQuery());
        responseMsg = std::make_shared<db::QueryResponse>(std::move(result));
        sendUpdateNotification(msg->getInterface(), msg->getQuery()->type);
        auto query     = msg->getQuery();
        auto queryType = query->type;
        auto result    = interface->runQuery(std::move(query));
        responseMsg    = std::make_shared<db::QueryResponse>(std::move(result));
        sendUpdateNotification(msg->getInterface(), queryType);
    } break;

    case MessageType::DBServiceBackup: {

M module-services/service-db/messages/QueryMessage.cpp => module-services/service-db/messages/QueryMessage.cpp +11 -4
@@ 1,5 1,8 @@
#include "QueryMessage.hpp"

#include <memory>
#include <stdexcept>

namespace db
{
    QueryMessage::QueryMessage(db::Interface::Name interface, std::unique_ptr<db::Query> query)


@@ 11,17 14,21 @@ namespace db
        return interface;
    }

    auto QueryMessage::getQuery() const -> db::Query *
    auto QueryMessage::getQuery() -> std::unique_ptr<db::Query>
    {
        return query.get();
        if (query == nullptr) {
            throw std::runtime_error("Invalid query (already moved from)");
        }

        return std::move(query);
    }

    QueryResponse::QueryResponse(std::unique_ptr<db::QueryResult> result)
        : DBResponseMessage(0, 0, MessageType::DBQuery), result(std::move(result))
    {}

    auto QueryResponse::getResult() const -> db::QueryResult *
    auto QueryResponse::getResult() -> std::unique_ptr<db::QueryResult>
    {
        return result.get();
        return std::move(result);
    }
} // namespace db

M module-services/service-db/messages/QueryMessage.hpp => module-services/service-db/messages/QueryMessage.hpp +4 -2
@@ 4,6 4,8 @@
#include <module-db/Common/Query.hpp>
#include <module-db/Interface/BaseInterface.hpp>

#include <memory>

namespace db
{
    class QueryMessage : public DBMessage


@@ 14,7 16,7 @@ namespace db
      public:
        QueryMessage(db::Interface::Name interface, std::unique_ptr<db::Query> query);
        [[nodiscard]] auto getInterface() const -> db::Interface::Name;
        [[nodiscard]] auto getQuery() const -> db::Query *;
        [[nodiscard]] auto getQuery() -> std::unique_ptr<db::Query>;
    };

    ///@note please see that this message might carry more information than just result


@@ 25,6 27,6 @@ namespace db

      public:
        QueryResponse(std::unique_ptr<db::QueryResult> result);
        [[nodiscard]] auto getResult() const -> db::QueryResult *;
        [[nodiscard]] auto getResult() -> std::unique_ptr<db::QueryResult>;
    };
} // namespace db