Allow pointers as one relations values.
* Allow to define pointers to receive one relations values: this solves self-referencing issues (e.g. UserInfo.user in example model).
This commit is contained in:
parent
3501c48eaf
commit
9567e57278
2 changed files with 54 additions and 9 deletions
|
@ -150,12 +150,27 @@ pub fn ResultMapper(comptime Model: type, comptime TableShape: type, comptime Me
|
|||
if (inlineRelations) |_inlineRelations| {
|
||||
// If there are loaded inline relations, map them to the result.
|
||||
inline for (_inlineRelations) |relation| {
|
||||
// Set the read inline relation value.
|
||||
@field(model.*, relation.field) = (
|
||||
// Read the inline related value.
|
||||
const relatedValue = (
|
||||
if (@field(rawModel, relation.field)) |relationVal|
|
||||
try relation.repositoryConfiguration().fromSql(relationVal)
|
||||
else null
|
||||
);
|
||||
|
||||
if (pointedType(@TypeOf(@field(model.*, relation.field)))) |childType| {
|
||||
if (relatedValue) |val| {
|
||||
// Allocate pointer value.
|
||||
@field(model.*, relation.field) = try mapperArena.allocator().create(childType);
|
||||
// Set pointer value.
|
||||
@field(model.*, relation.field).?.* = val;
|
||||
} else {
|
||||
// Set NULL value.
|
||||
@field(model.*, relation.field) = null;
|
||||
}
|
||||
} else {
|
||||
// Set simple value.
|
||||
@field(model.*, relation.field) = relatedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,3 +245,16 @@ pub fn ResultMapper(comptime Model: type, comptime TableShape: type, comptime Me
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Get pointed type of the given type.
|
||||
/// Return NULL if the type is not a pointer.
|
||||
fn pointedType(@"type": type) ?type {
|
||||
return switch (@typeInfo(@"type")) {
|
||||
.Pointer => |ptr| ptr.child,
|
||||
.Optional => |opt| switch (@typeInfo(opt.child)) {
|
||||
.Pointer => |ptr| ptr.child,
|
||||
else => null,
|
||||
},
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -110,8 +110,7 @@ pub const UserInfo = struct {
|
|||
user_id: i32,
|
||||
birthdate: i64,
|
||||
|
||||
//TODO is there a way to solve the "struct 'example.User' depends on itself" error when adding this relation?
|
||||
// user: ?User = null,
|
||||
user: ?*User = null,
|
||||
};
|
||||
pub const UserInfoRepository = zrm.Repository(UserInfo, UserInfo.Table, .{
|
||||
.table = "example_users_info",
|
||||
|
@ -123,11 +122,11 @@ pub const UserInfoRepository = zrm.Repository(UserInfo, UserInfo.Table, .{
|
|||
.toSql = zrm.helpers.TableModel(UserInfo, UserInfo.Table).copyModelToTable,
|
||||
});
|
||||
pub const UserInfoRelations = UserInfoRepository.relations.define(.{
|
||||
// .user = UserInfoRepository.relations.one(UserRepository, .{
|
||||
// .direct = .{
|
||||
// .foreignKey = "user_id",
|
||||
// },
|
||||
// }),
|
||||
.user = UserInfoRepository.relations.one(UserRepository, .{
|
||||
.direct = .{
|
||||
.foreignKey = "user_id",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
pub const Message = struct {
|
||||
|
@ -295,6 +294,24 @@ test "user has info" {
|
|||
|
||||
try std.testing.expectEqual(1, secondResult.models.len);
|
||||
try std.testing.expect(secondResult.models[0].info == null);
|
||||
|
||||
|
||||
|
||||
var thirdQuery = UserInfoRepository.QueryWith(
|
||||
// Retrieve info of users.
|
||||
&[_]zrm.relations.Relation{UserInfoRelations.user}
|
||||
).init(std.testing.allocator, poolConnector.connector(), .{});
|
||||
try thirdQuery.whereKey(2);
|
||||
defer thirdQuery.deinit();
|
||||
|
||||
var thirdResult = try thirdQuery.get(std.testing.allocator);
|
||||
defer thirdResult.deinit();
|
||||
|
||||
try std.testing.expectEqual(1, thirdResult.models.len);
|
||||
try std.testing.expectEqual(876348000000000, thirdResult.models[0].birthdate);
|
||||
try std.testing.expect(thirdResult.models[0].user != null);
|
||||
try std.testing.expectEqual(2, thirdResult.models[0].user.?.id);
|
||||
try std.testing.expectEqualStrings("madeorsk", thirdResult.models[0].user.?.name);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue