Add sql support for blobs

This commit is contained in:
jaina heartles 2022-07-23 21:14:46 -07:00
parent fb5a7f9f30
commit ada0eb71f5

View file

@ -7,6 +7,40 @@ const c = @cImport({
const Uuid = util.Uuid; const Uuid = util.Uuid;
const DateTime = util.DateTime; const DateTime = util.DateTime;
pub fn ByteArray(comptime n: usize) type {
return struct {
const Self = @This();
data: [n]u8,
pub fn bindToSqlite(self: Self, stmt: *PreparedStmt, idx: u15) !void {
return stmt.bindBlob(idx, &self.data);
}
pub fn getFromSqlite(row: *Row, idx: u15, _: std.mem.Alloc) !Self {
var self: Self = undefined;
_ = try row.getBlob(idx, &self.data);
return self;
}
};
}
pub const ByteSlice = struct {
const Self = @This();
data: []const u8,
pub fn bindToSqlite(self: Self, stmt: *PreparedStmt, idx: u15) !void {
return stmt.bindBlob(idx, self.data);
}
pub fn getFromSqlite(row: *Row, idx: u15, alloc: std.mem.Alloc) !void {
return Self{
.data = try row.getBlobAlloc(idx, alloc),
};
}
};
pub const Sqlite = struct { pub const Sqlite = struct {
db: *c.sqlite3, db: *c.sqlite3,
@ -63,6 +97,24 @@ pub const Row = struct {
return self.getText(idx, buf); return self.getText(idx, buf);
} }
pub fn getBlob(self: Row, idx: u15, buf: []u8) ![]u8 {
const ptr = c.sqlite3_column_blob(self.stmt, idx);
const size = @intCast(usize, c.sqlite3_column_bytes(self.stmt, idx));
if (size > buf.len) return error.StreamTooLong;
for (ptr[0..size]) |ch, i| buf[i] = ch;
return buf[0..size];
}
pub fn getBlobAlloc(self: Row, idx: u15, alloc: std.mem.Allocator) ![]u8 {
const size = c.sqlite3_column_bytes(self.stmt, idx);
var buf = try alloc.alloc(u8, @intCast(usize, size));
errdefer alloc.free(buf);
return self.getBlob(idx, buf);
}
pub fn getUuid(self: Row, idx: u15) !Uuid { pub fn getUuid(self: Row, idx: u15) !Uuid {
var buf: [Uuid.string_len + 1]u8 = undefined; var buf: [Uuid.string_len + 1]u8 = undefined;
_ = try self.getText(idx, &buf); _ = try self.getText(idx, &buf);
@ -87,6 +139,7 @@ pub const Row = struct {
c.SQLITE_NULL => return null, c.SQLITE_NULL => return null,
else => return try self.getAlloc(std.meta.Child(T), idx, alloc), else => return try self.getAlloc(std.meta.Child(T), idx, alloc),
}, },
.Struct, .Union, .Enum, .Opaque => if (@hasDecl(T, "getFromSqlite")) T.getFromSqlite(self, idx, alloc),
else => @compileError("unknown type " ++ @typeName(T)), else => @compileError("unknown type " ++ @typeName(T)),
} }
}, },
@ -117,6 +170,13 @@ pub const PreparedStmt = struct {
}; };
} }
pub fn bindBlob(self: *PreparedStmt, idx: u15, blob: []const u8) !void {
return switch (c.sqlite3_bind_blob64(self.stmt, idx, blob.ptr, blob.len, c.SQLITE_TRANSIENT)) {
c.SQLITE_OK => {},
else => error.UnknownError,
};
}
pub fn bindI64(self: *PreparedStmt, idx: u15, val: i64) !void { pub fn bindI64(self: *PreparedStmt, idx: u15, val: i64) !void {
return switch (c.sqlite3_bind_int64(self.stmt, idx, val)) { return switch (c.sqlite3_bind_int64(self.stmt, idx, val)) {
c.SQLITE_OK => {}, c.SQLITE_OK => {},
@ -137,6 +197,7 @@ pub const PreparedStmt = struct {
@TypeOf(null) => self.bindNull(idx), @TypeOf(null) => self.bindNull(idx),
else => |T| switch (@typeInfo(T)) { else => |T| switch (@typeInfo(T)) {
.Optional => if (val) |v| self.bind(idx, v) else self.bindNull(idx), .Optional => if (val) |v| self.bind(idx, v) else self.bindNull(idx),
.Struct, .Union, .Enum, .Opaque => if (@hasDecl(T, "bindToSqlite")) val.bindToSqlite(self, idx),
else => @compileError("Unknown Type" ++ @typeName(T)), else => @compileError("Unknown Type" ++ @typeName(T)),
}, },
}; };