From ce5077a5290a79f20ff85f07303ae3ad4d1ebc12 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 23 Jan 2024 04:58:45 +0300 Subject: [PATCH] reacted_shouts_updates-fix --- resolvers/reaction.py | 69 ++++++++++++++++++++++++++++--------------- resolvers/reader.py | 44 +++++++++++---------------- 2 files changed, 63 insertions(+), 50 deletions(-) diff --git a/resolvers/reaction.py b/resolvers/reaction.py index f80a8a7e..eaa854e6 100644 --- a/resolvers/reaction.py +++ b/resolvers/reaction.py @@ -4,6 +4,7 @@ import logging from sqlalchemy import and_, asc, case, desc, func, select, text, or_ from sqlalchemy.orm import aliased, joinedload +from sqlalchemy.sql import union from orm.author import Author from orm.reaction import Reaction, ReactionKind @@ -408,13 +409,17 @@ async def load_reactions_by(_, info, by, limit=50, offset=0): reaction, author, shout, - reacted_stat, commented_stat, - rating_stat, + likes_stat, + dislikes_stat, + _last_comment ] in result_rows: reaction.created_by = author reaction.shout = shout - reaction.stat = {"rating": rating_stat, "commented": commented_stat, "reacted": reacted_stat} + reaction.stat = { + "rating": int(likes_stat or 0) - int(dislikes_stat or 0), + "commented": commented_stat + } reactions.append(reaction) # sort if by stat is present @@ -426,38 +431,54 @@ async def load_reactions_by(_, info, by, limit=50, offset=0): -def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[Shout]: +async def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[Shout]: shouts: List[Shout] = [] with local_session() as session: author = session.query(Author).filter(Author.id == follower_id).first() if author: # Shouts where follower is the author - shouts_author, aliased_reaction = add_stat_columns( - session.query(Shout) - .outerjoin(Reaction, and_(Reaction.shout_id == Shout.id, Reaction.created_by == follower_id)) - .outerjoin(Author, Shout.authors.any(id=follower_id)) - .options(joinedload(Shout.reactions), joinedload(Shout.authors)), - aliased(Reaction) - ).filter(Author.id == follower_id).group_by(Shout.id).all() + q1 = select(Shout).outerjoin( + Reaction, and_(Reaction.shout_id == Shout.id, Reaction.created_by == follower_id) + ).outerjoin( + Author, Shout.authors.any(id=follower_id) + ).options( + joinedload(Shout.reactions), + joinedload(Shout.authors) + ) + q1 = add_stat_columns(q1, aliased(Reaction)) + q1 = q1.filter(Author.id == follower_id).group_by(Shout.id) - # Shouts where follower has reactions - shouts_reactions = ( - session.query(Shout) + # Shouts where follower reacted + q2 = ( + select(Shout) .join(Reaction, Reaction.shout_id == Shout.id) - .options(joinedload(Shout.reactions), joinedload(Shout.authors)) + .options( + joinedload(Shout.reactions), + joinedload(Shout.authors) + ) .filter(Reaction.created_by == follower_id) .group_by(Shout.id) - .all() ) - - # Combine shouts from both queries - shouts = list(set(shouts_author + shouts_reactions)) + q2 = add_stat_columns(q2, aliased(Reaction)) # Sort shouts by the `last_comment` field - shouts.sort(key=lambda shout: shout.last_comment, reverse=True) - - # Apply limit and offset - shouts = shouts[offset: offset + limit] + combined_query = union(q1, q2).order_by(desc("last_comment")).limit(limit).offset(offset) + results = session.execute(combined_query).scalars() + with local_session() as session: + for [ + shout, + commented_stat, + likes_stat, + dislikes_stat, + last_comment + ] in results: + shout.stat = { + "viewed": await ViewedStorage.get_shout(shot.slug), + "rating": int(likes_stat or 0) - int(dislikes_stat or 0), + "commented": commented_stat, + "last_comment": last_comment + } + shouts.append(shout) return shouts @@ -470,7 +491,7 @@ async def load_shouts_followed(_, info, limit=50, offset=0) -> List[Shout]: if author: try: author_id: int = author.dict()["id"] - shouts = reacted_shouts_updates(author_id, limit, offset) + shouts = await reacted_shouts_updates(author_id, limit, offset) return shouts except Exception as error: logger.debug(error) diff --git a/resolvers/reader.py b/resolvers/reader.py index e6617fad..8b8b6195 100644 --- a/resolvers/reader.py +++ b/resolvers/reader.py @@ -350,15 +350,14 @@ async def load_shouts_unrated(_, info, limit: int = 50, offset: int = 0): def get_shouts_from_query(q, author_id=None): shouts = [] with local_session() as session: - for [shout, reacted_stat, commented_stat, rating_stat, last_comment] in session.execute( + for [shout,commented_stat, likes_stat, dislikes_stat, last_comment] in session.execute( q, {"author_id": author_id} ).unique(): shouts.append(shout) shout.stat = { "viewed": shout.views, - "reacted": reacted_stat, "commented": commented_stat, - "rating": rating_stat, + "rating": int(likes_stat or 0) - int(dislikes_stat or 0), } return shouts @@ -385,13 +384,7 @@ async def load_shouts_random_top(_, _info, options): subquery = select(Shout.id).outerjoin(aliased_reaction).where(Shout.deleted_at.is_(None)) subquery = apply_filters(subquery, options.get("filters", {})) - subquery = subquery.group_by(Shout.id).order_by(desc(func.sum( - case( - (aliased_reaction.kind == str(ReactionKind.LIKE.value), 1), - (aliased_reaction.kind == str(ReactionKind.DISLIKE.value), -1), - else_=0, - ) - ))) + subquery = subquery.group_by(Shout.id).order_by(desc(get_rating_func(aliased_reaction))) random_limit = options.get("random_limit") if random_limit: @@ -405,37 +398,36 @@ async def load_shouts_random_top(_, _info, options): ) .where(Shout.id.in_(subquery)) ) - aliased_reaction = aliased(Reaction) q = add_stat_columns(q, aliased_reaction) - # Calculate the difference between likes_stat and dislikes_stat and use it for ordering - q = q.group_by(Shout.id).order_by(desc(func.sum(aliased_reaction.likes_stat - aliased_reaction.dislikes_stat))).limit(limit) + limit = options.get("limit", 10) + q = q.group_by(Shout.id).order_by(func.random()).limit(limit) # print(q.compile(compile_kwargs={"literal_binds": True})) return get_shouts_from_query(q) - @query.field("load_shouts_random_topic") async def load_shouts_random_topic(_, info, limit: int = 10): topic = get_random_topic() - - q = ( - select(Shout) - .options( - joinedload(Shout.authors), - joinedload(Shout.topics), + shouts = [] + if topic: + q = ( + select(Shout) + .options( + joinedload(Shout.authors), + joinedload(Shout.topics), + ) + .filter(and_(Shout.deleted_at.is_(None), Shout.visibility == "public", Shout.topics.any(slug=topic.slug))) ) - .filter(and_(Shout.deleted_at.is_(None), Shout.visibility == "public", Shout.topics.any(slug=topic.slug))) - ) - aliased_reaction = aliased(Reaction) - q = add_stat_columns(q, aliased_reaction) + aliased_reaction = aliased(Reaction) + q = add_stat_columns(q, aliased_reaction) - q = q.group_by(Shout.id).order_by(desc(Shout.created_at)).limit(limit) + q = q.group_by(Shout.id).order_by(desc(Shout.created_at)).limit(limit) - shouts = get_shouts_from_query(q) + shouts = get_shouts_from_query(q) return {"topic": topic, "shouts": shouts}