╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ event.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
964 // we retitle one of the two the other branch is about to drop 965 { 966 const event = evt.EventWithId{ .id = events_to_consume2[1].id, .author = author, .event = .{ .issue = .{ 967 .title = "Kept by the edit", 968 .description = edited_issue.description, 969 .tags = edited_issue.tags, 970 } } }; 971 try std.json.Stringify.value(event, .{}, &json.writer); 972 _ = try repo.commitAtRef(io, allocator, .{ .message = json.written() }, null, evt.events_ref); 973 } 974 975 // the other branch removes both 976 { 977 json.clearRetainingCapacity(); 978 const event = evt.EventWithId{ .id = events_to_consume2[0].id, .author = author, .event = .{ .issue = null } }; 979 try std.json.Stringify.value(event, .{}, &json.writer); 980 _ = try repo.commitAtRef(io, allocator, .{ .parent_oids = &.{base_oid}, .message = json.written() }, null, other_events_ref); 981 } 982 { 983 json.clearRetainingCapacity(); 984 const event = evt.EventWithId{ .id = events_to_consume2[1].id, .author = author, .event = .{ .issue = null } }; 985 try std.json.Stringify.value(event, .{}, &json.writer); 986 _ = try repo.commitAtRef(io, allocator, .{ .message = json.written() }, null, other_events_ref); 987 } 988 989 { 990 var result = try repo.switchDir(io, allocator, .{ .target = .{ .ref = evt.events_ref } }); 991 defer result.deinit(); 992 993 var merge = try repo.merge(io, allocator, .{ .kind = .full, .action = .{ .new = .{ .source = &.{.{ .ref = other_events_ref }} } } }, null); 994 defer merge.deinit(); 995 996 try std.testing.expect(.success == merge.result); 997 } 998 999 try evt.consume(.repo, .xit, repo_opts, io, allocator, &repo, evt.events_ref, &.{}); 1000 1001 const haxy_moment = try evt.currentMoment(repo_opts, &repo); 1002 1003 // the one we left alone is removed, and its tags left the index 1004 var dropped_id: [evt.event_id_size]u8 = undefined; 1005 _ = try std.fmt.hexToBytes(&dropped_id, &events_to_consume2[0].id); 1006 const dropped = try readIssue(Repo.DB, repo_opts.hash, haxy_moment, &arena, &dropped_id); 1007 try std.testing.expect(dropped.removed); 1008 1009 const tag_to_issues_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, "tag+status->issue-id-set")) orelse return error.NotFound; 1010 const tag_to_issues = try Repo.DB.SortedMap(.read_only).init(tag_to_issues_cursor); 1011 try std.testing.expect(null == try tag_to_issues.getCursor("kanban open")); 1012 1013 // the one we edited survives, with our edit 1014 var kept_id: [evt.event_id_size]u8 = undefined; 1015 _ = try std.fmt.hexToBytes(&kept_id, &events_to_consume2[1].id); 1016 const kept = try readIssue(Repo.DB, repo_opts.hash, haxy_moment, &arena, &kept_id); 1017 try std.testing.expect(!kept.removed); 1018 try std.testing.expectEqualStrings("Kept by the edit", kept.event.title); 1019 } 1020 } 1021 1022 // the commit that last set `field_name` on the issue `id` names 1023 fn readOid( 1024 comptime DB: type, 1025 comptime hash_kind: hash.HashKind, 1026 haxy_moment: DB.HashMap(.read_only), 1027 id: *const [evt.event_id_size]u8, 1028 comptime field_name: []const u8, 1029 ) ![hash.byteLen(hash_kind)]u8 { 1030 const id_to_field_to_oid_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, evt.Issue.id_to_field_to_oid_key)) orelse return error.NotFound; 1031 const id_to_field_to_oid = try DB.HashMap(.read_only).init(id_to_field_to_oid_cursor); 1032 const field_oids_cursor = try id_to_field_to_oid.getCursor(hash.hashInt(hash_kind, id)) orelse return error.NotFound; 1033 const field_oids = try DB.SortedMap(.read_only).init(field_oids_cursor); 1034 const cursor = try field_oids.getCursor(field_name) orelse return error.NotFound; 1035 var oid: [hash.byteLen(hash_kind)]u8 = undefined; 1036 _ = try cursor.readBytes(&oid); 1037 return oid; 1038 } 1039 1040 // the issue `id` names, read out of `event-id->issue` 1041 fn readIssue( 1042 comptime DB: type, 1043 comptime hash_kind: hash.HashKind, 1044 haxy_moment: DB.HashMap(.read_only), 1045 arena: *std.heap.ArenaAllocator, 1046 id: *const [evt.event_id_size]u8, 1047 ) !evt.Issue.Record { 1048 const event_id_to_issue_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "event-id->issue")) orelse return error.NotFound; 1049 const event_id_to_issue = try DB.HashMap(.read_only).init(event_id_to_issue_cursor); 1050 const issue_cursor = try event_id_to_issue.getCursor(hash.hashInt(hash_kind, id)) orelse return error.NotFound; 1051 const issue_map = try DB.HashMap(.read_only).init(issue_cursor); 1052 return try evt.read(evt.Issue.Record, DB, hash_kind, arena, issue_map); 1053 } 1054