~aleteoryx/muditaos

5c7e8a2d1bf26ba331bd057c9d7bb45907f04ef8 — Pawel Paprocki 5 years ago 47c817c
[EGD-4314] Indexer DB – support for ListView (#996)

M changelog.md => changelog.md +1 -0
@@ 12,6 12,7 @@
* `[audio]` Added support for headset microphone.
* `[filesystem]` Added support for standard file IO library.
* [`[messages]`] Added fetching text messages at phone startup.
* `[service/db]` Added support for ListView in FileIndexer DB.

## Changed


M module-services/service-db/agents/file_indexer/FileIndexerAgent.cpp => module-services/service-db/agents/file_indexer/FileIndexerAgent.cpp +159 -22
@@ 17,7 17,7 @@ FileIndexerAgent::FileIndexerAgent(sys::Service *parentService) : DatabaseAgent(

void FileIndexerAgent::initDb()
{
    LOG_INFO("[ServiceDB][File Indexer] Initializing");
    LOG_INFO("[ServiceDB][File Indexer] Initialized");
    database->execute(getDbInitString().c_str());
}



@@ 49,6 49,11 @@ void FileIndexerAgent::registerMessages()
                           std::bind(&FileIndexerAgent::handleGetAllProperties, this, _1));
    parentService->connect(FileIndexer::Messages::SetPropertiesMessage(),
                           std::bind(&FileIndexerAgent::handleSetProperties, this, _1));

    parentService->connect(FileIndexer::Messages::RegisterOnFileChange(),
                           std::bind(&FileIndexerAgent::handleRegisterOnFileChange, this, _1));
    parentService->connect(FileIndexer::Messages::UnregisterOnFileChange(),
                           std::bind(&FileIndexerAgent::handleUnregisterOnFileChange, this, _1));
}

auto FileIndexerAgent::getDbInitString() -> const std::string


@@ 61,7 66,6 @@ auto FileIndexerAgent::getDbInitString() -> const std::string

auto FileIndexerAgent::getDbFilePath() -> const std::string
{

    return USER_PATH("file_indexer.db");
}
auto FileIndexerAgent::getAgentName() -> const std::string


@@ 69,10 73,55 @@ auto FileIndexerAgent::getAgentName() -> const std::string
    return std::string("fileIndexerAgent");
}

auto FileIndexerAgent::dbRegisterFileChange(std::string dir, std::string service) -> bool
{
    auto retQuery = database->query(FileIndexer::Statements::getNotification, dir.c_str(), service.c_str());
    if (nullptr == retQuery || FileIndexer::ZERO_ROWS_FOUND == retQuery->getRowCount()) {
        // notification does not exist in db, insert a new one
        return database->execute(FileIndexer::Statements::setNotification, dir.c_str(), service.c_str());
    }
    // service already registered for the dir
    return false;
}

auto FileIndexerAgent::dbUnregisterFileChange(std::string dir, std::string service) -> bool
{
    return database->execute(FileIndexer::Statements::clearNotificationdRow, dir.c_str(), service.c_str());
}

