stat-refactored
All checks were successful
Deploy to core / deploy (push) Successful in 1m42s

This commit is contained in:
Untone 2024-02-23 02:08:43 +03:00
parent b0e2551e9b
commit 3d34c6c540
8 changed files with 87 additions and 208 deletions

View File

@ -10,7 +10,7 @@ from orm.reaction import Reaction, ReactionKind
from orm.shout import Shout, ShoutAuthor, ShoutTopic from orm.shout import Shout, ShoutAuthor, ShoutTopic
from orm.topic import Topic from orm.topic import Topic
from resolvers.follower import query_follows from resolvers.follower import query_follows
from resolvers.stat import get_authors_from_query, add_author_stat_columns from resolvers.stat import add_stat_columns, get_with_stat, unpack_stat
from services.auth import login_required from services.auth import login_required
from services.db import local_session from services.db import local_session
from services.rediscache import redis from services.rediscache import redis
@ -20,7 +20,7 @@ from services.logger import root_logger as logger
@mutation.field('update_author') @mutation.field('update_author')
@login_required @login_required
async def update_author(_, info, profile): def update_author(_, info, profile):
user_id = info.context['user_id'] user_id = info.context['user_id']
with local_session() as session: with local_session() as session:
author = session.query(Author).where(Author.user == user_id).first() author = session.query(Author).where(Author.user == user_id).first()
@ -32,7 +32,7 @@ async def update_author(_, info, profile):
# TODO: caching query # TODO: caching query
@query.field('get_authors_all') @query.field('get_authors_all')
async def get_authors_all(_, _info): def get_authors_all(_, _info):
authors = [] authors = []
with local_session() as session: with local_session() as session:
authors = session.query(Author).all() authors = session.query(Author).all()
@ -97,10 +97,8 @@ def count_author_shouts_rating(session, author_id) -> int:
return shouts_likes - shouts_dislikes return shouts_likes - shouts_dislikes
async def load_author_with_stats(q): def load_author_with_stats(q):
q = add_author_stat_columns(q) result = get_with_stat(q, Author, AuthorFollower)
result = await get_authors_from_query(q)
if result: if result:
[author] = result [author] = result
@ -140,7 +138,7 @@ async def load_author_with_stats(q):
@query.field('get_author') @query.field('get_author')
async def get_author(_, _info, slug='', author_id=None): def get_author(_, _info, slug='', author_id=None):
q = None q = None
if slug or author_id: if slug or author_id:
if bool(slug): if bool(slug):
@ -148,7 +146,7 @@ async def get_author(_, _info, slug='', author_id=None):
if author_id: if author_id:
q = select(Author).where(Author.id == author_id) q = select(Author).where(Author.id == author_id)
return await load_author_with_stats(q) return load_author_with_stats(q)
async def get_author_by_user_id(user_id: str): async def get_author_by_user_id(user_id: str):
@ -162,7 +160,7 @@ async def get_author_by_user_id(user_id: str):
logger.info(f'getting author id for {user_id}') logger.info(f'getting author id for {user_id}')
q = select(Author).filter(Author.user == user_id) q = select(Author).filter(Author.user == user_id)
author = await load_author_with_stats(q) author = load_author_with_stats(q)
if author: if author:
update_author(author) update_author(author)
return author return author
@ -174,9 +172,8 @@ async def get_author_id(_, _info, user: str):
@query.field('load_authors_by') @query.field('load_authors_by')
async def load_authors_by(_, _info, by, limit, offset): def load_authors_by(_, _info, by, limit, offset):
q = select(Author) q = select(Author)
q = add_author_stat_columns(q)
if by.get('slug'): if by.get('slug'):
q = q.filter(Author.slug.ilike(f"%{by['slug']}%")) q = q.filter(Author.slug.ilike(f"%{by['slug']}%"))
elif by.get('name'): elif by.get('name'):
@ -201,14 +198,14 @@ async def load_authors_by(_, _info, by, limit, offset):
q = q.order_by(desc(f'{order}_stat')) q = q.order_by(desc(f'{order}_stat'))
q = q.limit(limit).offset(offset) q = q.limit(limit).offset(offset)
q = q.group_by(Author.id)
authors = await get_authors_from_query(q) authors = get_with_stat(q, Author, AuthorFollower)
return authors return authors
@query.field('get_author_follows') @query.field('get_author_follows')
async def get_author_follows( def get_author_follows(
_, _info, slug='', user=None, author_id=None _, _info, slug='', user=None, author_id=None
) -> List[Author]: ) -> List[Author]:
with local_session() as session: with local_session() as session:
@ -228,7 +225,7 @@ async def get_author_follows(
@mutation.field('rate_author') @mutation.field('rate_author')
@login_required @login_required
async def rate_author(_, info, rated_slug, value): def rate_author(_, info, rated_slug, value):
user_id = info.context['user_id'] user_id = info.context['user_id']
with local_session() as session: with local_session() as session:
@ -262,7 +259,7 @@ async def rate_author(_, info, rated_slug, value):
return {} return {}
async def create_author(user_id: str, slug: str, name: str = ''): def create_author(user_id: str, slug: str, name: str = ''):
with local_session() as session: with local_session() as session:
new_author = Author(user=user_id, slug=slug, name=name) new_author = Author(user=user_id, slug=slug, name=name)
session.add(new_author) session.add(new_author)
@ -271,15 +268,15 @@ async def create_author(user_id: str, slug: str, name: str = ''):
@query.field('get_author_followers') @query.field('get_author_followers')
async def get_author_followers(_, _info, slug) -> List[Author]: def get_author_followers(_, _info, slug) -> List[Author]:
q = select(Author)
q = add_author_stat_columns(q)
aliased_author = aliased(Author) aliased_author = aliased(Author)
q = select(aliased_author)
q = ( q = (
q.join(AuthorFollower, AuthorFollower.follower == Author.id) q.join(AuthorFollower, AuthorFollower.follower == Author.id)
.join(aliased_author, aliased_author.id == AuthorFollower.author) .join(aliased_author, aliased_author.id == AuthorFollower.author)
.where(aliased_author.slug == slug) .where(aliased_author.slug == slug)
) )
q = add_stat_columns(q, aliased_author, AuthorFollower)
return await get_authors_from_query(q) q = q.group_by(aliased_author.id)
return unpack_stat(q)

View File

@ -14,7 +14,7 @@ from orm.shout import Shout, ShoutReactionsFollower
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from resolvers.community import community_follow, community_unfollow from resolvers.community import community_follow, community_unfollow
from resolvers.topic import topic_follow, topic_unfollow from resolvers.topic import topic_follow, topic_unfollow
from resolvers.stat import add_topic_stat_columns, get_topics_from_query, add_author_stat_columns from resolvers.stat import add_stat_columns, unpack_stat
from services.auth import login_required from services.auth import login_required
from services.db import local_session from services.db import local_session
from services.follows import DEFAULT_FOLLOWS from services.follows import DEFAULT_FOLLOWS
@ -110,55 +110,14 @@ def query_follows(user_id: str):
.filter(TopicFollower.topic == Topic.id) .filter(TopicFollower.topic == Topic.id)
) )
authors_query = add_author_stat_columns(authors_query) authors_query = add_stat_columns(authors_query, aliased_author, AuthorFollower)
topics_query = add_topic_stat_columns(topics_query) authors = unpack_stat(authors_query)
authors = [ topics_query = add_stat_columns(topics_query, aliased_author, TopicFollower)
{ authors = unpack_stat(topics_query)
'id': author_id,
'name': author.name,
'slug': author.slug,
'pic': author.pic,
'bio': author.bio,
'last_seen': author.last_seen or int(time.time()),
'stat': {
'shouts': shouts_stat,
'followers': followers_stat,
'followings': followings_stat, # TODO: rename to authors to
# TODO: use graphql to reserve universal type Stat { authors shouts followers views comments }
},
}
for [
author,
shouts_stat,
followers_stat,
followings_stat,
] in session.execute(authors_query)
]
topics = [
{
'id': topic.id,
'title': topic.title,
'slug': topic.slug,
'body': topic.body,
'stat': {
'shouts': shouts_stat,
'authors': authors_stat,
'followers': followers_stat,
},
}
for [
topic,
shouts_stat,
authors_stat,
followers_stat,
] in session.execute(topics_query)
]
return { return {
'topics': topics, 'topics': topics,
'authors': authors, 'authors': authors,
# Include other results (e.g., shouts) if needed
'communities': [{'id': 1, 'name': 'Дискурс', 'slug': 'discours'}], 'communities': [{'id': 1, 'name': 'Дискурс', 'slug': 'discours'}],
} }
@ -260,17 +219,17 @@ def author_unfollow(follower_id, slug):
@query.field('get_topic_followers') @query.field('get_topic_followers')
async def get_topic_followers(_, _info, slug: str, topic_id: int) -> List[Author]: def get_topic_followers(_, _info, slug: str, topic_id: int) -> List[Author]:
q = select(Author) q = select(Author)
q = add_topic_stat_columns(q)
q = ( q = (
q.join(TopicFollower, TopicFollower.follower == Author.id) q.join(TopicFollower, TopicFollower.follower == Author.id)
.join(Topic, Topic.id == TopicFollower.topic) .join(Topic, Topic.id == TopicFollower.topic)
.filter(or_(Topic.slug == slug, Topic.id == topic_id)) .filter(or_(Topic.slug == slug, Topic.id == topic_id))
) )
q = add_stat_columns(q, Author, TopicFollower)
q = q.group_by(Author.id)
return await get_topics_from_query(q) return unpack_stat(q)
@query.field('get_shout_followers') @query.field('get_shout_followers')

View File

@ -19,7 +19,7 @@ from services.viewed import ViewedStorage
from services.logger import root_logger as logger from services.logger import root_logger as logger
def add_stat_columns(q, aliased_reaction): def add_reaction_stat_columns(q, aliased_reaction):
q = q.outerjoin(aliased_reaction).add_columns( q = q.outerjoin(aliased_reaction).add_columns(
func.sum(aliased_reaction.id).label('reacted_stat'), func.sum(aliased_reaction.id).label('reacted_stat'),
func.sum( func.sum(
@ -229,7 +229,7 @@ async def update_reaction(_, info, reaction):
with local_session() as session: with local_session() as session:
reaction_query = select(Reaction).filter(Reaction.id == int(rid)) reaction_query = select(Reaction).filter(Reaction.id == int(rid))
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
reaction_query = add_stat_columns(reaction_query, aliased_reaction) reaction_query = add_reaction_stat_columns(reaction_query, aliased_reaction)
reaction_query = reaction_query.group_by(Reaction.id) reaction_query = reaction_query.group_by(Reaction.id)
try: try:
@ -358,7 +358,7 @@ async def load_reactions_by(_, info, by, limit=50, offset=0):
# calculate counters # calculate counters
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_stat_columns(q, aliased_reaction)
# filter # filter
q = apply_reaction_filters(by, q) q = apply_reaction_filters(by, q)
@ -425,7 +425,7 @@ async def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[S
.outerjoin(Author, Shout.authors.any(id=follower_id)) .outerjoin(Author, Shout.authors.any(id=follower_id))
.options(joinedload(Shout.reactions), joinedload(Shout.authors)) .options(joinedload(Shout.reactions), joinedload(Shout.authors))
) )
q1 = add_stat_columns(q1, aliased(Reaction)) q1 = add_reaction_stat_columns(q1, aliased(Reaction))
q1 = q1.filter(Author.id == follower_id).group_by(Shout.id) q1 = q1.filter(Author.id == follower_id).group_by(Shout.id)
# Shouts where follower reacted # Shouts where follower reacted
@ -436,7 +436,7 @@ async def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[S
.filter(Reaction.created_by == follower_id) .filter(Reaction.created_by == follower_id)
.group_by(Shout.id) .group_by(Shout.id)
) )
q2 = add_stat_columns(q2, aliased(Reaction)) q2 = add_reaction_stat_columns(q2, aliased(Reaction))
# Sort shouts by the `last_comment` field # Sort shouts by the `last_comment` field
combined_query = ( combined_query = (

View File

@ -7,7 +7,7 @@ from orm.author import Author, AuthorFollower
from orm.reaction import Reaction, ReactionKind from orm.reaction import Reaction, ReactionKind
from orm.shout import Shout, ShoutAuthor, ShoutTopic from orm.shout import Shout, ShoutAuthor, ShoutTopic
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from resolvers.reaction import add_stat_columns from resolvers.reaction import add_reaction_stat_columns
from resolvers.topic import get_random_topic from resolvers.topic import get_random_topic
from services.auth import login_required from services.auth import login_required
from services.db import local_session from services.db import local_session
@ -46,7 +46,7 @@ async def get_shout(_, _info, slug=None, shout_id=None):
with local_session() as session: with local_session() as session:
q = select(Shout).options(joinedload(Shout.authors), joinedload(Shout.topics)) q = select(Shout).options(joinedload(Shout.authors), joinedload(Shout.topics))
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_stat_columns(q, aliased_reaction)
if slug is not None: if slug is not None:
q = q.filter(Shout.slug == slug) q = q.filter(Shout.slug == slug)
@ -133,7 +133,7 @@ async def load_shouts_by(_, _info, options):
# stats # stats
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_stat_columns(q, aliased_reaction)
# filters # filters
filters = options.get('filters', {}) filters = options.get('filters', {})
@ -269,7 +269,7 @@ async def load_shouts_feed(_, info, options):
) )
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_stat_columns(q, aliased_reaction)
filters = options.get('filters', {}) filters = options.get('filters', {})
q = apply_filters(q, filters, reader.id) q = apply_filters(q, filters, reader.id)
@ -366,7 +366,7 @@ async def load_shouts_unrated(_, info, limit: int = 50, offset: int = 0):
q = q.having(func.count(distinct(Reaction.id)) <= 4) q = q.having(func.count(distinct(Reaction.id)) <= 4)
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_stat_columns(q, aliased_reaction)
q = q.group_by(Shout.id).order_by(func.random()).limit(limit).offset(offset) q = q.group_by(Shout.id).order_by(func.random()).limit(limit).offset(offset)
user_id = info.context.get('user_id') user_id = info.context.get('user_id')
@ -450,7 +450,7 @@ 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_reaction_stat_columns(q, aliased_reaction)
limit = options.get('limit', 10) limit = options.get('limit', 10)
q = q.group_by(Shout.id).order_by(func.random()).limit(limit) q = q.group_by(Shout.id).order_by(func.random()).limit(limit)
@ -486,7 +486,7 @@ def fetch_shouts_by_topic(topic, limit):
) )
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
q = add_stat_columns(q, aliased_reaction) q = add_reaction_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)

