╭ changed ──────────╮ │src/event/Issue.zig│ ╰───────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │ 8 description: []const u8, │ │ 9 tags: []const u8, // space-separated │ │10 status: Status = .open, │ │11 -author_email: ?[]const u8 = null, │ │12 -created_ts: u64 = 0, // the commit timestamp of the event that first created this issue │ │11 + │ │12 +// what the db stores: the event's data plus the commit-derived fields │ │13 +pub const Record = struct { │ │14 + event: Self, │ │15 + author_email: ?[]const u8 = null, │ │16 + created_ts: u64 = 0, // the commit timestamp of the event that first created this issue│ │17 +}; │ │18 + │ │19 +const Self = @This(); │ │20 │ │21 pub const Status = enum { │ │22 open, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │58 if (tag.len > tag_max_len) return false; │ │59 } │ │60 return true; │ │54 -} │ │55 - │ │56 -// the commit-derived fields must not appear in the JSON we output│ │57 -pub fn jsonStringify(self: @This(), jw: anytype) !void { │ │58 - try jw.beginObject(); │ │59 - inline for (std.meta.fields(@This())) |field| { │ │60 - if (comptime evt.derivedField(field.name)) continue; │ │61 - try jw.objectField(field.name); │ │62 - try jw.write(@field(self, field.name)); │ │63 - } │ │64 - try jw.endObject(); │ │61 } │ │62 │ │63 pub fn consume( │ ╰──────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │65 comptime hash_kind: hash.HashKind, │ │66 haxy_moment: DB.HashMap(.read_write), │ │67 event_id: *const [evt.event_id_size]u8, │ │72 - event_maybe: ?@This(), │ │68 + record_maybe: ?Record, │ │69 arena: *std.heap.ArenaAllocator, │ │70 // the commit this event came from, recorded against every field it │ │71 // changes. null from `merge`, which sets oids and conflicts itself.│ ╰────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 91 const issue_id_to_field_to_oid_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, id_to_field_to_oid_key));│ │ 92 const issue_id_to_field_to_oid = try DB.HashMap(.read_write).init(issue_id_to_field_to_oid_cursor); │ │ 93 │ │ 98 - if (event_maybe) |event| { │ │ 99 - var event_to_write = event; │ │ 94 + if (record_maybe) |record| { │ │ 95 + var record_to_write = record; │ │ 96 │ │101 - var existing_event_maybe: ?@This() = null; │ │ 97 + var existing_record_maybe: ?Record = null; │ │ 98 const existing_cursor_maybe = try event_id_to_issue.getCursor(issue_key); │ │ 99 if (existing_cursor_maybe) |existing_cursor| { │ │100 // updates preserve the original creation timestamp and author │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │101 const existing_issue = try DB.HashMap(.read_only).init(existing_cursor); │ │106 - const existing_event = try evt.read(@This(), DB, hash_kind, arena, existing_issue); │ │107 - existing_event_maybe = existing_event; │ │108 - event_to_write.created_ts = existing_event.created_ts; │ │109 - event_to_write.author_email = existing_event.author_email; │ │102 + const existing_record = try evt.read(Record, DB, hash_kind, arena, existing_issue); │ │103 + existing_record_maybe = existing_record; │ │104 + record_to_write.created_ts = existing_record.created_ts; │ │105 + record_to_write.author_email = existing_record.author_email; │ │106 │ │107 // drop the old status's and tags' entries; the current ones are re-added below │ │112 - const order_key = evt.orderKeyDesc(existing_event.created_ts, event_id); │ │113 - const status_set = try statusSet(DB, status_to_issues, existing_event.status); │ │108 + const order_key = evt.orderKeyDesc(existing_record.created_ts, event_id); │ │109 + const status_set = try statusSet(DB, status_to_issues, existing_record.event.status); │ │110 _ = try status_set.remove(&order_key); │ │115 - try removeFromTagSets(DB, tag_to_issues, existing_event.tags, existing_event.status, &order_key); │ │111 + try removeFromTagSets(DB, tag_to_issues, existing_record.event.tags, existing_record.event.status, &order_key);│ │112 │ │113 // any event settles the conflict, since resolving in the ui may │ │114 // keep our own values and so change nothing to detect │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │115 if (event_oid != null) _ = try conflicts.remove(&order_key); │ │116 } │ │117 │ │122 - try evt.writeOid(@This(), DB, hash_kind, issue_id_to_field_to_oid, issue_key, existing_event_maybe, event, event_oid); │ │118 + try evt.writeOid(Self, DB, hash_kind, issue_id_to_field_to_oid, issue_key, if (existing_record_maybe) |existing| existing.event else null, record.event, event_oid);│ │119 │ │120 const issue_cursor = try event_id_to_issue.putCursor(issue_key); │ │121 const issue = try DB.HashMap(.read_write).init(issue_cursor); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │126 - try evt.upsert(@This(), DB, hash_kind, issue, event_to_write); │ │122 + try evt.upsert(Record, DB, hash_kind, issue, record_to_write); │ │123 │ │128 - const order_key = evt.orderKeyDesc(event_to_write.created_ts, event_id); │ │124 + const order_key = evt.orderKeyDesc(record_to_write.created_ts, event_id);│ │125 │ │126 // first time we've seen this issue: add it to the set that enumerates │ │127 // every issue regardless of status │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │131 try issue_id_set.put(&order_key); │ │132 } │ │133 │ │138 - const status_set = try statusSet(DB, status_to_issues, event.status); │ │134 + const status_set = try statusSet(DB, status_to_issues, record.event.status);│ │135 try status_set.put(&order_key); │ │136 │ │141 - var tag_iter = tagIterator(event.tags); │ │137 + var tag_iter = tagIterator(record.event.tags); │ │138 while (tag_iter.next()) |tag| { │ │139 if (tag.len == 0) continue; │ │140 if (tag.len > tag_max_len) return error.TagTooLong; │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │141 var key_buffer: TagStatusKey = undefined; │ │146 - const tag_set_cursor = try tag_to_issues.putCursor(try tagStatusKey(&key_buffer, tag, event.status)); │ │142 + const tag_set_cursor = try tag_to_issues.putCursor(try tagStatusKey(&key_buffer, tag, record.event.status));│ │143 const tag_set = try DB.SortedSet(.read_write).init(tag_set_cursor); │ │144 try tag_set.put(&order_key); │ │145 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │147 // drop it from the ordered sets using its recorded creation timestamp and status │ │148 if (try event_id_to_issue.getCursor(issue_key)) |existing_cursor| { │ │149 const existing_issue = try DB.HashMap(.read_only).init(existing_cursor); │ │154 - const existing_event = try evt.read(@This(), DB, hash_kind, arena, existing_issue); │ │155 - const order_key = evt.orderKeyDesc(existing_event.created_ts, event_id); │ │150 + const existing_record = try evt.read(Record, DB, hash_kind, arena, existing_issue); │ │151 + const order_key = evt.orderKeyDesc(existing_record.created_ts, event_id); │ │152 │ │157 - const status_set = try statusSet(DB, status_to_issues, existing_event.status); │ │153 + const status_set = try statusSet(DB, status_to_issues, existing_record.event.status); │ │154 _ = try status_set.remove(&order_key); │ │155 │ │160 - try removeFromTagSets(DB, tag_to_issues, existing_event.tags, existing_event.status, &order_key); │ │156 + try removeFromTagSets(DB, tag_to_issues, existing_record.event.tags, existing_record.event.status, &order_key);│ │157 │ │158 const issue_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, id_set_key)); │ │159 const issue_id_set = try DB.SortedSet(.read_write).init(issue_id_set_cursor); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