╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────╮ │src/test/event.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │152 // │ │143 - // process events into the database │ │153 + // consume events into the database │ │154 // │ │155 │ │146 - const Ctx = struct { │ │147 - events: []evt.Event, │ │156 + try evt.consume(Repo.DB, repo_opts.hash, io, &repo.core.db, repo.core.db_file, events.items); │ │157 │ │149 - pub fn run(ctx: @This(), cursor: *Repo.DB.Cursor(.read_write)) !void { │ │150 - const moment = try Repo.DB.HashMap(.read_write).init(cursor.*); │ │151 - │ │152 - // the map with all of haxy's state and materialized views │ │153 - const haxy_cursor = try moment.putCursor(hash.hashInt(repo_opts.hash, "haxy")); │ │154 - const haxy = try Repo.DB.HashMap(.read_write).init(haxy_cursor); │ │155 - │ │156 - // try reading the last event id that was processed in the db │ │157 - var last_event_id_maybe: ?[evt.id_size]u8 = null; │ │158 - if (try haxy.getCursor(hash.hashInt(repo_opts.hash, "last-event-id"))) |last_event_id_cursor| { │ │159 - var last_event_id_buffer: [evt.id_size]u8 = undefined; │ │160 - _ = try last_event_id_cursor.readBytes(&last_event_id_buffer); │ │161 - last_event_id_maybe = last_event_id_buffer; │ │162 - } │ │158 + const history = try Repo.DB.ArrayList(.read_only).init(repo.core.db.rootCursor().readOnly()); │ │159 │ │164 - // for each event we want to process... │ │165 - for (ctx.events) |event| { │ │166 - // get the id of the current event as bytes │ │167 - var current_event_id_buffer: [evt.id_size]u8 = undefined; │ │168 - _ = try std.fmt.hexToBytes(&current_event_id_buffer, &event.id); │ │169 - │ │170 - // map with the views as they appeared when each event was processed. │ │171 - // we can use this to see (and revert) the views to any previous state. │ │172 - const event_id_to_views_cursor = try haxy.putCursor(hash.hashInt(repo_opts.hash, "event-id->views")); │ │173 - const event_id_to_views = try Repo.DB.HashMap(.read_write).init(event_id_to_views_cursor); │ │174 - │ │175 - // create a new views map for the current event we are processing │ │176 - var views_cursor = try event_id_to_views.putCursor(hash.hashInt(repo_opts.hash, &current_event_id_buffer)); │ │177 - │ │178 - // if there was a previous event, set the views map to have the same value as it. │ │179 - // this efficiently "clones" the map so we make further modifications based on it. │ │180 - if (last_event_id_maybe) |*last_event_id| { │ │181 - if (try event_id_to_views.getCursor(hash.hashInt(repo_opts.hash, last_event_id))) |last_view_cursor| { │ │182 - try views_cursor.write(.{ .slot = last_view_cursor.slot() }); │ │183 - } │ │184 - } │ │185 - │ │186 - // process the event into the views map │ │187 - { │ │188 - const views = try Repo.DB.HashMap(.read_write).init(views_cursor); │ │189 - │ │190 - switch (event.data) { │ │191 - .issue => |data| { │ │192 - const event_id_to_issue_cursor = try views.putCursor(hash.hashInt(repo_opts.hash, "event-id->issue")); │ │193 - const event_id_to_issue = try Repo.DB.HashMap(.read_write).init(event_id_to_issue_cursor); │ │194 - │ │195 - const issue_cursor = try event_id_to_issue.putCursor(hash.hashInt(repo_opts.hash, &current_event_id_buffer));│ │196 - const issue = try Repo.DB.HashMap(.read_write).init(issue_cursor); │ │197 - │ │198 - try putIfDifferent(issue, hash.hashInt(repo_opts.hash, "id"), &current_event_id_buffer); │ │199 - try putIfDifferent(issue, hash.hashInt(repo_opts.hash, "title"), data.title); │ │200 - try putIfDifferent(issue, hash.hashInt(repo_opts.hash, "description"), data.description); │ │201 - }, │ │202 - } │ │203 - } │ │204 - │ │205 - // the current event id is now the last one │ │206 - last_event_id_maybe = current_event_id_buffer; │ │207 - │ │208 - // prevent any of the data created above from being mutated by future iterations of this loop │ │209 - try cursor.db.freeze(); │ │210 - } │ │211 - │ │212 - if (last_event_id_maybe) |*last_event_id| { │ │213 - try haxy.put(hash.hashInt(repo_opts.hash, "last-event-id"), .{ .bytes = last_event_id }); │ │214 - } │ │215 - } │ │216 - │ │217 - fn putIfDifferent(map: Repo.DB.HashMap(.read_write), key: hash.HashInt(repo_opts.hash), value: []const u8) !void { │ │218 - if (try map.getCursor(key)) |value_cursor| { │ │219 - var buffer: [4096]u8 = undefined; │ │220 - const existing_value = try value_cursor.readBytes(&buffer); │ │221 - if (std.mem.eql(u8, existing_value, value)) { │ │222 - return; │ │223 - } │ │224 - } │ │225 - │ │226 - try map.put(key, .{ .bytes = value }); │ │227 - } │ │228 - }; │ │229 - │ │230 - try repo.core.db_file.lock(io, .exclusive); │ │231 - defer repo.core.db_file.unlock(io); │ │232 - │ │233 - // create a new transaction in the database that runs the above-defined Ctx function │ │234 - const history = try Repo.DB.ArrayList(.read_write).init(repo.core.db.rootCursor()); │ │235 - try history.appendContext(.{ .slot = try history.getSlot(-1) }, Ctx{ .events = events.items }); │ │236 - │ │160 // read the moment we just created │ │161 const moment_cursor = try history.getCursor(-1) orelse return error.NotFound; │ │162 const moment = try Repo.DB.HashMap(.read_only).init(moment_cursor); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │164 const haxy_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, "haxy")) orelse return error.NotFound; │ │165 const haxy = try Repo.DB.HashMap(.read_only).init(haxy_cursor); │ │166 │ │244 - const event_id_to_views_cursor = try haxy.getCursor(hash.hashInt(repo_opts.hash, "event-id->views")) orelse return error.NotFound; │ │245 - const event_id_to_views = try Repo.DB.HashMap(.read_only).init(event_id_to_views_cursor); │ │167 + const object_id_to_views_cursor = try haxy.getCursor(hash.hashInt(repo_opts.hash, "object-id->views")) orelse return error.NotFound;│ │168 + const object_id_to_views = try Repo.DB.HashMap(.read_only).init(object_id_to_views_cursor); │ │169 │ │170 // make sure the issue from the first event was correctly edited │ │171 { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │249 - // get the last event id │ │250 - const last_event_id_cursor = try haxy.getCursor(hash.hashInt(repo_opts.hash, "last-event-id")) orelse return error.NotFound; │ │251 - var last_event_id_buffer: [evt.id_size]u8 = undefined; │ │252 - _ = try last_event_id_cursor.readBytes(&last_event_id_buffer); │ │172 + // get the last object id │ │173 + const last_object_id_cursor = try haxy.getCursor(hash.hashInt(repo_opts.hash, "last-object-id")) orelse return error.NotFound; │ │174 + var last_object_id: [hash.byteLen(repo_opts.hash)]u8 = undefined; │ │175 + _ = try last_object_id_cursor.readBytes(&last_object_id); │ │176 │ │254 - // get the latest views (the views generated by the last event id) │ │255 - const views_cursor = try event_id_to_views.getCursor(hash.hashInt(repo_opts.hash, &last_event_id_buffer)) orelse return error.NotFound;│ │177 + // get the latest views (the views generated by the last object id) │ │178 + const views_cursor = try object_id_to_views.getCursor(hash.bytesToInt(repo_opts.hash, &last_object_id)) orelse return error.NotFound; │ │179 const views = try Repo.DB.HashMap(.read_only).init(views_cursor); │ │180 │ │181 // get the map of issues │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │190 const first_issue_description_cursor = try first_issue.getCursor(hash.hashInt(repo_opts.hash, "description")) orelse return error.NotFound;│ │191 const first_issue_description_value = try first_issue_description_cursor.readBytesAlloc(allocator, null); │ │192 defer allocator.free(first_issue_description_value); │ │270 - try std.testing.expectEqualStrings(events_to_process[1].data.issue.description, first_issue_description_value); │ │193 + try std.testing.expectEqualStrings(events_to_consume[1].data.issue.description, first_issue_description_value); │ │194 } │ │195 } │ │196 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