summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vincent Rischmann2021-09-07 00:18:22 +0200
committerGravatar Vincent Rischmann2021-09-07 00:56:30 +0200
commit8afc01f52a3aa32931fedd680efefcae59e3c390 (patch)
tree2e75afe33c41c419ff7ec0c17911939282c21cc6
parentMerge pull request #47 from vrischmann/fix-usingnamespace (diff)
downloadzig-sqlite-8afc01f52a3aa32931fedd680efefcae59e3c390.tar.gz
zig-sqlite-8afc01f52a3aa32931fedd680efefcae59e3c390.tar.xz
zig-sqlite-8afc01f52a3aa32931fedd680efefcae59e3c390.zip
Stop using anytype in the public API.
The need for using `options: anytype` in readXYZ functions is so that they can be used both when called by `one`/`next` or `oneAlloc`/`nextAlloc`. In the first case there won't be an allocator member in the tuple, in the latter there will be. But, since the public API takes an explicit allocator argument in `oneAlloc`/`nextAlloc` there's no need to take a `anytype` options in the public API. This commit changes the public API to always use `QueryOptions`. This commit also adds a bunch of explicit comptime checks to validate the options type passed to the readXYZ functions. Especially important is checking the presence of the `allocator` field if the function requires an allocator. Finally, cleanup some stuff and reorder arguments in `readPointer`.
Diffstat (limited to '')
-rw-r--r--sqlite.zig84
1 files changed, 52 insertions, 32 deletions
diff --git a/sqlite.zig b/sqlite.zig
index 5aef124..b6531f9 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -410,7 +410,7 @@ pub const Db = struct {
410 /// 410 ///
411 /// const journal_mode = try db.pragma([]const u8, allocator, .{}, "journal_mode", null); 411 /// const journal_mode = try db.pragma([]const u8, allocator, .{}, "journal_mode", null);
412 /// 412 ///
413 pub fn pragmaAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: anytype, comptime name: []const u8, comptime arg: ?[]const u8) !?Type { 413 pub fn pragmaAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, comptime name: []const u8, comptime arg: ?[]const u8) !?Type {
414 comptime var buf: [1024]u8 = undefined; 414 comptime var buf: [1024]u8 = undefined;
415 comptime var query = getPragmaQuery(&buf, name, arg); 415 comptime var query = getPragmaQuery(&buf, name, arg);
416 416
@@ -433,7 +433,7 @@ pub const Db = struct {
433 /// The pragma name must be known at comptime. 433 /// The pragma name must be known at comptime.
434 /// 434 ///
435 /// This cannot allocate memory. If your pragma command returns text you must use an array or call `pragmaAlloc`. 435 /// This cannot allocate memory. If your pragma command returns text you must use an array or call `pragmaAlloc`.
436 pub fn pragma(self: *Self, comptime Type: type, options: anytype, comptime name: []const u8, comptime arg: ?[]const u8) !?Type { 436 pub fn pragma(self: *Self, comptime Type: type, options: QueryOptions, comptime name: []const u8, comptime arg: ?[]const u8) !?Type {
437 comptime var buf: [1024]u8 = undefined; 437 comptime var buf: [1024]u8 = undefined;
438 comptime var query = getPragmaQuery(&buf, name, arg); 438 comptime var query = getPragmaQuery(&buf, name, arg);
439 439
@@ -615,7 +615,7 @@ pub fn Iterator(comptime Type: type) type {
615 } 615 }
616 616
617 if (@typeInfo(Type.BaseType) == .Int) { 617 if (@typeInfo(Type.BaseType) == .Int) {
618 const innervalue = try self.readField(Type.BaseType, 0, options); 618 const innervalue = try self.readField(Type.BaseType, options, 0);
619 return @intToEnum(Type, @intCast(TI.tag_type, innervalue)); 619 return @intToEnum(Type, @intCast(TI.tag_type, innervalue));
620 } 620 }
621 621
@@ -683,14 +683,16 @@ pub fn Iterator(comptime Type: type) type {
683 }, 683 },
684 .Pointer => { 684 .Pointer => {
685 debug.assert(columns == 1); 685 debug.assert(columns == 1);
686 return try self.readPointer(Type, allocator, 0); 686 return try self.readPointer(Type, .{
687 .allocator = allocator,
688 }, 0);
687 }, 689 },
688 .Enum => |TI| { 690 .Enum => |TI| {
689 debug.assert(columns == 1); 691 debug.assert(columns == 1);
690 692
691 const innervalue = try self.readField(Type.BaseType, 0, .{ 693 const innervalue = try self.readField(Type.BaseType, .{
692 .allocator = allocator, 694 .allocator = allocator,
693 }); 695 }, 0);
694 696
695 if (comptime std.meta.trait.isZigString(Type.BaseType)) { 697 if (comptime std.meta.trait.isZigString(Type.BaseType)) {
696 return std.meta.stringToEnum(Type, innervalue) orelse unreachable; 698 return std.meta.stringToEnum(Type, innervalue) orelse unreachable;
@@ -847,7 +849,14 @@ pub fn Iterator(comptime Type: type) type {
847 } 849 }
848 } 850 }
849 851
850 fn readPointer(self: *Self, comptime PointerType: type, allocator: *mem.Allocator, i: usize) !PointerType { 852 fn readPointer(self: *Self, comptime PointerType: type, options: anytype, i: usize) !PointerType {
853 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
854 @compileError("options passed to readPointer must be a struct");
855 }
856 if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) {
857 @compileError("options passed to readPointer must have an allocator field");
858 }
859
851 const type_info = @typeInfo(PointerType); 860 const type_info = @typeInfo(PointerType);
852 861
853 var ret: PointerType = undefined; 862 var ret: PointerType = undefined;
@@ -855,13 +864,13 @@ pub fn Iterator(comptime Type: type) type {
855 .Pointer => |ptr| { 864 .Pointer => |ptr| {
856 switch (ptr.size) { 865 switch (ptr.size) {
857 .One => { 866 .One => {
858 ret = try allocator.create(ptr.child); 867 ret = try options.allocator.create(ptr.child);
859 errdefer allocator.destroy(ret); 868 errdefer options.allocator.destroy(ret);
860 869
861 ret.* = try self.readField(ptr.child, i, .{ .allocator = allocator }); 870 ret.* = try self.readField(ptr.child, options, i);
862 }, 871 },
863 .Slice => switch (ptr.child) { 872 .Slice => switch (ptr.child) {
864 u8 => ret = try self.readBytes(PointerType, allocator, i, .Text), 873 u8 => ret = try self.readBytes(PointerType, options.allocator, i, .Text),
865 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), 874 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)),
866 }, 875 },
867 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), 876 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)),
@@ -874,6 +883,10 @@ pub fn Iterator(comptime Type: type) type {
874 } 883 }
875 884
876 fn readOptional(self: *Self, comptime OptionalType: type, options: anytype, _i: usize) !OptionalType { 885 fn readOptional(self: *Self, comptime OptionalType: type, options: anytype, _i: usize) !OptionalType {
886 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
887 @compileError("options passed to readOptional must be a struct");
888 }
889
877 const i = @intCast(c_int, _i); 890 const i = @intCast(c_int, _i);
878 const type_info = @typeInfo(OptionalType); 891 const type_info = @typeInfo(OptionalType);
879 892
@@ -887,7 +900,7 @@ pub fn Iterator(comptime Type: type) type {
887 if (datatype == c.SQLITE_NULL) { 900 if (datatype == c.SQLITE_NULL) {
888 return null; 901 return null;
889 } else { 902 } else {
890 const val = try self.readField(opt.child, _i, options); 903 const val = try self.readField(opt.child, options, _i);
891 ret = val; 904 ret = val;
892 return ret; 905 return ret;
893 } 906 }
@@ -918,12 +931,16 @@ pub fn Iterator(comptime Type: type) type {
918 // 931 //
919 // TODO(vincent): add comptime checks for the fields/columns. 932 // TODO(vincent): add comptime checks for the fields/columns.
920 fn readStruct(self: *Self, options: anytype) !Type { 933 fn readStruct(self: *Self, options: anytype) !Type {
934 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
935 @compileError("options passed to readStruct must be a struct");
936 }
937
921 var value: Type = undefined; 938 var value: Type = undefined;
922 939
923 inline for (@typeInfo(Type).Struct.fields) |field, _i| { 940 inline for (@typeInfo(Type).Struct.fields) |field, _i| {
924 const i = @as(usize, _i); 941 const i = @as(usize, _i);
925 942
926 const ret = try self.readField(field.field_type, i, options); 943 const ret = try self.readField(field.field_type, options, i);
927 944
928 @field(value, field.name) = ret; 945 @field(value, field.name) = ret;
929 } 946 }
@@ -931,22 +948,36 @@ pub fn Iterator(comptime Type: type) type {
931 return value; 948 return value;
932 } 949 }
933 950
934 fn readField(self: *Self, comptime FieldType: type, i: usize, options: anytype) !FieldType { 951 fn readField(self: *Self, comptime FieldType: type, options: anytype, i: usize) !FieldType {
952 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
953 @compileError("options passed to readField must be a struct");
954 }
955
935 const field_type_info = @typeInfo(FieldType); 956 const field_type_info = @typeInfo(FieldType);
936 957
937 return switch (FieldType) { 958 return switch (FieldType) {
938 Blob => try self.readBytes(Blob, options.allocator, i, .Blob), 959 Blob => blk: {
939 Text => try self.readBytes(Text, options.allocator, i, .Text), 960 if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) {
961 @compileError("options passed to readPointer must have an allocator field when reading a Blob");
962 }
963 break :blk try self.readBytes(Blob, options.allocator, i, .Blob);
964 },
965 Text => blk: {
966 if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) {
967 @compileError("options passed to readField must have an allocator field when reading a Text");
968 }
969 break :blk try self.readBytes(Text, options.allocator, i, .Text);
970 },
940 else => switch (field_type_info) { 971 else => switch (field_type_info) {
941 .Int => try self.readInt(FieldType, i), 972 .Int => try self.readInt(FieldType, i),
942 .Float => try self.readFloat(FieldType, i), 973 .Float => try self.readFloat(FieldType, i),
943 .Bool => try self.readBool(i), 974 .Bool => try self.readBool(i),
944 .Void => {}, 975 .Void => {},
945 .Array => try self.readArray(FieldType, i), 976 .Array => try self.readArray(FieldType, i),
946 .Pointer => try self.readPointer(FieldType, options.allocator, i), 977 .Pointer => try self.readPointer(FieldType, options, i),
947 .Optional => try self.readOptional(FieldType, options, i), 978 .Optional => try self.readOptional(FieldType, options, i),
948 .Enum => |TI| { 979 .Enum => |TI| {
949 const innervalue = try self.readField(FieldType.BaseType, i, options); 980 const innervalue = try self.readField(FieldType.BaseType, options, i);
950 981
951 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { 982 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) {
952 return std.meta.stringToEnum(FieldType, innervalue) orelse unreachable; 983 return std.meta.stringToEnum(FieldType, innervalue) orelse unreachable;
@@ -1242,11 +1273,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1242 /// in the input query string. 1273 /// in the input query string.
1243 /// 1274 ///
1244 /// This cannot allocate memory. If you need to read TEXT or BLOB columns you need to use arrays or alternatively call `oneAlloc`. 1275 /// This cannot allocate memory. If you need to read TEXT or BLOB columns you need to use arrays or alternatively call `oneAlloc`.
1245 pub fn one(self: *Self, comptime Type: type, options: anytype, values: anytype) !?Type { 1276 pub fn one(self: *Self, comptime Type: type, options: QueryOptions, values: anytype) !?Type {
1246 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
1247 @compileError("options passed to iterator must be a struct");
1248 }
1249
1250 var iter = try self.iterator(Type, values); 1277 var iter = try self.iterator(Type, values);
1251 1278
1252 const row = (try iter.next(options)) orelse return null; 1279 const row = (try iter.next(options)) orelse return null;
@@ -1254,11 +1281,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1254 } 1281 }
1255 1282
1256 /// oneAlloc is like `one` but can allocate memory. 1283 /// oneAlloc is like `one` but can allocate memory.
1257 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: anytype, values: anytype) !?Type { 1284 pub fn oneAlloc(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) !?Type {
1258 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
1259 @compileError("options passed to iterator must be a struct");
1260 }
1261
1262 var iter = try self.iterator(Type, values); 1285 var iter = try self.iterator(Type, values);
1263 1286
1264 const row = (try iter.nextAlloc(allocator, options)) orelse return null; 1287 const row = (try iter.nextAlloc(allocator, options)) orelse return null;
@@ -1291,10 +1314,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1291 /// in the input query string. 1314 /// in the input query string.
1292 /// 1315 ///
1293 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory. 1316 /// Note that this allocates all rows into a single slice: if you read a lot of data this can use a lot of memory.
1294 pub fn all(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: anytype, values: anytype) ![]Type { 1317 pub fn all(self: *Self, comptime Type: type, allocator: *mem.Allocator, options: QueryOptions, values: anytype) ![]Type {
1295 if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) {
1296 @compileError("options passed to iterator must be a struct");
1297 }
1298 var iter = try self.iterator(Type, values); 1318 var iter = try self.iterator(Type, values);
1299 1319
1300 var rows = std.ArrayList(Type).init(allocator); 1320 var rows = std.ArrayList(Type).init(allocator);