~aleteoryx/muditaos

56344b0579c474262880a6d50f666a3d553e4dcd — Adam Dobrowolski 4 years ago c88c82a
[EGD-6680] Notes crash fix on search

Changed query for all matches to query with limit
29 files changed, 286 insertions(+), 205 deletions(-)

M module-apps/application-notes/ApplicationNotes.cpp
M module-apps/application-notes/CMakeLists.txt
M module-apps/application-notes/data/NotesFoundData.cpp
M module-apps/application-notes/data/NotesFoundData.hpp
M module-apps/application-notes/model/NotesListModel.hpp
R module-apps/application-notes/model/{SearchResultsListModel => NotesListProvider}.hpp
M module-apps/application-notes/model/NotesRepository.cpp
M module-apps/application-notes/model/NotesRepository.hpp
A module-apps/application-notes/model/NotesSearchListModel.cpp
A module-apps/application-notes/model/NotesSearchListModel.hpp
D module-apps/application-notes/model/SearchResultsListModel.cpp
M module-apps/application-notes/presenter/NotesMainWindowPresenter.cpp
M module-apps/application-notes/presenter/NotesMainWindowPresenter.hpp
A module-apps/application-notes/presenter/NotesSearchResultPresenter.cpp
A module-apps/application-notes/presenter/NotesSearchResultPresenter.hpp
M module-apps/application-notes/presenter/SearchEngineWindowPresenter.cpp
M module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp
M module-apps/application-notes/windows/SearchEngineWindow.cpp
M module-apps/application-notes/windows/SearchEngineWindow.hpp
M module-apps/application-notes/windows/SearchResultsWindow.cpp
M module-apps/application-notes/windows/SearchResultsWindow.hpp
M module-db/Interface/NotesRecord.cpp
M module-db/Interface/NotesRecord.hpp
M module-db/Tables/NotesTable.cpp
M module-db/Tables/NotesTable.hpp
M module-db/queries/notes/QueryNotesGetByText.cpp
M module-db/queries/notes/QueryNotesGetByText.hpp
M module-db/tests/NotesRecord_tests.cpp
M module-db/tests/NotesTable_tests.cpp
M module-apps/application-notes/ApplicationNotes.cpp => module-apps/application-notes/ApplicationNotes.cpp +7 -5
@@ 107,12 107,14 @@ namespace app
            return std::make_unique<notes::NoteEditWindow>(app, std::move(presenter));
        });
        windowsFactory.attach(gui::name::window::notes_search, [](Application *app, const std::string &name) {
            auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
            auto presenter       = std::make_unique<notes::SearchEngineWindowPresenter>(std::move(notesRepository));
            return std::make_unique<notes::SearchEngineWindow>(app, std::move(presenter));
            return std::make_unique<notes::SearchEngineWindow>(app,
                                                               std::make_unique<notes::SearchEngineWindowPresenter>());
        });
        windowsFactory.attach(gui::name::window::notes_search_result, [](Application *app, const std::string &name) {
            return std::make_unique<notes::SearchResultsWindow>(app);
        windowsFactory.attach(gui::name::window::notes_search_result, [](Application *app, const std::string &) {
            auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
            auto notesProvider   = std::make_shared<notes::NotesSearchListModel>(app, std::move(notesRepository));
            auto presenter       = std::make_unique<notes::NotesSearchWindowPresenter>(notesProvider);
            return std::make_unique<notes::SearchResultsWindow>(app, std::move(presenter));
        });
        windowsFactory.attach(gui::name::window::note_dialog, [](Application *app, const std::string &name) {
            return std::make_unique<gui::Dialog>(app, name);

M module-apps/application-notes/CMakeLists.txt => module-apps/application-notes/CMakeLists.txt +4 -2
@@ 13,12 13,13 @@ target_sources( ${PROJECT_NAME}
	PRIVATE
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationNotes.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesListModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/SearchResultsListModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesSearchListModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesRepository.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesMainWindowPresenter.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotePreviewWindowPresenter.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NoteEditWindowPresenter.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/SearchEngineWindowPresenter.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesSearchResultPresenter.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/NotesItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/NoteMainWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/NotePreviewWindow.cpp"


@@ 31,12 32,13 @@ target_sources( ${PROJECT_NAME}
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationNotes.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesListModel.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/SearchResultsListModel.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesSearchListModel.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/model/NotesRepository.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesMainWindowPresenter.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotePreviewWindowPresenter.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NoteEditWindowPresenter.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/SearchEngineWindowPresenter.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesSearchResultPresenter.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/NotesItem.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/NoteMainWindow.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/NotePreviewWindow.hpp"

M module-apps/application-notes/data/NotesFoundData.cpp => module-apps/application-notes/data/NotesFoundData.cpp +3 -9
@@ 1,22 1,16 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesFoundData.hpp"

namespace app::notes
{
    NotesFoundData::NotesFoundData(std::string searchText, std::vector<NotesRecord> notes)
        : gui::SwitchData(std::string{"NotesFoundData"}), searchText{std::move(searchText)}, recordsFound{
                                                                                                 std::move(notes)}
    NotesFoundData::NotesFoundData(std::string searchText)
        : gui::SwitchData(std::string{"NotesFoundData"}), searchText{std::move(searchText)}
    {}

    const std::string &NotesFoundData::getSearchText() const noexcept
    {
        return searchText;
    }

    const std::vector<NotesRecord> &NotesFoundData::getFoundRecords() const noexcept
    {
        return recordsFound;
    }
} // namespace app::notes

M module-apps/application-notes/data/NotesFoundData.hpp => module-apps/application-notes/data/NotesFoundData.hpp +2 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 13,13 13,11 @@ namespace app::notes
    class NotesFoundData : public gui::SwitchData
    {
      public:
        NotesFoundData(std::string searchText, std::vector<NotesRecord> notes);
        explicit NotesFoundData(std::string searchText);

        const std::string &getSearchText() const noexcept;
        const std::vector<NotesRecord> &getFoundRecords() const noexcept;

      private:
        std::string searchText;
        std::vector<NotesRecord> recordsFound;
    };
} // namespace app::notes

M module-apps/application-notes/model/NotesListModel.hpp => module-apps/application-notes/model/NotesListModel.hpp +3 -13
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 6,23 6,14 @@
#include <cstdint>
#include <vector>

#include <module-apps/Application.hpp>
#include <module-apps/DatabaseModel.hpp>

#include <module-db/Interface/NotesRecord.hpp>

#include <module-gui/gui/widgets/ListItemProvider.hpp>

#include "NotesRepository.hpp"
#include "NotesListProvider.hpp"

namespace app::notes
{
    class NotesListItemProvider : public app::DatabaseModel<NotesRecord>, public gui::ListItemProvider
    {
      public:
        explicit NotesListItemProvider(app::Application *app);
    };

    class NotesListModel : public NotesListItemProvider
    {
      public:


@@ 35,9 26,8 @@ namespace app::notes
        [[nodiscard]] gui::ListItem *getItem(gui::Order order) override;
        [[nodiscard]] unsigned int getMinimalItemHeight() const override;

      private:
      protected:
        bool onNotesRetrieved(const std::vector<NotesRecord> &records, unsigned int notesRepoCount);

        std::shared_ptr<AbstractNotesRepository> notesRepository;
    };
} // namespace app::notes

R module-apps/application-notes/model/SearchResultsListModel.hpp => module-apps/application-notes/model/NotesListProvider.hpp +4 -18
@@ 3,29 3,15 @@

#pragma once

#include <application-notes/widgets/NotesItem.hpp>
#include <module-apps/DatabaseModel.hpp>
#include <module-db/Interface/NotesRecord.hpp>
#include <ListItemProvider.hpp>
#include <InternalModel.hpp>
#include <Application.hpp>
#include <module-apps/Application.hpp>

namespace app::notes
{
    class SearchResultsListModel : public InternalModel<gui::NotesItem *>, public gui::ListItemProvider
    class NotesListItemProvider : public app::DatabaseModel<NotesRecord>, public gui::ListItemProvider
    {
      public:
        explicit SearchResultsListModel(Application *application);

        void setResults(const std::vector<NotesRecord> &results);

        void requestRecords(std::uint32_t offset, std::uint32_t limit) override;
        unsigned int requestRecordsCount() override;
        unsigned int getMinimalItemHeight() const override;
        gui::ListItem *getItem(gui::Order order) override;

      private:
        gui::NotesItem *createItem(const NotesRecord &record) const;

        Application *application;
        explicit NotesListItemProvider(app::Application *app);
    };
} // namespace app::notes

M module-apps/application-notes/model/NotesRepository.cpp => module-apps/application-notes/model/NotesRepository.cpp +7 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesRepository.hpp"


@@ 33,9 33,12 @@ namespace app::notes
        task->execute(application, this);
    }

    void NotesDBRepository::getByText(const std::string &text, const OnFilteredCallback &callback)
    void NotesDBRepository::getByText(const std::string &text,
                                      std::uint32_t offset,
                                      std::uint32_t limit,
                                      const OnGetCallback &callback)
    {
        auto query = std::make_unique<db::query::QueryNotesGetByText>(text);
        auto query = std::make_unique<db::query::QueryNotesGetByText>(text, offset, limit);
        auto task  = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Notes);
        task->setCallback([callback](auto response) {
            auto result = dynamic_cast<db::query::NotesGetByTextResult *>(response);


@@ 43,7 46,7 @@ namespace app::notes
                return false;
            }
            if (callback) {
                callback(result->getRecords());
                callback(result->getRecords(), result->getCount());
            }
            return true;
        });

M module-apps/application-notes/model/NotesRepository.hpp => module-apps/application-notes/model/NotesRepository.hpp +9 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 15,13 15,15 @@ namespace app::notes
    {
      public:
        using OnGetCallback      = std::function<bool(const std::vector<NotesRecord> &, unsigned int)>;
        using OnFilteredCallback = std::function<void(const std::vector<NotesRecord> &)>;
        using OnResultCallback   = std::function<void(bool)>;

        virtual ~AbstractNotesRepository() noexcept = default;

        virtual void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) = 0;
        virtual void getByText(const std::string &text, const OnFilteredCallback &callback)        = 0;
        virtual void getByText(const std::string &text,
                               std::uint32_t offset,
                               std::uint32_t limit,
                               const OnGetCallback &callback)                                      = 0;
        virtual void save(const NotesRecord &note, const OnResultCallback &callback)               = 0;
        virtual void remove(const NotesRecord &note, const OnResultCallback &callback)             = 0;
    };


@@ 32,7 34,10 @@ namespace app::notes
        explicit NotesDBRepository(Application *application);

        void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) override;
        void getByText(const std::string &text, const OnFilteredCallback &callback) override;
        void getByText(const std::string &text,
                       std::uint32_t offset,
                       std::uint32_t limit,
                       const OnGetCallback &callback) override;
        void save(const NotesRecord &note, const OnResultCallback &callback) override;
        void remove(const NotesRecord &note, const OnResultCallback &callback) override;


A module-apps/application-notes/model/NotesSearchListModel.cpp => module-apps/application-notes/model/NotesSearchListModel.cpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesSearchListModel.hpp"
#include "log/log.hpp"

namespace app::notes
{
    void NotesSearchListModel::requestRecords(std::uint32_t offset, std::uint32_t limit)
    {
        notesRepository->getByText(
            searchText, offset, limit, [this](const std::vector<NotesRecord> &records, unsigned int notesRepoCount) {
                return onNotesRetrieved(records, notesRepoCount);
            });
    }
} // namespace app::notes

A module-apps/application-notes/model/NotesSearchListModel.hpp => module-apps/application-notes/model/NotesSearchListModel.hpp +32 -0
@@ 0,0 1,32 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <utility>

#include "NotesListModel.hpp"

namespace app::notes
{

    class NotesSearchListModel : public NotesListModel
    {
      public:
        NotesSearchListModel(app::Application *app, std::shared_ptr<AbstractNotesRepository> notesRepository)
            : NotesListModel(app, std::move(notesRepository))
        {}
        void setSearchText(const std::string &text)
        {
            searchText = text;
        }
        void requestRecords(std::uint32_t offset, std::uint32_t limit) override;
        const std::string &getSearchText() const noexcept
        {
            return searchText;
        }

      private:
        std::string searchText;
    };
} // namespace app::notes

D module-apps/application-notes/model/SearchResultsListModel.cpp => module-apps/application-notes/model/SearchResultsListModel.cpp +0 -59
@@ 1,59 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SearchResultsListModel.hpp"

#include "module-apps/application-notes/style/NotesListStyle.hpp"
#include "module-apps/application-notes/data/NoteSwitchData.hpp"

#include <module-gui/gui/widgets/ListView.hpp>
#include <module-apps/application-notes/ApplicationNotes.hpp>

namespace app::notes
{
    SearchResultsListModel::SearchResultsListModel(Application *application) : application{application}
    {}

    void SearchResultsListModel::setResults(const std::vector<NotesRecord> &results)
    {
        eraseInternalData();
        for (const auto &note : results) {
            auto item = createItem(note);
            internalData.push_back(std::move(item));
        }
    }

    gui::NotesItem *SearchResultsListModel::createItem(const NotesRecord &record) const
    {
        auto item               = new gui::NotesItem(std::make_shared<NotesRecord>(record));
        item->deleteByList      = false;
        item->activatedCallback = [this, record](gui::Item &) {
            auto data                        = std::make_unique<NoteSwitchData>(record);
            data->ignoreCurrentWindowOnStack = true;
            application->switchWindow(gui::name::window::note_preview, std::move(data));
            return true;
        };
        return item;
    }

    void SearchResultsListModel::requestRecords(std::uint32_t offset, std::uint32_t limit)
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();
    }

    unsigned int SearchResultsListModel::requestRecordsCount()
    {
        return internalData.size();
    }

    gui::ListItem *SearchResultsListModel::getItem(gui::Order order)
    {
        return getRecord(order);
    }

    unsigned int SearchResultsListModel::getMinimalItemHeight() const
    {
        return style::list::item::Height;
    }
} // namespace app::notes

