diff options
| -rw-r--r-- | sqlite.zig | 34 |
1 files changed, 32 insertions, 2 deletions
| @@ -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 | ||
| 1410 | test "sqlite: statement reset" { | 1440 | test "sqlite: statement reset" { |