+pub fn Paginate(comptime T: type) type {
+ return struct {
+ const Self = @This();
+
+ const IterateResult = T.Base.View.Iterator.Result;
+
+ res: *http.Response,
+ view: T.View,
+ per_page: u64,
+
+ it: T.Base.View.Iterator,
+ starting_idx: ?T.Base.Key,
+ count: u64 = 0,
+
+ pub fn init(res: *http.Response, view: T.View, per_page: u64) !Self {
+ var it = view.reverse_iterator();
+ if (res.req.get_param("starting_at")) |starting_at_str| {
+ it.idx = try parse_enum(T.Base.Key, starting_at_str, 16);
+ }
+
+ return .{
+ .res = res,
+ .view = view,
+ .per_page = per_page,
+ .it = it,
+ .starting_idx = it.idx,
+ };
+ }
+ pub fn next(self: *Self) IterateResult {
+ if (self.it.next()) |kv| {
+ if (self.count < self.per_page) {
+ self.count += 1;
+ return kv;
+ }
+ }
+ return null;
+ }
+ pub fn write_navigation(self: *Self) !void {
+ const next_idx = self.it.next();
+
+ if (self.view.base.head.last != self.starting_idx) {
+ var prev_it = self.view.iterator();
+ prev_it.idx = self.starting_idx.?;
+ var oldest_idx = self.starting_idx.?;
+
+ var count: u64 = 0;
+ while (prev_it.next()) |kv| {
+ oldest_idx = kv.key;
+
+ if (count > self.per_page) {
+ break;
+ } else {
+ count += 1;
+ }
+ }
+
+ try self.res.write("<a href=\"{s}?starting_at={x}\">Prev</a> ", .{ self.res.req.target, @intFromEnum(oldest_idx) });
+ }
+
+ if (next_idx) |kv| {
+ try self.res.write("<a href=\"{s}?starting_at={x}\">Next</a>", .{ self.res.req.target, @intFromEnum(kv.key) });
+ }
+ }
+ };
+}