╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────────╮ │src/event/Discussion.zig│ ╰────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │86 const record = try DB.HashMap(.read_write).init(try records.putCursor(discussion_key)); │ │87 try evt.upsert(Record, DB, hash_kind, record, record_to_write); │ │81 - try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .discuss, record_to_write.created_ts, record_to_write.removed); │ │88 + try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .discuss, record_to_write.created_order, record_to_write.removed); │ │89 │ │83 - const order_key = evt.orderKeyDesc(record_to_write.created_ts, event_id); │ │90 + const order_key = evt.orderKeyDesc(activity_order, event_id); │ │91 if (existing_cursor_maybe == null) { │ │92 + const activity = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, activity_order_key)));│ │93 + try activity.put(discussion_key, .{ .uint = activity_order }); │ │94 const ids = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, id_set_key))); │ │86 - try ids.put(&order_key); │ │95 + try ids.put(&evt.orderKeyDesc(record_to_write.created_order, event_id)); │ │96 } │ │97 │ │98 if (!record_to_write.removed) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 99 try active.put(&order_key); │ │ 91 - var tag_iter = tagIterator(record_to_write.event.tags); │ │ 92 - while (tag_iter.next()) |tag| { │ │ 93 - if (tag.len == 0 or tag.len > tag_max_len) continue; │ │ 94 - const set = try DB.SortedSet(.read_write).init(try tags.putCursor(tag)); │ │ 95 - try set.put(&order_key); │ │ 96 - } │ │100 + try addToTagSets(DB, tags, record_to_write.event.tags, &order_key); │ │101 + } │ │102 +} │ │103 + │ │104 +pub fn touch( │ │105 + comptime DB: type, │ │106 + comptime hash_kind: hash.HashKind, │ │107 + haxy_moment: DB.HashMap(.read_write), │ │108 + event_id: *const [evt.event_id_size]u8, │ │109 + order: u64, │ │110 + arena: *std.heap.ArenaAllocator, │ │111 +) !void { │ │112 + const discussion_key = hash.hashInt(hash_kind, event_id); │ │113 + const records_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, record_map_key)) orelse return; │ │114 + const records = try DB.HashMap(.read_only).init(records_cursor); │ │115 + const record_cursor = try records.getCursor(discussion_key) orelse return; │ │116 + const record = try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(record_cursor)); │ │117 + const current = try activityOrder(DB, hash_kind, haxy_moment.readOnly(), event_id); │ │118 + if (order <= current) return; │ │119 + │ │120 + const active = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, active_id_set_key))); │ │121 + const tags = try DB.SortedMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, tag_to_id_set_key))); │ │122 + if (!record.removed) { │ │123 + const old_key = evt.orderKeyDesc(current, event_id); │ │124 + _ = try active.remove(&old_key); │ │125 + try removeFromTagSets(DB, tags, record.event.tags, &old_key); │ │126 + } │ │127 + │ │128 + const activity = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, activity_order_key))); │ │129 + try activity.put(discussion_key, .{ .uint = order }); │ │130 + if (!record.removed) { │ │131 + const new_key = evt.orderKeyDesc(order, event_id); │ │132 + try active.put(&new_key); │ │133 + try addToTagSets(DB, tags, record.event.tags, &new_key); │ │134 } │ │135 +} │ │136 + │ │137 +pub fn activityOrder( │ │138 + comptime DB: type, │ │139 + comptime hash_kind: hash.HashKind, │ │140 + haxy_moment: DB.HashMap(.read_only), │ │141 + event_id: *const [evt.event_id_size]u8, │ │142 +) !u64 { │ │143 + const map_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, activity_order_key)) orelse return error.CursorNotFound;│ │144 + const map = try DB.HashMap(.read_only).init(map_cursor); │ │145 + const order_cursor = try map.getCursor(hash.hashInt(hash_kind, event_id)) orelse return error.CursorNotFound; │ │146 + return try order_cursor.readUint(); │ │147 } │ │148 │ │149 pub fn update( │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │188 } │ │189 } │ │190 │ │191 +fn addToTagSets(comptime DB: type, tags: DB.SortedMap(.read_write), names: []const u8, order_key: []const u8) !void {│ │192 + var tag_iter = tagIterator(names); │ │193 + while (tag_iter.next()) |tag| { │ │194 + if (tag.len == 0 or tag.len > tag_max_len) continue; │ │195 + const set = try DB.SortedSet(.read_write).init(try tags.putCursor(tag)); │ │196 + try set.put(order_key); │ │197 + } │ │198 +} │ │199 + │ │200 pub fn readById( │ │201 comptime repo_kind: rp.RepoKind, │ │202 comptime repo_opts: rp.RepoOpts(repo_kind), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────╮ │src/event/Issue.zig│ ╰───────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │15 event: Self, │ │16 removed: bool = false, │ │17 author_email: ?[]const u8 = null, │ │18 - created_ts: u64 = 0, // the commit timestamp of the event that first created this issue│ │18 + created_order: u64 = 0, │ │19 }; │ │20 │ │21 const Self = @This(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │78 const event_id_to_issue_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "event-id->issue")); │ │79 const event_id_to_issue = try DB.HashMap(.read_write).init(event_id_to_issue_cursor); │ │80 │ │81 - // the per-status sets the issues views list, ordered by creation time, │ │81 + // the per-status sets the issues views list, ordered by creation, │ │82 // keyed by status name │ │83 const status_to_issues_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "status->issue-id-set"));│ │84 const status_to_issues = try DB.SortedMap(.read_write).init(status_to_issues_cursor); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │109 }; │ │110 │ │111 if (existing_record_maybe) |existing_record| { │ │112 - // updates preserve the original creation timestamp and author │ │113 - record_to_write.created_ts = existing_record.created_ts; │ │112 + // updates preserve the original creation order and author │ │113 + record_to_write.created_order = existing_record.created_order; │ │114 record_to_write.author_email = existing_record.author_email; │ │115 │ │116 // drop the old status's and tags' entries; active values are re-added below│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │117 - const order_key = evt.orderKeyDesc(existing_record.created_ts, event_id); │ │117 + const order_key = evt.orderKeyDesc(existing_record.created_order, event_id); │ │118 if (!existing_record.removed) { │ │119 const status_set = try statusSet(DB, status_to_issues, existing_record.event.status);│ │120 _ = try status_set.remove(&order_key); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │131 const issue_cursor = try event_id_to_issue.putCursor(issue_key); │ │132 const issue = try DB.HashMap(.read_write).init(issue_cursor); │ │133 try evt.upsert(Record, DB, hash_kind, issue, record_to_write); │ │134 - try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .issue, record_to_write.created_ts, record_to_write.removed); │ │134 + try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .issue, record_to_write.created_order, record_to_write.removed);│ │135 │ │136 - const order_key = evt.orderKeyDesc(record_to_write.created_ts, event_id); │ │136 + const order_key = evt.orderKeyDesc(record_to_write.created_order, event_id); │ │137 │ │138 // the id set retains removed records so merges can carry removals │ │139 if (existing_cursor_maybe == null) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │266 │ │267 const conflicts_cursor = (try moment.getCursor(hash.hashInt(repo_opts.hash, conflicts_key))) orelse return updated;│ │268 const conflicts = try DB.SortedMap(.read_only).init(conflicts_cursor); │ │269 - const order_key = evt.orderKeyDesc(live.created_ts, id_bytes); │ │269 + const order_key = evt.orderKeyDesc(live.created_order, id_bytes); │ │270 const conflict_cursor = (try conflicts.getCursor(&order_key)) orelse return updated; │ │271 const entry = try DB.HashMap(.read_only).init(conflict_cursor); │ │272 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │11 pub const Record = struct { │ │12 event: Self, │ │13 removed: bool = false, │ │14 - created_ts: u64 = 0, // the commit timestamp of the event that first created this repo│ │14 + created_order: u64 = 0, │ │15 │ │16 // a repo's key in the name index. it's unique per owner, so the read side │ │17 // resolves the url's username to its user id first. │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