auto FileIndexerAgent::handleRegisterOnFileChange(sys::Message *req) -> sys::MessagePointer
{
    if (auto msg = dynamic_cast<FileIndexer::Messages::RegisterOnFileChange *>(req)) {
        if (dbRegisterFileChange(msg->directory, msg->sender)) {
            auto it = fileChangeRecipents.find(msg->directory);
            if (fileChangeRecipents.end() == it) {
                fileChangeRecipents[msg->directory] = {msg->sender};
            }
            else {
                it->second.insert(msg->sender);
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}

auto FileIndexerAgent::handleUnregisterOnFileChange(sys::Message *req) -> sys::MessagePointer
{
    if (auto msg = dynamic_cast<FileIndexer::Messages::UnregisterOnFileChange *>(req)) {
        if (dbUnregisterFileChange(msg->directory, msg->sender)) {
            auto it = fileChangeRecipents.find(msg->directory);
            if (fileChangeRecipents.end() != it) {
                it->second.erase(msg->sender);
            }
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}

auto FileIndexerAgent::dbGetFilesCount() -> unsigned int
{
    auto retQuery = database->query(FileIndexer::Statements::getFilesCount);
    if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
    if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
        return 0;
    }
    return (*retQuery)[0].getInt32();


@@ 81,20 130,41 @@ auto FileIndexerAgent::dbGetFilesCount() -> unsigned int
auto FileIndexerAgent::dbListDir(std::unique_ptr<FileIndexer::ListDirData> listDir)
    -> std::unique_ptr<FileIndexer::ListDirData>
{

    auto retQuery = database->query(FileIndexer::Statements::getFilesByDir, listDir->directory.c_str());
    if (nullptr == retQuery) {
    if (nullptr == retQuery || FileIndexer::ZERO_ROWS_FOUND == retQuery->getRowCount()) {
        listDir->count = 0;
        listDir->fileList.clear();
        return listDir;
    }
    listDir->count     = retQuery->getRowCount();
    unsigned int index = 0;

    listDir->count = retQuery->getRowCount();
    if (retQuery->getRowCount() > 0) {
        listDir->fileList.clear();
    // returns all files in directory
    if (listDir->list_limit == 0) {
        do {
            listDir->fileList.push_back(FileIndexer::FileRecord(retQuery.get()));
        } while (retQuery->nextRow());
        return listDir;
    }

    // returns files from  directory in chunks (offset,limit)
    // validate offset against count
    if (listDir->list_offset > listDir->count) {
        listDir->count = 0;
        return listDir;
    }
    // Navigate to the proper row specified by offset
    if (listDir->list_offset > 0) {
        do {
            index++;
        } while (retQuery->nextRow() && (index < listDir->list_offset));
    }
    // Add records to the file list starting form list_offset and limited by list_limit
    do {
        listDir->fileList.push_back(FileIndexer::FileRecord(retQuery.get()));
        index++;
    } while (retQuery->nextRow() && (index < listDir->list_offset + listDir->list_limit));

    return listDir;
}



@@ 112,13 182,13 @@ auto FileIndexerAgent::dbGetRecord(std::unique_ptr<FileIndexer::FileRecord> reco

    if (false == record->path.empty()) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoByPath, record->path.c_str());
        if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return FileIndexer::FileRecord{};
        }
    }
    else if (record->file_id != FileIndexer::FILE_ID_NOT_EXISTS) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoById, record->file_id);
        if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return FileIndexer::FileRecord{};
        }
    }


@@ 130,14 200,30 @@ auto FileIndexerAgent::dbGetRecord(std::unique_ptr<FileIndexer::FileRecord> reco

auto FileIndexerAgent::dbSetRecord(std::unique_ptr<FileIndexer::FileRecord> record) -> bool
{
    return database->execute(FileIndexer::Statements::insertFileInfo,
                             record->file_id,

    auto retQuery = database->query(FileIndexer::Statements::getFileInfoByPath, record->path.c_str());
    FileIndexer::FileRecord retRecord(retQuery.get());

    if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
        // file do not exist in db, insert a new file record
        return database->execute(FileIndexer::Statements::insertFileInfo,
                                 // retRecord.file_id,
                                 record->path.c_str(),
                                 record->size,
                                 record->mime_type,
                                 record->mtime,
                                 record->directory.c_str(),
                                 record->file_type);
    }
    // update existing file record
    return database->execute(FileIndexer::Statements::updateFileInfo,
                             record->path.c_str(),
                             record->size,
                             record->mime_type,
                             record->mtime,
                             record->directory.c_str(),
                             record->file_type);
                             record->file_type,
                             retRecord.file_id);
}

auto FileIndexerAgent::dbUpdateRecord(std::unique_ptr<FileIndexer::FileRecord> record) -> bool


@@ 177,6 263,11 @@ auto FileIndexerAgent::handleSetRecord(sys::Message *req) -> sys::MessagePointer
            sys::Bus::SendUnicast(std::move(updateMsg), msg->sender, parentService);
            dbSetRecord(std::make_unique<FileIndexer::FileRecord>(record));
        }

        for (auto recipient : fileChangeRecipents[record.directory]) {
            auto notifeMsg = std::make_shared<FileIndexer::Messages::FileChanged>(record.directory);
            sys::Bus::SendUnicast(std::move(notifeMsg), recipient, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}


@@ 189,7 280,7 @@ auto FileIndexerAgent::dbGetProperty(std::unique_ptr<FileIndexer::FileMetadata> 
    std::unique_ptr<QueryResult> retQuery = nullptr;

    retQuery = database->query(FileIndexer::Statements::getPropertyValue, property.c_str(), metaData->path.c_str());
    if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
    if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
        return *metaData;
    }
    FileIndexer::FileMetadata retMetaData;


@@ 221,21 312,62 @@ auto FileIndexerAgent::dbGetAllProperties(std::unique_ptr<FileIndexer::FileMetad

auto FileIndexerAgent::dbSetProperty(std::unique_ptr<FileIndexer::FileMetadata> metaData) -> bool
{
    std::unique_ptr<QueryResult> retQuery = nullptr;
    unsigned int fileId;

    if (false == metaData->path.empty()) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoByPath, metaData->path.c_str());
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return false;
        }
        fileId = (*retQuery)[0].getInt32();
    }
    else if (metaData->file_id != FileIndexer::FILE_ID_NOT_EXISTS) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoById, metaData->file_id);
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return false;
        }
        fileId = metaData->file_id;
    }
    else {
        // there is no way to identify the file (id or path)
        return false;
    }

    auto itr      = metaData->properties.begin();
    auto property = itr->first;
    auto value    = itr->second;
    return database->execute(
        FileIndexer::Statements::insertPropertyValue, metaData->file_id, property.c_str(), value.c_str());
    return database->execute(FileIndexer::Statements::insertPropertyValue, fileId, property.c_str(), value.c_str());
}

