╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1775 const event_id_hex = std.fmt.bytesToHex(id_bytes, .lower); │ │1776 │ │1680 - try consume(.server, .admin, .xit, admin_repo_opts, io, allocator, &repo, events_ref, &[_]EventWithId{.{ │ │1777 + try consume(.server, .user, .xit, user_repo_opts, io, allocator, &user_repo, events_ref, &[_]EventWithId{.{│ │1778 .id = event_id_hex, │ │1779 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │1780 .author = .{ .name = owner.event.name, .email = owner.event.email }, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/Fork.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │ 3 const xit = @import("xit"); │ │ 4 const hash = xit.hash; │ │ 5 │ │ 6 -user_id: []const u8, │ │ 6 repo_id: []const u8, │ │ 7 +// the target repo's owner, whose user repo holds the target │ │ 8 +repo_user_id: []const u8, │ │ 9 stage: Stage = .draft, │ │10 │ │11 // what the db stores: the event's data plus the commit-derived fields│ ╰──────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │26 pub const merge_policy: evt.MergePolicy = .target_wins; │ │27 pub const record_map_key = "event-id->fork"; │ │28 pub const all_id_set_key = "fork-id-set"; │ │28 -pub const user_id_to_fork_id_set_key = "user-id->fork-id-set"; │ │29 -pub const repo_user_to_draft_id_set_key = "repo+user->draft-id-set"; │ │30 -pub const DraftKey = [evt.event_id_size * 2]u8; │ │29 +pub const active_id_set_key = "active-fork-id-set"; │ │30 +pub const repo_to_draft_id_set_key = "repo->draft-id-set"; │ │31 │ │32 -pub fn draftKey(repo_id: []const u8, user_id: []const u8) DraftKey { │ │33 - var key: DraftKey = undefined; │ │34 - @memcpy(key[0..evt.event_id_size], repo_id); │ │35 - @memcpy(key[evt.event_id_size..], user_id); │ │36 - return key; │ │37 -} │ │38 - │ │32 fn validate(record: Record) !void { │ │40 - if (record.event.user_id.len != evt.event_id_size) return error.InvalidUserId; │ │33 if (record.event.repo_id.len != evt.event_id_size) return error.InvalidRepoId; │ │34 + if (record.event.repo_user_id.len != evt.event_id_size) return error.InvalidUserId;│ │35 } │ │36 │ │37 pub fn consume( │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │45 ) !void { │ │46 const fork_key = hash.hashInt(hash_kind, event_id); │ │47 const records = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, record_map_key))); │ │55 - const user_forks = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, user_id_to_fork_id_set_key)));│ │56 - const drafts = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, repo_user_to_draft_id_set_key))); │ │48 + const active = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, active_id_set_key))); │ │49 + const drafts = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, repo_to_draft_id_set_key))); │ │50 │ │51 var existing_maybe: ?Record = null; │ │52 const existing_cursor_maybe = try records.getCursor(fork_key); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │59 if (!record.removed) try validate(record); │ │60 │ │61 if (existing_maybe) |existing| { │ │69 - if (!std.mem.eql(u8, existing.event.user_id, record.event.user_id) or │ │70 - !std.mem.eql(u8, existing.event.repo_id, record.event.repo_id)) return error.ForkChanged; │ │62 + if (!std.mem.eql(u8, existing.event.repo_id, record.event.repo_id) or │ │63 + !std.mem.eql(u8, existing.event.repo_user_id, record.event.repo_user_id)) return error.ForkChanged; │ │64 if (existing.event.stage == .publish and record.event.stage != .publish) return error.ForkAlreadyPublished;│ │65 record.created_order = existing.created_order; │ │66 if (!existing.removed) { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │67 const order_key = evt.orderKeyDesc(existing.created_order, event_id); │ │75 - try removeFromParentSet(DB, hash_kind, user_forks, existing.event.user_id, &order_key);│ │68 + _ = try active.remove(&order_key); │ │69 if (existing.event.stage == .draft) { │ │77 - const key = draftKey(existing.event.repo_id, existing.event.user_id); │ │78 - try removeFromParentSet(DB, hash_kind, drafts, &key, &order_key); │ │70 + try removeFromParentSet(DB, hash_kind, drafts, existing.event.repo_id, &order_key);│ │71 } │ │72 } │ │73 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │83 } │ │84 │ │85 if (!record.removed) { │ │94 - const by_user = try DB.SortedSet(.read_write).init(try user_forks.putCursor(hash.hashInt(hash_kind, record.event.user_id)));│ │95 - try by_user.put(&order_key); │ │86 + try active.put(&order_key); │ │87 if (record.event.stage == .draft) { │ │97 - const key = draftKey(record.event.repo_id, record.event.user_id); │ │98 - const by_repo_user = try DB.SortedSet(.read_write).init(try drafts.putCursor(hash.hashInt(hash_kind, &key))); │ │99 - try by_repo_user.put(&order_key); │ │88 + const by_repo = try DB.SortedSet(.read_write).init(try drafts.putCursor(hash.hashInt(hash_kind, record.event.repo_id)));│ │89 + try by_repo.put(&order_key); │ │90 } │ │91 } │ │92 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │19 removed: bool = false, │ │20 created_order: u64 = 0, │ │21 updated_order: u64 = 0, │ │22 - │ │23 - // a repo's key in the name index. it's unique per owner, so the read side │ │24 - // resolves the url's username to its user id first. │ │25 - pub fn indexKey(self: Record, allocator: std.mem.Allocator) ![]const u8 { │ │26 - return std.fmt.allocPrint(allocator, "{s}/{s}", .{ self.event.user_id, self.event.name });│ │27 - } │ │22 }; │ │23 │ │24 const Self = @This(); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │129 try validateUserIds(record_to_write.event.owner_user_ids); │ │130 } │ │131 │ │138 - const user_id_to_repo_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "user-id->repo-id-set"));│ │139 - const user_id_to_repo_id_set = try DB.HashMap(.read_write).init(user_id_to_repo_id_set_cursor); │ │140 - │ │132 if (existing_record_maybe) |existing_record| { │ │133 // updates preserve the original creation metadata │ │134 record_to_write.created_order = existing_record.created_order; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │144 - const order_key = evt.orderKeyDesc(existing_record.created_order, event_id); │ │135 │ │146 - // drop the old active indexes; active values are re-added below │ │136 + // drop the old active index; active values are re-added below │ │137 if (!existing_record.removed) { │ │148 - const existing_path = try existing_record.indexKey(arena.allocator()); │ │149 - _ = try name_to_repo_id.remove(hash.hashInt(hash_kind, existing_path)); │ │150 - │ │151 - const old_user_repos_cursor = try user_id_to_repo_id_set.putCursor(hash.hashInt(hash_kind, existing_record.event.user_id));│ │152 - const old_user_repos = try DB.SortedSet(.read_write).init(old_user_repos_cursor); │ │153 - _ = try old_user_repos.remove(&order_key); │ │138 + _ = try name_to_repo_id.remove(hash.hashInt(hash_kind, existing_record.event.name)); │ │139 } │ │140 } │ │141 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