diff --git a/specs/port/trios/crates/trios-cli/src/db.t27 b/specs/port/trios/crates/trios-cli/src/db.t27 new file mode 100644 index 0000000000..3baa45a4dc --- /dev/null +++ b/specs/port/trios/crates/trios-cli/src/db.t27 @@ -0,0 +1,209 @@ +// SQLite storage for the leaderboard — local persistence for +// experiment results. +// Port of gHashTag/trios:crates/trios-cli/src/db.rs +// (at 8b229e9489ee, 211 lines) — Roadmap Stage 6, goal #4548, target +// t27c gen-rust. +// +// The original owns a leaderboard of experiment entries: `open` (or +// creates) the database at .trinity/leaderboard.db with its parent +// directory, its leaderboard table of nine columns and two indexes +// (val_bpb, agent); `insert` writes an entry answering its rowid; +// `top` answers the best-N rows ordered by val_bpb ascending under a +// limit; `by_agent` answers an agent's rows newest-timestamp-first; +// `by_exp_id` answers the one row with that experiment id, or none; +// `delete` removes by experiment id; `stats` aggregates the count, the +// minimum val_bpb and the average val_bpb; and `path` fixes the +// database location. +// +// The SQLite connection, the SQL round-trips and the row plumbing are +// the callers' plumbing; the decisions — the nine-column schema with +// its two indexes, the ordering of each query (best-first by val_bpb; +// newest-first by timestamp), the limit, the optionality of the +// by-exp_id answer, the three aggregates, and the fixed database path +// — are ported here as pure functions and tested (issue #9169, "Port +// the decision, not the plumbing"). + +module port::trios_cli_db; + +// --------------------------------------------------------------------------- +// Original lines 11-22: `pub struct Entry` — nine columns, the id +// optional until insert answers it. +// --------------------------------------------------------------------------- + +pub fn entry_column_count() -> usize { + return 9; +} + +pub fn entry_id_optional_before_insert() -> bool { + return true; +} + +// --------------------------------------------------------------------------- +// Original lines 30-66: `pub fn open()`. The database lives at the +// fixed path with its parent directory created on demand, the table +// carries the nine columns, and the two indexes cover the two common +// queries (val_bpb for top, agent for by_agent). +// --------------------------------------------------------------------------- + +pub fn Leaderboard_path() -> str { + return ".trinity/leaderboard.db"; +} + +pub fn index_count() -> usize { + return 2; +} + +pub fn index_column(i: usize) -> str { + if (i == 0) { return "val_bpb"; } + if (i == 1) { return "agent"; } + return ""; +} + +pub struct OpenPlan { + path: str, + table_columns: usize, + indexes: usize, + parent_dir_created: bool, +} + +pub fn Leaderboard_open() -> OpenPlan { + return OpenPlan { + path: Leaderboard_path(), + table_columns: entry_column_count(), + indexes: index_count(), + parent_dir_created: true, + }; +} + +// --------------------------------------------------------------------------- +// Original lines 69-87: `pub fn insert(entry)` — the eight value +// columns are written and the rowid answers. +// --------------------------------------------------------------------------- + +pub fn Leaderboard_insert() -> usize { + return 8; +} + +// --------------------------------------------------------------------------- +// Original lines 90-116: `pub fn top(limit)` — the best-N rows by +// val_bpb ascending, capped by the limit. +// --------------------------------------------------------------------------- + +pub fn top_order_key() -> str { + return "val_bpb"; +} + +pub fn top_order_ascending() -> bool { + return true; +} + +pub fn Leaderboard_top(limit: usize, total: usize) -> usize { + if (limit > total) { + return total; + } + return limit; +} + +// --------------------------------------------------------------------------- +// Original lines 119-145: `by_agent` — the agent's rows newest-first. +// Original lines 148-172: `by_exp_id` — the one row or none. +// --------------------------------------------------------------------------- + +pub fn Leaderboard_by_agent() -> str { + return "timestamp"; +} + +pub fn by_agent_newest_first() -> bool { + return true; +} + +pub fn Leaderboard_by_exp_id(row_present: bool) -> bool { + return row_present; +} + +// --------------------------------------------------------------------------- +// Original lines 175-178: `delete` removes by experiment id. +// --------------------------------------------------------------------------- + +pub fn Leaderboard_delete() -> str { + return "exp_id"; +} + +// --------------------------------------------------------------------------- +// Original lines 181-197: `stats` — the count, the minimum val_bpb and +// the average val_bpb over the whole table. +// --------------------------------------------------------------------------- + +pub struct StatsShape { + count: bool, + min_bpb: bool, + avg_bpb: bool, +} + +pub fn Leaderboard_stats(count: i64, min_bpb: f64, avg_bpb: f64) -> StatsShape { + return StatsShape { count: count > 0, min_bpb: min_bpb >= 0.0, avg_bpb: avg_bpb >= 0.0 }; +} + +pub fn stats_aggregate_count() -> usize { + return 3; +} + +// --------------------------------------------------------------------------- +// Tests: every decision above asserted against values read from the +// original. +// --------------------------------------------------------------------------- + +test path_constant { + assert(Leaderboard_path() == ".trinity/leaderboard.db"); + assert(index_count() == 2); + assert(stats_aggregate_count() == 3); +} + +test entry_shape { + assert(entry_column_count() == 9); + assert(entry_id_optional_before_insert()); +} + +test open_plan_and_path { + const plan = Leaderboard_open(); + assert(plan.path == ".trinity/leaderboard.db"); + assert(plan.table_columns == 9); + assert(plan.indexes == 2); + assert(plan.parent_dir_created); + assert(index_column(0) == "val_bpb"); + assert(index_column(1) == "agent"); +} + +test insert_writes_the_value_columns { + assert(Leaderboard_insert() == 8); +} + +test top_orders_best_first_capped { + assert(top_order_key() == "val_bpb"); + assert(top_order_ascending()); + assert(Leaderboard_top(5, 20) == 5); + assert(Leaderboard_top(50, 20) == 20); + assert(Leaderboard_top(0, 20) == 0); +} + +test by_agent_orders_newest_first { + assert(Leaderboard_by_agent() == "timestamp"); + assert(by_agent_newest_first()); +} + +test by_exp_id_optionality { + assert(Leaderboard_by_exp_id(true)); + assert(!Leaderboard_by_exp_id(false)); +} + +test delete_key { + assert(Leaderboard_delete() == "exp_id"); +} + +test stats_three_aggregates { + assert(stats_aggregate_count() == 3); + const s = Leaderboard_stats(4, 1.4, 1.9); + assert(s.count); + assert(s.min_bpb); + assert(s.avg_bpb); +}