code review, all authors query restored

This commit is contained in:
Igor Lobanov 2022-11-18 01:38:29 +01:00
parent 7969f67c67
commit aee83c31b5
5 changed files with 133 additions and 89 deletions

View File

@ -12,6 +12,7 @@ from orm.user import AuthorFollower, Role, User, UserRating, UserRole
from services.auth.users import UserStorage from services.auth.users import UserStorage
from services.stat.reacted import ReactedStorage from services.stat.reacted import ReactedStorage
from services.stat.topicstat import TopicStat from services.stat.topicstat import TopicStat
from services.zine.authors import AuthorsStorage
from services.zine.shoutauthor import ShoutAuthorStorage from services.zine.shoutauthor import ShoutAuthorStorage
# from .community import followed_communities # from .community import followed_communities
@ -174,12 +175,9 @@ def author_unfollow(user, slug):
@query.field("authorsAll") @query.field("authorsAll")
async def get_authors_all(_, _info): async def get_authors_all(_, _info):
users = await UserStorage.get_all_users() authors = await AuthorsStorage.get_all_authors()
authors = [] for author in authors:
for author in users:
if ShoutAuthorStorage.shouts_by_author.get(author.slug):
author.stat = await get_author_stat(author.slug) author.stat = await get_author_stat(author.slug)
authors.append(author)
return authors return authors

View File