auto FileIndexerAgent::dbSetProperties(std::unique_ptr<FileIndexer::FileMetadata> metaData) -> bool
{
    bool statusCode = true;
    bool statusCode                       = true;
    std::unique_ptr<QueryResult> retQuery = nullptr;
    unsigned int fileId;

    if (false == metaData->path.empty()) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoByPath, metaData->path.c_str());
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return false;
        }
        fileId = (*retQuery)[0].getInt32();
    }
    else if (metaData->file_id != FileIndexer::FILE_ID_NOT_EXISTS) {
        retQuery = database->query(FileIndexer::Statements::getFileInfoById, metaData->file_id);
        if (nullptr == retQuery || FileIndexer::ONE_ROW_FOUND != retQuery->getRowCount()) {
            return false;
        }
        fileId = metaData->file_id;
    }
    else {
        // there is no way to identify the file (id or path)
        return false;
    }

    for (auto propVal : metaData->properties) {
        statusCode = database->execute(FileIndexer::Statements::insertPropertyValue,
                                       metaData->file_id,
                                       propVal.first.c_str(),
                                       propVal.second.c_str());
        statusCode = database->execute(
            FileIndexer::Statements::insertPropertyValue, fileId, propVal.first.c_str(), propVal.second.c_str());
        if (!statusCode)
            return statusCode;
    }


@@ 312,7 444,12 @@ auto FileIndexerAgent::handleSetProperties(sys::Message *req) -> sys::MessagePoi
        auto updateMsg                     = std::make_shared<FileIndexer::Messages::PropertyChangedMessage>(
            std::move(metaDataPtr), std::make_unique<FileIndexer::FileMetadata>(msg->dbMetaData));
        sys::Bus::SendUnicast(std::move(updateMsg), msg->sender, parentService);
        dbSetProperty(std::make_unique<FileIndexer::FileMetadata>(metaData));
        dbSetProperties(std::make_unique<FileIndexer::FileMetadata>(metaData));

        for (auto recipient : fileChangeRecipents[metaData.directory]) {
            auto notifyMsg = std::make_shared<FileIndexer::Messages::FileChanged>(metaData.directory);
            sys::Bus::SendUnicast(std::move(notifyMsg), recipient, parentService);
        }
    }
    return std::make_shared<sys::ResponseMessage>();
}

