╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────╮ │src/event/Issue.zig│ ╰───────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │245 const event_id_to_issue = try DB.HashMap(.read_only).init(event_id_to_issue_cursor); │ │246 const issue_cursor = (try event_id_to_issue.getCursor(hash.hashInt(repo_opts.hash, id_bytes))) orelse return null;│ │247 const issue_map = try DB.HashMap(.read_only).init(issue_cursor); │ │252 - return try evt.read(@This(), DB, repo_opts.hash, arena, issue_map); │ │248 + return try evt.read(Record, DB, repo_opts.hash, arena, issue_map); │ │249 } │ │250 │ │251 // remove an issue's order key from its tags' `status` sets, pruning entries │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 6 user_id: []const u8, │ │ 7 name: []const u8, │ │ 8 description: []const u8, │ │ 9 -created_ts: u64 = 0, // the commit timestamp of the event that first created this repo │ │ 9 + │ │10 +// what the db stores: the event's data plus the commit-derived fields │ │11 +pub const Record = struct { │ │12 + event: Self, │ │13 + created_ts: u64 = 0, // the commit timestamp of the event that first created this repo │ │14 + │ │15 + // a repo's key in the name index. it's unique per owner, so the read side │ │16 + // resolves the url's username to its user id first. │ │17 + pub fn indexKey(self: Record, allocator: std.mem.Allocator) ![]const u8 { │ │18 + return std.fmt.allocPrint(allocator, "{s}/{s}", .{ self.event.user_id, self.event.name });│ │19 + } │ │20 +}; │ │21 │ │22 const Self = @This(); │ │23 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │29 pub const name_index_key = "name->repo-id"; │ │30 pub const conflicts_key = "conflicted-repo-id->conflict"; │ │31 pub const id_to_field_to_oid_key = "repo-id->field->oid"; │ │21 - │ │22 -// a repo's key in the name index. it's unique per owner, so the read side │ │23 -// resolves the url's username to its user id first. │ │24 -pub fn indexKey(self: Self, allocator: std.mem.Allocator) ![]const u8 { │ │25 - return std.fmt.allocPrint(allocator, "{s}/{s}", .{ self.user_id, self.name });│ │26 -} │ │32 │ │33 pub fn validateName(name: []const u8) !void { │ │34 if (name.len == 0) return error.NameEmpty; │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │41 } │ │42 } │ │43 │ │39 -// the commit-derived fields must not appear in the JSON we output│ │40 -pub fn jsonStringify(self: @This(), jw: anytype) !void { │ │41 - try jw.beginObject(); │ │42 - inline for (std.meta.fields(@This())) |field| { │ │43 - if (comptime evt.derivedField(field.name)) continue; │ │44 - try jw.objectField(field.name); │ │45 - try jw.write(@field(self, field.name)); │ │46 - } │ │47 - try jw.endObject(); │ │48 -} │ │49 - │ │44 pub fn consume( │ │45 comptime DB: type, │ │46 comptime hash_kind: hash.HashKind, │ ╰──────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │47 haxy_moment: DB.HashMap(.read_write), │ │48 event_id: *const [evt.event_id_size]u8, │ │55 - event_maybe: ?@This(), │ │49 + record_maybe: ?Record, │ │50 arena: *std.heap.ArenaAllocator, │ │51 // the commit this event came from, recorded against every field it │ │52 // changes. null from `merge`, which sets oids and conflicts itself.│ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │66 const repo_id_to_field_to_oid_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, id_to_field_to_oid_key)); │ │67 const repo_id_to_field_to_oid = try DB.HashMap(.read_write).init(repo_id_to_field_to_oid_cursor); │ │68 │ │75 - if (event_maybe) |event| { │ │76 - try validateName(event.name); │ │69 + if (record_maybe) |record| { │ │70 + try validateName(record.event.name); │ │71 │ │78 - var event_to_write = event; │ │72 + var record_to_write = record; │ │73 │ │80 - const repo_path = try event.indexKey(arena.allocator()); │ │74 + const repo_path = try record.indexKey(arena.allocator()); │ │75 │ │76 const user_id_to_repo_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "user-id->repo-id-set"));│ │77 const user_id_to_repo_id_set = try DB.HashMap(.read_write).init(user_id_to_repo_id_set_cursor); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │78 │ │79 // if this event_id already maps to a repo under a different key (its │ │80 // name or owner changed), drop the stale index entries first │ │87 - var existing_event_maybe: ?@This() = null; │ │81 + var existing_record_maybe: ?Record = null; │ │82 const existing_cursor_maybe = try event_id_to_repo.getCursor(repo_key); │ │83 if (existing_cursor_maybe) |existing_cursor| { │ │84 const existing_repo = try DB.HashMap(.read_only).init(existing_cursor);│ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │91 - const existing_event = try evt.read(@This(), DB, hash_kind, arena, existing_repo);│ │92 - existing_event_maybe = existing_event; │ │85 + const existing_record = try evt.read(Record, DB, hash_kind, arena, existing_repo);│ │86 + existing_record_maybe = existing_record; │ │87 // updates preserve the original creation timestamp │ │94 - event_to_write.created_ts = existing_event.created_ts; │ │88 + record_to_write.created_ts = existing_record.created_ts; │ │89 │ │90 // any event settles the conflict, since resolving in the ui may │ │91 // keep our own values and so change nothing to detect │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 92 if (event_oid != null) { │ │ 99 - _ = try conflicts.remove(&evt.orderKeyDesc(existing_event.created_ts, event_id)); │ │ 93 + _ = try conflicts.remove(&evt.orderKeyDesc(existing_record.created_ts, event_id));│ │ 94 } │ │101 - const existing_path = try existing_event.indexKey(arena.allocator()); │ │ 95 + const existing_path = try existing_record.indexKey(arena.allocator()); │ │ 96 if (!std.mem.eql(u8, existing_path, repo_path)) { │ │ 97 _ = try name_to_repo_id.remove(hash.hashInt(hash_kind, existing_path)); │ │ 98 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │105 - if (!std.mem.eql(u8, existing_event.user_id, event.user_id)) { │ │106 - const old_user_repos_cursor = try user_id_to_repo_id_set.putCursor(hash.hashInt(hash_kind, existing_event.user_id)); │ │ 99 + if (!std.mem.eql(u8, existing_record.event.user_id, record.event.user_id)) { │ │100 + const old_user_repos_cursor = try user_id_to_repo_id_set.putCursor(hash.hashInt(hash_kind, existing_record.event.user_id));│ │101 const old_user_repos = try DB.SortedSet(.read_write).init(old_user_repos_cursor); │ │108 - const order_key = evt.orderKeyDesc(existing_event.created_ts, event_id); │ │102 + const order_key = evt.orderKeyDesc(existing_record.created_ts, event_id); │ │103 _ = try old_user_repos.remove(&order_key); │ │104 } │ │105 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