@ -6,8 +6,8 @@ from timeit import default_timer as timer
from auth.authenticate import login_required from auth.authenticate import login_required
from base.orm import local_session from base.orm import local_session
from base.resolvers import mutation, query from base.resolvers import mutation, query
from orm.shout import Shout from orm.shout import Shout, ShoutAuthor
from orm.reaction import Reaction, ReactionsWeights, ReactionKind from orm.reaction import Reaction, ReactionKind
# from resolvers.community import community_follow, community_unfollow # from resolvers.community import community_follow, community_unfollow
from resolvers.profile import author_follow, author_unfollow from resolvers.profile import author_follow, author_unfollow
from resolvers.reactions import reactions_follow, reactions_unfollow from resolvers.reactions import reactions_follow, reactions_unfollow
@ -16,10 +16,24 @@ from services.zine.shoutauthor import ShoutAuthorStorage
from services.stat.reacted import ReactedStorage from services.stat.reacted import ReactedStorage
@query.field("loadShoutsBy") @query.field("loadShout")
async def load_shouts_by(_, info, filter_by, limit, offset, order_by="createdAt", order_by_desc=True): async def load_shout(_, info, slug):
shout = select(Shout).options(
# TODO add cation
selectinload(Shout.authors),
selectinload(Shout.topics),
).where(
Shout.deletedAt.is_(None)
).one()
return shout
@query.field("loadShouts")
async def load_shouts_by(_, info, options):
""" """
:param filterBy: { :param options: {
filters: {
layout: 'audio', layout: 'audio',
visibility: "public", visibility: "public",
author: 'discours', author: 'discours',
@ -28,10 +42,12 @@ async def load_shouts_by(_, info, filter_by, limit, offset, order_by="createdAt"
body: 'something else', body: 'something else',
days: 30 days: 30
} }
:param order_by: 'rating' | 'comments' | 'reacted' | 'views' | 'createdAt offset: 0
:param order_by_desc: order be desc/ask (desc by default) limit: 50
:param limit: int amount of shouts order_by: 'createdAt'
:param offset: int offset in this order order_by_desc: tr
}
:return: Shout[] :return: Shout[]
""" """
@ -43,36 +59,35 @@ async def load_shouts_by(_, info, filter_by, limit, offset, order_by="createdAt"
Shout.deletedAt.is_(None) Shout.deletedAt.is_(None)
) )
if filter_by.get("slug"): if options.get("filters"):
q = q.filter(Shout.slug == filter_by["slug"]) if options.get("filters").get("reacted"):
else:
if filter_by.get("reacted"):
user = info.context["request"].user user = info.context["request"].user
q.join(Reaction, Reaction.createdBy == user.slug) q.join(Reaction, Reaction.createdBy == user.slug)
if filter_by.get("visibility"): if options.get("filters").get("visibility"):
q = q.filter(or_( q = q.filter(or_(
Shout.visibility.ilike(f"%{filter_by.get('visibility')}%"), Shout.visibility.ilike(f"%{options.get('filters').get('visibility')}%"),
Shout.visibility.ilike(f"%{'public'}%"), Shout.visibility.ilike(f"%{'public'}%"),
)) ))
if filter_by.get("layout"): if options.get("filters").get("layout"):
q = q.filter(Shout.layout == filter_by["layout"]) q = q.filter(Shout.layout == options.get("filters").get("layout"))
if filter_by.get("author"): if options.get("filters").get("author"):
q = q.filter(Shout.authors.any(slug=filter_by["author"])) q = q.filter(Shout.authors.any(slug=options.get("filters").get("author")))
if filter_by.get("topic"): if options.get("filters").get("topic"):
q = q.filter(Shout.topics.any(slug=filter_by["topic"])) q = q.filter(Shout.topics.any(slug=options.get("filters").get("topic")))
if filter_by.get("title"): if options.get("filters").get("title"):
q = q.filter(Shout.title.ilike(f'%{filter_by["title"]}%')) q = q.filter(Shout.title.ilike(f'%{options.get("filters").get("title")}%'))
if filter_by.get("body"): if options.get("filters").get("body"):
q = q.filter(Shout.body.ilike(f'%{filter_by["body"]}%')) q = q.filter(Shout.body.ilike(f'%{options.get("filters").get("body")}%s'))
if filter_by.get("days"): if options.get("filters").get("days"):
before = datetime.now() - timedelta(days=int(filter_by["days"]) or 30) before = datetime.now() - timedelta(days=int(options.get("filter").get("days")) or 30)
q = q.filter(Shout.createdAt > before) q = q.filter(Shout.createdAt > before)
if order_by == 'comments':
q = q.join(Reaction).add_columns(sa.func.count(Reaction.id).label(order_by)) if options.get("order_by") == 'comments':
if order_by == 'reacted': q = q.join(Reaction, Shout.slug == Reaction.shout and Reaction.body.is_not(None)).add_columns(
# TODO ? sa.func.count(Reaction.id).label(options.get("order_by")))
q = q.join(Reaction).add_columns(sa.func.count(Reaction.id).label(order_by)) if options.get("order_by") == 'reacted':
if order_by == "rating": q = q.join(Reaction).add_columns(sa.func.max(Reaction.createdAt).label(options.get("order_by")))
if options.get("order_by") == "rating":
q = q.join(Reaction).add_columns(sa.func.sum(case( q = q.join(Reaction).add_columns(sa.func.sum(case(
(Reaction.kind == ReactionKind.AGREE, 1), (Reaction.kind == ReactionKind.AGREE, 1),
(Reaction.kind == ReactionKind.DISAGREE, -1), (Reaction.kind == ReactionKind.DISAGREE, -1),
@ -83,13 +98,16 @@ async def load_shouts_by(_, info, filter_by, limit, offset, order_by="createdAt"
(Reaction.kind == ReactionKind.LIKE, 1), (Reaction.kind == ReactionKind.LIKE, 1),
(Reaction.kind == ReactionKind.DISLIKE, -1), (Reaction.kind == ReactionKind.DISLIKE, -1),
else_=0 else_=0
)).label(order_by)) )).label(options.get("order_by")))
# if order_by == 'views': # if order_by == 'views':
# TODO dump ackee data to db periodically # TODO dump ackee data to db periodically
query_order_by = desc(order_by) if order_by_desc else asc(order_by) order_by = options.get("order_by") if options.get("order_by") else 'createdAt'
q = q.group_by(Shout.id).order_by(query_order_by).limit(limit).offset(offset) query_order_by = desc(order_by) if options.get('order_by_desc') else asc(order_by)
q = q.group_by(Shout.id).order_by(query_order_by).limit(options.get("limit")).offset(
options.get("offset") if options.get("offset") else 0)
with local_session() as session: with local_session() as session:
# post query stats and author's captions # post query stats and author's captions

View File

@ -225,6 +225,25 @@ input ShoutsFilterBy {
stat: String stat: String
} }
input LoadShoutsFilters {
title: String
body: String
topic: String
author: String
layout: String
visibility: String
days: Int
reacted: Boolean
}
input LoadShoutsOptions {
filters: LoadShoutsFilters
limit: Int!
offset: Int
order_by: String
order_by_desc: Boolean
}
input ReactionBy { input ReactionBy {
shout: String shout: String
shouts: [String] shouts: [String]
@ -251,7 +270,8 @@ type Query {
# zine # zine
loadAuthorsBy(by: AuthorsBy, limit: Int, offset: Int): [Author]! loadAuthorsBy(by: AuthorsBy, limit: Int, offset: Int): [Author]!
loadShoutsBy(filter_by: ShoutsFilterBy!, limit: Int!, offset: Int!, order_by: String, order_by_desc: Boolean): [Shout]! loadShout(slug: String!): Shout
loadShouts(options: LoadShoutsOptions): [Shout]!
loadReactionsBy(by: ReactionBy!, limit: Int, offset: Int): [Reaction]! loadReactionsBy(by: ReactionBy!, limit: Int, offset: Int): [Reaction]!
userFollowers(slug: String!): [Author]! userFollowers(slug: String!): [Author]!
userFollowedAuthors(slug: String!): [Author]! userFollowedAuthors(slug: String!): [Author]!

12
services/zine/authors.py Normal file
View File

@ -0,0 +1,12 @@
from base.orm import local_session
from orm.user import User
from orm.shout import ShoutAuthor
class AuthorsStorage:
@staticmethod
async def get_all_authors():
with local_session() as session:
query = session.query(User).join(ShoutAuthor)
result = query.all()
return result

View File

@ -6,7 +6,6 @@ from orm.shout import ShoutAuthor, Shout
class ShoutAuthorStorage: class ShoutAuthorStorage:
authors_by_shout = {} authors_by_shout = {}
shouts_by_author = {}
lock = asyncio.Lock() lock = asyncio.Lock()
period = 30 * 60 # sec period = 30 * 60 # sec
@ -17,10 +16,7 @@ class ShoutAuthorStorage:
for sa in sas: for sa in sas:
self.authors_by_shout[sa.shout] = self.authors_by_shout.get(sa.shout, []) self.authors_by_shout[sa.shout] = self.authors_by_shout.get(sa.shout, [])
self.authors_by_shout[sa.shout].append([sa.user, sa.caption]) self.authors_by_shout[sa.shout].append([sa.user, sa.caption])
self.shouts_by_author[sa.user] = self.shouts_by_author.get(sa.user, [])
self.shouts_by_author[sa.user].append(sa.shout)
print("[zine.authors] %d shouts indexed by authors" % len(self.authors_by_shout)) print("[zine.authors] %d shouts indexed by authors" % len(self.authors_by_shout))
print("[zine.authors] %d authors indexed by shouts" % len(self.shouts_by_author))
@staticmethod @staticmethod
async def get_authors(shout): async def get_authors(shout):