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

This commit is contained in:
Untone 2024-10-31 14:48:15 +03:00
parent 882ef0288a
commit 5f2f4262a5

View File

@ -39,41 +39,48 @@ def query_shouts(slug=None, shout_id=None):
# Подзапрос для уникальных авторов, агрегированных в JSON # Подзапрос для уникальных авторов, агрегированных в JSON
authors_subquery = ( authors_subquery = (
select( select(
ShoutAuthor.shout.label("shout_id"),
func.json_agg( func.json_agg(
func.json_build_object( func.json_build_object(
"id", "id", Author.id,
Author.id, "name", Author.name,
"name", "slug", Author.slug,
Author.name, "pic", Author.pic,
"slug", "caption", ShoutAuthor.caption,
Author.slug,
"pic",
Author.pic,
"caption",
ShoutAuthor.caption,
) )
).label("authors"), ).label("authors"),
) )
.join(Author, ShoutAuthor.author == Author.id) .join(Author, ShoutAuthor.author == Author.id)
.group_by(ShoutAuthor.shout) .group_by(ShoutAuthor.shout)
.subquery() .scalar_subquery()
) )
# Подзапрос для уникальных тем, агрегированных в JSON # Подзапрос для уникальных тем, агрегированных в JSON
topics_subquery = ( topics_subquery = (
select( select(
ShoutTopic.shout.label("shout_id"),
func.json_agg( func.json_agg(
func.json_build_object( func.json_build_object(
"id", Topic.id, "title", Topic.title, "slug", Topic.slug, "is_main", ShoutTopic.main "id", Topic.id,
"title", Topic.title,
"slug", Topic.slug,
"is_main", ShoutTopic.main
) )
).label("topics"), ).label("topics")
func.max(case((ShoutTopic.main.is_(True), Topic.slug))).label("main_topic_slug"),
) )
.select_from(ShoutTopic)
.join(Topic, ShoutTopic.topic == Topic.id) .join(Topic, ShoutTopic.topic == Topic.id)
.group_by(ShoutTopic.shout) .where(ShoutTopic.shout == Shout.id)
.subquery() .correlate(Shout)
.scalar_subquery()
)
# Новый подзапрос для main_topic_slug
main_topic_subquery = (
select(func.max(Topic.slug).label("main_topic_slug"))
.select_from(ShoutTopic)
.join(Topic, ShoutTopic.topic == Topic.id)
.where(and_(ShoutTopic.shout == Shout.id, ShoutTopic.main.is_(True)))
.correlate(Shout)
.scalar_subquery()
) )
# Подзапрос для комментариев # Подзапрос для комментариев
@ -120,22 +127,15 @@ def query_shouts(slug=None, shout_id=None):
Shout, Shout,
comments_subq, comments_subq,
ratings_subq, ratings_subq,
func.max(last_reaction.created_at).label("last_reacted_at"), func.max(Reaction.created_at).label("last_reacted_at"),
authors_subquery.c.authors.label("authors"), authors_subquery,
topics_subquery.c.topics.label("topics"), topics_subquery,
topics_subquery.c.main_topic_slug.label("main_topic_slug"), main_topic_subquery,
) )
.outerjoin(last_reaction, and_(last_reaction.shout == Shout.id, last_reaction.deleted_at.is_(None))) .outerjoin(last_reaction, and_(last_reaction.shout == Shout.id, last_reaction.deleted_at.is_(None)))
.outerjoin(authors_subquery, authors_subquery.c.shout_id == Shout.id)
.outerjoin(topics_subquery, topics_subquery.c.shout_id == Shout.id)
.outerjoin(ShoutReactionsFollower, ShoutReactionsFollower.shout == Shout.id) .outerjoin(ShoutReactionsFollower, ShoutReactionsFollower.shout == Shout.id)
.where(and_(Shout.published_at.is_not(None), Shout.deleted_at.is_(None))) .where(and_(Shout.published_at.is_not(None), Shout.deleted_at.is_(None)))
.group_by( .group_by(Shout.id)
Shout.id,
text("authors_subquery.authors::text"),
text("topics_subquery.topics::text"),
text("topics_subquery.main_topic_slug"),
)
) )
if slug: if slug:
@ -161,11 +161,16 @@ def get_shouts_with_stats(q, limit=20, offset=0, author_id=None):
select( select(
func.json_agg( func.json_agg(
func.json_build_object( func.json_build_object(
"id", Author.id, "id",
"name", Author.name, Author.id,
"slug", Author.slug, "name",
"pic", Author.pic, Author.name,
"caption", ShoutAuthor.caption "slug",
Author.slug,
"pic",
Author.pic,
"caption",
ShoutAuthor.caption,
) )
).label("authors") ).label("authors")
) )
@ -181,18 +186,10 @@ def get_shouts_with_stats(q, limit=20, offset=0, author_id=None):
select( select(
func.json_agg( func.json_agg(
func.json_build_object( func.json_build_object(
"id", Topic.id, "id", Topic.id, "title", Topic.title, "slug", Topic.slug, "is_main", ShoutTopic.main
"title", Topic.title,
"slug", Topic.slug,
"is_main", ShoutTopic.main
) )
).label("topics"), ).label("topics"),
func.max( func.max(case((ShoutTopic.main, Topic.slug), else_=None)).label("main_topic_slug"),
case(
(ShoutTopic.main, Topic.slug),
else_=None
)
).label("main_topic_slug")
) )
.select_from(ShoutTopic) .select_from(ShoutTopic)
.join(Topic, ShoutTopic.topic == Topic.id) .join(Topic, ShoutTopic.topic == Topic.id)
@ -203,9 +200,7 @@ def get_shouts_with_stats(q, limit=20, offset=0, author_id=None):
# Скалярный подзапрос для основного топика # Скалярный подзапрос для основного топика
main_topic_subquery = ( main_topic_subquery = (
select( select(func.max(Topic.slug).label("main_topic_slug"))
func.max(Topic.slug).label("main_topic_slug")
)
.select_from(ShoutTopic) .select_from(ShoutTopic)
.join(Topic, ShoutTopic.topic == Topic.id) .join(Topic, ShoutTopic.topic == Topic.id)
.where( .where(
@ -227,22 +222,16 @@ def get_shouts_with_stats(q, limit=20, offset=0, author_id=None):
case( case(
(Reaction.kind == ReactionKind.LIKE.value, 1), (Reaction.kind == ReactionKind.LIKE.value, 1),
(Reaction.kind == ReactionKind.DISLIKE.value, -1), (Reaction.kind == ReactionKind.DISLIKE.value, -1),
else_=0 else_=0,
) )
).label("rating_stat"), ).label("rating_stat"),
func.max(Reaction.created_at).label("last_reacted_at"), func.max(Reaction.created_at).label("last_reacted_at"),
authors_subquery, authors_subquery,
topics_subquery, topics_subquery,
main_topic_subquery main_topic_subquery,
) )
.outerjoin(Reaction, Reaction.shout == Shout.id) .outerjoin(Reaction, Reaction.shout == Shout.id)
.where( .where(and_(Shout.published_at.is_not(None), Shout.deleted_at.is_(None), Shout.featured_at.is_not(None)))
and_(
Shout.published_at.isnot(None),
Shout.deleted_at.is_(None),
Shout.featured_at.isnot(None)
)
)
.group_by(Shout.id) .group_by(Shout.id)
.order_by(Shout.published_at.desc().nulls_last()) .order_by(Shout.published_at.desc().nulls_last())
.limit(limit) .limit(limit)
@ -256,15 +245,9 @@ def get_shouts_with_stats(q, limit=20, offset=0, author_id=None):
# Формирование списка публикаций с их данными # Формирование списка публикаций с их данными
shouts = [] shouts = []
with local_session() as session: with local_session() as session:
for row in session.execute(query).all() or []: for [shout, comments_stat, rating_stat, last_reacted_at, authors_json, topics_json, main_topic_slug] in (
shout = row.Shout session.execute(query).all() or []
comments_stat = row.comments_stat ):
rating_stat = row.rating_stat
last_reacted_at = row.last_reacted_at
authors_json = row.authors
topics_json = row.topics
main_topic_slug = row.main_topic_slug
# Преобразование JSON данных в объекты # Преобразование JSON данных в объекты
shout.authors = [Author(**author) for author in authors_json] if authors_json else [] 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.topics = [Topic(**topic) for topic in topics_json] if topics_json else []
@ -417,7 +400,7 @@ async def load_shouts_by(_, _info, options):
:return: Список публикаций, удовлетворяющих критериям. :return: Список публикаций, удовлетворяющих критериям.
""" """
# Базовый запрос # Базовый запрос
q, aliased_reaction = query_shouts() q, _aliased_reaction = query_shouts()
# Применение фильтров # Применение фильтров
filters = options.get("filters", {}) filters = options.get("filters", {})