Type-introspected insert

This commit is contained in:
jaina heartles 2022-07-15 22:29:08 -07:00
parent c9c5958849
commit 40e7037444
2 changed files with 57 additions and 8 deletions

View File

@ -22,7 +22,7 @@ fn join(comptime vals: anytype, comptime joiner: String) String {
result = std.fmt.comptimePrint("{s}{s}{s}", .{ result, joiner, v });
}
return result[2..];
return result[joiner.len..];
}
}
@ -42,6 +42,26 @@ const Query = struct {
}
};
const Insert = struct {
into: String,
columns: []const String,
count: usize = 1,
pub fn str(comptime self: Insert) String {
comptime {
const row = std.fmt.comptimePrint(
"({s})",
.{join(.{"?"} ** self.columns.len, ", ")},
);
return std.fmt.comptimePrint(
"INSERT INTO {s} ({s}) VALUES {s};",
.{ self.into, join(self.columns, ", "), join(.{row} ** self.count, ", ") },
);
}
}
};
fn filterOut(comptime vals: []const String, comptime to_ignore: []const String) []const String {
comptime {
var result: [vals.len]String = undefined;
@ -82,6 +102,12 @@ pub const Database = struct {
\\ content TEXT NOT NULL
\\) STRICT;
\\
\\CREATE TABLE IF NOT EXISTS
\\user(
\\ id TEXT PRIMARY KEY,
\\ handle TEXT NOT NULL
\\) STRICT;
\\
);
defer stmt.finalize();
@ -128,14 +154,33 @@ pub const Database = struct {
return self.getById(models.Note, id, alloc);
}
pub fn insertNote(self: *Database, note: models.Note) !void {
var stmt = try self.db.prepare("INSERT INTO note (id, content) VALUES(?, ?);");
pub fn insert(self: *Database, comptime T: type, val: T) !void {
const fields = comptime std.meta.fieldNames(T);
const q = comptime (Insert{
.into = tableName(T),
.columns = fields,
.count = 1,
}).str();
var stmt = try self.db.prepare(q);
defer stmt.finalize();
const id_str = note.id.toCharArray();
try stmt.bindText(1, &id_str);
try stmt.bindText(2, note.content);
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"),
}
}
if ((try stmt.step()) != null) return error.UnexpectedError;
if ((try stmt.step()) != null) return error.UnknownError;
}
pub fn insertNote(self: *Database, note: models.Note) !void {
return self.insert(models.Note, note);
}
};

View File

@ -86,7 +86,11 @@ pub const PreparedStmt = struct {
c.SQLITE_ROW => Row{ .stmt = self.stmt, .db = self.db },
c.SQLITE_DONE => null,
else => error.UnknownError,
else => |err| blk: {
std.debug.print("sql error {}\n", .{err});
std.debug.print("{s}\n", .{c.sqlite3_errmsg(self.db)});
break :blk error.UnknownError;
},
};
}