diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index 0b6ad976d..23f7eb29d 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -1,4 +1,5 @@ const util = require('./util'); +const DataLoader = require('dataloader'); const CommentModel = require('../../models/comment'); @@ -135,6 +136,95 @@ const getCommentsByQuery = ({user}, {ids, statuses, asset_id, parent_id, author_ .limit(limit); }; +const genRecentReplies = (_, ids) => { + return CommentModel.aggregate([ + + // get all the replies for the comments in question + {$match: { + parent_id: { + $in: ids + } + }}, + + // sort these by their created at timestamp, CHRONOLOGICAL'y as these are + // replies + {$sort: { + created_at: 1 + }}, + + // group these replies by their parent_id + {$group: { + _id: '$parent_id', + replies: { + $push: '$$ROOT' + } + }}, + + // project it so that we only retain the first 3 replies of each parent + // comment + {$project: { + _id: '$_id', + replies: { + $slice: [ + '$replies', + 0, + 3 + ] + } + }}, + + {$unwind: '$replies'}, + + ]) + .then((replies) => replies.map((reply) => reply.replies)) + .then(util.arrayJoinBy(ids, 'parent_id')); +}; + +const genRecentComments = (_, ids) => { + return CommentModel.aggregate([ + + // get all the replies for the comments in question + {$match: { + asset_id: { + $in: ids + } + }}, + + // sort these by their created at timestamp, CHRONOLOGICAL'y as these are + // replies + {$sort: { + created_at: 1 + }}, + + // group these replies by their parent_id + {$group: { + _id: '$asset_id', + comments: { + $push: '$$ROOT' + } + }}, + + // project it so that we only retain the first 3 replies of each parent + // comment + {$project: { + _id: '$_id', + comments: { + $slice: [ + '$comments', + 0, + 3 + ] + } + }}, + + // Unwind these comments. + {$unwind: '$comments'}, + + ]) + .then((replies) => replies.map((reply) => reply.comments)) + .then(util.arrayJoinBy(ids, 'asset_id')); +}; + /** * Creates a set of loaders based on a GraphQL context. * @param {Object} context the context of the GraphQL request @@ -144,6 +234,8 @@ module.exports = (context) => ({ Comments: { getByQuery: (query) => getCommentsByQuery(context, query), countByAssetID: new util.SharedCacheDataLoader('Comments.countByAssetID', 3600, (ids) => getCountsByAssetID(context, ids)), - countByParentID: new util.SharedCacheDataLoader('Comments.countByParentID', 3600, (ids) => getCountsByParentID(context, ids)) + countByParentID: new util.SharedCacheDataLoader('Comments.countByParentID', 3600, (ids) => getCountsByParentID(context, ids)), + genRecentReplies: new DataLoader((ids) => genRecentReplies(context, ids)), + genRecentComments: new DataLoader((ids) => genRecentComments(context, ids)) } }); diff --git a/graph/resolvers/asset.js b/graph/resolvers/asset.js index 60b44fa62..2077b9e7a 100644 --- a/graph/resolvers/asset.js +++ b/graph/resolvers/asset.js @@ -1,4 +1,7 @@ const Asset = { + recentComments({id}, _, {loaders: {Comments}}) { + return Comments.genRecentComments.load(id); + }, comments({id}, {sort, limit}, {loaders: {Comments}}) { return Comments.getByQuery({ asset_id: id, diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index b3d79225e..110067174 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -2,6 +2,9 @@ const Comment = { user({author_id}, _, {loaders: {Users}}) { return Users.getByID.load(author_id); }, + recentReplies({id}, _, {loaders: {Comments}}) { + return Comments.genRecentReplies.load(id); + }, replies({id, asset_id}, {sort, limit}, {loaders: {Comments}}) { return Comments.getByQuery({ asset_id, diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index b1f9b82f7..8369b93c6 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -72,6 +72,9 @@ type Comment { # the user who authored the comment. user: User + # the recent replies made against this comment. + recentReplies: [Comment] + # the replies that were made to the comment. replies(sort: SORT_ORDER = CHRONOLOGICAL, limit: Int = 3): [Comment] @@ -148,6 +151,9 @@ type Asset { # The URL that the asset is located on. url: String + # Returns recent comments + recentComments: [Comment] + # The top level comments that are attached to the asset. comments(sort: SORT_ORDER = REVERSE_CHRONOLOGICAL, limit: Int = 10): [Comment]