M module-services/service-db/agents/file_indexer/FileIndexerAgent.hpp => module-services/service-db/agents/file_indexer/FileIndexerAgent.hpp +6 -0
@@ 19,6 19,12 @@ class FileIndexerAgent : public DatabaseAgent
    void dbTest();

  private:
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    MapOfRecipentsToBeNotified fileChangeRecipents;
    auto handleRegisterOnFileChange(sys::Message *req) -> sys::MessagePointer;
    auto handleUnregisterOnFileChange(sys::Message *req) -> sys::MessagePointer;
    auto dbRegisterFileChange(std::string dir, std::string service) -> bool;
    auto dbUnregisterFileChange(std::string dir, std::string service) -> bool;
    auto dbListDir(std::unique_ptr<FileIndexer::ListDirData> listDir) -> std::unique_ptr<FileIndexer::ListDirData>;
    auto dbGetProperty(std::unique_ptr<FileIndexer::FileMetadata> metaData) -> FileIndexer::FileMetadata;
    auto dbSetProperty(std::unique_ptr<FileIndexer::FileMetadata> metaData) -> bool;

M module-services/service-db/agents/file_indexer/FileIndexer_queries.hpp => module-services/service-db/agents/file_indexer/FileIndexer_queries.hpp +28 -2
@@ 47,8 47,8 @@ namespace FileIndexer::Statements
                        )sql";

    constexpr auto insertFileInfo = R"sql(
                        INSERT OR REPLACE INTO file_tab (file_id, path, size, mime_type, mtime, directory, file_type) VALUES
                        ( '%lu', '%q', '%lu', '%lu' , '%lu', '%q', '%lu') ;
                        INSERT OR REPLACE INTO file_tab (path, size, mime_type, mtime, directory, file_type) VALUES
                        ('%q', '%lu', '%lu' , '%lu', '%q', '%lu') ;
                        )sql";

    constexpr auto updateFileInfo = R"sql(


@@ 85,4 85,30 @@ namespace FileIndexer::Statements
                        WHERE file_id= '%lu' AND property = '%q' ;
                        )sql";

    constexpr auto setNotification = R"sql(
                        INSERT OR REPLACE INTO notifications_tab (path, service) VALUES
                        ( '%q' , '%q' ) ;
                        )sql";

    constexpr auto updateNotification = R"sql(
                        UPDATE notifications_tab SET path = '%q', service = '%q'
                        WHERE id = '%lu';
                        )sql";

    constexpr auto clearNotificationdRow = R"sql(
                        DELETE FROM notifications_tab
                        WHERE path = '%q' AND service = '%q';
                        )sql";

    constexpr auto getAllNotifications = R"sql(
                        SELECT id, path, service
                        FROM notifications_tab  AS NT;
                        )sql";

    constexpr auto getNotification = R"sql(
                        SELECT id, path, service
                        FROM notifications_tab  AS NT
                        WHERE path= '%q' AND service = '%q';
                        )sql";

} // namespace FileIndexer::Statements

M module-services/service-db/agents/file_indexer/file_indexer.sql => module-services/service-db/agents/file_indexer/file_indexer.sql +15 -5
@@ 34,24 34,34 @@ CREATE TABLE IF NOT EXISTS notifications_tab (
    path TEXT NOT NULL,
    service TEXT,
    CONSTRAINT notification_unique
        UNIQUE(path, service)
         UNIQUE(path, service)
);

-- ----------- insert default values ----------------------

INSERT OR REPLACE INTO file_tab (file_id, path, size, mime_type, mtime, directory, file_type) VALUES
    (1, 'mp3/track1.mp3', 456666, 1, 1603929600, 'mp3',12297),
    (2, 'mp3/track2.mp3', 345354 ,1, 1603929604, 'mp3',12297);
    (2, 'mp3/track2.mp3', 345354 ,1, 1603929604, 'mp3',12297),
    (3, 'mp3/track3.mp3', 34534 ,1, 1603929604, 'mp3',12297),
    (4, 'mp3/track4.mp3', 345354 ,1, 1603929604, 'mp3',12297);