M module-apps/application-notes/presenter/NotesMainWindowPresenter.cpp => module-apps/application-notes/presenter/NotesMainWindowPresenter.cpp +1 -11
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesMainWindowPresenter.hpp"


@@ 13,14 13,4 @@ namespace app::notes
    {
        return notesProvider;
    }

    bool NotesMainWindowPresenter::isNoteListEmpty()
    {
        return notesProvider->requestRecordsCount() == 0U;
    }

    bool NotesMainWindowPresenter::updateNotes(std::vector<NotesRecord> &&records)
    {
        return notesProvider->updateRecords(std::move(records));
    }
} // namespace app::notes

M module-apps/application-notes/presenter/NotesMainWindowPresenter.hpp => module-apps/application-notes/presenter/NotesMainWindowPresenter.hpp +1 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 23,8 23,6 @@ namespace app::notes
            virtual ~Presenter() noexcept = default;

            virtual std::shared_ptr<gui::ListItemProvider> getNotesItemProvider() const = 0;
            virtual bool isNoteListEmpty()                                              = 0;
            virtual bool updateNotes(std::vector<NotesRecord> &&records)                = 0;
        };
    };



@@ 34,8 32,6 @@ namespace app::notes
        explicit NotesMainWindowPresenter(std::shared_ptr<NotesListItemProvider> notesListItemProvider);

        std::shared_ptr<gui::ListItemProvider> getNotesItemProvider() const override;
        bool isNoteListEmpty() override;
        bool updateNotes(std::vector<NotesRecord> &&records) override;

      private:
        std::shared_ptr<NotesListItemProvider> notesProvider;

