refactor post reactions
This commit is contained in:
parent
2519fc77d2
commit
5379d29c5f
13 changed files with 129 additions and 97 deletions
|
@ -1,3 +1,3 @@
|
|||
namespace Femto.Modules.Blog.Application.Queries.GetPosts.Dto;
|
||||
|
||||
public record GetPostsQueryResult(IList<PostDto> Posts, Guid? Next);
|
||||
public record GetPostsQueryResult(IList<PostDto> Posts);
|
|
@ -1,3 +1,3 @@
|
|||
namespace Femto.Modules.Blog.Application.Queries.GetPosts.Dto;
|
||||
|
||||
public record PostReactionDto(string Emoji, int Count, bool DidReact);
|
||||
public record PostReactionDto(string Emoji, string AuthorName, DateTimeOffset ReactedOn);
|
||||
|
|
|
@ -3,22 +3,27 @@ using Femto.Modules.Blog.Application.Queries.GetPosts.Dto;
|
|||
|
||||
namespace Femto.Modules.Blog.Application.Queries.GetPosts;
|
||||
|
||||
/// <summary>
|
||||
/// Get posts in reverse chronological order
|
||||
/// </summary>
|
||||
/// <param name="CurrentUserId"></param>
|
||||
public record GetPostsQuery(Guid? CurrentUserId) : IQuery<GetPostsQueryResult>
|
||||
{
|
||||
public Guid? From { get; init; }
|
||||
/// <summary>
|
||||
/// Id of the specific post to load. If specified, After and Amount are ignored
|
||||
/// </summary>
|
||||
public Guid? PostId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If specified, loads posts from after the given Id. Used for paging
|
||||
/// </summary>
|
||||
public Guid? After { get; init; }
|
||||
public int Amount { get; init; } = 20;
|
||||
public Guid? AuthorId { get; init; }
|
||||
public string? Author { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Default is to load in reverse chronological order
|
||||
/// TODO this is not exposed on the client as it probably wouldn't work that well
|
||||
/// </summary>
|
||||
public GetPostsDirection Direction { get; init; } = GetPostsDirection.Backward;
|
||||
}
|
||||
|
||||
public enum GetPostsDirection
|
||||
{
|
||||
Forward,
|
||||
Backward,
|
||||
}
|
||||
public GetPostsQuery(Guid postId, Guid? currentUserId) : this(currentUserId)
|
||||
{
|
||||
this.PostId = postId;
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ public class GetPostsQueryHandler(IDbConnectionFactory connectionFactory)
|
|||
|
||||
var username = query.Author;
|
||||
var authorGuid = query.AuthorId;
|
||||
var cursor = query.From;
|
||||
var cursor = query.After;
|
||||
var showPrivate = query.CurrentUserId is not null;
|
||||
|
||||
var loadPostsResult = await conn.QueryAsync<LoadPostRow>(
|
||||
|
@ -33,9 +33,10 @@ public class GetPostsQueryHandler(IDbConnectionFactory connectionFactory)
|
|||
from blog.post
|
||||
inner join blog.author on blog.author.id = blog.post.author_id
|
||||
where (@username is null or blog.author.username = @username)
|
||||
and (@postId is null or blog.post.id = @postId)
|
||||
and (@showPrivate or blog.post.is_public = true)
|
||||
and (@authorGuid is null or blog.author.id = @authorGuid)
|
||||
and (@cursor is null or blog.post.id <= @cursor)
|
||||
and (@cursor is null or blog.post.id < @cursor)
|
||||
order by blog.post.id desc
|
||||
limit @amount
|
||||
""",
|
||||
|
@ -44,15 +45,13 @@ public class GetPostsQueryHandler(IDbConnectionFactory connectionFactory)
|
|||
username,
|
||||
authorGuid,
|
||||
cursor,
|
||||
// load an extra one to take for the cursor
|
||||
amount = query.Amount + 1,
|
||||
amount = query.PostId is not null ? 1 : query.Amount,
|
||||
showPrivate,
|
||||
postId = query.PostId,
|
||||
}
|
||||
);
|
||||
|
||||
var loadedPosts = loadPostsResult.ToList();
|
||||
var posts = loadedPosts.Take(query.Amount).ToList();
|
||||
var next = loadedPosts.LastOrDefault()?.PostId;
|
||||
var posts = loadPostsResult.ToList();
|
||||
|
||||
var postIds = posts.Select(p => p.PostId).ToList();
|
||||
|
||||
|
@ -69,70 +68,46 @@ public class GetPostsQueryHandler(IDbConnectionFactory connectionFactory)
|
|||
""",
|
||||
new { postIds }
|
||||
);
|
||||
|
||||
var media = loadMediaResult.ToList();
|
||||
|
||||
var loadReactionsResult = await conn.QueryAsync<LoadReactionRow>(
|
||||
"""
|
||||
select
|
||||
pr.post_id as PostId,
|
||||
pr.author_id as AuthorId,
|
||||
pr.emoji as Emoji
|
||||
a.username as AuthorName,
|
||||
pr.emoji as Emoji,
|
||||
pr.created_at as CreatedOn
|
||||
from blog.post_reaction pr
|
||||
join blog.author a on a.id = pr.author_id
|
||||
where pr.post_id = ANY (@postIds)
|
||||
""",
|
||||
new { postIds }
|
||||
);
|
||||
|
||||
var reactionsByPostId = loadReactionsResult
|
||||
.GroupBy(r => r.PostId)
|
||||
.ToDictionary(
|
||||
group => group.Key,
|
||||
group =>
|
||||
group
|
||||
.GroupBy(
|
||||
r => r.Emoji,
|
||||
(key, g) =>
|
||||
{
|
||||
var reactions = g.ToList();
|
||||
return new PostReactionDto(
|
||||
key,
|
||||
reactions.Count,
|
||||
reactions.Any(r => r.AuthorId == query.CurrentUserId)
|
||||
);
|
||||
}
|
||||
)
|
||||
.ToList()
|
||||
);
|
||||
|
||||
var mediaByPostId = loadMediaResult
|
||||
.GroupBy(m => m.PostId)
|
||||
.ToDictionary(
|
||||
g => g.Key,
|
||||
g =>
|
||||
g.Select(m => new PostMediaDto(
|
||||
new Uri(m.MediaUrl),
|
||||
m.MediaWidth,
|
||||
m.MediaHeight
|
||||
))
|
||||
.ToList()
|
||||
);
|
||||
var reactions = loadReactionsResult.ToList();
|
||||
|
||||
return new GetPostsQueryResult(
|
||||
posts
|
||||
.Select(p => new PostDto(
|
||||
p.PostId,
|
||||
p.Content,
|
||||
mediaByPostId.TryGetValue(p.PostId, out var mediaDtos) ? mediaDtos : [],
|
||||
media.Where(m => m.PostId == p.PostId).Select(m => new PostMediaDto(
|
||||
new Uri(m.MediaUrl),
|
||||
m.MediaWidth,
|
||||
m.MediaHeight
|
||||
)).ToList(),
|
||||
p.PostedOn,
|
||||
new PostAuthorDto(p.AuthorId, p.Username),
|
||||
reactionsByPostId.TryGetValue(p.PostId, out var reactionDtos)
|
||||
? reactionDtos.ToList()
|
||||
: [],
|
||||
reactions
|
||||
.Where(r => r.PostId == p.PostId)
|
||||
.Select(r => new PostReactionDto(r.Emoji, r.AuthorName, r.CreatedAt))
|
||||
.ToList(),
|
||||
!string.IsNullOrEmpty(p.PossibleReactions)
|
||||
? JsonSerializer.Deserialize<IEnumerable<string>>(p.PossibleReactions)!
|
||||
: []
|
||||
))
|
||||
.ToList(),
|
||||
next
|
||||
.ToList()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -158,7 +133,8 @@ public class GetPostsQueryHandler(IDbConnectionFactory connectionFactory)
|
|||
internal record LoadReactionRow
|
||||
{
|
||||
public Guid PostId { get; init; }
|
||||
public Guid AuthorId { get; init; }
|
||||
public string AuthorName { get; init; }
|
||||
public string Emoji { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue