This repository has no description
1//! the appview: a derived, disposable index over the repo.
2//!
3//! the repo (signed CAR) is the only source of truth. this layer exists so
4//! reads don't walk the MST, and it can be deleted and rebuilt from the repo
5//! at any time (`hydrate` does exactly that on boot).
6//!
7//! backends are swappable behind the union: burner-redis (embedded,
8//! in-process, the default) today; a real redis client or docket-backed
9//! index slot in beside it without touching call sites.
10
11const std = @import("std");
12const burner = @import("burner_redis");
13
14pub const Cache = union(enum) {
15 burner: Burner,
16
17 pub fn initBurner(allocator: std.mem.Allocator, io: std.Io) Cache {
18 return .{ .burner = .{ .store = burner.Store.init(allocator, io) } };
19 }
20
21 pub fn deinit(self: *Cache) void {
22 switch (self.*) {
23 .burner => |*b| b.store.deinit(),
24 }
25 }
26
27 pub fn set(self: *Cache, key: []const u8, value: []const u8) !void {
28 switch (self.*) {
29 .burner => |*b| _ = try b.store.set(key, value, .{}),
30 }
31 }
32
33 /// returned slice is owned by out_alloc
34 pub fn get(self: *Cache, out_alloc: std.mem.Allocator, key: []const u8) ?[]u8 {
35 return switch (self.*) {
36 .burner => |*b| b.store.get(out_alloc, key) catch null,
37 };
38 }
39
40 // set ops back the appview's secondary indexes (runs by state, by flow)
41 // — the same shape as the cloud prototype's redis run-state indices.
42
43 pub fn sadd(self: *Cache, key: []const u8, member: []const u8) !void {
44 switch (self.*) {
45 .burner => |*b| _ = try b.store.sadd(key, &.{member}),
46 }
47 }
48
49 pub fn srem(self: *Cache, key: []const u8, member: []const u8) !void {
50 switch (self.*) {
51 .burner => |*b| _ = b.store.srem(key, &.{member}) catch 0,
52 }
53 }
54
55 /// returned members owned by out_alloc
56 pub fn smembers(self: *Cache, out_alloc: std.mem.Allocator, key: []const u8) ![][]u8 {
57 return switch (self.*) {
58 .burner => |*b| b.store.smembers(out_alloc, key) catch &.{},
59 };
60 }
61
62 pub fn scard(self: *Cache, key: []const u8) i64 {
63 return switch (self.*) {
64 .burner => |*b| b.store.scard(key) catch 0,
65 };
66 }
67};
68
69const Burner = struct {
70 store: burner.Store,
71};
72
73test "cache set/get round trip" {
74 var threaded = std.Io.Threaded.init(std.testing.allocator, .{});
75 defer threaded.deinit();
76 const io = threaded.io();
77
78 var cache = Cache.initBurner(std.testing.allocator, io);
79 defer cache.deinit();
80
81 try cache.set("flow:name:hello", "abc-123");
82 const got = cache.get(std.testing.allocator, "flow:name:hello").?;
83 defer std.testing.allocator.free(got);
84 try std.testing.expectEqualStrings("abc-123", got);
85 try std.testing.expect(cache.get(std.testing.allocator, "missing") == null);
86}