summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sqlite.zig34
1 files changed, 32 insertions, 2 deletions
diff --git a/sqlite.zig b/sqlite.zig
index d96c956..2600ee2 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -548,6 +548,29 @@ pub fn Iterator(comptime Type: type) type {
548 return ret; 548 return ret;
549 } 549 }
550 550
551 fn readOptional(self: *Self, comptime OptionalType: type, options: anytype, _i: usize) !OptionalType {
552 const i = @intCast(c_int, _i);
553 const type_info = @typeInfo(OptionalType);
554
555 var ret: OptionalType = undefined;
556 switch (type_info) {
557 .Optional => |opt| {
558 // Easy way to know if the column represents a null value.
559 const value = c.sqlite3_column_value(self.stmt, i);
560 const datatype = c.sqlite3_value_type(value);
561
562 if (datatype == c.SQLITE_NULL) {
563 return null;
564 } else {
565 const val = try self.readField(opt.child, _i, options);
566 ret = val;
567 return ret;
568 }
569 },
570 else => @compileError("cannot read optional of type " ++ @typeName(OptionalType)),
571 }
572 }
573
551 // readStruct reads an entire sqlite row into a struct. 574 // readStruct reads an entire sqlite row into a struct.
552 // 575 //
553 // Each field correspond to a column; its position in the struct determines the column used for it. 576 // Each field correspond to a column; its position in the struct determines the column used for it.
@@ -596,6 +619,7 @@ pub fn Iterator(comptime Type: type) type {
596 .Void => {}, 619 .Void => {},
597 .Array => try self.readArray(FieldType, i), 620 .Array => try self.readArray(FieldType, i),
598 .Pointer => try self.readPointer(FieldType, options.allocator, i), 621 .Pointer => try self.readPointer(FieldType, options.allocator, i),
622 .Optional => try self.readOptional(FieldType, options, i),
599 else => @compileError("cannot populate field of type " ++ @typeName(FieldType)), 623 else => @compileError("cannot populate field of type " ++ @typeName(FieldType)),
600 }, 624 },
601 }; 625 };
@@ -758,6 +782,12 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: ParsedQuery) t
758 else => @compileError("cannot bind field " ++ field_name ++ " of type array of " ++ @typeName(arr.child)), 782 else => @compileError("cannot bind field " ++ field_name ++ " of type array of " ++ @typeName(arr.child)),
759 } 783 }
760 }, 784 },
785 .Optional => |opt| if (field) |non_null_field| {
786 self.bindField(opt.child, field_name, i, non_null_field);
787 } else {
788 _ = c.sqlite3_bind_null(self.stmt, column);
789 },
790 .Null => _ = c.sqlite3_bind_null(self.stmt, column),
761 else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), 791 else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)),
762 }, 792 },
763 } 793 }
@@ -1403,8 +1433,8 @@ test "sqlite: optional" {
1403 ); 1433 );
1404 1434
1405 testing.expect(row != null); 1435 testing.expect(row != null);
1406 testing.expect(row.data == null); 1436 testing.expect(row.?.data == null);
1407 testing.expectEqual(true, row.is_published.?); 1437 testing.expectEqual(true, row.?.is_published.?);
1408} 1438}
1409 1439
1410test "sqlite: statement reset" { 1440test "sqlite: statement reset" {