summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--sqlite.zig84
-rw-r--r--zigmod.lock1
3 files changed, 71 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index b31f6d3..b2d5672 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
1/build_runner.zig 1/build_runner.zig
2zig-* 2zig-*
3.zigmod
4deps.zig
diff --git a/sqlite.zig b/sqlite.zig
index bbf7043..abeea55 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -906,6 +906,17 @@ pub fn Iterator(comptime Type: type) type {
906 .Array => try self.readArray(FieldType, i), 906 .Array => try self.readArray(FieldType, i),
907 .Pointer => try self.readPointer(FieldType, options.allocator, i), 907 .Pointer => try self.readPointer(FieldType, options.allocator, i),
908 .Optional => try self.readOptional(FieldType, options, i), 908 .Optional => try self.readOptional(FieldType, options, i),
909 .Enum => |TI| {
910 const innervalue = try self.readField(FieldType.BaseType, i, options);
911
912 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) {
913 return std.meta.stringToEnum(FieldType, innervalue) orelse unreachable;
914 }
915 if (@typeInfo(FieldType.BaseType) == .Int) {
916 return @intToEnum(FieldType, @intCast(TI.tag_type, innervalue));
917 }
918 @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int");
919 },
909 else => @compileError("cannot populate field of type " ++ @typeName(FieldType)), 920 else => @compileError("cannot populate field of type " ++ @typeName(FieldType)),
910 }, 921 },
911 }; 922 };
@@ -1039,8 +1050,15 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1039 inline for (StructTypeInfo.fields) |struct_field, _i| { 1050 inline for (StructTypeInfo.fields) |struct_field, _i| {
1040 const bind_marker = query.bind_markers[_i]; 1051 const bind_marker = query.bind_markers[_i];
1041 switch (bind_marker) { 1052 switch (bind_marker) {
1042 .Typed => |typ| if (struct_field.field_type != typ) { 1053 .Typed => |typ| {
1043 @compileError("value type " ++ @typeName(struct_field.field_type) ++ " is not the bind marker type " ++ @typeName(typ)); 1054 const FieldTypeInfo = @typeInfo(struct_field.field_type);
1055 switch (FieldTypeInfo) {
1056 .Struct, .Enum, .Union => comptime assertMarkerType(
1057 if (@hasDecl(struct_field.field_type, "BaseType")) struct_field.field_type.BaseType else struct_field.field_type,
1058 typ,
1059 ),
1060 else => comptime assertMarkerType(struct_field.field_type, typ),
1061 }
1044 }, 1062 },
1045 .Untyped => {}, 1063 .Untyped => {},
1046 } 1064 }
@@ -1051,6 +1069,12 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1051 } 1069 }
1052 } 1070 }
1053 1071
1072 fn assertMarkerType(comptime Actual: type, comptime Expected: type) void {
1073 if (Actual != Expected) {
1074 @compileError("value type " ++ @typeName(Actual) ++ " is not the bind marker type " ++ @typeName(Expected));
1075 }
1076 }
1077
1054 fn bindField(self: *Self, comptime FieldType: type, comptime field_name: []const u8, i: c_int, field: FieldType) void { 1078 fn bindField(self: *Self, comptime FieldType: type, comptime field_name: []const u8, i: c_int, field: FieldType) void {
1055 const field_type_info = @typeInfo(FieldType); 1079 const field_type_info = @typeInfo(FieldType);
1056 const column = i + 1; 1080 const column = i + 1;
@@ -1089,6 +1113,15 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
1089 _ = c.sqlite3_bind_null(self.stmt, column); 1113 _ = c.sqlite3_bind_null(self.stmt, column);
1090 }, 1114 },
1091 .Null => _ = c.sqlite3_bind_null(self.stmt, column), 1115 .Null => _ = c.sqlite3_bind_null(self.stmt, column),
1116 .Enum => {
1117 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) {
1118 return self.bindField(FieldType.BaseType, field_name, i, @tagName(field));
1119 }
1120 if (@typeInfo(FieldType.BaseType) == .Int) {
1121 return self.bindField(FieldType.BaseType, field_name, i, @enumToInt(field));
1122 }
1123 @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int to bind");
1124 },
1092 else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), 1125 else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)),
1093 }, 1126 },
1094 } 1127 }
@@ -1240,12 +1273,30 @@ const TestUser = struct {
1240 id: usize, 1273 id: usize,
1241 age: usize, 1274 age: usize,
1242 weight: f32, 1275 weight: f32,
1276 favorite_color: Color,
1277
1278 pub const Color = enum {
1279 red,
1280 majenta,
1281 violet,
1282 indigo,
1283 blue,
1284 cyan,
1285 green,
1286 lime,
1287 yellow,
1288 //
1289 orange,
1290 //
1291
1292 pub const BaseType = []const u8;
1293 };
1243}; 1294};
1244 1295
1245const test_users = &[_]TestUser{ 1296const test_users = &[_]TestUser{
1246 .{ .name = "Vincent", .id = 20, .age = 33, .weight = 85.4 }, 1297 .{ .name = "Vincent", .id = 20, .age = 33, .weight = 85.4, .favorite_color = .violet },
1247 .{ .name = "Julien", .id = 40, .age = 35, .weight = 100.3 }, 1298 .{ .name = "Julien", .id = 40, .age = 35, .weight = 100.3, .favorite_color = .green },
1248 .{ .name = "José", .id = 60, .age = 40, .weight = 240.2 }, 1299 .{ .name = "José", .id = 60, .age = 40, .weight = 240.2, .favorite_color = .indigo },
1249}; 1300};
1250 1301
1251fn createTestTables(db: *Db) !void { 1302fn createTestTables(db: *Db) !void {
@@ -1254,10 +1305,11 @@ fn createTestTables(db: *Db) !void {
1254 "DROP TABLE IF EXISTS article", 1305 "DROP TABLE IF EXISTS article",
1255 "DROP TABLE IF EXISTS test_blob", 1306 "DROP TABLE IF EXISTS test_blob",
1256 \\CREATE TABLE user( 1307 \\CREATE TABLE user(
1257 \\ id integer PRIMARY KEY,
1258 \\ name text, 1308 \\ name text,
1309 \\ id integer PRIMARY KEY,
1259 \\ age integer, 1310 \\ age integer,
1260 \\ weight real 1311 \\ weight real,
1312 \\ favorite_color text
1261 \\) 1313 \\)
1262 , 1314 ,
1263 \\CREATE TABLE article( 1315 \\CREATE TABLE article(
@@ -1279,7 +1331,7 @@ fn addTestData(db: *Db) !void {
1279 try createTestTables(db); 1331 try createTestTables(db);
1280 1332
1281 for (test_users) |user| { 1333 for (test_users) |user| {
1282 try db.exec("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})", .{}, user); 1334 try db.exec("INSERT INTO user(name, id, age, weight, favorite_color) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32}, ?{[]const u8})", .{}, user);
1283 1335
1284 const rows_inserted = db.rowsAffected(); 1336 const rows_inserted = db.rowsAffected();
1285 try testing.expectEqual(@as(usize, 1), rows_inserted); 1337 try testing.expectEqual(@as(usize, 1), rows_inserted);
@@ -1371,7 +1423,7 @@ test "sqlite: read a single user into a struct" {
1371 var db = try getTestDb(); 1423 var db = try getTestDb();
1372 try addTestData(&db); 1424 try addTestData(&db);
1373 1425
1374 var stmt = try db.prepare("SELECT name, id, age, weight FROM user WHERE id = ?{usize}"); 1426 var stmt = try db.prepare("SELECT * FROM user WHERE id = ?{usize}");
1375 defer stmt.deinit(); 1427 defer stmt.deinit();
1376 1428
1377 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{ 1429 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{
@@ -1432,7 +1484,7 @@ test "sqlite: read all users into a struct" {
1432 var db = try getTestDb(); 1484 var db = try getTestDb();
1433 try addTestData(&db); 1485 try addTestData(&db);
1434 1486
1435 var stmt = try db.prepare("SELECT name, id, age, weight FROM user"); 1487 var stmt = try db.prepare("SELECT * FROM user");
1436 defer stmt.deinit(); 1488 defer stmt.deinit();
1437 1489
1438 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{}); 1490 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{});
@@ -1751,13 +1803,13 @@ test "sqlite: statement reset" {
1751 1803
1752 // Add data 1804 // Add data
1753 1805
1754 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})"); 1806 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight, favorite_color) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32}, ?{[]const u8})");
1755 defer stmt.deinit(); 1807 defer stmt.deinit();
1756 1808
1757 const users = &[_]TestUser{ 1809 const users = &[_]TestUser{
1758 .{ .id = 200, .name = "Vincent", .age = 33, .weight = 10.0 }, 1810 .{ .id = 200, .name = "Vincent", .age = 33, .weight = 10.0, .favorite_color = .violet },
1759 .{ .id = 400, .name = "Julien", .age = 35, .weight = 12.0 }, 1811 .{ .id = 400, .name = "Julien", .age = 35, .weight = 12.0, .favorite_color = .green },
1760 .{ .id = 600, .name = "José", .age = 40, .weight = 14.0 }, 1812 .{ .id = 600, .name = "José", .age = 40, .weight = 14.0, .favorite_color = .indigo },
1761 }; 1813 };
1762 1814
1763 for (users) |user| { 1815 for (users) |user| {
@@ -1781,14 +1833,14 @@ test "sqlite: statement iterator" {
1781 try db.exec("DELETE FROM user", .{}, .{}); 1833 try db.exec("DELETE FROM user", .{}, .{});
1782 1834
1783 // Add data 1835 // Add data
1784 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})"); 1836 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight, favorite_color) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32}, ?{[]const u8})");
1785 defer stmt.deinit(); 1837 defer stmt.deinit();
1786 1838
1787 var expected_rows = std.ArrayList(TestUser).init(allocator); 1839 var expected_rows = std.ArrayList(TestUser).init(allocator);
1788 var i: usize = 0; 1840 var i: usize = 0;
1789 while (i < 20) : (i += 1) { 1841 while (i < 20) : (i += 1) {
1790 const name = try std.fmt.allocPrint(allocator, "Vincent {d}", .{i}); 1842 const name = try std.fmt.allocPrint(allocator, "Vincent {d}", .{i});
1791 const user = TestUser{ .id = i, .name = name, .age = i + 200, .weight = @intToFloat(f32, i + 200) }; 1843 const user = TestUser{ .id = i, .name = name, .age = i + 200, .weight = @intToFloat(f32, i + 200), .favorite_color = .indigo };
1792 1844
1793 try expected_rows.append(user); 1845 try expected_rows.append(user);
1794 1846
diff --git a/zigmod.lock b/zigmod.lock
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/zigmod.lock
@@ -0,0 +1 @@
2