summaryrefslogtreecommitdiff
path: root/sqlite.zig
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sqlite.zig111
1 files changed, 78 insertions, 33 deletions
diff --git a/sqlite.zig b/sqlite.zig
index 20ccc6d..f68d13f 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -529,7 +529,12 @@ pub fn Iterator(comptime Type: type) type {
529 switch (type_info) { 529 switch (type_info) {
530 .Pointer => |ptr| { 530 .Pointer => |ptr| {
531 switch (ptr.size) { 531 switch (ptr.size) {
532 .One => unreachable, 532 .One => {
533 ret = try allocator.create(ptr.child);
534 errdefer allocator.destroy(ret);
535
536 ret.* = try self.readField(ptr.child, i, .{ .allocator = allocator });
537 },
533 .Slice => switch (ptr.child) { 538 .Slice => switch (ptr.child) {
534 u8 => ret = try self.readBytes(PointerType, allocator, i, .Text), 539 u8 => ret = try self.readBytes(PointerType, allocator, i, .Text),
535 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)), 540 else => @compileError("cannot read pointer of type " ++ @typeName(PointerType)),
@@ -569,27 +574,32 @@ pub fn Iterator(comptime Type: type) type {
569 574
570 inline for (@typeInfo(Type).Struct.fields) |field, _i| { 575 inline for (@typeInfo(Type).Struct.fields) |field, _i| {
571 const i = @as(usize, _i); 576 const i = @as(usize, _i);
572 const field_type_info = @typeInfo(field.field_type); 577
573 578 const ret = try self.readField(field.field_type, i, options);
574 const ret = switch (field.field_type) {
575 Blob => try self.readBytes(Blob, options.allocator, i, .Blob),
576 Text => try self.readBytes(Text, options.allocator, i, .Text),
577 else => switch (field_type_info) {
578 .Int => try self.readInt(field.field_type, i),
579 .Float => try self.readFloat(field.field_type, i),
580 .Bool => try self.readBool(i),
581 .Void => {},
582 .Array => try self.readArray(field.field_type, i),
583 .Pointer => try self.readPointer(field.field_type, options.allocator, i),
584 else => @compileError("cannot populate field " ++ field.name ++ " of type " ++ @typeName(field.field_type)),
585 },
586 };
587 579
588 @field(value, field.name) = ret; 580 @field(value, field.name) = ret;
589 } 581 }
590 582
591 return value; 583 return value;
592 } 584 }
585
586 fn readField(self: *Self, comptime FieldType: type, i: usize, options: anytype) !FieldType {
587 const field_type_info = @typeInfo(FieldType);
588
589 return switch (FieldType) {
590 Blob => try self.readBytes(Blob, options.allocator, i, .Blob),
591 Text => try self.readBytes(Text, options.allocator, i, .Text),
592 else => switch (field_type_info) {
593 .Int => try self.readInt(FieldType, i),
594 .Float => try self.readFloat(FieldType, i),
595 .Bool => try self.readBool(i),
596 .Void => {},
597 .Array => try self.readArray(FieldType, i),
598 .Pointer => try self.readPointer(FieldType, options.allocator, i),
599 else => @compileError("cannot populate field " ++ field.name ++ " of type " ++ @typeName(FieldType)),
600 },
601 };
602 }
593 }; 603 };
594} 604}
595 605
@@ -889,16 +899,16 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
889} 899}
890 900
891const TestUser = struct { 901const TestUser = struct {
892 id: usize,
893 name: []const u8, 902 name: []const u8,
903 id: usize,
894 age: usize, 904 age: usize,
895 weight: f32, 905 weight: f32,
896}; 906};
897 907
898const test_users = &[_]TestUser{ 908const test_users = &[_]TestUser{
899 .{ .id = 20, .name = "Vincent", .age = 33, .weight = 85.4 }, 909 .{ .name = "Vincent", .id = 20, .age = 33, .weight = 85.4 },
900 .{ .id = 40, .name = "Julien", .age = 35, .weight = 100.3 }, 910 .{ .name = "Julien", .id = 40, .age = 35, .weight = 100.3 },
901 .{ .id = 60, .name = "José", .age = 40, .weight = 240.2 }, 911 .{ .name = "José", .id = 60, .age = 40, .weight = 240.2 },
902}; 912};
903 913
904fn addTestData(db: *Db) !void { 914fn addTestData(db: *Db) !void {
@@ -925,7 +935,7 @@ fn addTestData(db: *Db) !void {
925 } 935 }
926 936
927 for (test_users) |user| { 937 for (test_users) |user| {
928 try db.exec("INSERT INTO user(id, name, age, weight) VALUES(?{usize}, ?{[]const u8}, ?{usize}, ?{f32})", user); 938 try db.exec("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})", user);
929 939
930 const rows_inserted = db.rowsAffected(); 940 const rows_inserted = db.rowsAffected();
931 testing.expectEqual(@as(usize, 1), rows_inserted); 941 testing.expectEqual(@as(usize, 1), rows_inserted);
@@ -1010,7 +1020,7 @@ test "sqlite: read a single user into a struct" {
1010 try db.init(initOptions()); 1020 try db.init(initOptions());
1011 try addTestData(&db); 1021 try addTestData(&db);
1012 1022
1013 var stmt = try db.prepare("SELECT id, name, age, weight FROM user WHERE id = ?{usize}"); 1023 var stmt = try db.prepare("SELECT name, id, age, weight FROM user WHERE id = ?{usize}");
1014 defer stmt.deinit(); 1024 defer stmt.deinit();
1015 1025
1016 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{ 1026 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{
@@ -1026,11 +1036,11 @@ test "sqlite: read a single user into a struct" {
1026 { 1036 {
1027 var row = try db.one( 1037 var row = try db.one(
1028 struct { 1038 struct {
1029 id: usize,
1030 name: [128:0]u8, 1039 name: [128:0]u8,
1040 id: usize,
1031 age: usize, 1041 age: usize,
1032 }, 1042 },
1033 "SELECT id, name, age FROM user WHERE id = ?{usize}", 1043 "SELECT name, id, age FROM user WHERE id = ?{usize}",
1034 .{}, 1044 .{},
1035 .{@as(usize, 20)}, 1045 .{@as(usize, 20)},
1036 ); 1046 );
@@ -1046,12 +1056,12 @@ test "sqlite: read a single user into a struct" {
1046 { 1056 {
1047 var row = try db.oneAlloc( 1057 var row = try db.oneAlloc(
1048 struct { 1058 struct {
1049 id: usize,
1050 name: Text, 1059 name: Text,
1060 id: usize,
1051 age: usize, 1061 age: usize,
1052 }, 1062 },
1053 &arena.allocator, 1063 &arena.allocator,
1054 "SELECT id, name, age FROM user WHERE id = ?{usize}", 1064 "SELECT name, id, age FROM user WHERE id = ?{usize}",
1055 .{}, 1065 .{},
1056 .{@as(usize, 20)}, 1066 .{@as(usize, 20)},
1057 ); 1067 );
@@ -1072,7 +1082,7 @@ test "sqlite: read all users into a struct" {
1072 try db.init(initOptions()); 1082 try db.init(initOptions());
1073 try addTestData(&db); 1083 try addTestData(&db);
1074 1084
1075 var stmt = try db.prepare("SELECT id, name, age, weight FROM user"); 1085 var stmt = try db.prepare("SELECT name, id, age, weight FROM user");
1076 defer stmt.deinit(); 1086 defer stmt.deinit();
1077 1087
1078 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{}); 1088 var rows = try stmt.all(TestUser, &arena.allocator, .{}, .{});
@@ -1094,13 +1104,13 @@ test "sqlite: read in an anonymous struct" {
1094 try db.init(initOptions()); 1104 try db.init(initOptions());
1095 try addTestData(&db); 1105 try addTestData(&db);
1096 1106
1097 var stmt = try db.prepare("SELECT id, name, name, age, id, weight FROM user WHERE id = ?{usize}"); 1107 var stmt = try db.prepare("SELECT name, id, name, age, id, weight FROM user WHERE id = ?{usize}");
1098 defer stmt.deinit(); 1108 defer stmt.deinit();
1099 1109
1100 var row = try stmt.oneAlloc( 1110 var row = try stmt.oneAlloc(
1101 struct { 1111 struct {
1102 id: usize,
1103 name: []const u8, 1112 name: []const u8,
1113 id: usize,
1104 name_2: [200:0xAD]u8, 1114 name_2: [200:0xAD]u8,
1105 age: usize, 1115 age: usize,
1106 is_id: bool, 1116 is_id: bool,
@@ -1129,13 +1139,13 @@ test "sqlite: read in a Text struct" {
1129 try db.init(initOptions()); 1139 try db.init(initOptions());
1130 try addTestData(&db); 1140 try addTestData(&db);
1131 1141
1132 var stmt = try db.prepare("SELECT id, name, age FROM user WHERE id = ?{usize}"); 1142 var stmt = try db.prepare("SELECT name, id, age FROM user WHERE id = ?{usize}");
1133 defer stmt.deinit(); 1143 defer stmt.deinit();
1134 1144
1135 var row = try stmt.oneAlloc( 1145 var row = try stmt.oneAlloc(
1136 struct { 1146 struct {
1137 id: usize,
1138 name: Text, 1147 name: Text,
1148 id: usize,
1139 age: usize, 1149 age: usize,
1140 }, 1150 },
1141 &arena.allocator, 1151 &arena.allocator,
@@ -1335,6 +1345,41 @@ test "sqlite: bind pointer" {
1335 } 1345 }
1336} 1346}
1337 1347
1348test "sqlite: read pointers" {
1349 var arena = std.heap.ArenaAllocator.init(testing.allocator);
1350 defer arena.deinit();
1351
1352 var db: Db = undefined;
1353 try db.init(initOptions());
1354 try addTestData(&db);
1355
1356 const query = "SELECT id, name, age, weight FROM user";
1357
1358 var stmt = try db.prepare(query);
1359 defer stmt.deinit();
1360
1361 const rows = try stmt.all(
1362 struct {
1363 id: *usize,
1364 name: *[]const u8,
1365 age: *u32,
1366 weight: *f32,
1367 },
1368 &arena.allocator,
1369 .{},
1370 .{},
1371 );
1372
1373 testing.expectEqual(@as(usize, 3), rows.len);
1374 for (rows) |row, i| {
1375 const exp = test_users[i];
1376 testing.expectEqual(exp.id, row.id.*);
1377 testing.expectEqualStrings(exp.name, row.name.*);
1378 testing.expectEqual(exp.age, row.age.*);
1379 testing.expectEqual(exp.weight, row.weight.*);
1380 }
1381}
1382
1338test "sqlite: statement reset" { 1383test "sqlite: statement reset" {
1339 var db: Db = undefined; 1384 var db: Db = undefined;
1340 try db.init(initOptions()); 1385 try db.init(initOptions());
@@ -1342,7 +1387,7 @@ test "sqlite: statement reset" {
1342 1387
1343 // Add data 1388 // Add data
1344 1389
1345 var stmt = try db.prepare("INSERT INTO user(id, name, age, weight) VALUES(?{usize}, ?{[]const u8}, ?{usize}, ?{f32})"); 1390 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})");
1346 defer stmt.deinit(); 1391 defer stmt.deinit();
1347 1392
1348 const users = &[_]TestUser{ 1393 const users = &[_]TestUser{
@@ -1373,7 +1418,7 @@ test "sqlite: statement iterator" {
1373 try db.exec("DELETE FROM user", .{}); 1418 try db.exec("DELETE FROM user", .{});
1374 1419
1375 // Add data 1420 // Add data
1376 var stmt = try db.prepare("INSERT INTO user(id, name, age, weight) VALUES(?{usize}, ?{[]const u8}, ?{usize}, ?{f32})"); 1421 var stmt = try db.prepare("INSERT INTO user(name, id, age, weight) VALUES(?{[]const u8}, ?{usize}, ?{usize}, ?{f32})");
1377 defer stmt.deinit(); 1422 defer stmt.deinit();
1378 1423
1379 var expected_rows = std.ArrayList(TestUser).init(allocator); 1424 var expected_rows = std.ArrayList(TestUser).init(allocator);