Remove storage policy from sql lib
This commit is contained in:
parent
ada0eb71f5
commit
3e91d66565
2 changed files with 90 additions and 88 deletions
|
@ -1,11 +1,47 @@
|
|||
const std = @import("std");
|
||||
const sql = @import("sql");
|
||||
const models = @import("./models.zig");
|
||||
const util = @import("util");
|
||||
|
||||
const Uuid = @import("util").Uuid;
|
||||
const Uuid = util.Uuid;
|
||||
const DateTime = util.DateTime;
|
||||
const String = []const u8;
|
||||
const comptimePrint = std.fmt.comptimePrint;
|
||||
|
||||
pub fn ByteArray(comptime n: usize) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
data: [n]u8,
|
||||
|
||||
pub fn bindToSql(self: Self, stmt: sql.PreparedStmt, idx: u15) !void {
|
||||
return stmt.bindBlob(idx, &self.data);
|
||||
}
|
||||
|
||||
pub fn getFromSql(row: sql.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 bindToSql(self: Self, stmt: sql.PreparedStmt, idx: u15) !void {
|
||||
return stmt.bindBlob(idx, self.data);
|
||||
}
|
||||
|
||||
pub fn getFromSql(row: sql.Row, idx: u15, alloc: std.mem.Alloc) !void {
|
||||
return Self{
|
||||
.data = try row.getBlobAlloc(idx, alloc),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
fn tableName(comptime T: type) String {
|
||||
return switch (T) {
|
||||
models.Note => "note",
|
||||
|
@ -98,6 +134,38 @@ fn fieldsExcept(comptime T: type, comptime to_ignore: []const String) []const St
|
|||
}
|
||||
}
|
||||
|
||||
fn bind(stmt: sql.PreparedStmt, idx: u15, val: anytype) !void {
|
||||
return switch (@TypeOf(val)) {
|
||||
[]u8, []const u8 => stmt.bindText(idx, val),
|
||||
i64 => stmt.bindI64(idx, val),
|
||||
Uuid => stmt.bindUuid(idx, val),
|
||||
DateTime => stmt.bindDateTime(idx, val),
|
||||
@TypeOf(null) => stmt.bindNull(idx),
|
||||
else => |T| switch (@typeInfo(T)) {
|
||||
.Optional => if (val) |v| bind(stmt, idx, v) else stmt.bindNull(idx),
|
||||
.Struct, .Union, .Enum, .Opaque => if (@hasDecl(T, "bindToSql")) val.bindToSql(stmt, idx),
|
||||
else => @compileError("Unknown Type" ++ @typeName(T)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn getAlloc(row: sql.Row, comptime T: type, idx: u15, alloc: std.mem.Allocator) !T {
|
||||
return switch (T) {
|
||||
[]u8, []const u8 => row.getTextAlloc(idx, alloc),
|
||||
i64 => row.getI64(idx),
|
||||
Uuid => row.getUuid(idx),
|
||||
DateTime => row.getDateTime(idx),
|
||||
|
||||
else => {
|
||||
switch (@typeInfo(T)) {
|
||||
.Optional => if (row.isNull(idx)) return null else return try getAlloc(row, std.meta.Child(T), idx, alloc),
|
||||
.Struct, .Union, .Enum, .Opaque => if (@hasDecl(T, "getFromSql")) T.getFromSql(row, idx, alloc),
|
||||
else => @compileError("unknown type " ++ @typeName(T)),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub const Database = struct {
|
||||
db: sql.Sqlite,
|
||||
|
||||
|
@ -194,14 +262,14 @@ pub const Database = struct {
|
|||
var stmt = try self.db.prepare(q);
|
||||
defer stmt.finalize();
|
||||
|
||||
try stmt.bind(1, val);
|
||||
try bind(stmt, 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) = row.getAlloc(@TypeOf(@field(result, f)), i, alloc) catch unreachable;
|
||||
@field(result, f) = getAlloc(row, @TypeOf(@field(result, f)), i, alloc) catch unreachable;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -225,7 +293,7 @@ pub const Database = struct {
|
|||
var stmt = try self.db.prepare(q);
|
||||
defer stmt.finalize();
|
||||
|
||||
try stmt.bind(1, val);
|
||||
try bind(stmt, 1, val);
|
||||
|
||||
var results = std.ArrayList(T).init(alloc);
|
||||
|
||||
|
@ -233,7 +301,7 @@ pub const Database = struct {
|
|||
var item: T = undefined;
|
||||
@field(item, field_name) = val;
|
||||
inline for (fields) |f, i| {
|
||||
@field(item, f) = row.getAlloc(@TypeOf(@field(item, f)), i, alloc) catch unreachable;
|
||||
@field(item, f) = getAlloc(row, @TypeOf(@field(item, f)), i, alloc) catch unreachable;
|
||||
}
|
||||
|
||||
try results.append(item);
|
||||
|
@ -258,7 +326,7 @@ pub const Database = struct {
|
|||
var stmt = try self.db.prepare(q);
|
||||
defer stmt.finalize();
|
||||
|
||||
try stmt.bind(1, val);
|
||||
try bind(stmt, 1, val);
|
||||
|
||||
const row = (try stmt.step()) orelse unreachable;
|
||||
return @intCast(usize, try row.getI64(0));
|
||||
|
@ -282,7 +350,7 @@ pub const Database = struct {
|
|||
var stmt = try self.db.prepare(q);
|
||||
defer stmt.finalize();
|
||||
|
||||
try stmt.bind(1, val);
|
||||
try bind(stmt, 1, val);
|
||||
|
||||
const row = (try stmt.step()) orelse unreachable;
|
||||
return (try row.getI64(0)) > 0;
|
||||
|
@ -300,7 +368,7 @@ pub const Database = struct {
|
|||
defer stmt.finalize();
|
||||
|
||||
inline for (fields) |f, i| {
|
||||
try stmt.bind(i + 1, @field(val, f));
|
||||
try bind(stmt, i + 1, @field(val, f));
|
||||
}
|
||||
|
||||
if ((try stmt.step()) != null) return error.UnknownError;
|
||||
|
|
|
@ -7,40 +7,6 @@ const c = @cImport({
|
|||
const Uuid = util.Uuid;
|
||||
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 {
|
||||
db: *c.sqlite3,
|
||||
|
||||
|
@ -75,6 +41,10 @@ pub const Row = struct {
|
|||
stmt: *c.sqlite3_stmt,
|
||||
db: *c.sqlite3,
|
||||
|
||||
pub fn isNull(self: Row, idx: u15) bool {
|
||||
return c.sqlite3_column_type(self.stmt, idx) == c.SQLITE_NULL;
|
||||
}
|
||||
|
||||
pub fn getI64(self: Row, idx: u15) !i64 {
|
||||
return @intCast(i64, c.sqlite3_column_int64(self.stmt, idx));
|
||||
}
|
||||
|
@ -124,86 +94,50 @@ pub const Row = struct {
|
|||
pub fn getDateTime(self: Row, idx: u15) !DateTime {
|
||||
return DateTime{ .seconds_since_epoch = try self.getI64(idx) };
|
||||
}
|
||||
|
||||
pub fn getAlloc(self: Row, comptime T: type, idx: u15, alloc: std.mem.Allocator) !T {
|
||||
// TODO: handle optionals
|
||||
return switch (T) {
|
||||
[]u8, []const u8 => self.getTextAlloc(idx, alloc),
|
||||
i64 => self.getI64(idx),
|
||||
Uuid => self.getUuid(idx),
|
||||
DateTime => self.getDateTime(idx),
|
||||
|
||||
else => {
|
||||
switch (@typeInfo(T)) {
|
||||
.Optional => switch (c.sqlite3_column_type(self.stmt, idx)) {
|
||||
c.SQLITE_NULL => return null,
|
||||
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)),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const PreparedStmt = struct {
|
||||
stmt: *c.sqlite3_stmt,
|
||||
db: *c.sqlite3,
|
||||
|
||||
pub fn bindNull(self: *PreparedStmt, idx: u15) !void {
|
||||
pub fn bindNull(self: PreparedStmt, idx: u15) !void {
|
||||
return switch (c.sqlite3_bind_null(self.stmt, idx)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => error.UnknownError,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bindUuid(self: *PreparedStmt, idx: u15, id: Uuid) !void {
|
||||
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 {
|
||||
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 => {},
|
||||
else => error.UnknownError,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bindBlob(self: *PreparedStmt, idx: u15, blob: []const u8) !void {
|
||||
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)) {
|
||||
c.SQLITE_OK => {},
|
||||
else => error.UnknownError,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bindDateTime(self: *PreparedStmt, idx: u15, val: DateTime) !void {
|
||||
pub fn bindDateTime(self: PreparedStmt, idx: u15, val: DateTime) !void {
|
||||
return self.bindI64(idx, val.seconds_since_epoch);
|
||||
}
|
||||
|
||||
pub fn bind(self: *PreparedStmt, idx: u15, val: anytype) !void {
|
||||
return switch (@TypeOf(val)) {
|
||||
[]u8, []const u8 => self.bindText(idx, val),
|
||||
i64 => self.bindI64(idx, val),
|
||||
Uuid => self.bindUuid(idx, val),
|
||||
DateTime => self.bindDateTime(idx, val),
|
||||
@TypeOf(null) => self.bindNull(idx),
|
||||
else => |T| switch (@typeInfo(T)) {
|
||||
.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)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn step(self: *PreparedStmt) !?Row {
|
||||
pub fn step(self: PreparedStmt) !?Row {
|
||||
return switch (c.sqlite3_step(self.stmt)) {
|
||||
c.SQLITE_ROW => Row{ .stmt = self.stmt, .db = self.db },
|
||||
c.SQLITE_DONE => null,
|
||||
|
@ -216,15 +150,15 @@ pub const PreparedStmt = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn finalize(self: *PreparedStmt) void {
|
||||
pub fn finalize(self: PreparedStmt) void {
|
||||
_ = c.sqlite3_finalize(self.stmt);
|
||||
}
|
||||
|
||||
pub fn reset(self: *PreparedStmt) void {
|
||||
pub fn reset(self: PreparedStmt) void {
|
||||
_ = c.sqlite3_reset(self.stmt);
|
||||
}
|
||||
|
||||
fn getGeneratingSql(self: *PreparedStmt) ?[*:0]const u8 {
|
||||
fn getGeneratingSql(self: PreparedStmt) ?[*:0]const u8 {
|
||||
return c.sqlite3_sql(self.stmt);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue