diff options
Diffstat (limited to '')
| -rw-r--r-- | sqlite.zig | 84 |
1 files changed, 52 insertions, 32 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; |
| @@ -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); |