diff --git a/dDatabase/GameDatabase/ITables/IUgc.h b/dDatabase/GameDatabase/ITables/IUgc.h index 50b55a415..7e1397ed9 100644 --- a/dDatabase/GameDatabase/ITables/IUgc.h +++ b/dDatabase/GameDatabase/ITables/IUgc.h @@ -142,6 +142,13 @@ public: }; virtual std::vector GetUgcRunSummaries() = 0; + // One model's makes (ugc_process_runs), the newest first, at most `limit` + struct ModelRun { + int64_t madeAt{}; // unix seconds + ProcessRun run; + }; + virtual std::vector GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) = 0; + virtual std::optional GetUgcProcessInfo(const LWOOBJID id) = 0; // Sets models back to pending with no attempts: one (`id`), or all of them (`id` nullopt; only the failed ones diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index 3f996f9c9..00efae042 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -482,6 +482,7 @@ public: uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override; void RecordUgcModelRun(const ProcessRun& run) override; std::vector GetUgcRunSummaries() override; + std::vector GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) override; IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override; std::vector GetUgcProcessList(const std::optional state, const std::string_view search, const uint32_t offset, const uint32_t limit) override; std::vector> GetUgcProcessCounts() override; diff --git a/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp b/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp index 0b66419a0..b3dfb4694 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp @@ -192,6 +192,18 @@ std::vector MySQLDatabase::GetUgcRunSummaries() { return summaries; } +std::vector MySQLDatabase::GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) { + auto result = ExecuteSelect("SELECT made_at, options, process_ms, process_cpu_ms, hsr_ms, ao_ms, icon_ms, bricks, triangles_before, triangles FROM ugc_process_runs " + "WHERE ugc_id = ? ORDER BY made_at DESC, id DESC LIMIT ?;", id, limit); + std::vector runs; + while (result->next()) { + const auto field = [&](const char* name) { return static_cast(result->getUInt(name)); }; + runs.push_back({ result->getInt64("made_at"), { id, std::string(result->getString("options").c_str()), field("process_ms"), field("process_cpu_ms"), + field("hsr_ms"), field("ao_ms"), field("icon_ms"), field("bricks"), field("triangles_before"), field("triangles") } }); + } + return runs; +} + std::vector MySQLDatabase::GetUgcProcessList(const std::optional state, const std::string_view search, const uint32_t offset, const uint32_t limit) { const std::string select = "SELECT u.id, u.character_id, c.name AS character_name, u.is_optimized, u.process_attempts, u.processed_at, u.process_error, u.bake_ao, u.process_after " diff --git a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h index 4da7960c4..9ae481132 100644 --- a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h +++ b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h @@ -466,6 +466,7 @@ public: uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override; void RecordUgcModelRun(const ProcessRun& run) override; std::vector GetUgcRunSummaries() override; + std::vector GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) override; IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override; std::vector GetUgcProcessList(const std::optional state, const std::string_view search, const uint32_t offset, const uint32_t limit) override; std::vector> GetUgcProcessCounts() override; diff --git a/dDatabase/GameDatabase/SQLite/Tables/Ugc.cpp b/dDatabase/GameDatabase/SQLite/Tables/Ugc.cpp index 6bc7ed375..2a55b49c6 100644 --- a/dDatabase/GameDatabase/SQLite/Tables/Ugc.cpp +++ b/dDatabase/GameDatabase/SQLite/Tables/Ugc.cpp @@ -194,6 +194,19 @@ std::vector SQLiteDatabase::GetUgcRunSummaries() { return summaries; } +std::vector SQLiteDatabase::GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) { + auto [_, result] = ExecuteSelect("SELECT made_at, options, process_ms, process_cpu_ms, hsr_ms, ao_ms, icon_ms, bricks, triangles_before, triangles FROM ugc_process_runs " + "WHERE ugc_id = ? ORDER BY made_at DESC, id DESC LIMIT ?;", id, limit); + std::vector runs; + while (!result.eof()) { + const auto field = [&](const char* name) { return static_cast(result.getInt64Field(name, 0)); }; + runs.push_back({ result.getInt64Field("made_at", 0), { id, result.getStringField("options", ""), field("process_ms"), field("process_cpu_ms"), + field("hsr_ms"), field("ao_ms"), field("icon_ms"), field("bricks"), field("triangles_before"), field("triangles") } }); + result.nextRow(); + } + return runs; +} + std::vector SQLiteDatabase::GetUgcProcessList(const std::optional state, const std::string_view search, const uint32_t offset, const uint32_t limit) { const std::string select = "SELECT u.id, u.character_id, c.name AS character_name, u.is_optimized, u.process_attempts, u.processed_at, u.process_error, u.bake_ao, u.process_after " diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h index 20a8602e8..d0a595247 100644 --- a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h @@ -461,6 +461,7 @@ class TestSQLDatabase : public GameDatabase { uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override { return 0; } void RecordUgcModelRun(const ProcessRun& run) override {} std::vector GetUgcRunSummaries() override { return {}; } + std::vector GetUgcModelRuns(const LWOOBJID id, const uint32_t limit) override { return {}; } IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override { return {}; } std::vector GetUgcProcessList(const std::optional state, const std::string_view search, const uint32_t offset, const uint32_t limit) override { return {}; } std::vector> GetUgcProcessCounts() override { return {}; } diff --git a/tests/dDatabaseTests/DatabaseParityTests.cpp b/tests/dDatabaseTests/DatabaseParityTests.cpp index 58911e9d7..d5e5564f5 100644 --- a/tests/dDatabaseTests/DatabaseParityTests.cpp +++ b/tests/dDatabaseTests/DatabaseParityTests.cpp @@ -825,6 +825,11 @@ TEST_F(ParitySeeded, UgcModel) { for (const auto& s : db.GetUgcRunSummaries()) { out.push_back({ s.options, s.runs, s.models, s.milliseconds, s.cpuMilliseconds, s.hsrMilliseconds, s.aoMilliseconds, s.iconMilliseconds, s.bricks, s.trianglesBefore, s.triangles }); } + // One model's makes, the newest first, limited + for (const auto& [madeAt, r] : db.GetUgcModelRuns(1152921510000500001LL, 2)) { + out.push_back({ madeAt > 0, r.options, r.milliseconds, r.cpuMilliseconds, r.hsrMilliseconds, r.aoMilliseconds, r.iconMilliseconds, r.bricks, r.trianglesBefore, r.triangles }); + } + out.push_back(db.GetUgcModelRuns(1152921510000500002LL, 10).size()); return out; }); Both("Modular build processing", [&](GameDatabase& db) {