diff --git a/resolvers/__init__.py b/resolvers/__init__.py index 66ed0eb7..18f811f9 100644 --- a/resolvers/__init__.py +++ b/resolvers/__init__.py @@ -26,6 +26,8 @@ from resolvers.reaction import ( load_shouts_followed, load_shouts_followed_by, update_reaction, + load_shout_comments, + load_shout_ratings ) from resolvers.reader import ( get_shout, @@ -36,7 +38,7 @@ from resolvers.reader import ( load_shouts_search, load_shouts_unrated, load_shouts_coauthored, - load_shouts_discussed, + load_shouts_discussed ) from resolvers.topic import ( get_topic, @@ -98,6 +100,8 @@ __all__ = [ "update_reaction", "delete_reaction", "load_reactions_by", + "load_shout_comments", + "load_shout_ratings", # notifier "load_notifications", "notifications_seen_thread", diff --git a/resolvers/reaction.py b/resolvers/reaction.py index 14ea8881..a24b55e6 100644 --- a/resolvers/reaction.py +++ b/resolvers/reaction.py @@ -21,15 +21,15 @@ from services.viewed import ViewedStorage def add_reaction_stat_columns(q, aliased_reaction): - q = q.outerjoin(aliased_reaction).add_columns( + q = q.outerjoin(aliased_reaction, aliased_reaction.deleted_at.is_(None)).add_columns( func.sum(aliased_reaction.id).label("reacted_stat"), func.sum(case((aliased_reaction.kind == str(ReactionKind.COMMENT.value), 1), else_=0)).label("comments_stat"), func.sum(case((aliased_reaction.kind == str(ReactionKind.LIKE.value), 1), else_=0)).label("likes_stat"), func.sum(case((aliased_reaction.kind == str(ReactionKind.DISLIKE.value), 1), else_=0)).label("dislikes_stat"), func.max( case( - (aliased_reaction.kind != str(ReactionKind.COMMENT.value), None), - else_=aliased_reaction.created_at, + (aliased_reaction.kind == str(ReactionKind.COMMENT.value), aliased_reaction.created_at), + else_=None, ) ).label("last_comment_stat"), ) @@ -37,6 +37,8 @@ def add_reaction_stat_columns(q, aliased_reaction): return q + + def is_featured_author(session, author_id): """checks if author has at least one featured publication""" return ( @@ -432,7 +434,7 @@ async def load_reactions_by(_, info, by, limit=50, offset=0): "reacted": reacted_stat, "commented": commented_stat, } - reactions.add(reaction) # Используем список для хранения реакций + reactions.add(reaction) return reactions @@ -447,7 +449,7 @@ async def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[S select(Shout) .outerjoin( Reaction, - and_(Reaction.shout == Shout.id, Reaction.created_by == follower_id), + and_(Reaction.shout == Shout.id, Reaction.created_by == follower_id, Reaction.deleted_at.is_(None)), ) .outerjoin(Author, Shout.authors.any(id=follower_id)) .options(joinedload(Shout.reactions), joinedload(Shout.authors)) @@ -460,7 +462,7 @@ async def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[S select(Shout) .join(Reaction, Reaction.shout == Shout.id) .options(joinedload(Shout.reactions), joinedload(Shout.authors)) - .filter(Reaction.created_by == follower_id) + .filter(and_(Reaction.created_by == follower_id, Reaction.deleted_at.is_(None))) .group_by(Shout.id) ) q2 = add_reaction_stat_columns(q2, aliased(Reaction)) @@ -517,3 +519,96 @@ async def load_shouts_followed_by(_, info, slug: str, limit=50, offset=0) -> Lis except Exception as error: logger.debug(error) return [] + + + +@query.field("load_shout_ratings") +async def load_shout_ratings(_, info, shout: int, limit=100, offset=0): + """ + get paginated reactions with no stats + :param info: graphql meta + :param shout: int shout id + :param limit: int amount of shouts + :param offset: int offset in this order + :return: Reaction[] + """ + + q = ( + select(Reaction, Author, Shout) + .select_from(Reaction) + .join(Author, Reaction.created_by == Author.id) + .join(Shout, Reaction.shout == Shout.id) + ) + + # filter, group, order, limit, offset + q = q.filter(and_(Reaction.deleted_at.is_(None), Reaction.shout == shout, Reaction.kind.in_(RATING_REACTIONS))) + q = q.group_by(Reaction.id) + q = q.order_by(desc(Reaction.created_at)) + q = q.limit(limit).offset(offset) + + reactions = set() + with local_session() as session: + result_rows = session.execute(q) + for [ + reaction, + author, + shout, + ] in result_rows: + reaction.created_by = author + reaction.shout = shout + reactions.add(reaction) + + return reactions + + +@query.field("load_shout_comments") +async def load_shout_comments(_, info, shout: int, limit=50, offset=0): + """ + getting paginated comments with stats + :param info: graphql meta + :param shout: int shout id + :param limit: int amount of shouts + :param offset: int offset in this order + :return: Reaction[] + """ + + q = ( + select(Reaction, Author, Shout) + .select_from(Reaction) + .join(Author, Reaction.created_by == Author.id) + .join(Shout, Reaction.shout == Shout.id) + ) + + # calculate counters + aliased_reaction = aliased(Reaction) + q = add_reaction_stat_columns(q, aliased_reaction) + + # filter, group, order, limit, offset + q = q.filter(and_(Reaction.deleted_at.is_(None), Reaction.shout == shout, Reaction.body.is_not(None))) + q = q.group_by(Reaction.id) + q = q.order_by(desc(Reaction.created_at)) + q = q.limit(limit).offset(offset) + + reactions = set() + with local_session() as session: + result_rows = session.execute(q) + for [ + reaction, + author, + shout, + reacted_stat, + commented_stat, + likes_stat, + dislikes_stat, + _last_comment, + ] in result_rows: + reaction.created_by = author + reaction.shout = shout + reaction.stat = { + "rating": int(likes_stat or 0) - int(dislikes_stat or 0), + "reacted": reacted_stat, + "commented": commented_stat, + } + reactions.add(reaction) + + return reactions diff --git a/schema/query.graphql b/schema/query.graphql index ccaee9bd..f688c5ca 100644 --- a/schema/query.graphql +++ b/schema/query.graphql @@ -27,6 +27,8 @@ type Query { # reader get_shout(slug: String): Shout load_shouts_by(options: LoadShoutsOptions): [Shout] + load_shout_comments(shout: Int!, limit: Int, offset: Int): [Reaction] + load_shout_ratings(shout: Int!, limit: Int, offset: Int): [Reaction] load_shouts_search(text: String!, limit: Int, offset: Int): [SearchResult] load_shouts_feed(options: LoadShoutsOptions): [Shout] load_shouts_unrated(limit: Int, offset: Int): [Shout]