diff --git a/src/db/Remote.zig b/src/db/Remote.zig index d71f527..d96b3a7 100644 --- a/src/db/Remote.zig +++ b/src/db/Remote.zig @@ -22,11 +22,7 @@ pub const Remote = struct { pub const BaseType = string; }; - pub fn byID(alloc: *std.mem.Allocator, id: u64) !?Remote { - return try db.first(alloc, Remote, "select * from remotes where id = ?", .{ - .id = id, - }); - } + pub const byKey = _internal.ByKeyGen(Remote, "remotes").byKey; pub fn findUserByName(self: Remote, alloc: *std.mem.Allocator, name: string) !?User { return try db.first(alloc, User, "select * from users where provider = ? and name = ?", .{ diff --git a/src/db/_internal.zig b/src/db/_internal.zig index 3cd5748..bed8cdf 100644 --- a/src/db/_internal.zig +++ b/src/db/_internal.zig @@ -1,5 +1,43 @@ const std = @import("std"); +const string = []const u8; const zorm = @import("zorm"); pub const Engine = zorm.engine(.sqlite3); pub var db: Engine = undefined; + +pub fn ByKeyGen(comptime T: type, comptime table_name: string) type { + return struct { + pub fn byKey(alloc: *std.mem.Allocator, comptime key: std.meta.FieldEnum(T), value: FieldType(T, @tagName(key))) !?T { + return try db.first( + alloc, + T, + "select * from " ++ table_name ++ " where " ++ @tagName(key) ++ " = ?", + foo(@tagName(key), value), + ); + } + }; +} + +fn FieldType(comptime T: type, comptime name: string) type { + inline for (std.meta.fields(T)) |item| { + if (std.mem.eql(u8, item.name, name)) { + return item.field_type; + } + } + @compileError(@typeName(T) ++ " does not have a field named " ++ name); +} + +pub fn foo(comptime name: string, value: anytype) Struct(name, @TypeOf(value)) { + const T = @TypeOf(value); + var x: Struct(name, T) = undefined; + @field(x, name) = value; + return x; +} + +pub fn Struct(comptime name: string, comptime T: type) type { + return @Type(.{ .Struct = .{ .layout = .Auto, .fields = &.{structField(name, T)}, .decls = &.{}, .is_tuple = false } }); +} + +pub fn structField(comptime name: string, comptime T: type) std.builtin.TypeInfo.StructField { + return .{ .name = name, .field_type = T, .default_value = null, .is_comptime = false, .alignment = @alignOf(T) }; +} diff --git a/src/handler/package.zig b/src/handler/package.zig index c75aa71..590a1cd 100644 --- a/src/handler/package.zig +++ b/src/handler/package.zig @@ -8,7 +8,7 @@ const _internal = @import("./_internal.zig"); pub fn get(_: void, response: *http.Response, request: http.Request, args: struct { remote: u64, user: string, package: string }) !void { const alloc = request.arena; - const r = try db.Remote.byID(alloc, args.remote); + const r = try db.Remote.byKey(alloc, .id, args.remote); const o = try r.?.findUserByName(alloc, args.user); const p = try o.?.findPackageByName(alloc, args.package); const v = try p.?.versions(alloc); diff --git a/src/handler/user.zig b/src/handler/user.zig index ba9667a..d2da96e 100644 --- a/src/handler/user.zig +++ b/src/handler/user.zig @@ -8,7 +8,7 @@ const _internal = @import("./_internal.zig"); pub fn get(_: void, response: *http.Response, request: http.Request, args: struct { remote: u64, user: string }) !void { const alloc = request.arena; - const r = try db.Remote.byID(alloc, args.remote); + const r = try db.Remote.byKey(alloc, .id, args.remote); const o = try r.?.findUserByName(alloc, args.user); const p = try o.?.packages(alloc);