View File

@ -1,81 +1,36 @@
from sqlalchemy import func, distinct from sqlalchemy import func, distinct
from sqlalchemy.orm import aliased
from orm.author import Author, AuthorFollower
from orm.shout import ShoutAuthor, ShoutTopic
from orm.topic import Topic, TopicFollower
from services.db import local_session from services.db import local_session
# from services.viewed import ViewedStorage from orm.author import AuthorFollower
from orm.shout import ShoutTopic, ShoutAuthor
def add_author_stat_columns(q): def add_stat_columns(q, author_alias, follower_model_alias):
shout_author_aliased = aliased(ShoutAuthor) shouts_stat_model = ShoutAuthor if isinstance(follower_model_alias, AuthorFollower) else ShoutTopic
q = q.outerjoin(shout_author_aliased).add_columns( q = q.outerjoin(shouts_stat_model).add_columns(func.count(distinct(shouts_stat_model.shout)).label('shouts_stat'))
func.count(distinct(shout_author_aliased.shout)).label('shouts_stat')
)
authors_table = aliased(AuthorFollower)
q = q.outerjoin( q = q.outerjoin(
authors_table, authors_table.follower == Author.id follower_model_alias, follower_model_alias.follower == author_alias.id
).add_columns(func.count(distinct(authors_table.author)).label('authors_stat')) ).add_columns(func.count(distinct(follower_model_alias.author)).label('authors_stat'))
q = q.outerjoin(follower_model_alias, follower_model_alias.author == author_alias.id).add_columns(
followers_table = aliased(AuthorFollower) func.count(distinct(follower_model_alias.follower)).label('followers_stat')
q = q.outerjoin(followers_table, followers_table.author == Author.id).add_columns(
func.count(distinct(followers_table.follower)).label('followers_stat')
) )
q = q.group_by(Author.id)
return q return q
async def get_authors_from_query(q): def unpack_stat(q):
authors = [] records = []
with local_session() as session: with local_session() as session:
for [author, shouts_stat, authors_stat, followers_stat] in session.execute(q): for [entity, shouts_stat, authors_stat, followers_stat] in session.execute(q):
author.stat = { entity.stat = {
'shouts': shouts_stat,
'followers': followers_stat,
'followings': authors_stat,
# viewed
}
authors.append(author)
return authors
def add_topic_stat_columns(q):
aliased_shout_author = aliased(ShoutAuthor)
aliased_topic_follower = aliased(TopicFollower)
q = (
q.outerjoin(ShoutTopic, Topic.id == ShoutTopic.topic)
.add_columns(func.count(distinct(ShoutTopic.shout)).label('shouts_stat'))
.outerjoin(aliased_shout_author, ShoutTopic.shout == aliased_shout_author.shout)
.add_columns(
func.count(distinct(aliased_shout_author.author)).label('authors_stat')
)
.outerjoin(aliased_topic_follower)
.add_columns(
func.count(distinct(aliased_topic_follower.follower)).label(
'followers_stat'
)
)
)
q = q.group_by(Topic.id)
return q
async def get_topics_from_query(q):
topics = []
with local_session() as session:
for [topic, shouts_stat, authors_stat, followers_stat] in session.execute(q):
topic.stat = {
'shouts': shouts_stat, 'shouts': shouts_stat,
'authors': authors_stat, 'authors': authors_stat,
'followers': followers_stat, 'followers': followers_stat
# 'viewed': await ViewedStorage.get_topic(topic.slug),
} }
topics.append(topic) records.append(entity)
return topics return records
def get_with_stat(q, author_alias, follower_model_alias):
q = add_stat_columns(q, author_alias, follower_model_alias)
return unpack_stat(q)

