Type-introspected insert
This commit is contained in:
parent
c9c5958849
commit
40e7037444
2 changed files with 57 additions and 8 deletions
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue