What's Changed
This release fixes an issue where there is no direct correlation ID between a top-level entity and a sub-level entity by introducing the concept of an ID join.
For example, before this release, there was no way to express the relationship between e.g. a PostDetails
and a User
because User
doesn't have a postId
field like Reply
does, as described in #33.
record PostDetails(Long id, Long userId, String content) {
}
record User(Long Id, String username) { // No correlation Id back to PostDetails
}
record Reply(Long id, Long postId, Long userId, String content) {
}
record Post(PostDetails post, User author, List<Reply> replies) {
}
Assembler<PostDetails, Post> assembler = assemblerOf(Post.class)
.withCorrelationIdResolver(PostDetails::id)
.withRules(
rule(XXXXX, oneToOne(call(PostDetails::userId, this::getUsersById))), // What should XXXXX be?
rule(Reply::postId, oneToMany(Reply::id, call(this::getRepliesById))),
Post::new)
.build();
Since 0.7.5, this relationship can now be expressed:
Assembler<PostDetails, Post> assembler = assemblerOf(Post.class)
.withCorrelationIdResolver(PostDetails::id)
.withRules(
rule(User::Id, PostDetails::userId, oneToOne(call(this::getUsersById))), // ID Join
rule(Reply::postId, oneToMany(Reply::id, call(this::getRepliesById))),
Post::new)
.build();
This would be semantically equivalent to the following SQL query if all entities were stored in the same relational database:
SELECT
p.id AS post_id,
p.userId AS post_userId,
p.content AS post_content,
u.id AS author_id,
u.username AS author_username,
r.id AS reply_id,
r.postId AS reply_postId,
r.userId AS reply_userId,
r.content AS reply_content
FROM
PostDetails p
JOIN
User u ON p.userId = u.id -- rule(User::Id, PostDetails::userId, ...)
LEFT JOIN
Reply r ON p.id = r.postId -- rule(Reply::postId, ...)
WHERE
p.id IN (1, 2, 3); -- withCorrelationIdResolver(PostDetails::id)