summaryrefslogtreecommitdiff
path: root/src/DB.zig
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2025-08-03 12:54:12 +0300
committerGravatar Uko Kokņevičs2025-08-03 12:54:12 +0300
commite5185f65051f881bf61e88542a1acd4957f8383b (patch)
treea030a8b32cd13ed6a7d9ed736f8fc626501c2749 /src/DB.zig
parentMoved inline bot handling to a new file (diff)
downloadukkobot-e5185f65051f881bf61e88542a1acd4957f8383b.tar.gz
ukkobot-e5185f65051f881bf61e88542a1acd4957f8383b.tar.xz
ukkobot-e5185f65051f881bf61e88542a1acd4957f8383b.zip
Move bot configuration to SQL land
Diffstat (limited to 'src/DB.zig')
-rw-r--r--src/DB.zig100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/DB.zig b/src/DB.zig
new file mode 100644
index 0000000..6510e7c
--- /dev/null
+++ b/src/DB.zig
@@ -0,0 +1,100 @@
1const sqlite = @import("sqlite");
2const std = @import("std");
3
4const DB = @This();
5
6const target_version = 1;
7
8sql: sqlite.Db,
9
10pub const InlineBotType = enum(u32) {
11 blacklisted = 0,
12 whitelisted = 1,
13};
14
15pub fn init(db_path: [:0]const u8) !DB {
16 const sql = try sqlite.Db.init(.{
17 .mode = .{ .File = db_path },
18 .open_flags = .{
19 .write = true,
20 .create = true,
21 },
22 .threading_mode = .MultiThread,
23 });
24
25 return DB{
26 .sql = sql,
27 };
28}
29
30pub fn deinit(self: *DB) void {
31 self.sql.deinit();
32}
33
34pub fn getInlineBotType(self: *DB, id: i64) !?InlineBotType {
35 const row = try self.sql.one(u32, "SELECT type FROM inline_bots WHERE id = ?", .{}, .{ .id = id });
36 if (row) |r| {
37 return @enumFromInt(r);
38 }
39 return null;
40}
41
42pub fn setInlineBotType(self: *DB, id: i64, ty: InlineBotType) !void {
43 try self.sql.exec("INSERT OR REPLACE INTO inline_bots (id, type) VALUES (?, ?)", .{}, .{ id, @intFromEnum(ty) });
44}
45
46pub fn upgrade(self: *DB) !void {
47 try self.sql.exec("CREATE TABLE IF NOT EXISTS version(id INTEGER PRIMARY KEY, version INTEGER)", .{}, .{});
48 const row = try self.sql.one(struct { version: u32 }, "SELECT version FROM version WHERE id = 0", .{}, .{});
49 var current_ver: u32 = if (row) |r| r.version else 0;
50
51 if (current_ver == target_version) {
52 std.log.info("Database is up to date", .{});
53 return;
54 } else if (current_ver > target_version) {
55 std.log.err("Database has a higher version than supported?", .{});
56 return error.CorruptedDatabase;
57 }
58
59 std.log.info("Updating database from version {} to {}", .{ current_ver, target_version });
60
61 var setVerStmt = try self.sql.prepare("INSERT OR REPLACE INTO version(id, version) VALUES (0, ?)");
62 defer setVerStmt.deinit();
63
64 while (current_ver < target_version) : (current_ver += 1) {
65 std.log.info("Updating database step from {}", .{current_ver});
66 try self.upgradeStep(current_ver + 1);
67 setVerStmt.reset();
68 try setVerStmt.exec(.{}, .{ current_ver + 1 });
69 }
70}
71
72fn upgradeStep(self: *DB, new_version: u32) !void {
73 switch (new_version) {
74 1 => {
75 try self.sql.exec("DROP TABLE IF EXISTS inline_bots_enum", .{}, .{});
76 try self.sql.exec(
77 \\CREATE TABLE inline_bots_enum (
78 \\ id INTEGER PRIMARY KEY,
79 \\ value TEXT UNIQUE
80 \\)
81 , .{}, .{});
82 try self.sql.exec(
83 \\INSERT INTO inline_bots_enum(id, value)
84 \\VALUES (?, 'blacklisted'), (?, 'whitelisted')
85 , .{}, .{
86 .blacklisted = @intFromEnum(InlineBotType.blacklisted),
87 .whitelisted = @intFromEnum(InlineBotType.whitelisted),
88 });
89
90 try self.sql.exec("DROP TABLE IF EXISTS inline_bots", .{}, .{});
91 try self.sql.exec(
92 \\CREATE TABLE inline_bots (
93 \\ id INTEGER PRIMARY KEY,
94 \\ type INTEGER REFERENCES inline_bots_enum(id)
95 \\)
96 , .{}, .{});
97 },
98 else => unreachable,
99 }
100}