@@ -203,6 +203,7 @@ CREATE TABLE IF NOT EXISTS practice_exercises (
|
||||
if (ensured) {
|
||||
ensured = co_await execute_schema_statement(connection, "CREATE TRIGGER IF NOT EXISTS invalidate_" + std::string{table} + "_metadata AFTER UPDATE OF source_json ON " + table + " WHEN NEW.source_json != OLD.source_json BEGIN UPDATE " + table + " SET measure_count = NULL, total_pages = NULL, authored_key_signature = NULL WHERE id = NEW.id; END");
|
||||
}
|
||||
index_statements.push_back("CREATE INDEX IF NOT EXISTS idx_" + std::string{table} + "_pending_metadata ON " + table + "(id) WHERE measure_count IS NULL OR total_pages IS NULL OR authored_key_signature IS NULL");
|
||||
}
|
||||
for (auto &statement : index_statements) {
|
||||
if (!ensured) {
|
||||
@@ -255,8 +256,10 @@ auto now_ms() -> std::int64_t {
|
||||
.count();
|
||||
}
|
||||
|
||||
auto backfill_metadata(noto::connection &connection, std::string const &table) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||
auto backfill_metadata(boost::asio::any_io_executor executor, noto::connection &connection, std::string const &table) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||
for (;;) {
|
||||
// Bound immediate coroutine completion chains even for very large catalogues.
|
||||
co_await boost::asio::post(executor, boost::asio::use_awaitable);
|
||||
auto row = co_await connection.async_execute("SELECT id, source_path, source_json FROM " + table + " WHERE measure_count IS NULL OR total_pages IS NULL OR authored_key_signature IS NULL LIMIT 1");
|
||||
if (!row) {
|
||||
co_return std::unexpected(row.error());
|
||||
@@ -283,6 +286,20 @@ auto backfill_metadata(noto::connection &connection, std::string const &table) -
|
||||
}
|
||||
}
|
||||
|
||||
auto restore_imported_metadata(noto::connection &connection, std::string const &table, std::string const &id, vamp_zero::score_document const &document) -> boost::asio::awaitable<std::expected<void, modulus::error>> {
|
||||
auto params = std::vector<noto::sqlite_value>{
|
||||
noto::sqlite_value{static_cast<std::int64_t>(document.measure_count)},
|
||||
noto::sqlite_value{static_cast<std::int64_t>(document.pages.size())},
|
||||
noto::sqlite_value{document.authored_key_signature},
|
||||
noto::sqlite_value{id},
|
||||
};
|
||||
auto updated = co_await connection.async_execute("UPDATE " + table + " SET measure_count = ?1, total_pages = ?2, authored_key_signature = ?3 WHERE id = ?4 AND catalog_managed = 1 AND (measure_count IS NULL OR total_pages IS NULL OR authored_key_signature IS NULL)", std::move(params));
|
||||
if (!updated) {
|
||||
co_return std::unexpected(updated.error());
|
||||
}
|
||||
co_return std::expected<void, modulus::error>{};
|
||||
}
|
||||
|
||||
auto count_value(noto::sqlite_value const &value) -> std::size_t {
|
||||
auto count = std::get_if<std::int64_t>(&value.value);
|
||||
return count == nullptr || *count <= 0 ? 0U : static_cast<std::size_t>(*count);
|
||||
@@ -394,6 +411,7 @@ auto vamp_zero::async_import_catalogs(boost::asio::any_io_executor executor, vam
|
||||
if (!imported) {
|
||||
break;
|
||||
}
|
||||
co_await boost::asio::post(executor, boost::asio::use_awaitable);
|
||||
auto document = vamp_zero::read_score_document(path);
|
||||
if (!document) {
|
||||
imported = std::unexpected(document.error());
|
||||
@@ -445,6 +463,8 @@ WHERE songs.catalog_managed = 1
|
||||
std::move(params));
|
||||
if (!inserted) {
|
||||
imported = std::unexpected(inserted.error());
|
||||
} else {
|
||||
imported = co_await restore_imported_metadata(connection, "songs", part.id, *document);
|
||||
}
|
||||
}
|
||||
auto practice_ids = std::vector<std::string>{};
|
||||
@@ -453,6 +473,7 @@ WHERE songs.catalog_managed = 1
|
||||
if (!imported) {
|
||||
break;
|
||||
}
|
||||
co_await boost::asio::post(executor, boost::asio::use_awaitable);
|
||||
auto document = vamp_zero::read_score_document(path);
|
||||
if (!document) {
|
||||
imported = std::unexpected(document.error());
|
||||
@@ -526,6 +547,10 @@ WHERE practice_exercises.catalog_managed = 1
|
||||
imported = std::unexpected(inserted.error());
|
||||
break;
|
||||
}
|
||||
imported = co_await restore_imported_metadata(connection, "practice_exercises", variant.id, *document);
|
||||
if (!imported) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (imported) {
|
||||
@@ -565,7 +590,7 @@ auto vamp_zero::async_load_performance_library(boost::asio::any_io_executor exec
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
}
|
||||
auto filled = co_await backfill_metadata(connection, "songs");
|
||||
auto filled = co_await backfill_metadata(executor, connection, "songs");
|
||||
if (!filled) {
|
||||
static_cast<void>(co_await connection.async_close());
|
||||
co_return std::unexpected(filled.error());
|
||||
@@ -621,7 +646,7 @@ auto vamp_zero::async_load_practice_library(boost::asio::any_io_executor executo
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
}
|
||||
auto filled = co_await backfill_metadata(connection, "practice_exercises");
|
||||
auto filled = co_await backfill_metadata(executor, connection, "practice_exercises");
|
||||
if (!filled) {
|
||||
static_cast<void>(co_await connection.async_close());
|
||||
co_return std::unexpected(filled.error());
|
||||
|
||||
Reference in New Issue
Block a user