const std = @import("std"); const postgres = @import("./postgres.zig"); const sqlite = @import("./sqlite.zig"); const Allocator = std.mem.Allocator; pub const Type = enum { postgres, sqlite, }; pub const Config = union(Type) { postgres: struct { conn_str: [:0]const u8, }, sqlite: struct { file_path: [:0]const u8, }, }; //pub const OpenError = sqlite.OpenError | postgres.OpenError; // Represents a set of results. // row() must be called until it returns null, or the query may not complete // Must be deallocated by a call to finish() pub const Results = union(Type) { postgres: postgres.Results, sqlite: sqlite.Results, pub fn finish(self: Results) void { switch (self) { .postgres => |pg| pg.finish(), .sqlite => |lite| lite.finish(), } } // can be used as an optimization to reduce memory reallocation // only works on postgres pub fn rowCount(self: Results) ?usize { return switch (self) { .postgres => |pg| pg.rowCount(), .sqlite => null, // not possible without repeating the query }; } pub fn row(self: *Results) !?Row { return switch (self.*) { .postgres => |*pg| if (try pg.row()) |r| Row{ .postgres = r } else null, .sqlite => |*lite| if (try lite.row()) |r| Row{ .sqlite = r } else null, }; } }; // Row is invalidated by the next call to result.row() pub const Row = union(Type) { postgres: postgres.Row, sqlite: sqlite.Row, // Returns a value of type T from the zero-indexed column given by idx. // Not all types require an allocator to be present. If an allocator is needed but // not required, it will return error.AllocatorRequired. // The caller is responsible for deallocating T, if relevant. pub fn get(self: Row, comptime T: type, idx: u15, alloc: ?Allocator) !T { return switch (self) { .postgres => |pg| pg.get(T, idx, alloc), .sqlite => |lite| lite.get(T, idx, alloc), }; } }; pub const Db = union(Type) { postgres: postgres.Db, sqlite: sqlite.Db, pub fn open(cfg: Config) !Db { return switch (cfg) { .postgres => |postgres_cfg| Db{ .postgres = try postgres.Db.open(postgres_cfg.conn_str), }, .sqlite => |lite_cfg| Db{ .sqlite = try sqlite.Db.open(lite_cfg.file_path), }, }; } pub fn close(self: Db) void { switch (self) { .postgres => |pg| pg.close(), .sqlite => |lite| lite.close(), } } pub fn exec(self: Db, sql: [:0]const u8, args: anytype, alloc: Allocator) !Results { return switch (self) { .postgres => |pg| Results{ .postgres = try pg.exec(sql, args, alloc) }, .sqlite => |lite| Results{ .sqlite = try lite.exec(sql, args) }, }; } };