~aleteoryx/muditaos

ref: 4689c3909dce897740e785d69f42006615502cf4 muditaos/module-db/Database/DatabaseInitializer.cpp -rw-r--r-- 4.2 KiB
4689c390 — Tigran Soghbatyan [BH-1083] Fix TimeListItem on inputEvent crush 4 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DatabaseInitializer.hpp"

#include <algorithm>
#include <cstdio>
#include <memory>
#include <set>
#include <string>
#include <sstream>
#include <log/log.hpp>

DatabaseInitializer::DatabaseInitializer(Database *db) : db(db)
{}

bool DatabaseInitializer::run(std::filesystem::path path, std::string ext)
{
    // Database name is database file path, need to strip off all filesystem related stuff(path, extension)
    std::filesystem::path dbpath = db->getName();
    std::string dbname           = dbpath.filename().replace_extension();

    for (int i = 1;; i++) {
        auto fname = std::make_unique<std::stringstream>();
        (*fname) << dbname << "_" << std::setfill('0') << std::setw(3) << i << '.' << ext;
        auto file = path / fname->str();
        LOG_DEBUG("Runing db script: %s", file.c_str());
        auto commands = readCommands(file);
        if (commands.empty())
            break;
        if (!executeOnDb(commands)) {
            LOG_ERROR("Can't initialize database [%s] with [%s]", db->getName().c_str(), file.c_str());
            return false;
        }
    }
    return true;
}

std::string DatabaseInitializer::readContent(const char *filename) const noexcept
{
    std::unique_ptr<char[]> fcontent;
    long fsize = 0;

    auto fp = std::fopen(filename, "r");
    if (fp) {
        std::fseek(fp, 0, SEEK_END);
        fsize = std::ftell(fp);
        std::rewind(fp);

        fcontent = std::make_unique<char[]>(fsize + 1);

        std::fread(fcontent.get(), 1, fsize, fp);

        std::fclose(fp);
    }
    else
        return {};

    return std::string(fcontent.get());
}

std::vector<std::string> DatabaseInitializer::readCommands(std::filesystem::path filePath)
{
    auto fileContent = readContent(filePath.c_str());
    if (fileContent.empty())
        return {};

    std::string currentStatement{};
    std::vector<std::string> statements{};

    std::string line{};
    for (auto &c : fileContent) {
        if (c != '\n') {
            line += c;
        }
        else {
            if (line.empty() || starts_with(line, std::string("--"))) {
                line.clear();
                continue;
            }
            if (ends_with(line, std::string(";"))) {
                statements.push_back(currentStatement + line);
                currentStatement.clear();
                line.clear();
                continue;
            }
            currentStatement += line;

            line.clear();
        }
    }
    return statements;
}

std::array<std::string, 3> DatabaseInitializer::splitFilename(std::string filename)
{
    auto name    = filename.substr(0, filename.find("."));
    auto prefix  = name.substr(0, name.find_last_of("_"));
    auto postfix = name.substr(name.find_last_of("_") + 1, std::string::npos);

    return {name, prefix, postfix};
}

std::vector<std::filesystem::path> DatabaseInitializer::listFiles(std::filesystem::path path,
                                                                  std::string prefix,
                                                                  std::string ext)
{
    std::set<std::pair<int, std::filesystem::path>> orderedFiles;
    for (const auto &entry : std::filesystem::directory_iterator(path)) {
        if (!entry.is_directory() && entry.path().has_filename()) {
            try {
                auto parts      = splitFilename(entry.path().filename().string());
                auto filePrefix = parts[1];
                if (filePrefix == prefix) {
                    auto num = std::stoi(parts[2]);
                    orderedFiles.insert({num, entry.path()});
                }
            }
            catch (std::invalid_argument &e) {
                LOG_INFO("Ignoring file: %s", entry.path().c_str());
            }
        }
    }

    std::vector<std::filesystem::path> files;
    std::for_each(orderedFiles.begin(), orderedFiles.end(), [&](auto item) { files.push_back(item.second); });
    return files;
}

bool DatabaseInitializer::executeOnDb(const std::vector<std::string> statements)
{
    for (auto st : statements) {
        if (!db->execute(st.c_str())) {
            return false;
        }
    }
    return true;
}