╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────╮ │src/test/event.zig│ ╰──────────────────╯ ╭─────────────────────────────────────────────────────────╮ │1218 } │ │1219 } │ │1220 │ │ 841 -test "repos and users paginate in creation order" {│ │1221 +test "repos and users paginate newest first" { │ │1222 const io = std.testing.io; │ │1223 const allocator = std.testing.allocator; │ │1224 const temp_dir_name = "temp-event-order"; │ ╰─────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1267 try std.testing.expectEqual(expected.len, try set.count()); │ │1268 for (expected, 0..) |id, i| { │ │1269 const kv = (try set.getIndexKeyValuePair(@intCast(i))) orelse return error.NotFound;│ │ 890 - // the key is orderKey ([timestamp][event-id]); its trailing bytes are the id │ │1270 + // the key is orderKeyDesc ([timestamp][event-id]); its trailing bytes are the id │ │1271 var order_key: [@sizeOf(u64) + evt.event_id_size]u8 = undefined; │ │1272 _ = try kv.key_cursor.readBytes(&order_key); │ │1273 try std.testing.expectEqualSlices(u8, id, order_key[@sizeOf(u64)..]); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1288 │ │1289 { │ │1290 const moment = try evt.currentMoment(repo_opts, &repo); │ │ 911 - try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[0], &repo_ids[1], &repo_ids[2], &repo_ids[3] });│ │1291 + try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[3], &repo_ids[2], &repo_ids[1], &repo_ids[0] });│ │1292 │ │1293 // the single user shows up in its own ordered set │ │1294 const ucur = try moment.getCursor(hash.hashInt(repo_opts.hash, "user-id-set")) orelse return error.NotFound; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1302 }); │ │1303 { │ │1304 const moment = try evt.currentMoment(repo_opts, &repo); │ │ 925 - try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[0], &repo_ids[2], &repo_ids[3] }); │ │1305 + try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[3], &repo_ids[2], &repo_ids[0] }); │ │1306 } │ │1307 │ │ 928 - // update repo0 at a later timestamp -> keeps its original slot │ │1308 + // update repo0 at a later timestamp -> keeps its original place │ │1309 try evt.commitAndConsume(.xit, repo_opts, io, allocator, &repo, evt.events_ref, &[_]evt.EventWithId{ │ │1310 .{ .id = std.fmt.bytesToHex(repo_ids[0], .lower), .timestamp = 300, .event = .{ .repo = .{ .user_id = &user_id, .name = "repo0", .description = "updated" } } },│ │1311 }); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1312 { │ │1313 const moment = try evt.currentMoment(repo_opts, &repo); │ │ 934 - try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[0], &repo_ids[2], &repo_ids[3] }); │ │1314 + try Check.order(Repo.DB, repo_opts.hash, moment, &.{ &repo_ids[3], &repo_ids[2], &repo_ids[0] }); │ │1315 │ │1316 // the value really was updated │ │1317 const e2r_cur = try moment.getCursor(hash.hashInt(repo_opts.hash, "event-id->repo")) orelse return error.NotFound;│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │166 const admin_ssh_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKeIs8mJqigBZ5y84J4COgnAJJ5bHPKy+lM2SliMXbYm radar@roark";│ │167 │ │168 var events_to_consume: [user_data.len + repo_data.len]evt.EventWithId = undefined; │ │169 - for (user_data, 0..) |u, i| { │ │170 - events_to_consume[i] = .{ │ │169 + // inserted back to front, so the newest-first listing shows them in the │ │170 + // order they're written above │ │171 + for (0..user_data.len) |slot| { │ │172 + const i = user_data.len - 1 - slot; │ │173 + const u = user_data[i]; │ │174 + events_to_consume[slot] = .{ │ │175 .id = std.fmt.bytesToHex(user_ids[i], .lower), │ │176 // stepped timestamps so the seeded users/repos list in a stable order │ │173 - .timestamp = @intCast(i + 1), │ │177 + .timestamp = @intCast(slot + 1), │ │178 .event = .{ │ │179 .user = .{ │ │180 .name = u.name, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │181 .display_name = u.display_name, │ │182 .email = u.email, │ │183 .password_hash = password_hash, │ │180 - .ssh_keys = if (i == 0) admin_ssh_key else "", │ │184 + .ssh_keys = if (std.mem.eql(u8, "admin", u.name)) admin_ssh_key else "",│ │185 }, │ │186 }, │ │187 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Home/Repos.zig│ ╰─────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │32 │ │33 const empty: Self = .{ .repos = &.{}, .owner_names = &.{}, .start = start, .next_start = null }; │ │34 │ │35 - // the repos ordered by creation time (oldest first); absent until the first │ │35 + // the repos ordered by creation time (newest first); absent until the first │ │36 // repo exists. keyed by orderKey ([timestamp][event-id]); the trailing bytes │ │37 // of each key are the repo event id. │ │38 const repo_id_set_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "repo-id-set")) orelse return empty;│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Home/Users.zig│ ╰─────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │28 │ │29 var users: std.ArrayList(evt.User.Safe) = .empty; │ │30 │ │31 - // the users ordered by creation time (oldest first); absent until the first │ │31 + // the users ordered by creation time (newest first); absent until the first │ │32 // user exists. keyed by orderKey ([timestamp][event-id]); the trailing bytes │ │33 // of each key are the user event id. │ │34 const user_id_set_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "user-id-set")) orelse│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │54 var repos_next_start: ?usize = null; │ │55 │ │56 // the user-id->repo-id-set index maps each user to a set of their repo event │ │57 - // ids ordered by creation time (oldest first); it only exists once a repo has │ │57 + // ids ordered by creation time (newest first); it only exists once a repo has │ │58 // been consumed, so a user with no repos simply yields an empty list. │ │59 if (try haxy_moment.getCursor(hash.hashInt(hash_kind, "user-id->repo-id-set"))) |user_id_to_repo_id_set_cursor| {│ │60 const user_id_to_repo_id_set = try DB.HashMap(.read_only).init(user_id_to_repo_id_set_cursor); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