╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │35 repo: ?Repo, │ │36 issue: ?Issue, │ │37 }, │ │38 + timestamp: u64 = 0, // not serialized, because it comes from the commit timestamp│ │39 │ │40 pub fn jsonStringify(self: EventWithId, jw: anytype) !void { │ │41 try jw.beginObject(); │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │311 var current_event_id: [event_id_size]u8 = undefined; │ │312 _ = try std.fmt.hexToBytes(&current_event_id, &event_with_id.id); │ │313 │ │314 + const created_ts = commit_object.content.commit.metadata.timestamp; │ │315 + │ │316 switch (event_with_id.event) { │ │314 - .user => |event_maybe| try User.consume(DB, repo_opts.hash, haxy_moment, &current_event_id, event_maybe, &arena), │ │315 - .repo => |event_maybe| try Repo.consume(DB, repo_opts.hash, haxy_moment, &current_event_id, event_maybe, &arena), │ │317 + .user => |event_maybe| try User.consume(DB, repo_opts.hash, haxy_moment, &current_event_id, event_maybe, &arena, created_ts),│ │318 + .repo => |event_maybe| try Repo.consume(DB, repo_opts.hash, haxy_moment, &current_event_id, event_maybe, &arena, created_ts),│ │319 .issue => |event_maybe| try Issue.consume(DB, repo_opts.hash, haxy_moment, &current_event_id, event_maybe), │ │320 } │ │321 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │365 for (events) |event| { │ │366 json.clearRetainingCapacity(); │ │367 try std.json.Stringify.value(event, .{}, &json.writer); │ │365 - _ = try repo.commitAtRef(io, allocator, .{ .message = json.written() }, null, ref); │ │368 + _ = try repo.commitAtRef(io, allocator, .{ .message = json.written(), .timestamp = event.timestamp }, null, ref);│ │369 } │ │370 │ │371 try consume(repo_opts, io, allocator, repo, ref); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │372 +} │ │373 + │ │374 +// build the key for SortedMaps sorted by timestamp. the big-endian timestamp │ │375 +// makes byte order match creation order; the event id breaks ties and keeps │ │376 +// keys unique within the same timestamp. │ │377 +pub fn orderKey(timestamp: u64, event_id: *const [event_id_size]u8) [@sizeOf(u64) + event_id_size]u8 {│ │378 + var key: [@sizeOf(u64) + event_id_size]u8 = undefined; │ │379 + std.mem.writeInt(u64, key[0..@sizeOf(u64)], timestamp, .big); │ │380 + @memcpy(key[@sizeOf(u64)..], event_id); │ │381 + return key; │ │382 } │ │383 │ │384 // split a pushed "<owner>/<repo>" path into its two components, or null if it │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │436 │ │437 try commitAndConsume(admin_repo_opts, io, allocator, &repo, events_ref, &[_]EventWithId{.{│ │438 .id = event_id_hex, │ │439 + .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │440 .event = .{ .repo = .{ │ │441 .user_id = &owner_user_id, │ │442 .name = repo_name, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