Allow querying by other fields

This commit is contained in:
jaina heartles 2022-07-16 12:00:33 -07:00
parent 90d2dcd4c1
commit 1d6f7bfa08
3 changed files with 61 additions and 15 deletions

View file

@ -26,18 +26,15 @@ pub fn build(b: *std.build.Builder) void {
exe.setTarget(target);
exe.setBuildMode(mode);
const sql = std.build.Pkg{
.name = "sql",
.source = std.build.FileSource.relative("src/sql/lib.zig"),
};
const util = std.build.Pkg{
.name = "util",
.source = std.build.FileSource.relative("src/util/lib.zig"),
};
const sql = std.build.Pkg{ .name = "sql", .source = std.build.FileSource.relative("src/sql/lib.zig"), .dependencies = &.{util} };
const http = std.build.Pkg{
.name = "http",
.source = std.build.FileSource.relative("src/http/lib.zig"),
.dependencies = &[_]std.build.Pkg{util},
.dependencies = &.{util},
};
exe.addPackage(sql);
exe.addPackage(util);

View file

@ -123,7 +123,7 @@ pub const Database = struct {
self.db.close();
}
pub fn getById(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T {
pub fn getByIdOld(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T {
const fields = comptime fieldsExcept(T, &.{"id"});
const q = comptime (Query{
.select = fields,
@ -153,6 +153,46 @@ pub const Database = struct {
return val;
}
pub fn getById(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T {
return self.getBy(T, .id, id, alloc);
}
pub fn getBy(
self: *Database,
comptime T: type,
comptime field: std.meta.FieldEnum(T),
val: std.meta.fieldInfo(T, field).field_type,
alloc: std.mem.Allocator,
) !?T {
const field_name = std.meta.fieldInfo(T, field).name;
const fields = comptime fieldsExcept(T, &.{field_name});
const q = comptime (Query{
.select = fields,
.from = tableName(T),
.where = field_name ++ " = ?",
.limit = 1,
}).str();
var stmt = try self.db.prepare(q);
defer stmt.finalize();
try stmt.bind(1, val);
const row = (try stmt.step()) orelse return null;
var result: T = undefined;
@field(result, field_name) = val;
inline for (fields) |f, i| {
@field(result, f) = switch (@TypeOf(@field(result, f))) {
// TODO: Handle allocation failures gracefully
[]const u8 => row.getTextAlloc(i, alloc) catch unreachable,
else => @compileError("unknown type"),
};
}
return result;
}
pub fn getNoteById(self: *Database, id: Uuid, alloc: std.mem.Allocator) !?models.Note {
return self.getById(models.Note, id, alloc);
}
@ -169,15 +209,7 @@ pub const Database = struct {
defer stmt.finalize();
inline for (fields) |f, i| {
const arg_idx = i + 1;
switch (@TypeOf(@field(val, f))) {
[]const u8 => try stmt.bindText(arg_idx, @field(val, f)),
Uuid => {
const str = @field(val, f).toCharArray();
try stmt.bindText(arg_idx, &str);
},
else => @compileError("unknown type"),
}
try stmt.bind(i + 1, @field(val, f));
}
if ((try stmt.step()) != null) return error.UnknownError;

View file

@ -3,6 +3,8 @@ const c = @cImport({
@cInclude("sqlite3.h");
});
const Uuid = @import("util").Uuid;
pub const Sqlite = struct {
db: *c.sqlite3,
@ -71,6 +73,11 @@ pub const PreparedStmt = struct {
};
}
pub fn bindUuid(self: *PreparedStmt, idx: u15, id: Uuid) !void {
const str = id.toCharArray();
return self.bindText(idx, &str);
}
pub fn bindText(self: *PreparedStmt, idx: u15, str: []const u8) !void {
return switch (c.sqlite3_bind_text(self.stmt, idx, str.ptr, @intCast(c_int, str.len), c.SQLITE_TRANSIENT)) {
c.SQLITE_OK => {},
@ -85,6 +92,16 @@ pub const PreparedStmt = struct {
};
}
pub fn bind(self: *PreparedStmt, idx: u15, val: anytype) !void {
return switch (@TypeOf(val)) {
[]const u8 => self.bindText(idx, val),
i64 => self.bindI64(idx, val),
Uuid => self.bindUuid(idx, val),
@Type(.Null) => self.bindNull(idx),
else => @compileError("Unknown Type"),
};
}
pub fn step(self: *PreparedStmt) !?Row {
return switch (c.sqlite3_step(self.stmt)) {
c.SQLITE_ROW => Row{ .stmt = self.stmt, .db = self.db },