Skip to content

Commit 4f38d1d

Browse files
committed
add thread reply list pagination
1 parent 9122a6f commit 4f38d1d

File tree

31 files changed

+850
-616
lines changed

31 files changed

+850
-616
lines changed

api/openapi.yaml

+12-2
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,9 @@ paths:
11471147
created as well as a list of the posts within the thread.
11481148
security: []
11491149
tags: [threads]
1150-
parameters: [$ref: "#/components/parameters/ThreadMarkParam"]
1150+
parameters:
1151+
- $ref: "#/components/parameters/ThreadMarkParam"
1152+
- $ref: "#/components/parameters/PaginationQuery"
11511153
responses:
11521154
default: { $ref: "#/components/responses/InternalServerError" }
11531155
"404": { $ref: "#/components/responses/NotFound" }
@@ -4577,7 +4579,7 @@ components:
45774579
- type: object
45784580
required: [replies]
45794581
properties:
4580-
replies: { $ref: "#/components/schemas/ReplyList" }
4582+
replies: { $ref: "#/components/schemas/PaginatedReplyList" }
45814583

45824584
ThreadInitialProps:
45834585
type: object
@@ -4686,6 +4688,14 @@ components:
46864688
- { $ref: "#/components/schemas/PostProps" }
46874689
- { $ref: "#/components/schemas/ReplyProps" }
46884690

4691+
PaginatedReplyList:
4692+
allOf:
4693+
- $ref: "#/components/schemas/PaginatedResult"
4694+
- type: object
4695+
required: [replies]
4696+
properties:
4697+
replies: { $ref: "#/components/schemas/ReplyList" }
4698+
46894699
ReplyList:
46904700
type: array
46914701
items: { $ref: "#/components/schemas/Reply" }

