╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Fork.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯
16 removed: bool = false, 17 created_order: u64 = 0, 18 updated_order: u64 = 0, 19 }; 20 21 const Self = @This(); 22 23 pub const Stage = enum { 24 draft, 25 publish, 26 }; 27 28 pub const merge_policy: evt.MergePolicy = .target_wins; 29 pub const record_map_key = "event-id->fork"; 30 pub const all_id_set_key = "fork-id-set"; 31 pub const active_id_set_key = "active-fork-id-set"; 32 pub const repo_to_draft_id_set_key = "repo->draft-id-set"; 33 34 fn validate(record: Record) !void { 35 _ = try evt.parseEventId(&record.event.repo_id); 36 _ = try evt.parseEventId(&record.event.repo_user_id); 37 try evt.Repo.validateName(record.event.repo_name); 38 } 39 40 pub fn consume( 41 comptime DB: type, 42 comptime hash_kind: hash.HashKind, 43 haxy_moment: DB.HashMap(.read_write), 44 event_id: *const [evt.event_id_size]u8, 45 record_maybe: ?Record, 46 arena: *std.heap.ArenaAllocator, 47 _: ?[]const u8, 48 ) !void { 49 const fork_key = hash.hashInt(hash_kind, event_id); 50 const records = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, record_map_key))); 51 const active = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, active_id_set_key))); 52 const drafts = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, repo_to_draft_id_set_key))); 53 54 var existing_maybe: ?Record = null; 55 const existing_cursor_maybe = try records.getCursor(fork_key); 56 if (existing_cursor_maybe) |cursor| { 57 existing_maybe = try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(cursor)); 58 } 59 60 var record = record_maybe orelse try evt.removedRecord(Record, DB, hash_kind, haxy_moment.readOnly(), existing_maybe); 61 62 if (!record.removed) try validate(record); 63 64 if (existing_maybe) |existing| { 65 if (!std.mem.eql(u8, &existing.event.repo_id, &record.event.repo_id) or 66 !std.mem.eql(u8, &existing.event.repo_user_id, &record.event.repo_user_id)) return error.ForkChanged; 67 if (existing.event.stage == .publish and record.event.stage != .publish) return error.ForkAlreadyPublished; 68 record.created_order = existing.created_order; 69 if (!existing.removed) { 70 const order_key = evt.orderKeyDesc(existing.created_order, event_id); 71 _ = try active.remove(&order_key); 72 if (existing.event.stage == .draft) { 73 try removeFromParentSet(DB, hash_kind, drafts, &try evt.parseEventId(&existing.event.repo_id), &order_key); 74 } 75 } 76 } 77 78 const fork_cursor = try records.putCursor(fork_key); 79 try evt.upsert(Record, DB, hash_kind, try DB.HashMap(.read_write).init(fork_cursor), record); 80 try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .fork, existing_maybe, record); 81 82 const order_key = evt.orderKeyDesc(record.created_order, event_id); 83 if (existing_cursor_maybe == null) { 84 const ids = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, all_id_set_key))); 85 try ids.put(&order_key); 86 } 87 88 if (!record.removed) { 89 try active.put(&order_key); 90 if (record.event.stage == .draft) { 91 const repo_id = try evt.parseEventId(&record.event.repo_id); 92 const by_repo = try DB.SortedSet(.read_write).init(try drafts.putCursor(hash.hashInt(hash_kind, &repo_id))); 93 try by_repo.put(&order_key); 94 } 95 } 96 } 97 98 fn removeFromParentSet( 99 comptime DB: type, 100 comptime hash_kind: hash.HashKind, 101 index: DB.HashMap(.read_write), 102 parent_id: *const [evt.event_id_size]u8, 103 order_key: *const [@sizeOf(u64) + evt.event_id_size]u8, 104 ) !void { 105 const cursor = try index.putCursor(hash.hashInt(hash_kind, parent_id)); 106 const ids = try DB.SortedSet(.read_write).init(cursor); 107 _ = try ids.remove(order_key); 108 } 109 110 pub fn readById( 111 comptime DB: type, 112 comptime hash_kind: hash.HashKind, 113 haxy_moment: DB.HashMap(.read_only), 114 arena: *std.heap.ArenaAllocator, 115 fork_id: []const u8, 116 ) !?Record { 117 const records_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, record_map_key)) orelse return null; 118 const records = try DB.HashMap(.read_only).init(records_cursor); 119 const fork_cursor = try records.getCursor(hash.hashInt(hash_kind, fork_id)) orelse return null; 120 return try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(fork_cursor)); 121 } 122