INSERT OR REPLACE INTO metadata_tab (file_id, property, value) VALUES
    (1,'artist','Sting'),
    (1,'genre','Rock'),
    (1,'album','Album1'),
    (2,'artist','Nick Levis'),
    (2,'genre','Soul'),
    (2,'album','Album2');
    (2,'artist','Madonna'),
    (2,'genre','Rock'),
    (2,'album','Album2'),
    (3,'artist','Lady Gaga'),
    (3,'genre','Rock'),
    (3,'album','Album3'),
    (4,'artist','Nick Levis'),
    (4,'genre','Soul'),
    (4,'album','Album4');

INSERT OR REPLACE INTO notifications_tab (id, path, service) VALUES
    (1,'mp3','ServiceDB');

COMMIT;


M module-services/service-db/service-db/FileIndexerMessages.hpp => module-services/service-db/service-db/FileIndexerMessages.hpp +54 -4
@@ 15,21 15,24 @@ namespace FileIndexer
{
    constexpr unsigned int FILE_ID_NOT_EXISTS       = 0;
    constexpr unsigned int FILE_RECORD_COLUMN_COUNT = 7;
    constexpr unsigned int ONE_ROW_FOUND            = 1;
    constexpr unsigned int ZERO_ROWS_FOUND          = 0;

    // refers to file_tab
    struct FileRecord
    {
        unsigned int file_id = FILE_ID_NOT_EXISTS;
        std::string path     = "";
        std::string path;
        unsigned int size;
        unsigned int mime_type;
        unsigned int mtime;
        std::string directory = "";
        std::string directory;
        unsigned int file_type;

        [[nodiscard]] auto RecordEqual(FileRecord fr) const -> bool
        {
            bool records_equal = (fr.path == path) && (fr.mime_type == mime_type) && (fr.size == size);
            bool records_equal = (fr.path == path) && (fr.mime_type == mime_type) && (fr.size == size) &&
                                 (fr.mtime == mtime) && (fr.file_type == file_type) && (fr.directory == directory);
            return records_equal;
        }



@@ 46,6 49,22 @@ namespace FileIndexer
                file_type = (*query)[6].getInt32();
            }
        }
        explicit FileRecord(unsigned int fileId,
                            std::string fpath,
                            unsigned int fsize,
                            unsigned int fmime_type,
                            unsigned int fmtime,
                            std::string fdirectory,
                            unsigned int ftype)
        {
            file_id   = fileId;
            path      = fpath;
            size      = fsize;
            mime_type = fmime_type;
            mtime     = fmtime;
            directory = fdirectory;
            file_type = ftype;
        }
    };

    // refers to metadata_tab


@@ 59,7 78,6 @@ namespace FileIndexer
        std::vector<FileRecord> fileList;
        unsigned int list_limit;
        unsigned int list_offset;
        unsigned int list_size;
        unsigned int count;
    };



@@ 72,6 90,34 @@ namespace FileIndexer
            ~FileIndexerMessage() override = default;
        };

        class RegisterOnFileChange : public FileIndexerMessage
        {
          public:
            RegisterOnFileChange() = default;
            explicit RegisterOnFileChange(std::string dir) : directory(std::move(dir))
            {}
            std::string directory;
        };

        class UnregisterOnFileChange : public FileIndexerMessage
        {
          public:
            UnregisterOnFileChange() = default;
            explicit UnregisterOnFileChange(std::string dir) : directory(std::move(dir))
            {}
            std::string directory;
        };

        class FileChanged : public FileIndexerMessage
        {
          public:
            FileChanged() = default;
            explicit FileChanged(std::string dir) : directory(dir)
            {}

            std::string directory;
        };

        class GetListDirMessage : public FileIndexerMessage
        {
          public:


@@ 94,6 140,10 @@ namespace FileIndexer
            {
                return listDir->count;
            }
            auto getResults() -> std::vector<FileRecord>
            {
                return listDir->fileList;
            }
        };

        class RecordMessage : public FileIndexerMessage