Remove storage policy from sql lib

This commit is contained in:
jaina heartles 2022-07-23 21:29:38 -07:00
parent ada0eb71f5
commit 3e91d66565
2 changed files with 90 additions and 88 deletions

View file

@ -1,11 +1,47 @@
const std = @import("std"); const std = @import("std");
const sql = @import("sql"); const sql = @import("sql");
const models = @import("./models.zig"); 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 String = []const u8;
const comptimePrint = std.fmt.comptimePrint; 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 { fn tableName(comptime T: type) String {
return switch (T) { return switch (T) {
models.Note => "note", 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 { pub const Database = struct {
db: sql.Sqlite, db: sql.Sqlite,
@ -194,14 +262,14 @@ pub const Database = struct {
var stmt = try self.db.prepare(q); var stmt = try self.db.prepare(q);
defer stmt.finalize(); defer stmt.finalize();
try stmt.bind(1, val); try bind(stmt, 1, val);
const row = (try stmt.step()) orelse return null; const row = (try stmt.step()) orelse return null;
var result: T = undefined; var result: T = undefined;
@field(result, field_name) = val; @field(result, field_name) = val;
inline for (fields) |f, i| { 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; return result;
@ -225,7 +293,7 @@ pub const Database = struct {
var stmt = try self.db.prepare(q); var stmt = try self.db.prepare(q);
defer stmt.finalize(); defer stmt.finalize();
try stmt.bind(1, val); try bind(stmt, 1, val);
var results = std.ArrayList(T).init(alloc); var results = std.ArrayList(T).init(alloc);
@ -233,7 +301,7 @@ pub const Database = struct {
var item: T = undefined; var item: T = undefined;
@field(item, field_name) = val; @field(item, field_name) = val;
inline for (fields) |f, i| { 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); try results.append(item);
@ -258,7 +326,7 @@ pub const Database = struct {
var stmt = try self.db.prepare(q); var stmt = try self.db.prepare(q);
defer stmt.finalize(); defer stmt.finalize();
try stmt.bind(1, val); try bind(stmt, 1, val);
const row = (try stmt.step()) orelse unreachable; const row = (try stmt.step()) orelse unreachable;
return @intCast(usize, try row.getI64(0)); return @intCast(usize, try row.getI64(0));
@ -282,7 +350,7 @@ pub const Database = struct {
var stmt = try self.db.prepare(q); var stmt = try self.db.prepare(q);
defer stmt.finalize(); defer stmt.finalize();
try stmt.bind(1, val); try bind(stmt, 1, val);
const row = (try stmt.step()) orelse unreachable; const row = (try stmt.step()) orelse unreachable;
return (try row.getI64(0)) > 0; return (try row.getI64(0)) > 0;
@ -300,7 +368,7 @@ pub const Database = struct {
defer stmt.finalize(); defer stmt.finalize();
inline for (fields) |f, i| { 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; if ((try stmt.step()) != null) return error.UnknownError;

View file

@ -7,40 +7,6 @@ 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,
@ -75,6 +41,10 @@ pub const Row = struct {
stmt: *c.sqlite3_stmt, stmt: *c.sqlite3_stmt,
db: *c.sqlite3, 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 { pub fn getI64(self: Row, idx: u15) !i64 {
return @intCast(i64, c.sqlite3_column_int64(self.stmt, idx)); 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 { pub fn getDateTime(self: Row, idx: u15) !DateTime {
return DateTime{ .seconds_since_epoch = try self.getI64(idx) }; 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 { pub const PreparedStmt = struct {
stmt: *c.sqlite3_stmt, stmt: *c.sqlite3_stmt,
db: *c.sqlite3, 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)) { return switch (c.sqlite3_bind_null(self.stmt, idx)) {
c.SQLITE_OK => {}, c.SQLITE_OK => {},
else => error.UnknownError, 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(); const str = id.toCharArray();
return self.bindText(idx, &str); 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)) { return switch (c.sqlite3_bind_text(self.stmt, idx, str.ptr, @intCast(c_int, str.len), c.SQLITE_TRANSIENT)) {
c.SQLITE_OK => {}, c.SQLITE_OK => {},
else => error.UnknownError, 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)) { return switch (c.sqlite3_bind_blob64(self.stmt, idx, blob.ptr, blob.len, c.SQLITE_TRANSIENT)) {
c.SQLITE_OK => {}, c.SQLITE_OK => {},
else => error.UnknownError, 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 => {},
else => error.UnknownError, 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); return self.bindI64(idx, val.seconds_since_epoch);
} }
pub fn bind(self: *PreparedStmt, idx: u15, val: anytype) !void { pub fn step(self: PreparedStmt) !?Row {
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 {
return switch (c.sqlite3_step(self.stmt)) { return switch (c.sqlite3_step(self.stmt)) {
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,
@ -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); _ = c.sqlite3_finalize(self.stmt);
} }
pub fn reset(self: *PreparedStmt) void { pub fn reset(self: PreparedStmt) void {
_ = c.sqlite3_reset(self.stmt); _ = 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); return c.sqlite3_sql(self.stmt);
} }
}; };