╭ page.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const evt = @import("./event.zig"); 3 const xit = @import("xit"); 4 const rp = xit.repo; 5 const hash = xit.hash; 6 7 pub const Page = union(enum) { 8 user_repo: UserRepoPage, 9 }; 10 11 pub const UserRepoPage = struct { 12 users: []UserWithRepos, 13 14 pub const UserWithRepos = struct { 15 user: evt.User, 16 repos: []const evt.Repo, 17 }; 18 19 pub fn empty() UserRepoPage { 20 return .{ 21 .users = &.{}, 22 }; 23 } 24 25 pub fn init( 26 comptime repo_opts: rp.RepoOpts(.xit), 27 arena: *std.heap.ArenaAllocator, 28 repo: *rp.Repo(.xit, repo_opts), 29 ) !UserRepoPage { 30 const DB = rp.Repo(.xit, repo_opts).DB; 31 32 const history = try DB.ArrayList(.read_only).init(repo.core.db.rootCursor().readOnly()); 33 34 const moment_cursor = try history.getCursor(-1) orelse return error.NotFound; 35 const moment = try DB.HashMap(.read_only).init(moment_cursor); 36 37 const last_object_id_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, "haxy-last-object-id")) orelse return error.NotFound; 38 var last_object_id: [hash.byteLen(repo_opts.hash)]u8 = undefined; 39 _ = try last_object_id_cursor.readBytes(&last_object_id); 40 41 const haxy_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, "haxy")) orelse return error.NotFound; 42 const haxy = try DB.ArrayList(.read_only).init(haxy_cursor); 43 44 const haxy_moments_cursor = try haxy.getCursor(-1) orelse return error.NotFound; 45 const haxy_moments = try DB.HashMap(.read_only).init(haxy_moments_cursor); 46 47 const haxy_moment_cursor = try haxy_moments.getCursor(hash.bytesToInt(repo_opts.hash, &last_object_id)) orelse return error.NotFound; 48 const haxy_moment = try DB.HashMap(.read_only).init(haxy_moment_cursor); 49 50 // collect users, keyed by hash(user_event_id) so we can match repos to them 51 var hash_to_index: std.AutoArrayHashMapUnmanaged(hash.HashInt(repo_opts.hash), usize) = .empty; 52 53 var user_events: std.ArrayList(evt.User) = .empty; 54 55 var repos_lists: std.ArrayList(std.ArrayList(evt.Repo)) = .empty; 56 57 const event_id_to_user_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, "event-id->user")) orelse return error.NotFound; 58 const event_id_to_user = try DB.HashMap(.read_only).init(event_id_to_user_cursor); 59 60 var users_iter = try event_id_to_user.iterator(); 61 while (try users_iter.next()) |kv_cursor| { 62 const kv = try kv_cursor.readKeyValuePair(); 63 const user_map = try DB.HashMap(.read_only).init(kv.value_cursor); 64 const user_event = try evt.read(evt.User, DB, repo_opts.hash, arena, user_map); 65 66 try hash_to_index.put(arena.allocator(), kv.hash, user_events.items.len); 67 try user_events.append(arena.allocator(), user_event); 68 try repos_lists.append(arena.allocator(), .empty); 69 } 70 71 // collect repos, bucketed by their user_id 72 const event_id_to_repo_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, "event-id->repo")) orelse return error.NotFound; 73 const event_id_to_repo = try DB.HashMap(.read_only).init(event_id_to_repo_cursor); 74 75 var repos_iter = try event_id_to_repo.iterator(); 76 while (try repos_iter.next()) |kv_cursor| { 77 const kv = try kv_cursor.readKeyValuePair(); 78 const repo_map = try DB.HashMap(.read_only).init(kv.value_cursor); 79 const repo_event = try evt.read(evt.Repo, DB, repo_opts.hash, arena, repo_map); 80 81 const user_hash = hash.hashInt(repo_opts.hash, repo_event.user_id); 82 if (hash_to_index.get(user_hash)) |user_index| { 83 try repos_lists.items[user_index].append(arena.allocator(), repo_event); 84 } 85 } 86 87 var user_repos: std.ArrayList(UserWithRepos) = .empty; 88 89 for (user_events.items, repos_lists.items) |user_event, *repos| { 90 try user_repos.append(arena.allocator(), .{ 91 .user = user_event, 92 .repos = repos.items, 93 }); 94 } 95 96 return .{ 97 .users = user_repos.items, 98 }; 99 } 100 }; 101