Allow querying by other fields
This commit is contained in:
parent
90d2dcd4c1
commit
1d6f7bfa08
3 changed files with 61 additions and 15 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in a new issue