Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions __tests__/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,48 @@ describe('query userComments', () => {
});
});

describe('query topComments', () => {
const QUERY = `query TopComments($postId: ID!, $first: Int) {
topComments(postId: $postId, first: $first) {
id
numUpvotes
content
}
}`;

it('should return comments ordered by upvotes descending', async () => {
// Set different upvote counts for comments on p1
await con.getRepository(Comment).update({ id: 'c1' }, { upvotes: 5 });
await con.getRepository(Comment).update({ id: 'c3' }, { upvotes: 10 });
await con.getRepository(Comment).update({ id: 'c6' }, { upvotes: 3 });

const res = await client.query(QUERY, { variables: { postId: 'p1' } });
expect(res.errors).toBeFalsy();
expect(res.data.topComments).toHaveLength(3);
// Should be ordered by upvotes descending
expect(res.data.topComments[0].id).toEqual('c3');
expect(res.data.topComments[0].numUpvotes).toEqual(10);
expect(res.data.topComments[1].id).toEqual('c1');
expect(res.data.topComments[1].numUpvotes).toEqual(5);
expect(res.data.topComments[2].id).toEqual('c6');
expect(res.data.topComments[2].numUpvotes).toEqual(3);
});

it('should support querying by post slug', async () => {
// The slug is auto-generated from title and id: 'P1' + 'p1' -> 'p1-p1'
await con.getRepository(Comment).update({ id: 'c1' }, { upvotes: 5 });
await con.getRepository(Comment).update({ id: 'c3' }, { upvotes: 10 });

const res = await client.query(QUERY, {
variables: { postId: 'p1-p1' },
});
expect(res.errors).toBeFalsy();
expect(res.data.topComments).toHaveLength(3);
expect(res.data.topComments[0].id).toEqual('c3');
expect(res.data.topComments[0].numUpvotes).toEqual(10);
});
});

describe('query commentFeed', () => {
const QUERY = `query CommentFeed($after: String, $first: Int) {
commentFeed(after: $after, first: $first) {
Expand Down
48 changes: 48 additions & 0 deletions src/schema/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,21 @@ export const typeDefs = /* GraphQL */ `
"""
id: ID!
): CommentBalance!

"""
Get top comments of a post ordered by upvotes
"""
topComments(
"""
Post id
"""
postId: ID!

"""
Number of comments to return (max 20)
"""
first: Int
): [Comment!]!
}

extend type Mutation {
Expand Down Expand Up @@ -521,6 +536,11 @@ export interface GQLUserCommentsArgs extends ConnectionArguments {
userId: string;
}

export interface GQLTopCommentsArgs {
postId: string;
first?: number;
}

export interface MentionedUser {
id: string;
username?: string;
Expand Down Expand Up @@ -986,6 +1006,34 @@ export const resolvers: IResolvers<unknown, BaseContext> = traceResolvers<

return result;
},
topComments: async (
_,
args: GQLTopCommentsArgs,
ctx: Context,
info,
): Promise<GQLComment[]> => {
const maxLimit = 20;
const limit = Math.min(args.first ?? maxLimit, maxLimit);

const post = await ctx.con.getRepository(Post).findOneOrFail({
select: ['id', 'sourceId'],
where: [{ id: args.postId }, { slug: args.postId }],
});
await ensureSourcePermissions(ctx, post.sourceId);

return graphorm.query<GQLComment>(ctx, info, (builder) => {
builder.queryBuilder = builder.queryBuilder
.andWhere(`${builder.alias}.postId = :postId`, {
postId: post.id,
})
.andWhere(`${builder.alias}.parentId is null`)
.andWhere(whereVordrFilter(builder.alias, ctx.userId))
.orderBy(`${builder.alias}.upvotes`, 'DESC')
.limit(limit);

return builder;
});
},
},
Mutation: {
commentOnPost: async (
Expand Down
Loading