A module-apps/application-notes/presenter/NotesSearchResultPresenter.cpp => module-apps/application-notes/presenter/NotesSearchResultPresenter.cpp +34 -0
@@ 0,0 1,34 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesSearchResultPresenter.hpp"

namespace app::notes
{

    NotesSearchWindowPresenter::NotesSearchWindowPresenter(std::shared_ptr<NotesSearchListModel> notesListItemProvider)
        : notesProvider(std::move(notesListItemProvider))
    {}

    std::shared_ptr<gui::ListItemProvider> NotesSearchWindowPresenter::getNotesItemProvider() const
    {
        return notesProvider;
    }

    void NotesSearchWindowPresenter::handleSearchResults(db::NotificationMessage *msgNotification)
    {
        if (msgNotification->dataModified()) {
            getView()->onResultsFilled();
        }
    }

    void NotesSearchWindowPresenter::setSearchText(const std::string &text)
    {
        notesProvider->setSearchText(text);
    }

    const std::string &NotesSearchWindowPresenter::getSearchText() const
    {
        return notesProvider->getSearchText();
    }
} // namespace app::notes

A module-apps/application-notes/presenter/NotesSearchResultPresenter.hpp => module-apps/application-notes/presenter/NotesSearchResultPresenter.hpp +48 -0
@@ 0,0 1,48 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <module-apps/BasePresenter.hpp>