View File

@ -3,7 +3,7 @@ from sqlalchemy import and_, distinct, func, select
from orm.author import Author from orm.author import Author
from orm.shout import ShoutTopic from orm.shout import ShoutTopic
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from resolvers.stat import add_topic_stat_columns, get_topics_from_query from resolvers.stat import get_with_stat
from services.auth import login_required from services.auth import login_required
from services.db import local_session from services.db import local_session
from services.schema import mutation, query from services.schema import mutation, query
@ -11,33 +11,24 @@ from services.logger import root_logger as logger
@query.field('get_topics_all') @query.field('get_topics_all')
async def get_topics_all(_, _info): def get_topics_all(_, _info):
q = select(Topic) q = select(Topic)
q = add_topic_stat_columns(q) q = q.group_by(Topic.id)
topics = get_with_stat(q, Author, TopicFollower)
return await get_topics_from_query(q) return topics
async def topics_followed_by(author_id):
q = select(Topic, TopicFollower)
q = add_topic_stat_columns(q)
q = q.join(TopicFollower).where(TopicFollower.follower == author_id)
return await get_topics_from_query(q)
@query.field('get_topics_by_community') @query.field('get_topics_by_community')
async def get_topics_by_community(_, _info, community_id: int): async def get_topics_by_community(_, _info, community_id: int):
q = select(Topic).where(Topic.community == community_id) q = select(Topic).where(Topic.community == community_id)
q = add_topic_stat_columns(q) q = q.group_by(Topic.id)
topics = await get_with_stat(q, Author, TopicFollower)
return await get_topics_from_query(q) return topics
@query.field('get_topics_by_author') @query.field('get_topics_by_author')
async def get_topics_by_author(_, _info, author_id=None, slug='', user=''): async def get_topics_by_author(_, _info, author_id=None, slug='', user=''):
q = select(Topic) q = select(Topic)
q = add_topic_stat_columns(q)
if author_id: if author_id:
q = q.join(Author).where(Author.id == author_id) q = q.join(Author).where(Author.id == author_id)
elif slug: elif slug:
@ -45,15 +36,16 @@ async def get_topics_by_author(_, _info, author_id=None, slug='', user=''):
elif user: elif user:
q = q.join(Author).where(Author.user == user) q = q.join(Author).where(Author.user == user)
return await get_topics_from_query(q) q = q.group_by(Topic.id)
topics = await get_with_stat(q, Author, TopicFollower)
return topics
@query.field('get_topic') @query.field('get_topic')
async def get_topic(_, _info, slug): async def get_topic(_, _info, slug):
q = select(Topic).where(Topic.slug == slug) q = select(Topic).filter(Topic.slug == slug)
q = add_topic_stat_columns(q) q = q.group_by(Topic.id)
topics = await get_with_stat(q, Author, TopicFollower)
topics = await get_topics_from_query(q)
if topics: if topics:
return topics[0] return topics[0]

