╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────╮ │src/event/User.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │146 name: []const u8, │ │147 password: []const u8, │ │148 ) !VerifyResult { │ │154 - const name_index_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "name->user-id")) orelse return .unknown_user; │ │155 - const name_index = try DB.HashMap(.read_only).init(name_index_cursor); │ │156 - │ │157 - const user_id_cursor = try name_index.getCursor(hash.hashInt(hash_kind, name)) orelse return .unknown_user; │ │158 - var user_id: [evt.event_id_size]u8 = undefined; │ │159 - _ = try user_id_cursor.readBytes(&user_id); │ │149 + const user_id = try readIdByName(DB, hash_kind, haxy_moment, name) orelse return .unknown_user; │ │150 │ │151 const user_key = hash.hashInt(hash_kind, &user_id); │ │152 const event_id_to_user_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "event-id->user")) orelse return .unknown_user;│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │202 haxy_moment: DB.HashMap(.read_only), │ │203 name: []const u8, │ │204 ) !?[evt.event_id_size]u8 { │ │215 - return try readIdFromIndex(DB, hash_kind, haxy_moment, name_index_key, name); │ │205 + const index_cursor = (try haxy_moment.getCursor(hash.hashInt(hash_kind, name_index_key))) orelse return null;│ │206 + const index = try DB.SortedMap(.read_only).init(index_cursor); │ │207 + const user_id_cursor = (try index.getCursor(name)) orelse return null; │ │208 + var user_id: [evt.event_id_size]u8 = undefined; │ │209 + _ = try user_id_cursor.readBytes(&user_id); │ │210 + return user_id; │ │211 } │ │212 │ │213 // a user's id via the email->user-id index │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │216 comptime hash_kind: hash.HashKind, │ │217 haxy_moment: DB.HashMap(.read_only), │ │218 email: []const u8, │ │224 -) !?[evt.event_id_size]u8 { │ │225 - return try readIdFromIndex(DB, hash_kind, haxy_moment, email_to_user_id_key, email); │ │226 -} │ │227 - │ │228 -fn readIdFromIndex( │ │229 - comptime DB: type, │ │230 - comptime hash_kind: hash.HashKind, │ │231 - haxy_moment: DB.HashMap(.read_only), │ │232 - index_key: []const u8, │ │233 - key: []const u8, │ │219 ) !?[evt.event_id_size]u8 { │ │235 - const index_cursor = (try haxy_moment.getCursor(hash.hashInt(hash_kind, index_key))) orelse return null; │ │220 + const index_cursor = (try haxy_moment.getCursor(hash.hashInt(hash_kind, email_to_user_id_key))) orelse return null;│ │221 const index = try DB.HashMap(.read_only).init(index_cursor); │ │237 - const user_id_cursor = (try index.getCursor(hash.hashInt(hash_kind, key))) orelse return null; │ │222 + const user_id_cursor = (try index.getCursor(hash.hashInt(hash_kind, email))) orelse return null; │ │223 var user_id: [evt.event_id_size]u8 = undefined; │ │224 _ = try user_id_cursor.readBytes(&user_id); │ │225 return user_id; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │255 │ │256 const moment = try evt.currentMoment(evt.admin_repo_opts, &repo); │ │257 │ │273 - const name_to_user_id_cursor = try moment.getCursor(hash.hashInt(evt.admin_repo_opts.hash, "name->user-id")) orelse return null;│ │274 - const name_to_user_id = try evt.AdminDB.HashMap(.read_only).init(name_to_user_id_cursor); │ │275 - const user_id_cursor = try name_to_user_id.getCursor(hash.hashInt(evt.admin_repo_opts.hash, name)) orelse return null; │ │276 - var user_id: [evt.event_id_size]u8 = undefined; │ │277 - _ = try user_id_cursor.readBytes(&user_id); │ │258 + const user_id = try readIdByName(evt.AdminDB, evt.admin_repo_opts.hash, moment, name) orelse return null; │ │259 │ │260 return try readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, arena, &user_id); │ │261 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/test/event/admin.zig│ ╰────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │118 │ │119 try std.testing.expectEqualSlices(u8, &user_event_id, repo_record.event.user_id); │ │120 try std.testing.expectEqualStrings("ziglings", repo_record.event.name); │ │121 - │ │122 - // get the repos created by the user │ │123 - const user_repos_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, evt.Repo.active_id_set_key)) orelse return error.NotFound;│ │124 - const user_repos = try Repo.DB.SortedSet(.read_only).init(user_repos_cursor); │ │121 │ │126 - try std.testing.expectEqual(1, try user_repos.count()); │ │127 - │ │128 - // the set is keyed by orderKeyDesc([created-order][event-id]) │ │129 - const order_key = evt.orderKeyDesc(repo_record.created_order, &repo_event_id); │ │130 - try std.testing.expect(try user_repos.contains(&order_key)); │ │131 - │ │122 // the repo resolves by its name alone │ │123 const found = (try evt.Repo.readByName(Repo.DB, repo_opts.hash, haxy_moment, &arena, "ziglings")) orelse return error.NotFound; │ │124 try std.testing.expectEqualSlices(u8, &repo_event_id, &found.event_id); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │151 const repo_record = try evt.read(evt.Repo.Record, Repo.DB, repo_opts.hash, &arena, repo_map); │ │152 try std.testing.expect(repo_record.removed); │ │153 │ │164 - // get the repos created by the user │ │165 - const user_repos_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, evt.Repo.active_id_set_key)) orelse return error.NotFound;│ │166 - const user_repos = try Repo.DB.SortedSet(.read_only).init(user_repos_cursor); │ │167 - │ │168 - // removing the repo emptied the user's set │ │169 - try std.testing.expectEqual(0, try user_repos.count()); │ │154 + // removing the repo dropped it from the name index │ │155 try std.testing.expectEqual(null, try evt.Repo.readByName(Repo.DB, repo_opts.hash, haxy_moment, &arena, "ziglings")); │ │156 } │ │157 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │167 const repo_record = try evt.read(evt.Repo.Record, Repo.DB, repo_opts.hash, &arena, repo_map); │ │168 try std.testing.expect(!repo_record.removed); │ │169 │ │185 - const user_repos_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, evt.Repo.active_id_set_key)) orelse return error.NotFound;│ │186 - const user_repos = try Repo.DB.SortedSet(.read_only).init(user_repos_cursor); │ │187 - try std.testing.expectEqual(1, try user_repos.count()); │ │170 + try std.testing.expect(try evt.Repo.readByName(Repo.DB, repo_opts.hash, haxy_moment, &arena, "ziglings") != null); │ │171 } │ │172 │ │173 // │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │212 const admin_ssh_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKeIs8mJqigBZ5y84J4COgnAJJ5bHPKy+lM2SliMXbYm radar@roark";│ │213 │ │214 var events_to_consume: [user_data.len]evt.EventWithId = undefined; │ │215 - // inserted back to front, so the newest-first listing shows them in the │ │216 - // order they're written above │ │217 - for (0..user_data.len) |slot| { │ │218 - const i = user_data.len - 1 - slot; │ │219 - const u = user_data[i]; │ │220 - events_to_consume[slot] = .{ │ │215 + for (user_data, 0..) |u, i| { │ │216 + events_to_consume[i] = .{ │ │217 .id = std.fmt.bytesToHex(user_ids[i], .lower), │ │222 - // stepped timestamps so the seeded users/repos list in a stable order │ │223 - .timestamp = @intCast(slot + 1), │ │218 + // stepped timestamps give the seeds a stable creation order │ │219 + .timestamp = @intCast(i + 1), │ │220 .author = .{ .name = "admin", .email = "admin@example.test" }, │ │221 .event = .{ │ │222 .user = .{ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │71 // user pages always read from the admin db. │ │72 return switch (route.parent()) { │ │73 .home => .{ .home = try Home.init(arena, session, session.haxy_moment orelse return error.NoMoment, switch (route) {│ │74 - .home_users => |start| start, │ │75 - else => 0, │ │74 + .home_users => |u| u, │ │75 + else => .{}, │ │76 }) }, │ │77 .user => blk: { │ │78 const haxy_moment = session.haxy_moment orelse return error.NoMoment; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │79 break :blk switch (route) { │ │80 - .user_repos => |u| .{ .user = try User.init(arena, session, haxy_moment, u.name, u.start, 0) }, │ │81 - .user_forks => |u| .{ .user = try User.init(arena, session, haxy_moment, u.name, 0, u.start) }, │ │82 - .user_settings, .user_auth => |name| .{ .user = try User.init(arena, session, haxy_moment, name, 0, 0) }, │ │80 + .user_repos => |u| .{ .user = try User.init(arena, session, haxy_moment, u.name, u.start, u.search.slice(), 0) },│ │81 + .user_forks => |u| .{ .user = try User.init(arena, session, haxy_moment, u.name, 0, "", u.start) }, │ │82 + .user_settings, .user_auth => |name| .{ .user = try User.init(arena, session, haxy_moment, name, 0, "", 0) }, │ │83 else => return error.UnexpectedRoute, │ │84 }; │ │85 }, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