#include <module-apps/application-notes/model/NotesSearchListModel.hpp>
#include <module-services/service-db/service-db/DBNotificationMessage.hpp>

namespace app::notes
{
    class NotesSearchWindowContract
    {
      public:
        class View
        {
          public:
            virtual void onNothingFound(const std::string &searchText) = 0;
            virtual void onResultsFilled()                             = 0;
            virtual ~View() noexcept                                   = default;
        };

        class Presenter : public BasePresenter<NotesSearchWindowContract::View>
        {
          public:
            virtual ~Presenter() noexcept                                               = default;
            virtual std::shared_ptr<gui::ListItemProvider> getNotesItemProvider() const = 0;
            virtual void handleSearchResults(db::NotificationMessage *)                 = 0;
            virtual void setSearchText(const std::string &str)                          = 0;
            virtual const std::string &getSearchText() const                            = 0;
        };
    };

    class NotesSearchWindowPresenter : public NotesSearchWindowContract::Presenter
    {
      public:
        explicit NotesSearchWindowPresenter(std::shared_ptr<NotesSearchListModel> notesListItemProvider);

        std::shared_ptr<gui::ListItemProvider> getNotesItemProvider() const override;
        void handleSearchResults(db::NotificationMessage *msg) override;
        virtual void setSearchText(const std::string &text) override;
        virtual const std::string &getSearchText() const override;

