From e5185f65051f881bf61e88542a1acd4957f8383b Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Sun, 3 Aug 2025 12:54:12 +0300 Subject: Move bot configuration to SQL land --- src/DB.zig | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/DB.zig (limited to 'src/DB.zig') 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 @@ +const sqlite = @import("sqlite"); +const std = @import("std"); + +const DB = @This(); + +const target_version = 1; + +sql: sqlite.Db, + +pub const InlineBotType = enum(u32) { + blacklisted = 0, + whitelisted = 1, +}; + +pub fn init(db_path: [:0]const u8) !DB { + const sql = try sqlite.Db.init(.{ + .mode = .{ .File = db_path }, + .open_flags = .{ + .write = true, + .create = true, + }, + .threading_mode = .MultiThread, + }); + + return DB{ + .sql = sql, + }; +} + +pub fn deinit(self: *DB) void { + self.sql.deinit(); +} + +pub fn getInlineBotType(self: *DB, id: i64) !?InlineBotType { + const row = try self.sql.one(u32, "SELECT type FROM inline_bots WHERE id = ?", .{}, .{ .id = id }); + if (row) |r| { + return @enumFromInt(r); + } + return null; +} + +pub fn setInlineBotType(self: *DB, id: i64, ty: InlineBotType) !void { + try self.sql.exec("INSERT OR REPLACE INTO inline_bots (id, type) VALUES (?, ?)", .{}, .{ id, @intFromEnum(ty) }); +} + +pub fn upgrade(self: *DB) !void { + try self.sql.exec("CREATE TABLE IF NOT EXISTS version(id INTEGER PRIMARY KEY, version INTEGER)", .{}, .{}); + const row = try self.sql.one(struct { version: u32 }, "SELECT version FROM version WHERE id = 0", .{}, .{}); + var current_ver: u32 = if (row) |r| r.version else 0; + + if (current_ver == target_version) { + std.log.info("Database is up to date", .{}); + return; + } else if (current_ver > target_version) { + std.log.err("Database has a higher version than supported?", .{}); + return error.CorruptedDatabase; + } + + std.log.info("Updating database from version {} to {}", .{ current_ver, target_version }); + + var setVerStmt = try self.sql.prepare("INSERT OR REPLACE INTO version(id, version) VALUES (0, ?)"); + defer setVerStmt.deinit(); + + while (current_ver < target_version) : (current_ver += 1) { + std.log.info("Updating database step from {}", .{current_ver}); + try self.upgradeStep(current_ver + 1); + setVerStmt.reset(); + try setVerStmt.exec(.{}, .{ current_ver + 1 }); + } +} + +fn upgradeStep(self: *DB, new_version: u32) !void { + switch (new_version) { + 1 => { + try self.sql.exec("DROP TABLE IF EXISTS inline_bots_enum", .{}, .{}); + try self.sql.exec( + \\CREATE TABLE inline_bots_enum ( + \\ id INTEGER PRIMARY KEY, + \\ value TEXT UNIQUE + \\) + , .{}, .{}); + try self.sql.exec( + \\INSERT INTO inline_bots_enum(id, value) + \\VALUES (?, 'blacklisted'), (?, 'whitelisted') + , .{}, .{ + .blacklisted = @intFromEnum(InlineBotType.blacklisted), + .whitelisted = @intFromEnum(InlineBotType.whitelisted), + }); + + try self.sql.exec("DROP TABLE IF EXISTS inline_bots", .{}, .{}); + try self.sql.exec( + \\CREATE TABLE inline_bots ( + \\ id INTEGER PRIMARY KEY, + \\ type INTEGER REFERENCES inline_bots_enum(id) + \\) + , .{}, .{}); + }, + else => unreachable, + } +} -- cgit v1.2.3