diff options
| author | 2021-09-07 01:16:21 +0200 | |
|---|---|---|
| committer | 2021-09-07 01:16:21 +0200 | |
| commit | 658f9fab1f61ee207d1951f93c5ab3e242828e08 (patch) | |
| tree | bd63753b6489e99482ebdb49a1b298720316c7f8 /sqlite.zig | |
| parent | Merge pull request #47 from vrischmann/fix-usingnamespace (diff) | |
| parent | more minor cleanups (diff) | |
| download | zig-sqlite-658f9fab1f61ee207d1951f93c5ab3e242828e08.tar.gz zig-sqlite-658f9fab1f61ee207d1951f93c5ab3e242828e08.tar.xz zig-sqlite-658f9fab1f61ee207d1951f93c5ab3e242828e08.zip | |
Merge pull request #48 from vrischmann/clarify-options
stop using anytype for options
Diffstat (limited to 'sqlite.zig')
| -rw-r--r-- | sqlite.zig | 94 |
1 files changed, 54 insertions, 40 deletions
| @@ -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; |
| @@ -779,8 +781,7 @@ pub fn Iterator(comptime Type: type) type { | |||
| 779 | 781 | ||
| 780 | // dupeWithSentinel is like dupe/dupeZ but allows for any sentinel value. | 782 | // dupeWithSentinel is like dupe/dupeZ but allows for any sentinel value. |
| 781 | fn dupeWithSentinel(comptime SliceType: type, allocator: *mem.Allocator, data: []const u8) !SliceType { | 783 | fn dupeWithSentinel(comptime SliceType: type, allocator: *mem.Allocator, data: []const u8) !SliceType { |
| 782 | const type_info = @typeInfo(SliceType); | 784 | switch (@typeInfo(SliceType)) { |
| 783 | switch (type_info) { | ||
| 784 | .Pointer => |ptr_info| { | 785 | .Pointer => |ptr_info| { |
| 785 | if (ptr_info.sentinel) |sentinel| { | 786 | if (ptr_info.sentinel) |sentinel| { |
| 786 | const slice = try allocator.alloc(u8, data.len + 1); | 787 | const slice = try allocator.alloc(u8, data.len + 1); |
| @@ -847,21 +848,26 @@ pub fn Iterator(comptime Type: type) type { | |||
| 847 | } | 848 | } |
| 848 | } | 849 | } |
| 849 | 850 | ||
| 850 | fn readPointer(self: *Self, comptime PointerType: type, allocator: *mem.Allocator, i: usize) !PointerType { | 851 | fn readPointer(self: *Self, comptime PointerType: type, options: anytype, i: usize) !PointerType { |
| 851 | const type_info = @typeInfo(PointerType); | 852 | if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) { |
| 853 | @compileError("options passed to readPointer must be a struct"); | ||
| 854 | } | ||
| 855 | if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) { | ||
| 856 | @compileError("options passed to readPointer must have an allocator field"); | ||
| 857 | } | ||
| 852 | 858 | ||
| 853 | var ret: PointerType = undefined; | 859 | var ret: PointerType = undefined; |
| 854 | switch (type_info) { | 860 | switch (@typeInfo(PointerType)) { |
| 855 | .Pointer => |ptr| { | 861 | .Pointer => |ptr| { |
| 856 | switch (ptr.size) { | 862 | switch (ptr.size) { |
| 857 | .One => { | 863 | .One => { |
| 858 | ret = try allocator.create(ptr.child); | 864 | ret = try options.allocator.create(ptr.child); |
| 859 | errdefer allocator.destroy(ret); | 865 | errdefer options.allocator.destroy(ret); |
| 860 | 866 | ||
| 861 | ret.* = try self.readField(ptr.child, i, .{ .allocator = allocator }); | 867 | ret.* = try self.readField(ptr.child, options, i); |
| 862 | }, | 868 | }, |
| 863 | .Slice => switch (ptr.child) { | 869 | .Slice => switch (ptr.child) { |
| 864 | u8 => ret = try self.readBytes(PointerType, allocator, i, .Text), | 870 | u8 => ret = try self.readBytes(PointerType, options.allocator, i, .Text), |
| 865 | else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), | 871 | else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), |
| 866 | }, | 872 | }, |
| 867 | else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), | 873 | else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), |
| @@ -874,20 +880,21 @@ pub fn Iterator(comptime Type: type) type { | |||
| 874 | } | 880 | } |
| 875 | 881 | ||
| 876 | fn readOptional(self: *Self, comptime OptionalType: type, options: anytype, _i: usize) !OptionalType { | 882 | fn readOptional(self: *Self, comptime OptionalType: type, options: anytype, _i: usize) !OptionalType { |
| 877 | const i = @intCast(c_int, _i); | 883 | if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) { |
| 878 | const type_info = @typeInfo(OptionalType); | 884 | @compileError("options passed to readOptional must be a struct"); |
| 885 | } | ||
| 879 | 886 | ||
| 880 | var ret: OptionalType = undefined; | 887 | var ret: OptionalType = undefined; |
| 881 | switch (type_info) { | 888 | switch (@typeInfo(OptionalType)) { |
| 882 | .Optional => |opt| { | 889 | .Optional => |opt| { |
| 883 | // Easy way to know if the column represents a null value. | 890 | // Easy way to know if the column represents a null value. |
| 884 | const value = c.sqlite3_column_value(self.stmt, i); | 891 | const value = c.sqlite3_column_value(self.stmt, @intCast(c_int, _i)); |
| 885 | const datatype = c.sqlite3_value_type(value); | 892 | const datatype = c.sqlite3_value_type(value); |
| 886 | 893 | ||
| 887 | if (datatype == c.SQLITE_NULL) { | 894 | if (datatype == c.SQLITE_NULL) { |
| 888 | return null; | 895 | return null; |
| 889 | } else { | 896 | } else { |
| 890 | const val = try self.readField(opt.child, _i, options); | 897 | const val = try self.readField(opt.child, options, _i); |
| 891 | ret = val; | 898 | ret = val; |
| 892 | return ret; | 899 | return ret; |
| 893 | } | 900 | } |
| @@ -918,12 +925,16 @@ pub fn Iterator(comptime Type: type) type { | |||
| 918 | // | 925 | // |
| 919 | // TODO(vincent): add comptime checks for the fields/columns. | 926 | // TODO(vincent): add comptime checks for the fields/columns. |
| 920 | fn readStruct(self: *Self, options: anytype) !Type { | 927 | fn readStruct(self: *Self, options: anytype) !Type { |
| 928 | if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) { | ||
| 929 | @compileError("options passed to readStruct must be a struct"); | ||
| 930 | } | ||
| 931 | |||
| 921 | var value: Type = undefined; | 932 | var value: Type = undefined; |
| 922 | 933 | ||
| 923 | inline for (@typeInfo(Type).Struct.fields) |field, _i| { | 934 | inline for (@typeInfo(Type).Struct.fields) |field, _i| { |
| 924 | const i = @as(usize, _i); | 935 | const i = @as(usize, _i); |
| 925 | 936 | ||
| 926 | const ret = try self.readField(field.field_type, i, options); | 937 | const ret = try self.readField(field.field_type, options, i); |
| 927 | 938 | ||
| 928 | @field(value, field.name) = ret; | 939 | @field(value, field.name) = ret; |
| 929 | } | 940 | } |
| @@ -931,22 +942,36 @@ pub fn Iterator(comptime Type: type) type { | |||
| 931 | return value; | 942 | return value; |
| 932 | } | 943 | } |
| 933 | 944 | ||
| 934 | fn readField(self: *Self, comptime FieldType: type, i: usize, options: anytype) !FieldType { | 945 | fn readField(self: *Self, comptime FieldType: type, options: anytype, i: usize) !FieldType { |
| 946 | if (!comptime std.meta.trait.is(.Struct)(@TypeOf(options))) { | ||
| 947 | @compileError("options passed to readField must be a struct"); | ||
| 948 | } | ||
| 949 | |||
| 935 | const field_type_info = @typeInfo(FieldType); | 950 | const field_type_info = @typeInfo(FieldType); |
| 936 | 951 | ||
| 937 | return switch (FieldType) { | 952 | return switch (FieldType) { |
| 938 | Blob => try self.readBytes(Blob, options.allocator, i, .Blob), | 953 | Blob => blk: { |
| 939 | Text => try self.readBytes(Text, options.allocator, i, .Text), | 954 | if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) { |
| 955 | @compileError("options passed to readPointer must have an allocator field when reading a Blob"); | ||
| 956 | } | ||
| 957 | break :blk try self.readBytes(Blob, options.allocator, i, .Blob); | ||
| 958 | }, | ||
| 959 | Text => blk: { | ||
| 960 | if (!comptime std.meta.trait.hasField("allocator")(@TypeOf(options))) { | ||
| 961 | @compileError("options passed to readField must have an allocator field when reading a Text"); | ||
| 962 | } | ||
| 963 | break :blk try self.readBytes(Text, options.allocator, i, .Text); | ||
| 964 | }, | ||
| 940 | else => switch (field_type_info) { | 965 | else => switch (field_type_info) { |
| 941 | .Int => try self.readInt(FieldType, i), | 966 | .Int => try self.readInt(FieldType, i), |
| 942 | .Float => try self.readFloat(FieldType, i), | 967 | .Float => try self.readFloat(FieldType, i), |
| 943 | .Bool => try self.readBool(i), | 968 | .Bool => try self.readBool(i), |
| 944 | .Void => {}, | 969 | .Void => {}, |
| 945 | .Array => try self.readArray(FieldType, i), | 970 | .Array => try self.readArray(FieldType, i), |
| 946 | .Pointer => try self.readPointer(FieldType, options.allocator, i), | 971 | .Pointer => try self.readPointer(FieldType, options, i), |
| 947 | .Optional => try self.readOptional(FieldType, options, i), | 972 | .Optional => try self.readOptional(FieldType, options, i), |
| 948 | .Enum => |TI| { | 973 | .Enum => |TI| { |
| 949 | const innervalue = try self.readField(FieldType.BaseType, i, options); | 974 | const innervalue = try self.readField(FieldType.BaseType, options, i); |
| 950 | 975 | ||
| 951 | if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { | 976 | if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { |
| 952 | return std.meta.stringToEnum(FieldType, innervalue) orelse unreachable; | 977 | return std.meta.stringToEnum(FieldType, innervalue) orelse unreachable; |
| @@ -1242,11 +1267,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t | |||
| 1242 | /// in the input query string. | 1267 | /// in the input query string. |
| 1243 | /// | 1268 | /// |
| 1244 | /// This cannot allocate memory. If you need to read TEXT or BLOB columns you need to use arrays or alternatively call `oneAlloc`. | 1269 | /// 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 { | 1270 | 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); | 1271 | var iter = try self.iterator(Type, values); |
| 1251 | 1272 | ||
| 1252 | const row = (try iter.next(options)) orelse return null; | 1273 | const row = (try iter.next(options)) orelse return null; |
| @@ -1254,11 +1275,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t | |||
| 1254 | } | 1275 | } |
| 1255 | 1276 | ||
| 1256 | /// oneAlloc is like `one` but can allocate memory. | 1277 | /// 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 { | 1278 | 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); | 1279 | var iter = try self.iterator(Type, values); |
| 1263 | 1280 | ||
| 1264 | const row = (try iter.nextAlloc(allocator, options)) orelse return null; | 1281 | const row = (try iter.nextAlloc(allocator, options)) orelse return null; |
| @@ -1291,10 +1308,7 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t | |||
| 1291 | /// in the input query string. | 1308 | /// in the input query string. |
| 1292 | /// | 1309 | /// |
| 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. | 1310 | /// 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 { | 1311 | 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); | 1312 | var iter = try self.iterator(Type, values); |
| 1299 | 1313 | ||
| 1300 | var rows = std.ArrayList(Type).init(allocator); | 1314 | var rows = std.ArrayList(Type).init(allocator); |