      private:
        std::shared_ptr<NotesSearchListModel> notesProvider;
    };
} // namespace app::notes

M module-apps/application-notes/presenter/SearchEngineWindowPresenter.cpp => module-apps/application-notes/presenter/SearchEngineWindowPresenter.cpp +4 -8
@@ 1,21 1,17 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SearchEngineWindowPresenter.hpp"
#include <utility>

namespace app::notes
{
    SearchEngineWindowPresenter::SearchEngineWindowPresenter(std::unique_ptr<AbstractNotesRepository> &&notesRepository)
        : notesRepository{std::move(notesRepository)}
    {}

    void SearchEngineWindowPresenter::searchFor(const std::string &searchText)
    {
        if (searchText.empty()) {
            getView()->notesFound({}, searchText);
            getView()->emptySearch();
            return;
        }
        notesRepository->getByText(
            searchText, [searchText, this](const auto &records) { getView()->notesFound(records, searchText); });
        getView()->processValidSearch(searchText);
    }
} // namespace app::notes

M module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp => module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp +5 -10
@@ 1,11 1,11 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "BasePresenter.hpp"

#include <module-apps/application-notes/model/NotesRepository.hpp>
#include <module-apps/application-notes/model/NotesListModel.hpp>

namespace app::notes
{


@@ 16,14 16,13 @@ namespace app::notes
        {
          public:
            virtual ~View() noexcept = default;

            virtual void notesFound(const std::vector<NotesRecord> &notes, const std::string &searchText) = 0;
            virtual void emptySearch()                                     = 0;
            virtual void processValidSearch(const std::string &searchText) = 0;
        };
        class Presenter : public BasePresenter<SearchEngineWindowContract::View>
        {
          public:
            virtual ~Presenter() noexcept = default;

            virtual void searchFor(const std::string &searchText) = 0;
        };
    };


@@ 31,11 30,7 @@ namespace app::notes
    class SearchEngineWindowPresenter : public SearchEngineWindowContract::Presenter
    {
      public:
        explicit SearchEngineWindowPresenter(std::unique_ptr<AbstractNotesRepository> &&notesRepository);

        SearchEngineWindowPresenter() = default;
        void searchFor(const std::string &searchText) override;

      private:
        std::unique_ptr<AbstractNotesRepository> notesRepository;
    };
} // namespace app::notes

M module-apps/application-notes/windows/SearchEngineWindow.cpp => module-apps/application-notes/windows/SearchEngineWindow.cpp +7 -3
@@ 53,9 53,13 @@ namespace app::notes
        return AppWindow::onInput(inputEvent);
    }

    void SearchEngineWindow::notesFound(const std::vector<NotesRecord> &notes, const std::string &searchText)
    void SearchEngineWindow::emptySearch()
    {
        application->switchWindow(gui::name::window::notes_search_result,
                                  std::make_unique<NotesFoundData>(searchText, notes));
        application->switchWindow(gui::name::window::notes_search_result, std::make_unique<NotesFoundData>(""));
    }

    void SearchEngineWindow::processValidSearch(const std::string &searchText)
    {
        application->switchWindow(gui::name::window::notes_search_result, std::make_unique<NotesFoundData>(searchText));
    }
} // namespace app::notes

