diff options
| author | 2021-01-06 02:13:56 +0100 | |
|---|---|---|
| committer | 2021-01-06 02:13:56 +0100 | |
| commit | 3571d8202edf3fce960f063c29c20b93e230d294 (patch) | |
| tree | 85b29c3e142b8148b2ace829c802aa4a27b2fe78 | |
| parent | Merge pull request #12 from vrischmann/read-pointers (diff) | |
| parent | allow binding and reading optionals (diff) | |
| download | zig-sqlite-3571d8202edf3fce960f063c29c20b93e230d294.tar.gz zig-sqlite-3571d8202edf3fce960f063c29c20b93e230d294.tar.xz zig-sqlite-3571d8202edf3fce960f063c29c20b93e230d294.zip | |
Merge pull request #15 from vrischmann/optional
Optional
Diffstat (limited to '')
| -rw-r--r-- | sqlite.zig | 59 |
1 files changed, 58 insertions, 1 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,7 +619,8 @@ 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), |
| 599 | else => @compileError("cannot populate field " ++ field.name ++ " of type " ++ @typeName(FieldType)), | 622 | .Optional => try self.readOptional(FieldType, options, i), |
| 623 | else => @compileError("cannot populate field of type " ++ @typeName(FieldType)), | ||
| 600 | }, | 624 | }, |
| 601 | }; | 625 | }; |
| 602 | } | 626 | } |
| @@ -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 | } |
| @@ -1380,6 +1410,33 @@ test "sqlite: read pointers" { | |||
| 1380 | } | 1410 | } |
| 1381 | } | 1411 | } |
| 1382 | 1412 | ||
| 1413 | test "sqlite: optional" { | ||
| 1414 | var arena = std.heap.ArenaAllocator.init(testing.allocator); | ||
| 1415 | defer arena.deinit(); | ||
| 1416 | |||
| 1417 | var db: Db = undefined; | ||
| 1418 | try db.init(initOptions()); | ||
| 1419 | try addTestData(&db); | ||
| 1420 | |||
| 1421 | try db.exec("INSERT INTO article(author_id, data, is_published) VALUES(?, ?, ?)", .{ 1, null, true }); | ||
| 1422 | |||
| 1423 | var stmt = try db.prepare("SELECT data, is_published FROM article"); | ||
| 1424 | defer stmt.deinit(); | ||
| 1425 | |||
| 1426 | const row = try stmt.one( | ||
| 1427 | struct { | ||
| 1428 | data: ?[128:0]u8, | ||
| 1429 | is_published: ?bool, | ||
| 1430 | }, | ||
| 1431 | .{}, | ||
| 1432 | .{}, | ||
| 1433 | ); | ||
| 1434 | |||
| 1435 | testing.expect(row != null); | ||
| 1436 | testing.expect(row.?.data == null); | ||
| 1437 | testing.expectEqual(true, row.?.is_published.?); | ||
| 1438 | } | ||
| 1439 | |||
| 1383 | test "sqlite: statement reset" { | 1440 | test "sqlite: statement reset" { |
| 1384 | var db: Db = undefined; | 1441 | var db: Db = undefined; |
| 1385 | try db.init(initOptions()); | 1442 | try db.init(initOptions()); |