reacted_shouts_updates-fix

This commit is contained in:
Untone 2024-01-23 04:58:45 +03:00
parent 43f0c517b3
commit ce5077a529
2 changed files with 63 additions and 50 deletions

View File

@ -4,6 +4,7 @@ import logging
from sqlalchemy import and_, asc, case, desc, func, select, text, or_ from sqlalchemy import and_, asc, case, desc, func, select, text, or_
from sqlalchemy.orm import aliased, joinedload from sqlalchemy.orm import aliased, joinedload
from sqlalchemy.sql import union
from orm.author import Author from orm.author import Author
from orm.reaction import Reaction, ReactionKind from orm.reaction import Reaction, ReactionKind
@ -408,13 +409,17 @@ async def load_reactions_by(_, info, by, limit=50, offset=0):
reaction, reaction,
author, author,
shout, shout,
reacted_stat,
commented_stat, commented_stat,
rating_stat, likes_stat,
dislikes_stat,
_last_comment
] in result_rows: ] in result_rows:
reaction.created_by = author reaction.created_by = author
reaction.shout = shout 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) reactions.append(reaction)
# sort if by stat is present # 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] = [] shouts: List[Shout] = []
with local_session() as session: with local_session() as session:
author = session.query(Author).filter(Author.id == follower_id).first() author = session.query(Author).filter(Author.id == follower_id).first()
if author: if author:
# Shouts where follower is the author # Shouts where follower is the author
shouts_author, aliased_reaction = add_stat_columns( q1 = select(Shout).outerjoin(
session.query(Shout) Reaction, and_(Reaction.shout_id == Shout.id, Reaction.created_by == follower_id)
.outerjoin(Reaction, and_(Reaction.shout_id == Shout.id, Reaction.created_by == follower_id)) ).outerjoin(
.outerjoin(Author, Shout.authors.any(id=follower_id)) Author, Shout.authors.any(id=follower_id)
.options(joinedload(Shout.reactions), joinedload(Shout.authors)), ).options(
aliased(Reaction) joinedload(Shout.reactions),
).filter(Author.id == follower_id).group_by(Shout.id).all() 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 where follower reacted
shouts_reactions = ( q2 = (
session.query(Shout) select(Shout)
.join(Reaction, Reaction.shout_id == Shout.id) .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) .filter(Reaction.created_by == follower_id)
.group_by(Shout.id) .group_by(Shout.id)
.all()
) )
q2 = add_stat_columns(q2, aliased(Reaction))
# Combine shouts from both queries
shouts = list(set(shouts_author + shouts_reactions))
# Sort shouts by the `last_comment` field # Sort shouts by the `last_comment` field
shouts.sort(key=lambda shout: shout.last_comment, reverse=True) combined_query = union(q1, q2).order_by(desc("last_comment")).limit(limit).offset(offset)
results = session.execute(combined_query).scalars()
# Apply limit and offset with local_session() as session:
shouts = shouts[offset: offset + limit] 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 return shouts
@ -470,7 +491,7 @@ async def load_shouts_followed(_, info, limit=50, offset=0) -> List[Shout]:
if author: if author:
try: try:
author_id: int = author.dict()["id"] 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 return shouts
except Exception as error: except Exception as error:
logger.debug(error) logger.debug(error)

View File

@ -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): def get_shouts_from_query(q, author_id=None):
shouts = [] shouts = []
with local_session() as session: 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} q, {"author_id": author_id}
).unique(): ).unique():
shouts.append(shout) shouts.append(shout)
shout.stat = { shout.stat = {
"viewed": shout.views, "viewed": shout.views,
"reacted": reacted_stat,
"commented": commented_stat, "commented": commented_stat,
"rating": rating_stat, "rating": int(likes_stat or 0) - int(dislikes_stat or 0),
} }
return shouts 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 = select(Shout.id).outerjoin(aliased_reaction).where(Shout.deleted_at.is_(None))
subquery = apply_filters(subquery, options.get("filters", {})) subquery = apply_filters(subquery, options.get("filters", {}))
subquery = subquery.group_by(Shout.id).order_by(desc(func.sum( subquery = subquery.group_by(Shout.id).order_by(desc(get_rating_func(aliased_reaction)))
case(
(aliased_reaction.kind == str(ReactionKind.LIKE.value), 1),
(aliased_reaction.kind == str(ReactionKind.DISLIKE.value), -1),
else_=0,
)
)))
random_limit = options.get("random_limit") random_limit = options.get("random_limit")
if random_limit: if random_limit:
@ -405,23 +398,22 @@ async def load_shouts_random_top(_, _info, options):
) )
.where(Shout.id.in_(subquery)) .where(Shout.id.in_(subquery))
) )
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_stat_columns(q, aliased_reaction)
# Calculate the difference between likes_stat and dislikes_stat and use it for ordering limit = options.get("limit", 10)
q = q.group_by(Shout.id).order_by(desc(func.sum(aliased_reaction.likes_stat - aliased_reaction.dislikes_stat))).limit(limit) q = q.group_by(Shout.id).order_by(func.random()).limit(limit)
# print(q.compile(compile_kwargs={"literal_binds": True})) # print(q.compile(compile_kwargs={"literal_binds": True}))
return get_shouts_from_query(q) return get_shouts_from_query(q)
@query.field("load_shouts_random_topic") @query.field("load_shouts_random_topic")
async def load_shouts_random_topic(_, info, limit: int = 10): async def load_shouts_random_topic(_, info, limit: int = 10):
topic = get_random_topic() topic = get_random_topic()
shouts = []
if topic:
q = ( q = (
select(Shout) select(Shout)
.options( .options(