M module-apps/application-notes/windows/SearchEngineWindow.hpp => module-apps/application-notes/windows/SearchEngineWindow.hpp +3 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 24,7 24,8 @@ namespace app::notes
        void destroyInterface() override;
        bool onInput(const gui::InputEvent &inputEvent) override;

        void notesFound(const std::vector<NotesRecord> &notes, const std::string &searchText) override;
        void emptySearch() override;
        virtual void processValidSearch(const std::string &searchText) override;

      private:
        std::unique_ptr<SearchEngineWindowContract::Presenter> presenter;

M module-apps/application-notes/windows/SearchResultsWindow.cpp => module-apps/application-notes/windows/SearchResultsWindow.cpp +21 -17
@@ 11,10 11,9 @@

namespace app::notes
{
    SearchResultsWindow::SearchResultsWindow(Application *application)
        : AppWindow(application, gui::name::window::notes_search_result), listModel{
                                                                              std::make_shared<SearchResultsListModel>(
                                                                                  application)}
    SearchResultsWindow::SearchResultsWindow(Application *application,
                                             std::unique_ptr<NotesSearchWindowContract::Presenter> &&windowPresenter)
        : AppWindow(application, gui::name::window::notes_search_result), presenter(std::move(windowPresenter))
    {
        buildInterface();
    }


@@ 39,9 38,10 @@ namespace app::notes
                                 style::list::Y,
                                 style::list::Width,
                                 style::list::Height,
                                 listModel,
                                 presenter->getNotesItemProvider(),
                                 gui::listview::ScrollBarType::Fixed);
        list->setScrollTopMargin(::style::margins::small);
        list->emptyListCallback = [&]() { onNothingFound(presenter->getSearchText()); };
        setFocusItem(list);
    }



@@ 53,19 53,9 @@ namespace app::notes

    void SearchResultsWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
    {
        auto foundNotesData = dynamic_cast<NotesFoundData *>(data);
        if (foundNotesData == nullptr) {
            onNothingFound();
            return;
        }

        if (const auto &records = foundNotesData->getFoundRecords(); !records.empty()) {
            listModel->setResults(records);
        if (auto foundNotesData = dynamic_cast<NotesFoundData *>(data); foundNotesData != nullptr) {
            presenter->setSearchText(foundNotesData->getSearchText());
            list->rebuildList();
            setFocusItem(list);
        }
        else {
            onNothingFound(foundNotesData->getSearchText());
        }
    }



@@ 78,4 68,18 @@ namespace app::notes
        data->ignoreCurrentWindowOnStack = true;
        application->switchWindow(gui::name::window::note_dialog, std::move(data));
    }

    void SearchResultsWindow::onResultsFilled()
    {
        list->rebuildList(gui::listview::RebuildType::InPlace);
    }

    bool SearchResultsWindow::onDatabaseMessage(sys::Message *msg)
    {
        if (auto *message = dynamic_cast<db::NotificationMessage *>(msg);
            message != nullptr && message->interface == db::Interface::Name::Notes) {
            presenter->handleSearchResults(message);
        }
        return false;
    }
} // namespace app::notes

M module-apps/application-notes/windows/SearchResultsWindow.hpp => module-apps/application-notes/windows/SearchResultsWindow.hpp +10 -8
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 8,27 8,29 @@
#include "AppWindow.hpp"

#include <module-apps/Application.hpp>
#include <module-apps/application-notes/model/SearchResultsListModel.hpp>
#include <module-apps/application-notes/presenter/NotesSearchResultPresenter.hpp>

#include <module-gui/gui/widgets/ListView.hpp>

namespace app::notes
{
    class SearchResultsWindow : public gui::AppWindow
    class SearchResultsWindow : public gui::AppWindow, public NotesSearchWindowContract::View
    {
      public:
        explicit SearchResultsWindow(Application *application);
        explicit SearchResultsWindow(app::Application *app,
                                     std::unique_ptr<NotesSearchWindowContract::Presenter> &&windowPresenter);
        ~SearchResultsWindow() noexcept override;

        void buildInterface() override;
        void destroyInterface() override;

        bool onDatabaseMessage(sys::Message *msg) override;
        void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;

      private:
        void onNothingFound(const std::string &searchText = {});
        std::unique_ptr<NotesSearchWindowContract::Presenter> presenter;

        std::shared_ptr<SearchResultsListModel> listModel;
      private:
        void onNothingFound(const std::string &searchText) override;
        virtual void onResultsFilled() override;
        gui::ListView *list = nullptr;
    };
} // namespace app::notes

