╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────────╮ │src/test/event/patch.zig│ ╰────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │28 }; │ │29 } │ │30 │ │31 +fn consumePatchWithRevision( │ │32 + comptime role: evt.RepoRole, │ │33 + io: std.Io, │ │34 + allocator: std.mem.Allocator, │ │35 + repo: *Repo, │ │36 + ref: rf.Ref, │ │37 + revision_id: [evt.event_id_size]u8, │ │38 + revision: evt.PatchRev, │ │39 + tree_entries: []const evt.EventTreeEntry, │ │40 + revision_timestamp: u64, │ │41 + patch_id: [evt.event_id_size]u8, │ │42 + patch_value: evt.Patch, │ │43 + patch_timestamp: u64, │ │44 +) !void { │ │45 + try evt.consume(role, .xit, repo_opts, io, allocator, repo, ref, &.{.{ │ │46 + .id = std.fmt.bytesToHex(revision_id, .lower), │ │47 + .timestamp = revision_timestamp, │ │48 + .author = author, │ │49 + .tree_entries = tree_entries, │ │50 + .event = .{ .patchrev = revision }, │ │51 + }}); │ │52 + │ │53 + var arena = std.heap.ArenaAllocator.init(allocator); │ │54 + defer arena.deinit(); │ │55 + const moment = try evt.currentMoment(repo_opts, repo); │ │56 + const record = (try evt.PatchRev.readById(Repo.DB, repo_opts.hash, moment, &arena, &revision_id)) orelse return error.NotFound;│ │57 + var patch = patch_value; │ │58 + patch.revision = evt.Patch.Revision.fromRecord(revision_id, record); │ │59 + try evt.consume(role, .xit, repo_opts, io, allocator, repo, ref, &.{.{ │ │60 + .id = std.fmt.bytesToHex(patch_id, .lower), │ │61 + .timestamp = patch_timestamp, │ │62 + .author = author, │ │63 + .event = .{ .patch = patch }, │ │64 + }}); │ │65 +} │ │66 + │ │67 test "patch event conflicts, stacking, and gc" { │ │68 const io = std.testing.io; │ │69 const allocator = std.testing.allocator; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────╮ │147 .title = "add the answer", │ │148 .description = "adds a reusable answer constant", │ │149 .tags = "enhancement", │ │113 - .patchrev_id = std.fmt.bytesToHex(patchrev_id, .lower), │ │150 }; │ │151 const tree_entries = [_]evt.EventTreeEntry{ │ │152 .{ .tree = .{ .name = "base", .oid = &base_tree_oid } },│ ╰─────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │158 // │ │159 │ │160 { │ │125 - try evt.consume(.repo, .xit, repo_opts, io, allocator, &target, evt.events_ref, &.{ │ │126 - .{ │ │127 - .id = std.fmt.bytesToHex(patchrev_id, .lower), │ │128 - .timestamp = 3, │ │129 - .author = author, │ │130 - .tree_entries = &tree_entries, │ │131 - .event = .{ .patchrev = .{ .base_oid = &base_oid, .source_oid = &source_oid, .target_ref = "refs/heads/master", .message = patch.title } },│ │132 - }, │ │133 - .{ │ │134 - .id = std.fmt.bytesToHex(patch_id, .lower), │ │135 - .timestamp = 4, │ │136 - .author = author, │ │137 - .event = .{ .patch = patch }, │ │138 - }, │ │139 - }); │ │161 + try consumePatchWithRevision( │ │162 + .repo, │ │163 + io, │ │164 + allocator, │ │165 + &target, │ │166 + evt.events_ref, │ │167 + patchrev_id, │ │168 + .{ .base_oid = &base_oid, .source_oid = &source_oid, .target_ref = "refs/heads/master", .message = patch.title }, │ │169 + &tree_entries, │ │170 + 3, │ │171 + patch_id, │ │172 + patch, │ │173 + 4, │ │174 + ); │ │175 } │ │176 │ │177 // │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │143 - // check the records and derived commit │ │178 + // check the records and squash commit │ │179 // │ │180 │ │181 var arena = std.heap.ArenaAllocator.init(allocator);│ ╰─────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │183 const moment = try evt.currentMoment(repo_opts, &target); │ │184 const patch_record = (try evt.Patch.readById(Repo.DB, repo_opts.hash, moment, &arena, &patch_id)) orelse return error.NotFound; │ │185 const patchrev_record = (try evt.PatchRev.readById(Repo.DB, repo_opts.hash, moment, &arena, &patchrev_id)) orelse return error.NotFound; │ │186 + const records_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, evt.Patch.record_map_key)) orelse return error.NotFound; │ │187 + const records = try Repo.DB.HashMap(.read_only).init(records_cursor); │ │188 + const record_cursor = try records.getCursor(hash.hashInt(repo_opts.hash, &patch_id)) orelse return error.NotFound; │ │189 + const record_map = try Repo.DB.HashMap(.read_only).init(record_cursor); │ │190 + const event_cursor = try record_map.getCursor(hash.hashInt(repo_opts.hash, "event")) orelse return error.NotFound; │ │191 + const event_map = try Repo.DB.HashMap(.read_only).init(event_cursor); │ │192 + const revision_cursor = try event_map.getCursor(hash.hashInt(repo_opts.hash, "revision")) orelse return error.NotFound; │ │193 + const revision_map = try Repo.DB.HashMap(.read_only).init(revision_cursor); │ │194 + try std.testing.expect(null != try revision_map.getCursor(hash.hashInt(repo_opts.hash, "id"))); │ │195 + try std.testing.expectEqual(null, try record_map.getCursor(hash.hashInt(repo_opts.hash, "title"))); │ │196 try std.testing.expectEqualStrings(&base_tree_oid, patchrev_record.base_tree_oid); │ │197 try std.testing.expectEqualStrings(&head_tree_oid, patchrev_record.head_tree_oid); │ │153 - try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_id, .lower), &(patch_record.event.patchrev_id orelse return error.NotFound));│ │198 + try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_id, .lower), &(patch_record.event.revision orelse return error.NotFound).id);│ │199 │ │200 var initial_patch_oid: [hash.hexLen(repo_opts.hash)]u8 = undefined; │ │201 @memcpy(&initial_patch_oid, patchrev_record.patch_oid); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │220 // │ │221 │ │222 var updated_patch = patch; │ │223 + updated_patch.revision = .{ │ │224 + .id = std.fmt.bytesToHex(patchrev_id, .lower), │ │225 + .squash_oid = &initial_patch_oid, │ │226 + .source_oid = &source_oid, │ │227 + .target_ref = "refs/heads/master", │ │228 + }; │ │229 updated_patch.title = "add a reusable answer"; │ │230 { │ │231 try evt.consume(.repo, .xit, repo_opts, io, allocator, &target, evt.events_ref, &.{.{│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │291 .{ .tree = .{ .name = "head", .oid = &source_a_tree } }, │ │292 }; │ │293 var target_patch = updated_patch; │ │243 - target_patch.patchrev_id = std.fmt.bytesToHex(patchrev_a_id, .lower); │ │294 target_patch.status = .closed; │ │295 { │ │246 - try evt.consume(.repo, .xit, repo_opts, io, allocator, &target, evt.events_ref, &.{ │ │247 - .{ │ │248 - .id = std.fmt.bytesToHex(patchrev_a_id, .lower), │ │249 - .timestamp = 8, │ │250 - .author = author, │ │251 - .tree_entries = &target_entries, │ │252 - .event = .{ .patchrev = .{ .base_oid = &base_oid, .source_oid = &source_a_oid, .target_ref = "refs/heads/master", .message = updated_patch.title } },│ │253 - }, │ │254 - .{ │ │255 - .id = std.fmt.bytesToHex(patch_id, .lower), │ │256 - .timestamp = 9, │ │257 - .author = author, │ │258 - .event = .{ .patch = target_patch }, │ │259 - }, │ │260 - }); │ │296 + try consumePatchWithRevision(.repo, io, allocator, &target, evt.events_ref, patchrev_a_id, .{ │ │297 + .base_oid = &base_oid, │ │298 + .source_oid = &source_a_oid, │ │299 + .target_ref = "refs/heads/master", │ │300 + .message = updated_patch.title, │ │301 + }, &target_entries, 8, patch_id, target_patch, 9); │ │302 } │ │303 │ │304 // │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │311 .{ .tree = .{ .name = "head", .oid = &source_b_tree } }, │ │312 }; │ │313 var parent_patch = updated_patch; │ │273 - parent_patch.patchrev_id = std.fmt.bytesToHex(patchrev_b_id, .lower); │ │314 parent_patch.status = .merged; │ │315 { │ │276 - try evt.consume(.repo, .xit, repo_opts, io, allocator, &target, side_events_ref, &.{ │ │277 - .{ │ │278 - .id = std.fmt.bytesToHex(patchrev_b_id, .lower), │ │279 - .timestamp = 10, │ │280 - .author = author, │ │281 - .tree_entries = &parent_entries, │ │282 - .event = .{ .patchrev = .{ .base_oid = &base_oid, .source_oid = &source_b_oid, .target_ref = "refs/heads/master", .message = updated_patch.title } },│ │283 - }, │ │284 - .{ │ │285 - .id = std.fmt.bytesToHex(patch_id, .lower), │ │286 - .timestamp = 11, │ │287 - .author = author, │ │288 - .event = .{ .patch = parent_patch }, │ │289 - }, │ │290 - }); │ │316 + try consumePatchWithRevision(.repo, io, allocator, &target, side_events_ref, patchrev_b_id, .{ │ │317 + .base_oid = &base_oid, │ │318 + .source_oid = &source_b_oid, │ │319 + .target_ref = "refs/heads/master", │ │320 + .message = updated_patch.title, │ │321 + }, &parent_entries, 10, patch_id, parent_patch, 11); │ │322 } │ │323 │ │324 // │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │337 _ = arena.reset(.retain_capacity); │ │338 const merged_moment = try evt.currentMoment(repo_opts, &target); │ │339 const merged = (try evt.Patch.readById(Repo.DB, repo_opts.hash, merged_moment, &arena, &patch_id)) orelse return error.NotFound; │ │309 - try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_a_id, .lower), &(merged.event.patchrev_id orelse return error.NotFound)); │ │340 + try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_a_id, .lower), &(merged.event.revision orelse return error.NotFound).id); │ │341 const merged_patchrev = (try evt.PatchRev.readById(Repo.DB, repo_opts.hash, merged_moment, &arena, &patchrev_a_id)) orelse return error.NotFound;│ │342 try std.testing.expectEqualStrings(&source_a_oid, merged_patchrev.event.source_oid); │ │343 try std.testing.expectEqualStrings(&source_a_tree, merged_patchrev.head_tree_oid); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │347 const conflict_cursor = try conflicts.getCursor(&evt.orderKeyDesc(merged.created_order, &patch_id)) orelse return error.NotFound; │ │348 const conflict = try Repo.DB.HashMap(.read_only).init(conflict_cursor); │ │349 const fields_cursor = try conflict.getCursor(hash.hashInt(repo_opts.hash, evt.conflicted_fields_key)) orelse return error.NotFound; │ │319 - try std.testing.expectEqualStrings("patchrev_id status", try fields_cursor.readBytesAlloc(arena.allocator(), null)); │ │350 + try std.testing.expectEqualStrings("revision status", try fields_cursor.readBytesAlloc(arena.allocator(), null)); │ │351 const their_cursor = try conflict.getCursor(hash.hashInt(repo_opts.hash, evt.their_record_key)) orelse return error.NotFound; │ │352 const theirs = try evt.read(evt.Patch.Record, Repo.DB, repo_opts.hash, &arena, try Repo.DB.HashMap(.read_only).init(their_cursor)); │ │322 - try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_b_id, .lower), &(theirs.event.patchrev_id orelse return error.NotFound));│ │353 + try std.testing.expectEqualStrings(&std.fmt.bytesToHex(patchrev_b_id, .lower), &(theirs.event.revision orelse return error.NotFound).id);│ │354 │ │355 // │ │356 // create a patch stacked on the selected revision │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