const std = @import("std"); const c = @cImport({ @cInclude("duckdb.h"); }); const Result = @import("Result.zig").Result; _q : c.duckdb_prepared_statement, _current_binding: usize, const Self = @This(); pub fn init(stmt: c.duckdb_prepared_statement) !Self{ return .{ ._q = stmt, ._current_binding = 1, }; } pub fn bindInt(self: *Self, param: anytype) !void{ const state = switch(@TypeOf(param)) { u8 => c.duckdb_bind_uint8 (self._q, self._current_binding, param), u16 => c.duckdb_bind_uint16(self._q, self._current_binding, param), u32 => c.duckdb_bind_uint32(self._q, self._current_binding, param), u64 => c.duckdb_bind_uint64(self._q, self._current_binding, param), i8 => c.duckdb_bind_int8 (self._q, self._current_binding, param), i16 => c.duckdb_bind_int16(self._q, self._current_binding, param), i32 => c.duckdb_bind_int32(self._q, self._current_binding, param), i64 => c.duckdb_bind_int64(self._q, self._current_binding, param), else => @compileError("Invalid int type for binding: " ++ @typeName(@TypeOf(param))), }; if ( state == c.DuckDBError ) { return error.DuckDbBindError; } self._current_binding += 1; } pub fn bindFloat(self: *Self, param: anytype) !void{ const state = switch(@TypeOf(param)) { f32 => c.duckdb_bind_float (self._q, self._current_binding, param), f64 => c.duckdb_bind_double(self._q, self._current_binding, param), else => @compileError("Invalid float type for binding: " ++ @typeName(@TypeOf(param))), }; if ( state == c.DuckDBError ) { return error.DuckDbBindError; } self._current_binding += 1; } pub fn bindBool(self: *Self, param: bool) !void{ const state = c.duckdb_bind_bool(self._q, self._current_binding, param); if ( state == c.DuckDBError ) { return error.DuckDbBindError; } self._current_binding += 1; } pub fn bindNull(self: *Self) !void{ const state = c.duckdb_bind_bool(self._q, self._current_binding); if ( state == c.DuckDBError ) { return error.DuckDbBindError; } self._current_binding += 1; } pub fn bindString(self: *Self, param: []const u8) !void{ const state = c.duckdb_bind_varchar_length(self._q, self._current_binding, param.ptr, param.len); if ( state == c.DuckDBError ) { return error.DuckDbBindError; } self._current_binding += 1; } pub fn bind(self: *Self, param: anytype) !void { switch (@typeInfo(@TypeOf(param))) { .Null => return try self.bindNull(), .Bool => return try self.bindBool(param), .Int => return try self.bindInt(param), .Float => return try self.bindFloat(param), .Array => |arr| { if (arr.child == u8){ return try self.bindString(param); } else { return error.UnbindableType; } }, .Pointer => |ptr| { if (ptr.size == .Slice and ptr.child == u8){ return try self.bindString(param); } else { return error.UnbindableType; } }, else => @compileError("Invalid type for binding: " ++ @typeName(@TypeOf(param))), } } pub fn bindAll(self: *Self, params: anytype) !void{ const param_count: usize = c.duckdb_nparams(self._q); switch (@typeInfo(@TypeOf(params))) { .Array => |arr| { if (arr.len == param_count){ inline for (params) |p|{ try self.bind(p); } return; } else { return error.BindingLengthsDoNotMatch; } }, .Struct => |str|{ const x = str.fields; if (x.len == param_count){ inline for (x) |field|{ try self.bind(@field(params, field.name)); } return; } else { return error.BindingLengthsDoNotMatch; } }, else => @compileError("Invalid type for binding: " ++ @typeName(@TypeOf(params))), } } pub fn exec(self: *Self, comptime T: type) !Result(T){ var result: c.duckdb_result = undefined; const state = c.duckdb_execute_prepared(self._q, &result); if ( state == c.DuckDBError ){ return error.DuckDbExecError; } return try Result(T).init(result); } pub fn clear(self: *Self) void { c.duckdb_clear_bindings(self._q); } pub fn deinit(self: *Self) void{ c.duckdb_destroy_prepare(&self._q); }