Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[draft] Add/sort works #138

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"python.formatting.provider": "black",
"python.formatting.provider": "none",
"[python]": {
"editor.defaultFormatter": null,
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
}
}
},
"cSpell.words": [
"fastapi",
"ilike",
"outerjoin",
"sqlalchemy",
"toybox"
]
}
151 changes: 122 additions & 29 deletions cruds/works/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import markdown
from fastapi import HTTPException
from sqlalchemy import desc, func, or_
from sqlalchemy import desc, asc, func, or_, case
from sqlalchemy.orm import aliased
from sqlalchemy.sql.functions import coalesce, count
from sqlalchemy.orm.session import Session

from cruds.assets import delete_asset_by_id
Expand Down Expand Up @@ -91,26 +93,106 @@ def get_works_by_limit(
tag_names: str,
tag_ids: str,
user: Optional[User],
search_word:str,
search_word: str,
order_by: str = "created_at",
order: str = "asc",
) -> ResWorks:
if tag_names != None and tag_ids != None:
raise HTTPException(
status_code=422, detail="tag name and ID cannot be specified at the same time."
status_code=422,
detail="tag name and ID cannot be specified at the same time.",
)

comment_count_subquery = (
db.query(
models.Comment.work_id, count(models.Comment.work_id).label("comment_count")
)
.group_by(models.Comment.work_id)
.subquery("comment_count_subquery")
)
favorite_count_subquery = (
db.query(
models.Favorite.work_id,
count(models.Favorite.work_id).label("favorite_count"),
)
.group_by(models.Favorite.work_id)
.subquery("favorite_count_subquery")
)
is_favorite_subquery = None
if user is not None:
is_favorite_subquery = (
db.query(
models.Favorite.work_id,
models.Favorite.user_id.label("is_favorite_flag"),
)
.filter(
models.Work.id == models.Favorite.work_id,
models.Favorite.user_id == user.id,
)
.subquery("is_favorite_subquery")
)

works_orm = (
db.query(models.Work)
.join(models.User,models.Work.user_id==models.User.id)
.join(models.Tagging,models.Work.id==models.Tagging.work_id)
.join(models.Tag,models.Tagging.tag_id==models.Tag.id)
.group_by(models.Work.id)
.order_by(desc(models.Work.created_at))
db.query(
models.Work,
coalesce(favorite_count_subquery.c.favorite_count, 0).label(
"favorite_count"
),
case(
[(is_favorite_subquery.c.is_favorite_flag == None, False)], else_=True
).label("is_favorite")
if is_favorite_subquery is not None
else False,
coalesce(comment_count_subquery.c.comment_count, 0).label("comment_count"),
)
.join(models.User, models.Work.user_id == models.User.id)
.join(models.Tagging, models.Work.id == models.Tagging.work_id)
.join(models.Tag, models.Tagging.tag_id == models.Tag.id)
# .group_by(models.Work.id)
.filter(models.Work.visibility != models.Visibility.draft)
)
if search_word:
works_orm = works_orm.filter(or_(models.User.name.ilike(f"%{search_word}%"),models.Tag.name.ilike(f"%{search_word}%"),models.Work.title.ilike(f"%{search_word}%")))

works_orm = works_orm.outerjoin(
favorite_count_subquery, models.Work.id == favorite_count_subquery.c.work_id
)
works_orm = works_orm.outerjoin(
comment_count_subquery, models.Work.id == comment_count_subquery.c.work_id
)

if is_favorite_subquery is not None:
works_orm = works_orm.outerjoin(
is_favorite_subquery, models.Work.id == is_favorite_subquery.c.work_id
)

# order_byの指定
if order_by == "created_at":
column_of_order_by = models.Work.created_at
elif order_by == "updated_at":
column_of_order_by = models.Work.updated_at
elif order_by == "favorite":
column_of_order_by = favorite_count_subquery.c.favorite_count
elif order_by == "comment":
column_of_order_by = comment_count_subquery.c.comment_count
else:
column_of_order_by = models.Work.created_at

# orderの指定
if order == "desc":
works_orm = works_orm.order_by(desc(column_of_order_by))
else:
works_orm = works_orm.order_by(asc(column_of_order_by))

# search_by_free_word
if search_word:
works_orm = works_orm.filter(
or_(
models.User.name.ilike(f"%{search_word}%"),
models.Tag.name.ilike(f"%{search_word}%"),
models.Work.title.ilike(f"%{search_word}%"),
)
)

# search_by_tag_ids
if tag_ids:
tag_id_list = tag_ids.split(",")
works_orm = works_orm.filter(models.Tagging.tag_id.in_(tag_id_list)).filter(
Expand All @@ -119,6 +201,8 @@ def get_works_by_limit(
works_orm = works_orm.group_by(models.Work.id).having(
func.count(models.Work.id) == len(tag_id_list)
)

# search_by_tag_names
if tag_names:
tag_name_list = tag_names.split(",")
works_orm = works_orm.filter(models.Tag.name.in_(tag_name_list)).filter(
Expand All @@ -128,13 +212,16 @@ def get_works_by_limit(
func.count(models.Work.id) == len(tag_name_list)
)

# check user
if user is None:
works_orm = works_orm.filter(models.Work.visibility == models.Visibility.public)
elif visibility is not None:
works_orm = works_orm.filter(models.Work.visibility == visibility)

# get works total count
works_total_count = works_orm.count()

# pagination
if oldest_work_id:
oldest_work = (
db.query(models.Work).filter(models.Work.id == oldest_work_id).first()
Expand All @@ -149,27 +236,33 @@ def get_works_by_limit(
if newest_work is None:
raise HTTPException(status_code=400, detail="this newest_id is invalid")
works_orm = works_orm.filter(models.Work.created_at < newest_work.created_at)

# works_orm = works_orm.group_by(models.Work.id)
print(works_orm)
works_orm = works_orm.limit(limit).all()

works = []
for work_orm in works_orm:
work = Work.from_orm(work_orm)
if user is not None:
work.is_favorite = (
db.query(models.Favorite)
.filter(
models.Favorite.work_id == work.id,
models.Favorite.user_id == user.id,
)
.first()
is not None
)
else:
work.is_favorite = False
work.favorite_count = (
db.query(models.Favorite).filter(models.Favorite.work_id == work.id).count()
works = list(
map(
lambda work_orm: Work(
id=work_orm[0].id,
title=work_orm[0].title,
description=work_orm[0].description,
description_html=work_orm[0].description_html,
user=work_orm[0].user,
assets=work_orm[0].assets,
urls=work_orm[0].urls,
visibility=work_orm[0].visibility,
tags=work_orm[0].tags,
thumbnail=work_orm[0].thumbnail,
created_at=work_orm[0].created_at,
updated_at=work_orm[0].updated_at,
comments=work_orm[0].comments,
favorite_count=work_orm[1],
is_favorite=work_orm[2],
),
works_orm,
)
works.append(work)
)

resWorks = ResWorks(works=works, works_total_count=works_total_count)
return resWorks
Expand Down
6 changes: 4 additions & 2 deletions routers/works/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ async def get_works(
tag_ids:str = None,
db: Session = Depends(get_db),
user: User = Depends(GetCurrentUser(auto_error=False)),
search_word:str= None
search_word:str= None,
order_by: str = None,
order: str = None,
):
works = get_works_by_limit(
db, limit, visibility, oldest_work_id, newest_work_id,tag_names, tag_ids, user,search_word
db, limit, visibility, oldest_work_id, newest_work_id,tag_names, tag_ids, user,search_word, order_by, order
)
return works

Expand Down