╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Comment.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
92 const thread_comments = try DB.SortedSet(.read_write).init(thread_comments_cursor); 93 try thread_comments.put(&thread_order_key); 94 95 const replies_cursor = try parent_id_to_comment_id_set.putCursor(hash.hashInt(hash_kind, &record_to_write.event.parent_id)); 96 const replies = try DB.SortedSet(.read_write).init(replies_cursor); 97 try replies.put(&thread_order_key); 98 } 99 100 // create a comment and return its event id. `repo` must be writable. 101 pub fn create( 102 host: evt.Host, 103 comptime repo_kind: rp.RepoKind, 104 comptime repo_opts: rp.RepoOpts(repo_kind), 105 io: std.Io, 106 allocator: std.mem.Allocator, 107 repo: *rp.Repo(repo_kind, repo_opts), 108 thread_id: *const [evt.event_id_size * 2]u8, 109 parent_id: *const [evt.event_id_size * 2]u8, 110 body: []const u8, 111 author: evt.CommitAuthor, 112 ) ![evt.event_id_size * 2]u8 { 113 if (!fieldsValid(body)) return error.InvalidFields; 114 115 var id_bytes: [evt.event_id_size]u8 = undefined; 116 io.random(&id_bytes); 117 const event_id = std.fmt.bytesToHex(id_bytes, .lower); 118 try evt.consume(host, .repo, repo_kind, repo_opts, io, allocator, repo, evt.events_ref, &.{.{ 119 .id = event_id, 120 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), 121 .author = author, 122 .event = .{ .comment = .{ 123 .thread_id = thread_id.*, 124 .parent_id = parent_id.*, 125 .body = body, 126 } }, 127 }}); 128 return event_id; 129 } 130 131 // replace a comment's body while preserving its thread and parent. `repo` must 132 // be writable. 133 pub fn update( 134 host: evt.Host, 135 comptime repo_kind: rp.RepoKind, 136 comptime repo_opts: rp.RepoOpts(repo_kind), 137 io: std.Io, 138 allocator: std.mem.Allocator, 139 repo: *rp.Repo(repo_kind, repo_opts), 140 thread_id: *const [evt.event_id_size * 2]u8, 141 comment_id: *const [evt.event_id_size]u8, 142 body: []const u8, 143 author: evt.CommitAuthor, 144 ) !void { 145 if (!fieldsValid(body)) return error.InvalidFields; 146 147 var arena = std.heap.ArenaAllocator.init(allocator); 148 defer arena.deinit(); 149 150 const comment = blk: { 151 const DB = evt.EventDB(repo_opts.hash); 152 var event_db_maybe: ?evt.LocalEventDB(repo_opts.hash) = if (repo_kind == .git) try evt.LocalEventDB(repo_opts.hash).openReadOnly(io, allocator, repo.core.repo_dir) else null; 153 defer if (event_db_maybe) |*event_db| event_db.deinit(io, allocator); 154 const moment = (if (event_db_maybe) |*event_db| 155 evt.currentMomentFromDb(repo_opts.hash, event_db.db) 156 else if (repo_kind == .git) 157 return error.NotFound 158 else 159 evt.currentMoment(repo_opts, repo)) catch return error.NotFound; 160 break :blk (try readById(DB, repo_opts.hash, moment, &arena, comment_id)) orelse return error.NotFound; 161 }; 162 if (!std.mem.eql(u8, &comment.event.thread_id, thread_id)) return error.NotFound; 163 if (comment.removed) return error.NotFound; 164 165 var updated = comment.event; 166 updated.body = body; 167 try evt.consume(host, .repo, repo_kind, repo_opts, io, allocator, repo, evt.events_ref, &.{.{ 168 .id = std.fmt.bytesToHex(comment_id.*, .lower), 169 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), 170 .author = author, 171 .event = .{ .comment = updated }, 172 }}); 173 } 174 175 // read a comment by event id, or null if the id isn't a known comment. field 176 // byte slices are allocated in `arena`. 177 pub fn readById( 178 comptime DB: type, 179 comptime hash_kind: hash.HashKind, 180 haxy_moment: DB.HashMap(.read_only), 181 arena: *std.heap.ArenaAllocator, 182 comment_id: []const u8, 183 ) !?Record { 184 const records_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, record_map_key)) orelse return null; 185 const records = try DB.HashMap(.read_only).init(records_cursor); 186 const record_cursor = try records.getCursor(hash.hashInt(hash_kind, comment_id)) orelse return null; 187 const record_map = try DB.HashMap(.read_only).init(record_cursor); 188 return try evt.read(Record, DB, hash_kind, arena, record_map); 189 } 190