+12
-81
@@ -93,13 +93,9 @@ auto valid_title_image(noto::sqlite_value const &value) -> std::bool_t {
|
||||
return text.size() == 64U && std::all_of(text.begin(), text.end(), [](std::char_t c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); });
|
||||
}
|
||||
|
||||
auto compatible_table(noto::connection &connection, std::string const &table) -> boost::asio::awaitable<std::bool_t> {
|
||||
auto columns = std::vector<std::string_view>{"id", "title", "composer", "key_signature", "source_path", "source_json", "measure_count", "total_pages", "title_image"};
|
||||
if (table == "practice_exercises") {
|
||||
columns.push_back("exercise_id");
|
||||
}
|
||||
columns.push_back("part");
|
||||
auto parameters = std::vector<noto::sqlite_value>{noto::sqlite_value{table}};
|
||||
auto compatible_catalog(noto::connection &connection) -> boost::asio::awaitable<std::bool_t> {
|
||||
auto columns = std::vector<std::string_view>{"id", "title", "composer", "key_signature", "source_path", "source_json", "measure_count", "total_pages", "title_image", "part"};
|
||||
auto parameters = std::vector<noto::sqlite_value>{noto::sqlite_value{"songs"}};
|
||||
auto selected = co_await connection.async_execute("SELECT name, type, \"notnull\", pk FROM pragma_table_info(?1) "
|
||||
"WHERE EXISTS (SELECT 1 FROM pragma_table_list WHERE schema = 'main' AND name = ?1 AND type = 'table' AND strict = 1) ORDER BY cid",
|
||||
std::move(parameters));
|
||||
@@ -138,14 +134,12 @@ auto vamp_zero::async_validate_database(boost::asio::any_io_executor executor, v
|
||||
if (!application || *application != application_id) {
|
||||
status = std::unexpected(vamp_zero::make_error(vamp_zero::error_code::PERSISTENCE, "invalid or incompatible catalog: " + config.path + "; rebuild or reinstall Product Vamp"));
|
||||
}
|
||||
for (auto table : {"songs", "practice_exercises"}) {
|
||||
if (status && !(co_await compatible_table(connection, table))) {
|
||||
status = std::unexpected(vamp_zero::make_error(vamp_zero::error_code::PERSISTENCE, "incompatible catalog table " + std::string{table} + ": " + config.path + "; rebuild or reinstall Product Vamp"));
|
||||
}
|
||||
if (status && !(co_await compatible_catalog(connection))) {
|
||||
status = std::unexpected(vamp_zero::make_error(vamp_zero::error_code::PERSISTENCE, "incompatible songs catalog: " + config.path + "; rebuild or reinstall Product Vamp"));
|
||||
}
|
||||
if (status && integrity) {
|
||||
auto checked = co_await connection.async_execute("PRAGMA quick_check(1)");
|
||||
if (!checked || checked->rows.size() != 1U || checked->rows[0].size() != 1U || text_value(checked->rows[0][0]) != "ok") {
|
||||
auto checked = co_await connection.async_quick_check();
|
||||
if (!checked || *checked != std::vector<std::string>{"ok"}) {
|
||||
status = std::unexpected(vamp_zero::make_error(vamp_zero::error_code::PERSISTENCE, "corrupt catalog: " + config.path + "; rebuild or reinstall Product Vamp"));
|
||||
}
|
||||
}
|
||||
@@ -156,8 +150,8 @@ auto vamp_zero::async_validate_database(boost::asio::any_io_executor executor, v
|
||||
co_return closed;
|
||||
}
|
||||
|
||||
auto vamp_zero::async_load_performance_library(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string assets_path)
|
||||
-> boost::asio::awaitable<std::expected<vamp_zero::library_state, modulus::error>> {
|
||||
auto vamp_zero::async_load_catalog(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string assets_path)
|
||||
-> boost::asio::awaitable<std::expected<vamp_zero::catalog, modulus::error>> {
|
||||
auto connection = noto::connection{executor, connection_config(config)};
|
||||
auto connected = co_await connection.async_connect();
|
||||
if (!connected) {
|
||||
@@ -165,7 +159,7 @@ auto vamp_zero::async_load_performance_library(boost::asio::any_io_executor exec
|
||||
}
|
||||
auto selected =
|
||||
co_await connection.async_prepare("SELECT id, title, composer, part, source_path, measure_count, key_signature, total_pages, title_image FROM "
|
||||
"songs ORDER BY title COLLATE NOCASE, part COLLATE NOCASE");
|
||||
"songs ORDER BY title, composer, part, id");
|
||||
if (!selected) {
|
||||
auto close = co_await connection.async_close();
|
||||
if (!close) {
|
||||
@@ -210,69 +204,7 @@ auto vamp_zero::async_load_performance_library(boost::asio::any_io_executor exec
|
||||
if (!closed) {
|
||||
co_return std::unexpected(closed.error());
|
||||
}
|
||||
co_return vamp_zero::group_library_parts(std::move(parts));
|
||||
}
|
||||
|
||||
auto vamp_zero::async_load_practice_library(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string assets_path)
|
||||
-> boost::asio::awaitable<std::expected<vamp_zero::practice_library, modulus::error>> {
|
||||
auto connection = noto::connection{executor, connection_config(config)};
|
||||
auto connected = co_await connection.async_connect();
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
}
|
||||
auto selected = co_await connection.async_prepare("SELECT id, title, composer, key_signature, source_path, measure_count, total_pages, part, exercise_id, title_image "
|
||||
"FROM practice_exercises ORDER BY exercise_id, id");
|
||||
if (!selected) {
|
||||
auto close = co_await connection.async_close();
|
||||
if (!close) {
|
||||
modulus::log_error("database close failed after practice load error: " + close.error().describe());
|
||||
}
|
||||
co_return std::unexpected(selected.error());
|
||||
}
|
||||
auto exercises = std::vector<vamp_zero::practice_exercise>{};
|
||||
auto status = std::expected<void, modulus::error>{};
|
||||
for (;;) {
|
||||
auto next = co_await selected->async_step();
|
||||
if (!next) {
|
||||
status = std::unexpected(next.error());
|
||||
break;
|
||||
}
|
||||
if (!*next) {
|
||||
break;
|
||||
}
|
||||
auto const &row = **next;
|
||||
if (row.size() != 10U || count_value(row[5]) == 0U || count_value(row[6]) == 0U || text_value(row[8]).empty() || text_value(row[3]).empty() || !valid_title_image(row[9])) {
|
||||
status = std::unexpected(vamp_zero::make_error(vamp_zero::error_code::PERSISTENCE, "invalid practice metadata"));
|
||||
break;
|
||||
}
|
||||
auto source = resolve_source_path(assets_path, text_value(row[4]));
|
||||
if (!source) {
|
||||
status = std::unexpected(source.error());
|
||||
break;
|
||||
}
|
||||
auto practice_part = vamp_zero::library_part{
|
||||
.id = text_value(row[0]),
|
||||
.title = text_value(row[1]),
|
||||
.composer = text_value(row[2]),
|
||||
.key_signature = text_value(row[3]),
|
||||
.part = text_value(row[7]),
|
||||
.source_path = std::move(*source),
|
||||
.measure_count = count_value(row[5]),
|
||||
.total_pages = count_value(row[6]),
|
||||
.title_image = text_value(row[9]),
|
||||
};
|
||||
exercises.push_back({
|
||||
.id = text_value(row[8]),
|
||||
.title = text_value(row[1]),
|
||||
.composer = text_value(row[2]),
|
||||
.parts = {std::move(practice_part)},
|
||||
});
|
||||
}
|
||||
auto closed = co_await close_catalog_query(connection, *selected, std::move(status));
|
||||
if (!closed) {
|
||||
co_return std::unexpected(closed.error());
|
||||
}
|
||||
co_return vamp_zero::group_practice_exercises(std::move(exercises));
|
||||
co_return vamp_zero::group_ordered_parts(std::move(parts));
|
||||
}
|
||||
|
||||
auto vamp_zero::async_load_score(boost::asio::any_io_executor executor, vamp_zero::database_config config, vamp_zero::score_reference reference, std::string assets_path) -> boost::asio::awaitable<std::expected<vamp_zero::score_document, modulus::error>> {
|
||||
@@ -283,8 +215,7 @@ auto vamp_zero::async_load_score(boost::asio::any_io_executor executor, vamp_zer
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
}
|
||||
auto table = reference.category == vamp_zero::score_category::PERFORMANCE ? "songs" : "practice_exercises";
|
||||
auto selected = co_await connection.async_prepare("SELECT source_json, source_path FROM " + std::string{table} + " WHERE id = ?1");
|
||||
auto selected = co_await connection.async_prepare("SELECT source_json, source_path FROM songs WHERE id = ?1");
|
||||
if (!selected) {
|
||||
static_cast<void>(co_await connection.async_close());
|
||||
co_return std::unexpected(selected.error());
|
||||
|
||||
Reference in New Issue
Block a user