From 7c22eb1507fd3dc3a33c7f4926b0e99e3762a291 Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Mon, 18 Oct 2021 19:39:42 +0200 Subject: make bindField clearer Be less clever with comptime reflection. This has the advantage of making the code a lot clearer, clearly identifying which case are converting an sqlite int result to an error. This also makes it easier to follow the error trace if there is an error while binding a field. --- sqlite.zig | 86 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 34 deletions(-) (limited to 'sqlite.zig') diff --git a/sqlite.zig b/sqlite.zig index 337ea90..4f25aa3 100644 --- a/sqlite.zig +++ b/sqlite.zig @@ -1130,17 +1130,9 @@ pub const DynamicStatement = struct { } } - fn translateError(value: anytype) !void { - if (@TypeOf(value) != void) { - if (@typeInfo(@TypeOf(value)) == .ErrorUnion and @typeInfo(@TypeOf(value)).ErrorUnion.payload == void) { - return value; - } else if (@TypeOf(value) == c_int and value == c.SQLITE_OK) { - return; - } else { - return errors.errorFromResultCode(value); - } - } else { - return; + fn convertResultToError(result: c_int) !void { + if (result != c.SQLITE_OK) { + return errors.errorFromResultCode(result); } } @@ -1148,53 +1140,79 @@ pub const DynamicStatement = struct { const field_type_info = @typeInfo(FieldType); const column = i + 1; - const val = switch (FieldType) { - Text => c.sqlite3_bind_text(self.stmt, column, field.data.ptr, @intCast(c_int, field.data.len), null), - Blob => c.sqlite3_bind_blob(self.stmt, column, field.data.ptr, @intCast(c_int, field.data.len), null), - ZeroBlob => c.sqlite3_bind_zeroblob64(self.stmt, column, field.length), + switch (FieldType) { + Text => { + const result = c.sqlite3_bind_text(self.stmt, column, field.data.ptr, @intCast(c_int, field.data.len), null); + return convertResultToError(result); + }, + Blob => { + const result = c.sqlite3_bind_blob(self.stmt, column, field.data.ptr, @intCast(c_int, field.data.len), null); + return convertResultToError(result); + }, + ZeroBlob => { + const result = c.sqlite3_bind_zeroblob64(self.stmt, column, field.length); + return convertResultToError(result); + }, else => switch (field_type_info) { - .Int, .ComptimeInt => c.sqlite3_bind_int64(self.stmt, column, @intCast(c_longlong, field)), - .Float, .ComptimeFloat => c.sqlite3_bind_double(self.stmt, column, field), - .Bool => c.sqlite3_bind_int64(self.stmt, column, @boolToInt(field)), + .Int, .ComptimeInt => { + const result = c.sqlite3_bind_int64(self.stmt, column, @intCast(c_longlong, field)); + return convertResultToError(result); + }, + .Float, .ComptimeFloat => { + const result = c.sqlite3_bind_double(self.stmt, column, field); + return convertResultToError(result); + }, + .Bool => { + const result = c.sqlite3_bind_int64(self.stmt, column, @boolToInt(field)); + return convertResultToError(result); + }, .Pointer => |ptr| switch (ptr.size) { - .One => self.bindField(ptr.child, options, field_name, i, field.*), + .One => { + try self.bindField(ptr.child, options, field_name, i, field.*); + }, .Slice => switch (ptr.child) { - u8 => c.sqlite3_bind_text(self.stmt, column, field.ptr, @intCast(c_int, field.len), null), + u8 => { + const result = c.sqlite3_bind_text(self.stmt, column, field.ptr, @intCast(c_int, field.len), null); + return convertResultToError(result); + }, else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), }, else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), }, .Array => |arr| switch (arr.child) { - u8 => u8arr: { + u8 => { const data: []const u8 = field[0..field.len]; - break :u8arr c.sqlite3_bind_text(self.stmt, column, data.ptr, @intCast(c_int, data.len), null); + const result = c.sqlite3_bind_text(self.stmt, column, data.ptr, @intCast(c_int, data.len), null); + return convertResultToError(result); }, else => @compileError("cannot bind field " ++ field_name ++ " of type array of " ++ @typeName(arr.child)), }, .Optional => |opt| if (field) |non_null_field| { - return try self.bindField(opt.child, options, field_name, i, non_null_field); - } else optional_null: { - break :optional_null c.sqlite3_bind_null(self.stmt, column); + try self.bindField(opt.child, options, field_name, i, non_null_field); + } else { + const result = c.sqlite3_bind_null(self.stmt, column); + return convertResultToError(result); + }, + .Null => { + const result = c.sqlite3_bind_null(self.stmt, column); + return convertResultToError(result); }, - .Null => c.sqlite3_bind_null(self.stmt, column), .Enum => { if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { - return try self.bindField(FieldType.BaseType, options, field_name, i, @tagName(field)); + try self.bindField(FieldType.BaseType, options, field_name, i, @tagName(field)); } else if (@typeInfo(FieldType.BaseType) == .Int) { - return try self.bindField(FieldType.BaseType, options, field_name, i, @enumToInt(field)); + try self.bindField(FieldType.BaseType, options, field_name, i, @enumToInt(field)); + } else { + @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int to bind"); } - // Above if-else tree should have return to bypass @compileError below. - @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int to bind"); }, .Struct => { - return try self.bindField(FieldType.BaseType, options, field_name, i, try field.bindField(options.allocator)); + try self.bindField(FieldType.BaseType, options, field_name, i, try field.bindField(options.allocator)); }, else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), }, - }; - - return translateError(val); + } } fn bind(self: *Self, options: anytype, values: anytype) !void { -- cgit v1.2.3