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 }); 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 { fn filterOut(comptime vals: []const String, comptime to_ignore: []const String) []const String {
comptime { comptime {
var result: [vals.len]String = undefined; var result: [vals.len]String = undefined;
@ -82,6 +102,12 @@ pub const Database = struct {
\\ content TEXT NOT NULL \\ content TEXT NOT NULL
\\) STRICT; \\) STRICT;
\\ \\
\\CREATE TABLE IF NOT EXISTS
\\user(
\\ id TEXT PRIMARY KEY,
\\ handle TEXT NOT NULL
\\) STRICT;
\\
); );
defer stmt.finalize(); defer stmt.finalize();
@ -128,14 +154,33 @@ pub const Database = struct {
return self.getById(models.Note, id, alloc); return self.getById(models.Note, id, alloc);
} }
pub fn insertNote(self: *Database, note: models.Note) !void { pub fn insert(self: *Database, comptime T: type, val: T) !void {
var stmt = try self.db.prepare("INSERT INTO note (id, content) VALUES(?, ?);"); 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(); defer stmt.finalize();
const id_str = note.id.toCharArray(); inline for (fields) |f, i| {
try stmt.bindText(1, &id_str); const arg_idx = i + 1;
try stmt.bindText(2, note.content); 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_ROW => Row{ .stmt = self.stmt, .db = self.db },
c.SQLITE_DONE => null, 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;
},
}; };
} }