M module-db/Interface/NotesRecord.cpp => module-db/Interface/NotesRecord.cpp +8 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesRecord.hpp"


@@ 105,15 105,17 @@ std::vector<NotesRecord> NotesRecordInterface::getNotes(std::uint32_t offset, st
    return records;
}

std::vector<NotesRecord> NotesRecordInterface::getNotesByText(const std::string &text) const
std::pair<std::vector<NotesRecord>, unsigned int> NotesRecordInterface::getNotesByText(const std::string &text,
                                                                                       unsigned int offset,
                                                                                       unsigned int limit) const
{
    std::vector<NotesRecord> records;
    const auto &notes = notesDB->notes.getByText(text);
    auto [notes, count] = notesDB->notes.getByText(text, offset, limit);
    for (const auto &note : notes) {
        NotesRecord record{note.ID, note.date, note.snippet};
        records.push_back(std::move(record));
    }
    return records;
    return {records, count};
}

std::unique_ptr<db::QueryResult> NotesRecordInterface::runQuery(std::shared_ptr<db::Query> query)


@@ 145,8 147,8 @@ std::unique_ptr<db::QueryResult> NotesRecordInterface::getQuery(const std::share
std::unique_ptr<db::QueryResult> NotesRecordInterface::getByTextQuery(const std::shared_ptr<db::Query> &query)
{
    const auto localQuery = static_cast<db::query::QueryNotesGetByText *>(query.get());
    const auto &records   = getNotesByText(localQuery->getText());
    auto response         = std::make_unique<db::query::NotesGetByTextResult>(records);
    auto [records, count] = getNotesByText(localQuery->getText(), localQuery->getOffset(), localQuery->getLimit());
    auto response         = std::make_unique<db::query::NotesGetByTextResult>(records, count);
    response->setRequestQuery(query);
    return response;
}

M module-db/Interface/NotesRecord.hpp => module-db/Interface/NotesRecord.hpp +4 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 47,7 47,9 @@ class NotesRecordInterface : public RecordInterface<NotesRecord, NotesRecordFiel

  private:
    std::vector<NotesRecord> getNotes(std::uint32_t offset, std::uint32_t limit) const;
    std::vector<NotesRecord> getNotesByText(const std::string &text) const;
    std::pair<std::vector<NotesRecord>, unsigned int> getNotesByText(const std::string &text,
                                                                     unsigned int offset,
                                                                     unsigned int limit) const;

    std::unique_ptr<db::QueryResult> getQuery(const std::shared_ptr<db::Query> &query);
    std::unique_ptr<db::QueryResult> getByTextQuery(const std::shared_ptr<db::Query> &query);

M module-db/Tables/NotesTable.cpp => module-db/Tables/NotesTable.cpp +20 -5
@@ 1,7 1,9 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotesTable.hpp"
#include "log/log.hpp"
#include <string>

NotesTable::NotesTable(Database *db) : Table(db)
{}


@@ 117,11 119,23 @@ std::vector<NotesTableRow> NotesTable::getLimitOffsetByField(std::uint32_t offse
    return ret;
}

std::vector<NotesTableRow> NotesTable::getByText(const std::string &text)
std::pair<std::vector<NotesTableRow>, int> NotesTable::getByText(const std::string &text,
                                                                 unsigned int offset,
                                                                 unsigned int limit)
{
    auto retQuery = db->query("SELECT *, INSTR(snippet,'%s') pos FROM notes WHERE pos > 0;", text.c_str());

    unsigned int count = 0;
    auto queryRet      = db->query("SELECT COUNT(*), INSTR(snippet,'%s') pos FROM notes WHERE pos > 0;", text.c_str());
    if (queryRet && queryRet->getRowCount() != 0) {
        count = (*queryRet)[0].getUInt32();
    }

    std::string queryText = "SELECT *, INSTR(snippet,'" + text + "') pos FROM notes WHERE pos > 0 LIMIT " +
                            std::to_string(limit) + " offset " + std::to_string(offset) + " ;";
    auto retQuery = db->query(queryText.c_str());

    if (retQuery == nullptr || retQuery->getRowCount() == 0) {
        return {};
        return {{}, count};
    }

    std::vector<NotesTableRow> records;


@@ 133,7 147,8 @@ std::vector<NotesTableRow> NotesTable::getByText(const std::string &text)
        };
        records.push_back(std::move(row));
    } while (retQuery->nextRow());
    return records;

    return {records, count};
}

