Skip to content

Commit

Permalink
stmt/query/session: move value/row/all to query, add db.exec/get()
Browse files Browse the repository at this point in the history
  • Loading branch information
cztomsik committed Aug 28, 2024
1 parent 63d9075 commit 0b5b18c
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 42 deletions.
13 changes: 5 additions & 8 deletions src/migrate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,11 @@ fn migrateObjects(db: *Session, pristine: *Session, kind: []const u8) !void {
// to know which columns are common to both and we need to do it in a
// new block so it gets deinitialized and we can then drop and rename
// the temp table
{
var stmt = try db.prepare("SELECT GROUP_CONCAT(name) FROM (SELECT name FROM pragma_table_xinfo(?) INTERSECT SELECT name FROM pragma_table_info('temp'))", .{obj.name});
defer stmt.deinit();

// Copy data from old table to temp table
const copy_sql = try std.fmt.allocPrint(db.arena, "INSERT INTO temp({0s}) SELECT {0s} FROM {1s}", .{ (try stmt.value([]const u8, db.arena)).?, obj.name });
try db.conn.execAll(copy_sql);
}
const cols = try db.get([]const u8, "SELECT GROUP_CONCAT(name) FROM (SELECT name FROM pragma_table_xinfo(?) INTERSECT SELECT name FROM pragma_table_info('temp'))", .{obj.name});

// Copy data from old table to temp table
const copy_sql = try std.fmt.allocPrint(db.arena, "INSERT INTO temp({0s}) SELECT {0s} FROM {1s}", .{ cols.?, obj.name });
try db.conn.execAll(copy_sql);

// Drop old table
const drop_sql = try std.fmt.allocPrint(db.arena, "DROP TABLE {s}", .{obj.name});
Expand Down
17 changes: 14 additions & 3 deletions src/query.zig
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ pub fn Query(comptime T: type, comptime R: type) type {
var stmt = try self.selectRaw(expr).limit(1).prepare();
defer stmt.deinit();

return stmt.value(V, self.session.arena);
if (try stmt.next(struct { V }, self.session.arena)) |row| {
return row[0];
}

return null;
}

pub fn exists(self: Q) !bool {
Expand Down Expand Up @@ -129,14 +133,21 @@ pub fn Query(comptime T: type, comptime R: type) type {
var stmt = try self.limit(1).prepare();
defer stmt.deinit();

return stmt.row(R, self.session.arena);
return stmt.next(R, self.session.arena);
}

pub fn findAll(self: Q) ![]const R {
var stmt = try self.prepare();
defer stmt.deinit();

return stmt.all(R, self.session.arena);
var res = std.ArrayList(R).init(self.session.arena);
errdefer res.deinit();

while (try stmt.next(R, self.session.arena)) |row| {
try res.append(row);
}

return res.toOwnedSlice();
}

pub fn insert(self: Q, data: anytype) !void {
Expand Down
36 changes: 35 additions & 1 deletion src/session.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ pub const Session = struct {

// TODO: begin/commit/rollback via self.conn.execAll(...)?

pub fn exec(self: *Session, sql: []const u8, args: anytype) !void {
var stmt = try self.prepare(sql, args);
defer stmt.deinit();

try stmt.exec();
}

pub fn get(self: *Session, comptime T: type, sql: []const u8, args: anytype) !?T {
var stmt = try self.prepare(sql, args);
defer stmt.deinit();

if (try stmt.next(struct { T }, self.arena)) |row| {
return row[0];
}

return null;
}

pub fn query(self: *Session, comptime T: type) Query(T, T) {
return .{ .session = self };
}
Expand Down Expand Up @@ -111,7 +129,23 @@ test "db.prepare()" {
var stmt = try db.prepare("SELECT 1 + ?", .{1});
defer stmt.deinit();

try t.expectEqual(2, try stmt.value(u32, db.arena));
try t.expectEqual(.{2}, stmt.next(struct { u32 }, db.arena));
}

test "db.exec()" {
var db = try open();
defer db.deinit();

try db.exec("INSERT INTO Person (name) VALUES (?)", .{"Charlie"});
try t.expectEqual(3, db.conn.lastInsertRowId());
try t.expectEqual(1, db.conn.rowsAffected());
}

test "db.get()" {
var db = try open();
defer db.deinit();

try t.expectEqual(123, try db.get(u32, "SELECT ? + 23", .{100}));
}

test "db.query(T).xxx() value methods" {
Expand Down
37 changes: 7 additions & 30 deletions src/statement.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,12 @@ pub const Statement = extern struct {
self.vtable.deinit(self.handle);
}

pub fn bind(self: *Statement, index: usize, val: Value) !void {
try self.vtable.bind(self.handle, index, val);
}

pub fn exec(self: *Statement) !void {
while (try self.step()) {
// SQLite needs this (should be harmless for others)
}
}

pub fn value(self: *Statement, comptime V: type, arena: std.mem.Allocator) !?V {
return if (try self.row(struct { V }, arena)) |r| r[0] else null;
}

pub fn row(self: *Statement, comptime R: type, arena: std.mem.Allocator) !?R {
if (try self.next(R, arena)) |r| {
try self.reset();
return r;
}

return null;
}

pub fn all(self: *Statement, comptime R: type, arena: std.mem.Allocator) ![]const R {
var res = std.ArrayList(R).init(arena);

while (try self.next(R, arena)) |r| {
try res.append(r);
}

return res.toOwnedSlice();
}

pub fn next(self: *Statement, comptime R: type, arena: std.mem.Allocator) !?R {
if (!try self.step()) {
return null;
Expand All @@ -70,14 +43,18 @@ pub const Statement = extern struct {
return res;
}

fn step(self: *Statement) !bool {
return self.vtable.step(self.handle);
pub fn bind(self: *Statement, index: usize, val: Value) !void {
try self.vtable.bind(self.handle, index, val);
}

fn column(self: *Statement, index: usize) !Value {
pub fn column(self: *Statement, index: usize) !Value {
return self.vtable.column(self.handle, index);
}

pub fn step(self: *Statement) !bool {
return self.vtable.step(self.handle);
}

pub fn reset(self: *Statement) !void {
try self.vtable.reset(self.handle);
}
Expand Down

0 comments on commit 0b5b18c

Please sign in to comment.