╭ Issue.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const evt = @import("../event.zig"); 3 const xit = @import("xit"); 4 const hash = xit.hash; 5 6 title: []const u8, 7 description: []const u8, 8 tags: []const u8, 9 created_ts: u64 = 0, // the commit timestamp of the event that first created this issue 10 11 // `created_ts` comes from the commit timestamp, not the event 12 // payload, so it must not appear in the JSON we output 13 pub fn jsonStringify(self: @This(), jw: anytype) !void { 14 try jw.beginObject(); 15 inline for (std.meta.fields(@This())) |field| { 16 if (comptime std.mem.eql(u8, field.name, "created_ts")) continue; 17 try jw.objectField(field.name); 18 try jw.write(@field(self, field.name)); 19 } 20 try jw.endObject(); 21 } 22 23 pub fn consume( 24 comptime DB: type, 25 comptime hash_kind: hash.HashKind, 26 haxy_moment: DB.HashMap(.read_write), 27 event_id: *const [evt.event_id_size]u8, 28 event_maybe: ?@This(), 29 arena: *std.heap.ArenaAllocator, 30 created_ts: u64, 31 ) !void { 32 const issue_key = hash.hashInt(hash_kind, event_id); 33 34 const event_id_to_issue_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "event-id->issue")); 35 const event_id_to_issue = try DB.HashMap(.read_write).init(event_id_to_issue_cursor); 36 37 if (event_maybe) |event| { 38 var event_to_write = event; 39 40 const existing_cursor_maybe = try event_id_to_issue.getCursor(issue_key); 41 if (existing_cursor_maybe) |existing_cursor| { 42 // updates preserve the original creation timestamp 43 const existing_issue = try DB.HashMap(.read_only).init(existing_cursor); 44 const existing_event = try evt.read(@This(), DB, hash_kind, arena, existing_issue); 45 event_to_write.created_ts = existing_event.created_ts; 46 } else { 47 // first time we've seen this issue: stamp it with the commit timestamp 48 event_to_write.created_ts = created_ts; 49 } 50 51 const issue_cursor = try event_id_to_issue.putCursor(issue_key); 52 const issue = try DB.HashMap(.read_write).init(issue_cursor); 53 try evt.upsert(@This(), DB, hash_kind, issue, event_to_write); 54 55 // first time we've seen this issue: add it to the set the issues view 56 // lists, ordered by creation time. the key (orderKey) embeds the event 57 // id, so the set needs no value. 58 if (existing_cursor_maybe == null) { 59 const issue_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "issue-id-set")); 60 const issue_id_set = try DB.SortedSet(.read_write).init(issue_id_set_cursor); 61 const order_key = evt.orderKey(event_to_write.created_ts, event_id); 62 try issue_id_set.put(&order_key); 63 } 64 } else { 65 // drop it from the ordered set using its recorded creation timestamp 66 if (try event_id_to_issue.getCursor(issue_key)) |existing_cursor| { 67 const existing_issue = try DB.HashMap(.read_only).init(existing_cursor); 68 const existing_event = try evt.read(@This(), DB, hash_kind, arena, existing_issue); 69 const issue_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "issue-id-set")); 70 const issue_id_set = try DB.SortedSet(.read_write).init(issue_id_set_cursor); 71 const order_key = evt.orderKey(existing_event.created_ts, event_id); 72 _ = try issue_id_set.remove(&order_key); 73 } 74 if (!try event_id_to_issue.remove(issue_key)) return error.EventNotFound; 75 } 76 } 77