std::uint32_t NotesTable::count()

M module-db/Tables/NotesTable.hpp => module-db/Tables/NotesTable.hpp +5 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 41,8 41,11 @@ class NotesTable : public Table<NotesTableRow, NotesTableFields>
                                                     std::uint32_t limit,
                                                     NotesTableFields field,
                                                     const char *str) override;
    std::vector<NotesTableRow> getByText(const std::string &text);
    std::pair<std::vector<NotesTableRow>, int> getByText(const std::string &text,
                                                         unsigned int offset,
                                                         unsigned int limit);

    std::uint32_t count() override;
    std::uint32_t countByText();
    std::uint32_t countByFieldId(const char *field, std::uint32_t id) override;
};

M module-db/queries/notes/QueryNotesGetByText.cpp => module-db/queries/notes/QueryNotesGetByText.cpp +7 -3
@@ 1,11 1,14 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QueryNotesGetByText.hpp"

#include <utility>

namespace db::query
{
    QueryNotesGetByText::QueryNotesGetByText(std::string text) : Query(Query::Type::Read), text{std::move(text)}
    QueryNotesGetByText::QueryNotesGetByText(std::string text, unsigned int offset, unsigned int limit)
        : Query(Query::Type::Read), offset(offset), limit(limit), text(std::move(text))
    {}

    const std::string &QueryNotesGetByText::getText() const noexcept


@@ 18,7 21,8 @@ namespace db::query
        return {"QueryNotesGetByText"};
    }

    NotesGetByTextResult::NotesGetByTextResult(std::vector<NotesRecord> notes) : records{std::move(notes)}
    NotesGetByTextResult::NotesGetByTextResult(std::vector<NotesRecord> notes, unsigned int count)
        : records{std::move(notes)}, dbRecordsCount(count)
    {}

    const std::vector<NotesRecord> &NotesGetByTextResult::getRecords() const noexcept

M module-db/queries/notes/QueryNotesGetByText.hpp => module-db/queries/notes/QueryNotesGetByText.hpp +19 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 13,24 13,40 @@ namespace db::query
    class QueryNotesGetByText : public Query
    {
      public:
        explicit QueryNotesGetByText(std::string text);
        explicit QueryNotesGetByText(std::string text, unsigned int offset, unsigned int limit);

        [[nodiscard]] const std::string &getText() const noexcept;
        [[nodiscard]] std::string debugInfo() const override;

        [[nodiscard]] unsigned int getOffset() const noexcept
        {
            return offset;
        }
        [[nodiscard]] unsigned int getLimit() const noexcept
        {
            return limit;
        };

      private:
        unsigned int offset;
        unsigned int limit;
        std::string text;
    };

    class NotesGetByTextResult : public QueryResult
    {
      public:
        explicit NotesGetByTextResult(std::vector<NotesRecord> notes);
        explicit NotesGetByTextResult(std::vector<NotesRecord> notes, unsigned int count);

        [[nodiscard]] const std::vector<NotesRecord> &getRecords() const noexcept;
        [[nodiscard]] unsigned int getCount() const noexcept
        {
            return dbRecordsCount;
        }
        [[nodiscard]] std::string debugInfo() const override;

      private:
        std::vector<NotesRecord> records;
        unsigned int dbRecordsCount;
    };
} // namespace db::query

M module-db/tests/NotesRecord_tests.cpp => module-db/tests/NotesRecord_tests.cpp +1 -1
@@ 46,7 46,7 @@ TEST_CASE("Notes Record tests")
    SECTION("Get notes by text query")
    {
        constexpr auto testSearch = "TEST";
        auto query                = std::make_unique<db::query::QueryNotesGetByText>(testSearch);
        auto query                = std::make_unique<db::query::QueryNotesGetByText>(testSearch, 0, 3);
        auto response             = notesRecordInterface.runQuery(std::move(query));
        auto getResult            = static_cast<db::query::NotesGetByTextResult *>(response.get());


M module-db/tests/NotesTable_tests.cpp => module-db/tests/NotesTable_tests.cpp +1 -1
@@ 38,7 38,7 @@ TEST_CASE("Notes Table tests")
    SECTION("Get notes by text query")
    {
        constexpr auto testSearch = "TEST";
        const auto &records       = table.getByText(testSearch);
        const auto [records, count] = table.getByText(testSearch, 0, 1);
        REQUIRE(records.size() == 1);
        REQUIRE(records[0].snippet == testSnippet);
    }