From 9c374d789ed440681f14589a6a6b0ed4a21996d6 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 7 Aug 2024 17:45:22 +0300 Subject: [PATCH] string_agg --- orm/reaction.py | 2 +- resolvers/reader.py | 45 ++++++++++++++++++++++++++------------------- resolvers/topic.py | 20 +++++++++++++++----- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/orm/reaction.py b/orm/reaction.py index fa9aaf9a..3178caca 100644 --- a/orm/reaction.py +++ b/orm/reaction.py @@ -38,7 +38,7 @@ class Reaction(Base): deleted_by = Column(ForeignKey("author.id"), nullable=True) reply_to = Column(ForeignKey("reaction.id"), nullable=True) quote = Column(String, nullable=True, comment="Original quoted text") - shout = Column(ForeignKey("shout.id"), nullable=False) + shout = Column(ForeignKey("shout.id"), nullable=False, index=True) created_by = Column(ForeignKey("author.id"), nullable=False) kind = Column(String, nullable=False, index=True) diff --git a/resolvers/reader.py b/resolvers/reader.py index fe744e27..be45cb58 100644 --- a/resolvers/reader.py +++ b/resolvers/reader.py @@ -27,43 +27,49 @@ from services.viewed import ViewedStorage def query_shouts(): """ - Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем. + Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем, + с агрегацией в строку вместо JSON. + :param session: Сессия SQLAlchemy для выполнения запроса. :return: Запрос для получения публикаций. """ # Создаем алиасы для таблиц для избежания конфликтов имен aliased_reaction = aliased(Reaction) - # Подзапрос для уникальных авторов + # Подзапрос для уникальных авторов, объединенных в строку authors_subquery = ( select( ShoutAuthor.shout.label("shout_id"), - func.json_agg( - func.json_build_object( - 'id', Author.id, - 'name', Author.name, - 'slug', Author.slug, - 'pic', Author.pic - ) - ).label("authors") + func.string_agg( + func.concat_ws( + ";", + func.concat("id:", Author.id), + func.concat("name:", Author.name), + func.concat("slug:", Author.slug), + func.concat("pic:", Author.pic), + ), + ", ", + ).label("authors"), ) .join(Author, ShoutAuthor.author == Author.id) .group_by(ShoutAuthor.shout) .subquery() ) - # Подзапрос для уникальных тем + # Подзапрос для уникальных тем, объединенных в строку topics_subquery = ( select( ShoutTopic.shout.label("shout_id"), - func.json_agg( - func.json_build_object( - 'id', Topic.id, - 'title', Topic.title, - 'body', Topic.body, - 'slug', Topic.slug - ) - ).label("topics") + func.string_agg( + func.concat_ws( + ";", + func.concat("id:", Topic.id), + func.concat("title:", Topic.title), + func.concat("body:", Topic.body), + func.concat("slug:", Topic.slug), + ), + ", ", + ).label("topics"), ) .join(Topic, ShoutTopic.topic == Topic.id) .group_by(ShoutTopic.shout) @@ -95,6 +101,7 @@ def query_shouts(): return q, aliased_reaction + def get_shouts_with_stats(q, limit, offset=0, author_id=None): """ Получение публикаций со статистикой, и подзапросами авторов и тем. diff --git a/resolvers/topic.py b/resolvers/topic.py index dfb1b27c..45239576 100644 --- a/resolvers/topic.py +++ b/resolvers/topic.py @@ -12,21 +12,23 @@ from cache.memorycache import cache_region from services.schema import mutation, query +# Запрос на получение всех тем @query.field("get_topics_all") def get_topics_all(_, _info): - cache_key = "get_topics_all" + cache_key = "get_topics_all" # Ключ для кеша @cache_region.cache_on_arguments(cache_key) def _get_topics_all(): topics_query = select(Topic) - return get_with_stat(topics_query) + return get_with_stat(topics_query) # Получение тем с учетом статистики return _get_topics_all() +# Запрос на получение тем по сообществу @query.field("get_topics_by_community") def get_topics_by_community(_, _info, community_id: int): - cache_key = f"get_topics_by_community_{community_id}" + cache_key = f"get_topics_by_community_{community_id}" # Ключ для кеша @cache_region.cache_on_arguments(cache_key) def _get_topics_by_community(): @@ -36,6 +38,7 @@ def get_topics_by_community(_, _info, community_id: int): return _get_topics_by_community() +# Запрос на получение тем по автору @query.field("get_topics_by_author") async def get_topics_by_author(_, _info, author_id=0, slug="", user=""): topics_by_author_query = select(Topic) @@ -49,6 +52,7 @@ async def get_topics_by_author(_, _info, author_id=0, slug="", user=""): return get_with_stat(topics_by_author_query) +# Запрос на получение одной темы по её slug @query.field("get_topic") async def get_topic(_, _info, slug: str): topic = await get_cached_topic_by_slug(slug, get_with_stat) @@ -56,12 +60,13 @@ async def get_topic(_, _info, slug: str): return topic +# Мутация для создания новой темы @mutation.field("create_topic") @login_required async def create_topic(_, _info, inp): with local_session() as session: - # TODO: check user permissions to create topic for exact community - # and actor is permitted to craete it + # TODO: проверить права пользователя на создание темы для конкретного сообщества + # и разрешение на создание new_topic = Topic(**inp) session.add(new_topic) session.commit() @@ -69,6 +74,7 @@ async def create_topic(_, _info, inp): return {"topic": new_topic} +# Мутация для обновления темы @mutation.field("update_topic") @login_required async def update_topic(_, _info, inp): @@ -85,6 +91,7 @@ async def update_topic(_, _info, inp): return {"topic": topic} +# Мутация для удаления темы @mutation.field("delete_topic") @login_required async def delete_topic(_, info, slug: str): @@ -105,6 +112,7 @@ async def delete_topic(_, info, slug: str): return {"error": "access denied"} +# Запрос на получение случайных тем @query.field("get_topics_random") def get_topics_random(_, _info, amount=12): q = select(Topic) @@ -121,6 +129,7 @@ def get_topics_random(_, _info, amount=12): return topics +# Запрос на получение подписчиков темы @query.field("get_topic_followers") async def get_topic_followers(_, _info, slug: str): logger.debug(f"getting followers for @{slug}") @@ -130,6 +139,7 @@ async def get_topic_followers(_, _info, slug: str): return followers +# Запрос на получение авторов темы @query.field("get_topic_authors") async def get_topic_authors(_, _info, slug: str): logger.debug(f"getting authors for @{slug}")