jsonify2
Some checks failed
Deploy on push / deploy (push) Failing after 10s

This commit is contained in:
Untone 2024-10-31 12:49:18 +03:00
parent 5b211c349e
commit 751f3de4b1

View File

@ -30,52 +30,44 @@ from utils.logger import root_logger as logger
def query_shouts(slug=None, shout_id=None): def query_shouts(slug=None, shout_id=None):
""" """
Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем, Базовый запрос для получения публикаций с подзапросами статистики, авторов и тем,
с агрегацией в строку. с агрегированием в JSON.
:param slug: Опциональный параметр для фильтрации по slug.
:param shout_id: Опциональный параметр для фильтрации по shout_id.
:return: Запрос для получения публикаций, aliased_reaction:
""" """
aliased_reaction = aliased(Reaction) aliased_reaction = aliased(Reaction)
# Подзапрос для уникальных авторов, объединенных в строку # Подзапрос для уникальных авторов, агрегированных в JSON
authors_subquery = ( authors_subquery = (
select( select(
ShoutAuthor.shout.label("shout_id"), ShoutAuthor.shout.label("shout_id"),
func.string_agg( func.json_agg(
func.concat_ws( func.json_build_object(
";", "id",
func.concat("id:", Author.id), Author.id,
func.concat("name:", Author.name), "name",
func.concat("slug:", Author.slug), Author.name,
func.concat("pic:", Author.pic), "slug",
func.concat("caption:", ShoutAuthor.caption), # Добавлено поле caption Author.slug,
), "pic",
" | ", Author.pic,
).label("authors"), # Используем символ | как разделитель "caption",
ShoutAuthor.caption,
)
).label("authors"),
) )
.join(Author, ShoutAuthor.author == Author.id) .join(Author, ShoutAuthor.author == Author.id)
.group_by(ShoutAuthor.shout) .group_by(ShoutAuthor.shout)
.subquery() .subquery()
) )
# Подзапрос для уникальных тем, объединенных в строку (включая main_topic_slug) # Подзапрос для уникальных тем, агрегированных в JSON
topics_subquery = ( topics_subquery = (
select( select(
ShoutTopic.shout.label("shout_id"), ShoutTopic.shout.label("shout_id"),
func.string_agg( func.json_agg(
func.concat_ws( func.json_build_object(
";", "id", Topic.id, "title", Topic.title, "slug", Topic.slug, "is_main", ShoutTopic.main
func.concat("id:", Topic.id), )
func.concat("title:", Topic.title), ).label("topics"),
func.concat("slug:", Topic.slug), func.max(case((ShoutTopic.main.is_(True), Topic.slug))).label("main_topic_slug"),
func.concat("is_main:", ShoutTopic.main),
),
" | ",
).label("topics"), # Используем символ | как разделитель
func.max(case((ShoutTopic.main.is_(True), Topic.slug))).label(
"main_topic_slug"
), # Получение основного топика
) )
.join(Topic, ShoutTopic.topic == Topic.id) .join(Topic, ShoutTopic.topic == Topic.id)
.group_by(ShoutTopic.shout) .group_by(ShoutTopic.shout)
@ -150,43 +142,6 @@ def query_shouts(slug=None, shout_id=None):
return q, aliased_reaction return q, aliased_reaction
def parse_aggregated_string(aggregated_str, model_class):
"""
Преобразует строку, полученную из string_agg, обратно в список объектов.
:param aggregated_str: Строка, содержащая агрегированные данные.
:param model_class: Класс модели, экземпляры которой нужно создать.
:return: Список объектов модели.
"""
if not aggregated_str:
return []
items = []
for item_str in aggregated_str.split(" | "):
item_data = {}
for field in item_str.split(";"):
if ":" in field:
key, value = field.split(":", 1)
item_data[key] = value
else:
logger.error(f"Некорректный формат поля: {field}")
continue
# Фильтрация item_data, чтобы использовать только допустимые поля модели
filtered_data = {k: v for k, v in item_data.items() if hasattr(model_class, k)}
# Создание экземпляра модели на основе фильтрованного словаря
item_object = model_class(**filtered_data)
# Добавление синтетического поля, если оно присутствует в item_data
if "is_main" in item_data:
item_object.is_main = item_data["is_main"] == "True" # Преобразование в логическое значение
items.append(item_object)
return items
def get_shouts_with_stats(q, limit, offset=0, author_id=None): def get_shouts_with_stats(q, limit, offset=0, author_id=None):
""" """
Получение публикаций со статистикой, и подзапросами авторов и тем. Получение публикаций со статистикой, и подзапросами авторов и тем.
@ -219,12 +174,13 @@ def get_shouts_with_stats(q, limit, offset=0, author_id=None):
# followers_stat, # followers_stat,
rating_stat, rating_stat,
last_reacted_at, last_reacted_at,
authors, authors_json,
topics, topics_json,
main_topic_slug, main_topic_slug,
] in results: ] in results:
shout.authors = parse_aggregated_string(authors, Author) # Преобразование JSON данных в объекты
shout.topics = parse_aggregated_string(topics, Topic) shout.authors = [Author(**author) for author in authors_json] if authors_json else []
shout.topics = [Topic(**topic) for topic in topics_json] if topics_json else []
shout.stat = { shout.stat = {
"viewed": ViewedStorage.get_shout(shout.id), "viewed": ViewedStorage.get_shout(shout.id),
# "followed": followers_stat or 0, # "followed": followers_stat or 0,
@ -337,8 +293,8 @@ async def get_shout(_, _info, slug="", shout_id=0):
# followers_stat, # followers_stat,
rating_stat, rating_stat,
last_reaction_at, last_reaction_at,
authors, authors_json,
topics, topics_json,
main_topic_slug, main_topic_slug,
] = results ] = results
@ -350,10 +306,10 @@ async def get_shout(_, _info, slug="", shout_id=0):
} }
# Преобразование строк в объекты Author без их создания # Преобразование строк в объекты Author без их создания
shout.authors = parse_aggregated_string(authors, Author) shout.authors = [Author(**author) for author in authors_json] if authors_json else []
# Преобразование строк в объекты Topic без их создания # Преобразование строк в объекты Topic без их создания
shout.topics = parse_aggregated_string(topics, Topic) shout.topics = [Topic(**topic) for topic in topics_json] if topics_json else []
# Добавляем основной топик, если он существует # Добавляем основной топик, если он существует
shout.main_topic = main_topic_slug shout.main_topic = main_topic_slug