From fd584886c6366b223fa0781b538015ac3b406433 Mon Sep 17 00:00:00 2001 From: Alan Daniels Date: Sun, 2 Nov 2025 22:47:45 +1100 Subject: [PATCH] getting tags from the backend --- src/context.zig | 14 +++++--- src/main.zig | 9 ++---- src/models/tag.zig | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 src/models/tag.zig diff --git a/src/context.zig b/src/context.zig index fd6ed07..cf1784a 100644 --- a/src/context.zig +++ b/src/context.zig @@ -6,24 +6,28 @@ const Allocator = std.mem.Allocator; const builtin = @import("builtin"); const optimize_mode = builtin.mode; -db_connection: sqlite.Db, +const model_tag = @import("./models/tag.zig"); + +db_connection: *sqlite.Db, counter: u32 = 0, -pub fn init(connection: sqlite.Db) @This() { +pub fn init(connection: *sqlite.Db) !@This() { + try connection.execDynamic(model_tag.schema, .{}, .{}); return .{ .db_connection = connection, }; } -pub fn SendInertiaResponse(endpoint: anytype, context: ?*@This(), r: zap.Request, arena: Allocator, component: []const u8, props: anytype) !void { - _ = context; +pub fn SendInertiaResponse(endpoint: anytype, context: *@This(), r: zap.Request, arena: Allocator, component: []const u8, props: anytype) !void { + const tags = try model_tag.getTopLevelTags(context.db_connection, arena); + const inertia_json = try std.fmt.allocPrint( arena, "{f}", .{std.json.fmt(.{ .component = component, .props = .{ - .nav = .{}, + .tags = tags, .page = props, }, .url = endpoint.path, diff --git a/src/main.zig b/src/main.zig index 5a12c7d..b178133 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,9 +1,3 @@ -//! -//! Part of the Zap examples. -//! -//! Build me with `zig build app_basic`. -//! Run me with `zig build run-app_basic`. -//! const std = @import("std"); const Allocator = std.mem.Allocator; const builtin = @import("builtin"); @@ -77,9 +71,10 @@ pub fn main() !void { .threading_mode = .MultiThread, }); defer db.deinit(); + try db.execDynamic("PRAGMA foreign_keys = ON;", .{}, .{}); // create an app context - var my_context = Context.init(db); + var my_context = try Context.init(&db); // create an App instance // const App = zap.App.Create(Context); diff --git a/src/models/tag.zig b/src/models/tag.zig new file mode 100644 index 0000000..e1d41c5 --- /dev/null +++ b/src/models/tag.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const builtin = @import("builtin"); +const optimize_mode = builtin.mode; + +const sqlite = @import("sqlite"); + +pub const schema = + \\CREATE TABLE IF NOT EXISTS tag( + \\ id INTEGER PRIMARY KEY AUTOINCREMENT, + \\ key TEXT UNIQUE NOT NULL, + \\ parent_key TEXT TEXT, + \\ FOREIGN KEY (parent_key) REFERENCES tag(key) ON DELETE RESTRICT + \\); +; + +id: usize, +key: []const u8, +parent: ?*@This() = null, +children: ?[]@This() = null, + +const internal = struct { + id: usize, + key: []const u8, + parent_key: ?[]const u8, +}; + +const ArrList = std.ArrayList(@This()); + +pub fn getTopLevelTags(conn: *sqlite.Db, arena: Allocator) ![]@This() { + var stmt = try conn.prepareDynamic("SELECT id, key, parent_key FROM tag WHERE parent_key IS NULL;"); + defer stmt.deinit(); + + var list = ArrList.empty; + defer list.deinit(arena); + + var iter = try stmt.iterator(internal, .{}); + while (try iter.nextAlloc(arena, .{})) |row| { + var tag: @This() = .{ + .id = row.id, + .key = row.key, + }; + try tag.getChildren(conn, arena); + try list.append(arena, tag); + } + + return list.toOwnedSlice(arena); +} + +pub fn getChildren(self: *@This(), conn: *sqlite.Db, arena: Allocator) !void { + var stmt = try conn.prepareDynamic("SELECT id, key, parent_key FROM tag WHERE parent_key LIKE ?;"); + defer stmt.deinit(); + + var list = ArrList.empty; + defer list.deinit(arena); + + var iter = try stmt.iterator(internal, .{self.key}); + while (try iter.nextAlloc(arena, .{})) |row| { + var tag: @This() = .{ + .id = row.id, + .key = row.key, + }; + tag.parent = self; + try tag.getChildren(conn, arena); + try list.append(arena, tag); + } + + self.children = try list.toOwnedSlice(arena); +} + +pub fn jsonStringify(v: @This(), jws: anytype) !void { + try jws.beginObject(); + + try jws.objectField("key"); + try jws.write(v.key); + + try jws.objectField("children"); + try jws.write(v.children); + + try jws.endObject(); +}