diff --git a/resolvers/author.py b/resolvers/author.py index 60672628..1a6a5619 100644 --- a/resolvers/author.py +++ b/resolvers/author.py @@ -95,46 +95,6 @@ def count_author_shouts_rating(session, author_id) -> int: return shouts_likes - shouts_dislikes -def load_author_ratings(author): - with local_session() as session: - comments_count = ( - session.query(Reaction) - .filter( - and_( - Reaction.created_by == author.id, - Reaction.kind == ReactionKind.COMMENT.value, - Reaction.deleted_at.is_(None), - ) - ) - .count() - ) - likes_count = ( - session.query(AuthorRating) - .filter( - and_(AuthorRating.author == author.id, AuthorRating.plus.is_(True)) - ) - .count() - ) - dislikes_count = ( - session.query(AuthorRating) - .filter( - and_( - AuthorRating.author == author.id, AuthorRating.plus.is_not(True) - ) - ) - .count() - ) - author.stat['rating'] = likes_count - dislikes_count - author.stat['rating_shouts'] = count_author_shouts_rating( - session, author.id - ) - author.stat['rating_comments'] = count_author_comments_rating( - session, author.id - ) - author.stat['commented'] = comments_count - return author - - @query.field('get_author') def get_author(_, _info, slug='', author_id=None): q = None @@ -146,14 +106,13 @@ def get_author(_, _info, slug='', author_id=None): if author_id: q = select(Author).where(Author.id == int(author_id)) - [author, ] = get_authors_with_stat(q) - author = load_author_ratings(author) + [author, ] = get_authors_with_stat(q, ratings=True) except Exception as exc: logger.error(exc) return author -async def get_author_by_user_id(user_id: str): +async def get_author_by_user_id(user_id: str, ratings=False): redis_key = f'user:{user_id}:author' author = None try: @@ -167,9 +126,7 @@ async def get_author_by_user_id(user_id: str): logger.info(f'getting author id for {user_id}') q = select(Author).filter(Author.user == user_id) - [author, ] = get_authors_with_stat(q) - author = load_author_ratings(author) - update_author(author) + [author, ] = get_authors_with_stat(q, ratings) except Exception as exc: logger.error(exc) return author @@ -177,7 +134,7 @@ async def get_author_by_user_id(user_id: str): @query.field('get_author_id') async def get_author_id(_, _info, user: str): - return await get_author_by_user_id(user) + return await get_author_by_user_id(user, ratings=True) @query.field('load_authors_by') @@ -207,7 +164,7 @@ def load_authors_by(_, _info, by, limit, offset): q = q.order_by(desc(f'{order}_stat')) q = q.limit(limit).offset(offset) - q = q.group_by(Author.id) + authors = get_authors_with_stat(q) return authors diff --git a/resolvers/stat.py b/resolvers/stat.py index c3f7cf64..cc268466 100644 --- a/resolvers/stat.py +++ b/resolvers/stat.py @@ -1,10 +1,15 @@ -from sqlalchemy import func, distinct, select, join +import asyncio + +from sqlalchemy import func, distinct, select, join, and_ from sqlalchemy.orm import aliased +from orm.reaction import Reaction, ReactionKind from orm.topic import TopicFollower, Topic +from resolvers.author import count_author_shouts_rating, count_author_comments_rating from services.db import local_session -from orm.author import AuthorFollower, Author +from orm.author import AuthorFollower, Author, AuthorRating from orm.shout import ShoutTopic, ShoutAuthor +from services.follows import update_author_cache from services.logger import root_logger as logger @@ -46,6 +51,46 @@ def add_author_stat_columns(q): return q +def load_author_ratings(author: Author): + with local_session() as session: + comments_count = ( + session.query(Reaction) + .filter( + and_( + Reaction.created_by == author.id, + Reaction.kind == ReactionKind.COMMENT.value, + Reaction.deleted_at.is_(None), + ) + ) + .count() + ) + likes_count = ( + session.query(AuthorRating) + .filter( + and_(AuthorRating.author == author.id, AuthorRating.plus.is_(True)) + ) + .count() + ) + dislikes_count = ( + session.query(AuthorRating) + .filter( + and_( + AuthorRating.author == author.id, AuthorRating.plus.is_not(True) + ) + ) + .count() + ) + author.stat['rating'] = likes_count - dislikes_count + author.stat['rating_shouts'] = count_author_shouts_rating( + session, author.id + ) + author.stat['rating_comments'] = count_author_comments_rating( + session, author.id + ) + author.stat['commented'] = comments_count + return author + + def execute_with_ministat(q): records = [] with local_session() as session: @@ -60,9 +105,16 @@ def execute_with_ministat(q): return records -def get_authors_with_stat(q): +def get_authors_with_stat(q, ratings=False): q = add_author_stat_columns(q) - return execute_with_ministat(q) + authors = execute_with_ministat(q) + if ratings: + authors_with_ratings = [] + for author in authors: + authors_with_ratings.append(load_author_ratings(author)) + _ = asyncio.create_task(update_author_cache(author)) + return authors_with_ratings + return authors def get_topics_with_stat(q): diff --git a/services/follows.py b/services/follows.py index 27d2c487..ca6919f5 100644 --- a/services/follows.py +++ b/services/follows.py @@ -16,18 +16,16 @@ DEFAULT_FOLLOWS = { } -async def update_author(author: Author, ttl=25 * 60 * 60): +async def update_author_cache(author: Author, ttl=25 * 60 * 60): payload = json.dumps(author.dict()) - redis_key = f'user:{author.user}:author' - await redis.execute('SETEX', redis_key, ttl, payload) - redis_key = f'author:{author.id}:author' - await redis.execute('SETEX', redis_key, ttl, payload) + await redis.execute('SETEX', f'user:{author.user}:author', ttl, payload) + await redis.execute('SETEX', f'id:{author.user}:author', ttl, payload) @event.listens_for(Author, 'after_insert') @event.listens_for(Author, 'after_update') def after_author_update(mapper, connection, author: Author): - asyncio.create_task(update_author(author)) + asyncio.create_task(update_author_cache(author)) @event.listens_for(TopicFollower, 'after_insert')