From 5e72a08e0f0b9ff6bf013d1dce7680b2b62ed032 Mon Sep 17 00:00:00 2001 From: Untone Date: Sat, 24 Feb 2024 20:42:19 +0300 Subject: [PATCH] circular-fix-2 --- resolvers/follower.py | 2 +- services/{follows.py => event_listeners.py} | 59 ++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) rename services/{follows.py => event_listeners.py} (67%) diff --git a/resolvers/follower.py b/resolvers/follower.py index 815f9dc1..6c41a6ec 100644 --- a/resolvers/follower.py +++ b/resolvers/follower.py @@ -16,7 +16,7 @@ from resolvers.topic import topic_follow, topic_unfollow from resolvers.stat import get_authors_with_stat, query_follows from services.auth import login_required from services.db import local_session -from services.follows import DEFAULT_FOLLOWS +from services.event_listeners import DEFAULT_FOLLOWS from services.notify import notify_follower from services.schema import mutation, query from services.logger import root_logger as logger diff --git a/services/follows.py b/services/event_listeners.py similarity index 67% rename from services/follows.py rename to services/event_listeners.py index b0fc9727..6200fd6b 100644 --- a/services/follows.py +++ b/services/event_listeners.py @@ -1,9 +1,11 @@ import asyncio -from sqlalchemy import select, event +from sqlalchemy import select, event, or_, exists, and_ import json from orm.author import Author, AuthorFollower +from orm.reaction import Reaction +from orm.shout import ShoutAuthor, Shout from orm.topic import Topic, TopicFollower from resolvers.stat import get_authors_with_stat, get_topics_with_stat from services.rediscache import redis @@ -22,6 +24,61 @@ async def update_author_cache(author: Author, ttl=25 * 60 * 60): await redis.execute('SETEX', f'id:{author.user}:author', ttl, payload) +@event.listens_for(Shout, 'after_insert') +@event.listens_for(Shout, 'after_update') +def after_shouts_update(mapper, connection, shout: Shout): + # Создаем подзапрос для проверки наличия авторов в списке shout.authors + subquery = ( + select(1) + .where(or_( + Author.id == int(shout.created_by), + and_( + Shout.id == shout.id, + ShoutAuthor.shout == Shout.id, + ShoutAuthor.author == Author.id + ) + )) + ) + + # Основной запрос с использованием объединения и подзапроса exists + authors_query = ( + select(Author) + .join(ShoutAuthor, Author.id == int(ShoutAuthor.author)) + .where(ShoutAuthor.shout == int(shout.id)) + .union( + select(Author) + .where(exists(subquery)) + ) + ) + authors = get_authors_with_stat(authors_query, ratings=True) + for author in authors: + asyncio.create_task(update_author_cache(author)) + + +@event.listens_for(Reaction, 'after_insert') +def after_reaction_insert(mapper, connection, reaction: Reaction): + author_subquery = ( + select(Author) + .where(Author.id == int(reaction.created_by)) + ) + replied_author_subquery = ( + select(Author) + .join(Reaction, Author.id == int(Reaction.created_by)) + .where(Reaction.id == int(reaction.reply_to)) + ) + + author_query = author_subquery.union(replied_author_subquery) + authors = get_authors_with_stat(author_query, ratings=True) + + for author in authors: + asyncio.create_task(update_author_cache(author)) + + shout = connection.execute(select(Shout).where(Shout.id == int(reaction.shout))).first() + if shout: + after_shouts_update(mapper, connection, shout) + + + @event.listens_for(Author, 'after_insert') @event.listens_for(Author, 'after_update') def after_author_update(mapper, connection, author: Author):