app/resources/datagraph/hydrate/hydrator.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/Southclaws/storyden/app/resources/datagraph"
1515
"github.com/Southclaws/storyden/app/resources/library"
1616
"github.com/Southclaws/storyden/app/resources/library/node_querier"
17+
"github.com/Southclaws/storyden/app/resources/pagination"
1718
"github.com/Southclaws/storyden/app/resources/post"
1819
"github.com/Southclaws/storyden/app/resources/post/reply"
1920
"github.com/Southclaws/storyden/app/resources/post/thread"
@@ -74,7 +75,7 @@ func (h *Hydrator) Hydrate(ctx context.Context, refs ...*datagraph.Ref) (datagra
7475

7576
case datagraph.KindThread:
7677
items, err = dt.MapErr(v, func(r *datagraph.Ref) (withRelevance, error) {
77-
i, err := h.threads.Get(ctx, post.ID(r.ID), nil)
78+
i, err := h.threads.Get(ctx, post.ID(r.ID), pagination.Parameters{}, nil)
7879
return withRelevance{Item: i, r: r.Relevance}, err
7980
})
8081

app/resources/post/thread/db.go

+36-16
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import (
1919

2020
"github.com/Southclaws/storyden/app/resources/account"
2121
"github.com/Southclaws/storyden/app/resources/collection/collection_item_status"
22+
"github.com/Southclaws/storyden/app/resources/pagination"
2223
"github.com/Southclaws/storyden/app/resources/post"
2324
"github.com/Southclaws/storyden/app/resources/post/category"
25+
"github.com/Southclaws/storyden/app/resources/post/reply"
2426
"github.com/Southclaws/storyden/internal/ent"
2527
"github.com/Southclaws/storyden/internal/ent/asset"
2628
"github.com/Southclaws/storyden/internal/ent/collection"
@@ -284,6 +286,19 @@ func (d *database) List(
284286
}, nil
285287
}
286288

289+
const repliesCountQuery = `select
290+
p.id post_id, -- post ID
291+
count(r.id) replies, -- number of replies,
292+
count(a.id) replied -- has this account replied
293+
from
294+
posts p
295+
inner join posts r on r.root_post_id = p.id and r.deleted_at is null
296+
left join accounts a on a.id = r.account_posts and a.id = $2
297+
where
298+
p.id = $1 or p.root_post_id = $1
299+
group by p.id
300+
`
301+
287302
const likesCountQuery = `select
288303
p.id post_id, -- the post (thread or reply) ID
289304
count(*) likes, -- number of likes
@@ -312,9 +327,15 @@ where
312327
group by p.id
313328
`
314329

315-
func (d *database) Get(ctx context.Context, threadID post.ID, accountID opt.Optional[account.AccountID]) (*Thread, error) {
330+
func (d *database) Get(ctx context.Context, threadID post.ID, pageParams pagination.Parameters, accountID opt.Optional[account.AccountID]) (*Thread, error) {
331+
var replyStats post.PostRepliesResults
332+
err := d.raw.SelectContext(ctx, &replyStats, repliesCountQuery, threadID.String(), accountID.String())
333+
if err != nil {
334+
return nil, fault.Wrap(err, fctx.With(ctx))
335+
}
336+
316337
var likes post.PostLikesResults
317-
err := d.raw.SelectContext(ctx, &likes, likesCountQuery, threadID.String(), accountID.String())
338+
err = d.raw.SelectContext(ctx, &likes, likesCountQuery, threadID.String(), accountID.String())
318339
if err != nil {
319340
return nil, fault.Wrap(err, fctx.With(ctx))
320341
}
@@ -354,6 +375,8 @@ func (d *database) Get(ctx context.Context, threadID post.ID, accountID opt.Opti
354375
lq.WithFaviconImage().WithPrimaryImage()
355376
lq.WithAssets().Order(link.ByCreatedAt(sql.OrderDesc()))
356377
}).
378+
Limit(pageParams.Limit()).
379+
Offset(pageParams.Offset()).
357380
Order(ent.Asc(ent_post.FieldCreatedAt))
358381
}).
359382
WithAuthor(func(aq *ent.AccountQuery) {
@@ -382,27 +405,24 @@ func (d *database) Get(ctx context.Context, threadID post.ID, accountID opt.Opti
382405
return nil, fault.Wrap(err, fctx.With(ctx), ftag.With(ftag.Internal))
383406
}
384407

385-
replies := post.PostRepliesMap{
386-
xid.ID(threadID): post.PostRepliesResult{
387-
PostID: xid.ID(threadID),
388-
Count: len(r.Edges.Posts),
389-
Replied: opt.Map(accountID, func(a account.AccountID) (replied int) {
390-
for _, p := range r.Edges.Posts {
391-
if p.Edges.Author.ID == xid.ID(a) {
392-
replied++
393-
}
394-
}
395-
return
396-
}).OrZero(),
397-
},
408+
replies, err := dt.MapErr(r.Edges.Posts, reply.FromModel(likes.Map()))
409+
if err != nil {
410+
return nil, fault.Wrap(err, fctx.With(ctx))
398411
}
399412

400-
mapper := FromModel(likes.Map(), collections.Map(), replies)
413+
replyStatsMap := replyStats.Map()
414+
totalReplies := replyStatsMap[r.ID].Count
415+
416+
repliesPage := pagination.NewPageResult(pageParams, totalReplies, replies)
417+
418+
mapper := FromModel(likes.Map(), collections.Map(), replyStatsMap)
401419
p, err := mapper(r)
402420
if err != nil {
403421
return nil, fault.Wrap(err, fctx.With(ctx))
404422
}
405423

424+
p.Replies = repliesPage
425+
406426
return p, nil
407427
}
408428

app/resources/post/thread/repo.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/Southclaws/storyden/app/resources/account"
1212
"github.com/Southclaws/storyden/app/resources/asset"
1313
"github.com/Southclaws/storyden/app/resources/datagraph"
14+
"github.com/Southclaws/storyden/app/resources/pagination"
1415
"github.com/Southclaws/storyden/app/resources/post"
1516
"github.com/Southclaws/storyden/app/resources/post/category"
1617
"github.com/Southclaws/storyden/app/resources/tag/tag_ref"
@@ -53,7 +54,7 @@ type Repository interface {
5354

5455
// GetPostCounts(ctx context.Context) (map[string]int, error)
5556

56-
Get(ctx context.Context, threadID post.ID, accountID opt.Optional[account.AccountID]) (*Thread, error)
57+
Get(ctx context.Context, threadID post.ID, pageParams pagination.Parameters, accountID opt.Optional[account.AccountID]) (*Thread, error)
5758

5859
Delete(ctx context.Context, id post.ID) error
5960
}

app/resources/post/thread/thread.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/Southclaws/storyden/app/resources/collection/collection_item_status"
1212
"github.com/Southclaws/storyden/app/resources/datagraph"
1313
"github.com/Southclaws/storyden/app/resources/link/link_ref"
14+
"github.com/Southclaws/storyden/app/resources/pagination"
1415
"github.com/Southclaws/storyden/app/resources/post"
1516
"github.com/Southclaws/storyden/app/resources/post/category"
1617
"github.com/Southclaws/storyden/app/resources/post/reaction"
@@ -30,7 +31,7 @@ type Thread struct {
3031
Pinned bool
3132

3233
ReplyStatus post.ReplyStatus
33-
Replies []*reply.Reply
34+
Replies pagination.Result[*reply.Reply]
3435
Category category.Category
3536
Visibility visibility.Visibility
3637
Tags tag_ref.Tags
@@ -65,11 +66,6 @@ func FromModel(ls post.PostLikesMap, cs collection_item_status.CollectionStatusM
6566
return nil, fault.Wrap(err)
6667
}
6768

68-
replies, err := dt.MapErr(m.Edges.Posts, reply.FromModel(ls))
69-
if err != nil {
70-
return nil, fault.Wrap(err)
71-
}
72-
7369
link := opt.Map(opt.NewPtr(m.Edges.Link), func(in ent.Link) link_ref.LinkRef {
7470
return *link_ref.Map(&in)
7571
})
@@ -110,7 +106,6 @@ func FromModel(ls post.PostLikesMap, cs collection_item_status.CollectionStatusM
110106
Pinned: m.Pinned,
111107

112108
ReplyStatus: rs.Status(m.ID),
113-
Replies: replies,
114109
Category: *category,
115110
Visibility: visibility.NewVisibilityFromEnt(m.Visibility),
116111
Tags: tags,

0 commit comments

Comments
 (0)