search-authors-fmt
All checks were successful
Deploy on push / deploy (push) Successful in 1m25s

This commit is contained in:
Untone 2024-02-25 15:22:48 +03:00
parent 9aabfacf84
commit a149091e3c
5 changed files with 77 additions and 17 deletions

View File

@ -8,6 +8,7 @@ from resolvers.author import (
get_authors_all, get_authors_all,
load_authors_by, load_authors_by,
update_author, update_author,
search_authors,
) )
from resolvers.rating import rate_author from resolvers.rating import rate_author
from resolvers.community import get_communities_all, get_community from resolvers.community import get_communities_all, get_community
@ -53,6 +54,7 @@ __all__ = [
'load_authors_by', 'load_authors_by',
'rate_author', 'rate_author',
'update_author', 'update_author',
'search_authors',
# community # community
'get_community', 'get_community',
'get_communities_all', 'get_communities_all',

View File

@ -1,7 +1,7 @@
import json import json
import time import time
from sqlalchemy import desc, select, or_, and_ from sqlalchemy import desc, select, or_, and_, func
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from orm.author import Author, AuthorFollower from orm.author import Author, AuthorFollower
@ -28,7 +28,6 @@ def update_author(_, info, profile):
return {'error': None, 'author': author} return {'error': None, 'author': author}
# TODO: caching query
@query.field('get_authors_all') @query.field('get_authors_all')
def get_authors_all(_, _info): def get_authors_all(_, _info):
with local_session() as session: with local_session() as session:
@ -209,3 +208,13 @@ def get_author_followers(_, _info, slug: str):
except Exception as exc: except Exception as exc:
logger.error(exc) logger.error(exc)
return [] return []
@query.field('search_authors')
def search_authors(_, info, text: str):
v1 = func.to_tsquery('russian', text)
v2 = func.to_tsvector(
'russian', Author.name or ' ' or Author.bio or ' ' or Author.about
)
q = select(Author).filter(v2.match(v1))
return get_with_stat(q)

View File

@ -6,7 +6,6 @@ from orm.topic import TopicFollower, Topic
from services.db import local_session from services.db import local_session
from orm.author import AuthorFollower, Author, AuthorRating from orm.author import AuthorFollower, Author, AuthorRating
from orm.shout import ShoutTopic, ShoutAuthor, Shout from orm.shout import ShoutTopic, ShoutAuthor, Shout
from services.logger import root_logger as logger
def add_topic_stat_columns(q): def add_topic_stat_columns(q):
@ -71,18 +70,50 @@ def add_author_stat_columns(q):
def add_author_ratings(q): def add_author_ratings(q):
aliased_author = aliased(Author) aliased_author = aliased(Author)
ratings_subquery = ( ratings_subquery = (
select([ select(
[
aliased_author.id.label('author_id'), aliased_author.id.label('author_id'),
func.count().filter(and_( func.count()
.filter(
and_(
Reaction.created_by == aliased_author.id, Reaction.created_by == aliased_author.id,
Reaction.kind == ReactionKind.COMMENT.value, Reaction.kind == ReactionKind.COMMENT.value,
Reaction.deleted_at.is_(None), Reaction.deleted_at.is_(None),
)).label('comments_count'), )
func.sum(case((AuthorRating.plus == true(), 1), else_=0)).label('likes_count'), )
func.sum(case((AuthorRating.plus != true(), 1), else_=0)).label('dislikes_count'), .label('comments_count'),
func.sum(case((and_(Reaction.kind == ReactionKind.LIKE.value, Shout.authors.any(id=aliased_author.id)), 1), else_=0)).label('shouts_likes'), func.sum(case((AuthorRating.plus == true(), 1), else_=0)).label(
func.sum(case((and_(Reaction.kind == ReactionKind.DISLIKE.value, Shout.authors.any(id=aliased_author.id)), 1), else_=0)).label('shouts_dislikes') 'likes_count'
]) ),
func.sum(case((AuthorRating.plus != true(), 1), else_=0)).label(
'dislikes_count'
),
func.sum(
case(
(
and_(
Reaction.kind == ReactionKind.LIKE.value,
Shout.authors.any(id=aliased_author.id),
),
1,
),
else_=0,
)
).label('shouts_likes'),
func.sum(
case(
(
and_(
Reaction.kind == ReactionKind.DISLIKE.value,
Shout.authors.any(id=aliased_author.id),
),
1,
),
else_=0,
)
).label('shouts_dislikes'),
]
)
.select_from(aliased_author) .select_from(aliased_author)
.join(AuthorRating, cast(AuthorRating.author, Integer) == aliased_author.id) .join(AuthorRating, cast(AuthorRating.author, Integer) == aliased_author.id)
.outerjoin(Shout, Shout.authors.any(id=aliased_author.id)) .outerjoin(Shout, Shout.authors.any(id=aliased_author.id))
@ -103,7 +134,7 @@ def get_with_stat(q):
elif is_topic: elif is_topic:
q = add_topic_stat_columns(q) q = add_topic_stat_columns(q)
records = [] records = []
logger.debug(f'{q}'.replace('\n', ' ')) # logger.debug(f'{q}'.replace('\n', ' '))
with local_session() as session: with local_session() as session:
for cols in session.execute(q): for cols in session.execute(q):
entity = cols[0] entity = cols[0]

View File

@ -4,6 +4,7 @@ type Query {
get_author_id(user: String!): Author get_author_id(user: String!): Author
get_authors_all: [Author] get_authors_all: [Author]
load_authors_by(by: AuthorsBy!, limit: Int, offset: Int): [Author] load_authors_by(by: AuthorsBy!, limit: Int, offset: Int): [Author]
search_authors(text: String!): [Author]
# community # community
get_community: Community get_community: Community

View File

@ -1,7 +1,7 @@
import math import math
import time import time
from functools import wraps from functools import wraps
from sqlalchemy import event, Engine from sqlalchemy import event, Engine, inspect
from typing import Any, Callable, Dict, TypeVar from typing import Any, Callable, Dict, TypeVar
from dogpile.cache import make_region from dogpile.cache import make_region
@ -110,3 +110,20 @@ def cache_method(cache_key: str):
return decorated_function return decorated_function
return decorator return decorator
author_fts_index_name = 'author_full_text_idx'
inspector = inspect(engine)
authors_indexes = inspector.get_indexes('authors')
author_fts_index_exists = any(
index['name'] == author_fts_index_name for index in authors_indexes
)
if not author_fts_index_exists:
with local_session() as session:
session.bind.execute(
"""
CREATE INDEX {index_name} ON authors
USING gin(to_tsvector('russian', COALESCE(name,'') || ' ' || COALESCE(bio,'') || ' ' || COALESCE(about,'')));
""".format(index_name=author_fts_index_name)
)
logger.info('Full text index created successfully.')