╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭────────────────────────────────────────╮ │11 pub const event_id_size: usize = 32;│ │12 │ │13 pub const EventKind = enum { │ │14 - remove, │ │14 user, │ │15 repo, │ │16 issue, │ ╰────────────────────────────────────────╯ ╭────────────────────────────────────────────╮ │17 }; │ │18 │ │19 pub const EventData = union(EventKind) {│ │21 - remove: struct { │ │22 - event_kind: EventKind, │ │23 - }, │ │24 - user: struct { │ │20 + user: ?struct { │ │21 name: []const u8, │ │22 email: []const u8, │ │23 password_hash: []const u8, │ ╰────────────────────────────────────────────╯ ╭────────────────────────────────╮ │24 }, │ │29 - repo: struct { │ │25 + repo: ?struct { │ │26 user_id: []const u8,│ │27 name: []const u8, │ │28 enable_issue: bool, │ ╰────────────────────────────────╯ ╭────────────────────────────────────╮ │29 }, │ │34 - issue: struct { │ │30 + issue: ?struct { │ │31 title: []const u8, │ │32 description: []const u8,│ │33 tags: []const u8, │ ╰────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │41 kind: EventKind, │ │42 ) !EventData { │ │43 return switch (kind) { │ │48 - .remove => return error.InvalidEventKind, │ │44 .user => .{ │ │45 .user = .{ │ │46 .name = try readBytes(DB, hash_kind, allocator, map, "name"),│ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │356 _ = try std.fmt.hexToBytes(&current_event_id, &event.id); │ │357 │ │358 switch (event.data) { │ │364 - .remove => |data| { │ │365 - const removed_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │366 - switch (data.event_kind) { │ │367 - .remove => return error.InvalidRemoveKind, │ │368 - .user => { │ │369 - const event_id_to_user_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->user")); │ │370 - const event_id_to_user = try DB.HashMap(.read_write).init(event_id_to_user_cursor); │ │371 - if (!try event_id_to_user.remove(removed_key)) return error.EventNotFound; │ │359 + .user => |data_maybe| { │ │360 + const user_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │361 │ │373 - const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos")); │ │374 - const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │375 - _ = try user_id_to_repos.remove(removed_key); │ │376 - }, │ │377 - .repo => { │ │378 - const event_id_to_repo_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->repo")); │ │379 - const event_id_to_repo = try DB.HashMap(.read_write).init(event_id_to_repo_cursor); │ │362 + const event_id_to_user_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->user")); │ │363 + const event_id_to_user = try DB.HashMap(.read_write).init(event_id_to_user_cursor); │ │364 │ │381 - if (try event_id_to_repo.getCursor(removed_key)) |existing_repo_cursor| { │ │382 - const existing_repo_map = try DB.HashMap(.read_only).init(existing_repo_cursor); │ │383 - const existing_repo = try EventData.read(DB, repo_opts.hash, arena.allocator(), existing_repo_map, .repo);│ │384 - const payload = existing_repo.repo; │ │365 + if (data_maybe) |data| { │ │366 + const user_cursor = try event_id_to_user.putCursor(user_key); │ │367 + const user_map = try DB.HashMap(.read_write).init(user_cursor); │ │368 + try upsert(DB, repo_opts.hash, user_map, @TypeOf(data), data); │ │369 + } else { │ │370 + if (!try event_id_to_user.remove(user_key)) return error.EventNotFound; │ │371 │ │386 - const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos"));│ │387 - const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │388 - │ │389 - const user_key = hash.hashInt(repo_opts.hash, payload.user_id); │ │390 - const user_repos_cursor = try user_id_to_repos.putCursor(user_key); │ │391 - const user_repos = try DB.CountedHashSet(.read_write).init(user_repos_cursor); │ │392 - _ = try user_repos.remove(removed_key); │ │393 - } │ │394 - if (!try event_id_to_repo.remove(removed_key)) return error.EventNotFound; │ │395 - }, │ │396 - .issue => { │ │397 - const event_id_to_issue_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->issue")); │ │398 - const event_id_to_issue = try DB.HashMap(.read_write).init(event_id_to_issue_cursor); │ │399 - if (!try event_id_to_issue.remove(removed_key)) return error.EventNotFound; │ │400 - }, │ │372 + const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos")); │ │373 + const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │374 + _ = try user_id_to_repos.remove(user_key); │ │375 } │ │376 }, │ │403 - .user => |data| { │ │404 - const event_id_to_user_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->user")); │ │405 - const event_id_to_user = try DB.HashMap(.read_write).init(event_id_to_user_cursor); │ │377 + .repo => |data_maybe| { │ │378 + const repo_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │379 │ │407 - const user_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │408 - const user_cursor = try event_id_to_user.putCursor(user_key); │ │409 - const user_map = try DB.HashMap(.read_write).init(user_cursor); │ │410 - try upsert(DB, repo_opts.hash, user_map, @TypeOf(data), data); │ │411 - }, │ │412 - .repo => |data| { │ │380 const event_id_to_repo_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->repo")); │ │381 const event_id_to_repo = try DB.HashMap(.read_write).init(event_id_to_repo_cursor); │ │382 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │416 - const repo_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │417 - const repo_cursor = try event_id_to_repo.putCursor(repo_key); │ │418 - const repo_map = try DB.HashMap(.read_write).init(repo_cursor); │ │419 - try upsert(DB, repo_opts.hash, repo_map, @TypeOf(data), data); │ │383 + if (data_maybe) |data| { │ │384 + const repo_cursor = try event_id_to_repo.putCursor(repo_key); │ │385 + const repo_map = try DB.HashMap(.read_write).init(repo_cursor); │ │386 + try upsert(DB, repo_opts.hash, repo_map, @TypeOf(data), data); │ │387 + │ │388 + const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos")); │ │389 + const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │390 │ │421 - const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos")); │ │422 - const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │391 + const user_repos_cursor = try user_id_to_repos.putCursor(hash.hashInt(repo_opts.hash, data.user_id)); │ │392 + const user_repos = try DB.CountedHashSet(.read_write).init(user_repos_cursor); │ │393 + try user_repos.put(repo_key, .{ .bytes = &current_event_id }); │ │394 + } else { │ │395 + if (try event_id_to_repo.getCursor(repo_key)) |existing_repo_cursor| { │ │396 + const existing_repo_map = try DB.HashMap(.read_only).init(existing_repo_cursor); │ │397 + const existing_repo = try EventData.read(DB, repo_opts.hash, arena.allocator(), existing_repo_map, .repo);│ │398 + const data = existing_repo.repo orelse return error.InvalidEventData; │ │399 + │ │400 + const user_id_to_repos_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "user-id->repos"));│ │401 + const user_id_to_repos = try DB.HashMap(.read_write).init(user_id_to_repos_cursor); │ │402 │ │424 - const user_repos_cursor = try user_id_to_repos.putCursor(hash.hashInt(repo_opts.hash, data.user_id)); │ │425 - const user_repos = try DB.CountedHashSet(.read_write).init(user_repos_cursor); │ │426 - try user_repos.put(repo_key, .{ .bytes = &current_event_id }); │ │403 + const user_key = hash.hashInt(repo_opts.hash, data.user_id); │ │404 + const user_repos_cursor = try user_id_to_repos.putCursor(user_key); │ │405 + const user_repos = try DB.CountedHashSet(.read_write).init(user_repos_cursor); │ │406 + _ = try user_repos.remove(repo_key); │ │407 + } │ │408 + if (!try event_id_to_repo.remove(repo_key)) return error.EventNotFound; │ │409 + } │ │410 }, │ │428 - .issue => |data| { │ │411 + .issue => |data_maybe| { │ │412 + const issue_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │413 + │ │414 const event_id_to_issue_cursor = try haxy_moment.putCursor(hash.hashInt(repo_opts.hash, "event-id->issue")); │ │415 const event_id_to_issue = try DB.HashMap(.read_write).init(event_id_to_issue_cursor); │ │416 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │432 - const issue_key = hash.hashInt(repo_opts.hash, &current_event_id); │ │433 - const issue_cursor = try event_id_to_issue.putCursor(issue_key); │ │434 - const issue = try DB.HashMap(.read_write).init(issue_cursor); │ │435 - try upsert(DB, repo_opts.hash, issue, @TypeOf(data), data); │ │417 + if (data_maybe) |data| { │ │418 + const issue_cursor = try event_id_to_issue.putCursor(issue_key); │ │419 + const issue = try DB.HashMap(.read_write).init(issue_cursor); │ │420 + try upsert(DB, repo_opts.hash, issue, @TypeOf(data), data); │ │421 + } else { │ │422 + if (!try event_id_to_issue.remove(issue_key)) return error.EventNotFound;│ │423 + } │ │424 }, │ │425 } │ │426 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────╮ │src/test/event.zig│ ╰──────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │150 const first_issue = try evt.EventData.read(Repo.DB, repo_opts.hash, arena.allocator(), first_issue_map, .issue); │ │151 │ │152 // the description was correctly edited │ │153 - try std.testing.expectEqualStrings(events_to_consume[1].data.issue.description, first_issue.issue.description); │ │153 + try std.testing.expectEqualStrings(events_to_consume[1].data.issue.?.description, first_issue.issue.?.description);│ │154 │ │155 // the tags were correctly edited │ │156 - try std.testing.expectEqualStrings(events_to_consume[1].data.issue.tags, first_issue.issue.tags); │ │156 + try std.testing.expectEqualStrings(events_to_consume[1].data.issue.?.tags, first_issue.issue.?.tags); │ │157 } │ │158 │ │159 // │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │286 const first_issue = try evt.EventData.read(Repo.DB, repo_opts.hash, arena.allocator(), first_issue_map, .issue); │ │287 │ │288 // the description is no longer edited │ │289 - try std.testing.expectEqualStrings(events_to_consume[0].data.issue.description, first_issue.issue.description); │ │289 + try std.testing.expectEqualStrings(events_to_consume[0].data.issue.?.description, first_issue.issue.?.description); │ │290 │ │291 // the tags are no longer edited │ │292 - try std.testing.expectEqualStrings(events_to_consume[0].data.issue.tags, first_issue.issue.tags); │ │292 + try std.testing.expectEqualStrings(events_to_consume[0].data.issue.?.tags, first_issue.issue.?.tags); │ │293 │ │294 // an event added by the second push is no longer there because it was wiped out by the rebase │ │295 try std.testing.expect(null == try event_id_to_issue.getCursor(hash.hashInt(repo_opts.hash, &events_to_consume2[0].id)));│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