View File

@ -1,14 +1,6 @@
type AuthorFollowings {
unread: Int
topics: [String]
authors: [String]
reactions: [Int]
communities: [String]
}
type AuthorStat { type AuthorStat {
shouts: Int shouts: Int
followings: Int authors: Int
followers: Int followers: Int
rating: Int rating: Int
rating_shouts: Int rating_shouts: Int

View File

@ -5,7 +5,7 @@ import json
from orm.author import Author, AuthorFollower from orm.author import Author, AuthorFollower
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from resolvers.stat import add_author_stat_columns, add_topic_stat_columns from resolvers.stat import get_with_stat
from services.rediscache import redis from services.rediscache import redis
@ -17,6 +17,7 @@ DEFAULT_FOLLOWS = {
], ],
} }
async def update_author(author: Author, ttl = 25 * 60 * 60): async def update_author(author: Author, ttl = 25 * 60 * 60):
redis_key = f'user:{author.user}:author' redis_key = f'user:{author.user}:author'
await redis.execute('SETEX', redis_key, ttl, json.dumps(author.dict())) await redis.execute('SETEX', redis_key, ttl, json.dumps(author.dict()))
@ -77,23 +78,15 @@ async def update_follows_for_user(
async def handle_author_follower_change(connection, author_id, follower_id, is_insert): async def handle_author_follower_change(connection, author_id, follower_id, is_insert):
q = select(Author).filter(Author.id == author_id) q = select(Author).filter(Author.id == author_id)
q = add_author_stat_columns(q) authors = get_with_stat(q, Author, AuthorFollower)
author = authors[0]
async with connection.begin() as conn: async with connection.begin() as conn:
[author, shouts_stat, followers_stat, followings_stat] = await conn.execute(
q
).first()
author.stat = {
'shouts': shouts_stat,
# 'viewed': await ViewedStorage.get_author(author.slug),
'followers': followers_stat,
'followings': followings_stat,
}
follower = await conn.execute( follower = await conn.execute(
select(Author).filter(Author.id == follower_id) select(Author).filter(Author.id == follower_id)
).first() ).first()
if follower and author: if follower and author:
await update_follows_for_user( await update_follows_for_user(
connection, conn,
follower.user, follower.user,
'author', 'author',
{ {
@ -110,23 +103,14 @@ async def handle_author_follower_change(connection, author_id, follower_id, is_i
async def handle_topic_follower_change(connection, topic_id, follower_id, is_insert): async def handle_topic_follower_change(connection, topic_id, follower_id, is_insert):
q = select(Topic).filter(Topic.id == topic_id) q = select(Topic).filter(Topic.id == topic_id)
q = add_topic_stat_columns(q) topics = get_with_stat(q, Author, TopicFollower)
topic = topics[0]
async with connection.begin() as conn: async with connection.begin() as conn:
[topic, shouts_stat, authors_stat, followers_stat] = await conn.execute( follower = conn.execute(select(Author).filter(Author.id == follower_id)).first()
q
).first()
topic.stat = {
'shouts': shouts_stat,
'authors': authors_stat,
'followers': followers_stat,
# 'viewed': await ViewedStorage.get_topic(topic.slug),
}
follower = connection.execute(
select(Author).filter(Author.id == follower_id)
).first()
if follower and topic: if follower and topic:
await update_follows_for_user( await update_follows_for_user(
connection, conn,
follower.user, follower.user,
'topic', 'topic',
{ {