Merge branch 'dev-ars' into dev
This commit is contained in:
commit
02f7685eaa
9 changed files with 809 additions and 381 deletions
|
|
@ -1,6 +1,10 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
oapi "nyanimedb/api"
|
||||
sqlc "nyanimedb/sql"
|
||||
"strconv"
|
||||
)
|
||||
|
|
@ -13,70 +17,83 @@ func NewServer(db *sqlc.Queries) Server {
|
|||
return Server{db: db}
|
||||
}
|
||||
|
||||
// type Cursor interface {
|
||||
// ParseCursor(sortBy oapi.TitleSort, data oapi.Cursor) (Cursor, error)
|
||||
func (s Server) mapTitle(ctx context.Context, title sqlc.GetTitleByIDRow) (oapi.Title, error) {
|
||||
|
||||
// Values() map[string]interface{}
|
||||
// // for logs only
|
||||
// Type() string
|
||||
// }
|
||||
oapi_title := oapi.Title{
|
||||
EpisodesAired: title.EpisodesAired,
|
||||
EpisodesAll: title.EpisodesAired,
|
||||
// EpisodesLen: &episodes_lens,
|
||||
Id: title.ID,
|
||||
// Poster: &oapi_image,
|
||||
Rating: title.Rating,
|
||||
RatingCount: title.RatingCount,
|
||||
// ReleaseSeason: &release_season,
|
||||
ReleaseYear: title.ReleaseYear,
|
||||
// Studio: &oapi_studio,
|
||||
// Tags: oapi_tag_names,
|
||||
// TitleNames: title_names,
|
||||
// TitleStatus: oapi_status,
|
||||
// AdditionalProperties:
|
||||
}
|
||||
|
||||
// type CursorByID struct {
|
||||
// ID int64
|
||||
// }
|
||||
title_names := make(map[string][]string, 0)
|
||||
err := json.Unmarshal(title.TitleNames, &title_names)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshal TitleNames: %v", err)
|
||||
}
|
||||
|
||||
// func (c CursorByID) ParseCursor(sortBy oapi.TitleSort, data oapi.Cursor) (Cursor, error) {
|
||||
// var cur CursorByID
|
||||
// if err := json.Unmarshal(data, &cur); err != nil {
|
||||
// return nil, fmt.Errorf("invalid cursor (id): %w", err)
|
||||
// }
|
||||
// if cur.ID == 0 {
|
||||
// return nil, errors.New("cursor id must be non-zero")
|
||||
// }
|
||||
// return cur, nil
|
||||
// }
|
||||
if title.EpisodesLen != nil && len(title.EpisodesLen) > 0 {
|
||||
episodes_lens := make(map[string]float64, 0)
|
||||
err = json.Unmarshal(title.EpisodesLen, &episodes_lens)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshal EpisodesLen: %v", err)
|
||||
}
|
||||
oapi_title.EpisodesLen = &episodes_lens
|
||||
}
|
||||
|
||||
// func (c CursorByID) Values() map[string]interface{} {
|
||||
// return map[string]interface{}{
|
||||
// "cursor_id": c.ID,
|
||||
// "cursor_year": nil,
|
||||
// "cursor_rating": nil,
|
||||
// }
|
||||
// }
|
||||
oapi_tag_names := make(oapi.Tags, 0)
|
||||
err = json.Unmarshal(title.TagNames, &oapi_tag_names)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshalling title_tag: %v", err)
|
||||
}
|
||||
|
||||
// func (c CursorByID) Type() string { return "id" }
|
||||
var oapi_studio oapi.Studio
|
||||
if title.StudioName != nil {
|
||||
oapi_studio.Name = *title.StudioName
|
||||
}
|
||||
if title.StudioID != 0 {
|
||||
oapi_studio.Id = title.StudioID
|
||||
oapi_studio.Description = title.StudioDesc
|
||||
if title.StudioIllustID != nil {
|
||||
oapi_studio.Poster.Id = title.StudioIllustID
|
||||
oapi_studio.Poster.ImagePath = title.StudioImagePath
|
||||
oapi_studio.Poster.StorageType = &title.StudioStorageType
|
||||
}
|
||||
}
|
||||
oapi_title.Studio = &oapi_studio
|
||||
|
||||
// func NewCursor(sortBy string) (Cursor, error) {
|
||||
// switch Type(sortBy) {
|
||||
// case TypeID:
|
||||
// return CursorByID{}, nil
|
||||
// case TypeYear:
|
||||
// return CursorByYear{}, nil
|
||||
// case TypeRating:
|
||||
// return CursorByRating{}, nil
|
||||
// default:
|
||||
// return nil, fmt.Errorf("unsupported sort_by: %q", sortBy)
|
||||
// }
|
||||
// }
|
||||
var oapi_image oapi.Image
|
||||
|
||||
// decodes a base64-encoded JSON string into a CursorObj
|
||||
// Returns the parsed CursorObj and an error
|
||||
// func parseCursor(encoded oapi.Cursor) (*oapi.CursorObj, error) {
|
||||
if title.PosterID != nil {
|
||||
oapi_image.Id = title.PosterID
|
||||
oapi_image.ImagePath = title.TitleImagePath
|
||||
oapi_image.StorageType = &title.TitleStorageType
|
||||
}
|
||||
|
||||
// // Decode base64
|
||||
// decoded, err := base64.StdEncoding.DecodeString(encoded)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("parseCursor: %v", err)
|
||||
// }
|
||||
var release_season oapi.ReleaseSeason
|
||||
if title.ReleaseSeason != nil {
|
||||
release_season = oapi.ReleaseSeason(*title.ReleaseSeason)
|
||||
}
|
||||
oapi_title.ReleaseSeason = &release_season
|
||||
|
||||
// // Parse JSON
|
||||
// var cursor oapi.CursorObj
|
||||
// if err := json.Unmarshal(decoded, &cursor); err != nil {
|
||||
// return nil, fmt.Errorf("parseCursor: %v", err)
|
||||
// }
|
||||
oapi_status, err := TitleStatus2oapi(&title.TitleStatus)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("TitleStatus2oapi: %v", err)
|
||||
}
|
||||
oapi_title.TitleStatus = oapi_status
|
||||
|
||||
// return &cursor, nil
|
||||
// }
|
||||
return oapi_title, nil
|
||||
}
|
||||
|
||||
func parseInt64(s string) (int32, error) {
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
|
|
|
|||
|
|
@ -26,25 +26,25 @@ type SqlcStatus struct {
|
|||
planned string
|
||||
}
|
||||
|
||||
func TitleStatus2Sqlc(s *[]oapi.TitleStatus) (*SqlcStatus, error) {
|
||||
var sqlc_status SqlcStatus
|
||||
if s == nil {
|
||||
return &sqlc_status, nil
|
||||
}
|
||||
for _, t := range *s {
|
||||
switch t {
|
||||
case oapi.TitleStatusFinished:
|
||||
sqlc_status.finished = "finished"
|
||||
case oapi.TitleStatusOngoing:
|
||||
sqlc_status.ongoing = "ongoing"
|
||||
case oapi.TitleStatusPlanned:
|
||||
sqlc_status.planned = "planned"
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected tittle status: %s", t)
|
||||
}
|
||||
}
|
||||
return &sqlc_status, nil
|
||||
}
|
||||
// func TitleStatus2Sqlc(s *[]oapi.TitleStatus) (*SqlcStatus, error) {
|
||||
// var sqlc_status SqlcStatus
|
||||
// if s == nil {
|
||||
// return &sqlc_status, nil
|
||||
// }
|
||||
// for _, t := range *s {
|
||||
// switch t {
|
||||
// case oapi.TitleStatusFinished:
|
||||
// sqlc_status.finished = "finished"
|
||||
// case oapi.TitleStatusOngoing:
|
||||
// sqlc_status.ongoing = "ongoing"
|
||||
// case oapi.TitleStatusPlanned:
|
||||
// sqlc_status.planned = "planned"
|
||||
// default:
|
||||
// return nil, fmt.Errorf("unexpected tittle status: %s", t)
|
||||
// }
|
||||
// }
|
||||
// return &sqlc_status, nil
|
||||
// }
|
||||
|
||||
func TitleStatus2oapi(s *sqlc.TitleStatusT) (*oapi.TitleStatus, error) {
|
||||
if s == nil {
|
||||
|
|
@ -158,78 +158,6 @@ func (s Server) GetStudio(ctx context.Context, id int64) (*oapi.Studio, error) {
|
|||
return &oapi_studio, nil
|
||||
}
|
||||
|
||||
func (s Server) mapTitle(ctx context.Context, title sqlc.SearchTitlesRow) (oapi.Title, error) {
|
||||
|
||||
// var oapi_title oapi.Title
|
||||
|
||||
title_names := make(map[string][]string, 0)
|
||||
err := json.Unmarshal(title.TitleNames, &title_names)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshal TitleNames: %v", err)
|
||||
}
|
||||
|
||||
episodes_lens := make(map[string]float64, 0)
|
||||
err = json.Unmarshal(title.EpisodesLen, &episodes_lens)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshal EpisodesLen: %v", err)
|
||||
}
|
||||
|
||||
oapi_tag_names := make(oapi.Tags, 0)
|
||||
err = json.Unmarshal(title.TagNames, &oapi_tag_names)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("unmarshalling title_tag: %v", err)
|
||||
}
|
||||
|
||||
var oapi_studio oapi.Studio
|
||||
|
||||
oapi_studio.Id = title.StudioID
|
||||
if title.StudioName != nil {
|
||||
oapi_studio.Name = *title.StudioName
|
||||
}
|
||||
oapi_studio.Description = title.StudioDesc
|
||||
if title.StudioIllustID != nil {
|
||||
oapi_studio.Poster.Id = title.StudioIllustID
|
||||
oapi_studio.Poster.ImagePath = title.StudioImagePath
|
||||
oapi_studio.Poster.StorageType = &title.StudioStorageType
|
||||
}
|
||||
|
||||
var oapi_image oapi.Image
|
||||
|
||||
if title.PosterID != nil {
|
||||
oapi_image.Id = title.PosterID
|
||||
oapi_image.ImagePath = title.TitleImagePath
|
||||
oapi_image.StorageType = &title.TitleStorageType
|
||||
}
|
||||
|
||||
var release_season oapi.ReleaseSeason
|
||||
if title.ReleaseSeason != nil {
|
||||
release_season = oapi.ReleaseSeason(*title.ReleaseSeason)
|
||||
}
|
||||
|
||||
oapi_status, err := TitleStatus2oapi(&title.TitleStatus)
|
||||
if err != nil {
|
||||
return oapi.Title{}, fmt.Errorf("TitleStatus2oapi: %v", err)
|
||||
}
|
||||
oapi_title := oapi.Title{
|
||||
EpisodesAired: title.EpisodesAired,
|
||||
EpisodesAll: title.EpisodesAired,
|
||||
EpisodesLen: &episodes_lens,
|
||||
Id: title.ID,
|
||||
Poster: &oapi_image,
|
||||
Rating: title.Rating,
|
||||
RatingCount: title.RatingCount,
|
||||
ReleaseSeason: &release_season,
|
||||
ReleaseYear: title.ReleaseYear,
|
||||
Studio: &oapi_studio,
|
||||
Tags: oapi_tag_names,
|
||||
TitleNames: title_names,
|
||||
TitleStatus: oapi_status,
|
||||
// AdditionalProperties:
|
||||
}
|
||||
|
||||
return oapi_title, nil
|
||||
}
|
||||
|
||||
func (s Server) GetTitlesTitleId(ctx context.Context, request oapi.GetTitlesTitleIdRequestObject) (oapi.GetTitlesTitleIdResponseObject, error) {
|
||||
var oapi_title oapi.Title
|
||||
|
||||
|
|
@ -241,29 +169,8 @@ func (s Server) GetTitlesTitleId(ctx context.Context, request oapi.GetTitlesTitl
|
|||
log.Errorf("%v", err)
|
||||
return oapi.GetTitlesTitleId500Response{}, nil
|
||||
}
|
||||
_sqlc_title := sqlc.SearchTitlesRow{
|
||||
ID: sqlc_title.ID,
|
||||
StudioID: sqlc_title.StudioID,
|
||||
PosterID: sqlc_title.PosterID,
|
||||
TitleStatus: sqlc_title.TitleStatus,
|
||||
Rating: sqlc_title.Rating,
|
||||
RatingCount: sqlc_title.RatingCount,
|
||||
ReleaseYear: sqlc_title.ReleaseYear,
|
||||
ReleaseSeason: sqlc_title.ReleaseSeason,
|
||||
Season: sqlc_title.Season,
|
||||
EpisodesAired: sqlc_title.EpisodesAired,
|
||||
EpisodesAll: sqlc_title.EpisodesAll,
|
||||
EpisodesLen: sqlc_title.EpisodesLen,
|
||||
TitleStorageType: sqlc_title.TitleStorageType,
|
||||
TitleImagePath: sqlc_title.TitleImagePath,
|
||||
TagNames: sqlc_title.TitleNames,
|
||||
StudioName: sqlc_title.StudioName,
|
||||
StudioIllustID: sqlc_title.StudioIllustID,
|
||||
StudioDesc: sqlc_title.StudioDesc,
|
||||
StudioStorageType: sqlc_title.StudioStorageType,
|
||||
StudioImagePath: sqlc_title.StudioImagePath,
|
||||
}
|
||||
oapi_title, err = s.mapTitle(ctx, _sqlc_title)
|
||||
|
||||
oapi_title, err = s.mapTitle(ctx, sqlc_title)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetTitlesTitleId500Response{}, nil
|
||||
|
|
@ -276,11 +183,6 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
|||
opai_titles := make([]oapi.Title, 0)
|
||||
|
||||
word := Word2Sqlc(request.Params.Word)
|
||||
status, err := TitleStatus2Sqlc(request.Params.Status)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetTitles400Response{}, err
|
||||
}
|
||||
|
||||
season, err := ReleaseSeason2sqlc(request.Params.ReleaseSeason)
|
||||
if err != nil {
|
||||
|
|
@ -288,16 +190,22 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
|||
return oapi.GetTitles400Response{}, err
|
||||
}
|
||||
|
||||
var statuses_sort []string
|
||||
if request.Params.Status != nil {
|
||||
for _, s := range *request.Params.Status {
|
||||
ss := string(s) // s type is alias for string
|
||||
statuses_sort = append(statuses_sort, ss)
|
||||
}
|
||||
}
|
||||
|
||||
params := sqlc.SearchTitlesParams{
|
||||
Word: word,
|
||||
Ongoing: status.ongoing,
|
||||
Finished: status.finished,
|
||||
Planned: status.planned,
|
||||
TitleStatuses: statuses_sort,
|
||||
Rating: request.Params.Rating,
|
||||
ReleaseYear: request.Params.ReleaseYear,
|
||||
ReleaseSeason: season,
|
||||
Forward: true,
|
||||
SortBy: "id",
|
||||
Forward: true, // default
|
||||
SortBy: "id", // default
|
||||
Limit: request.Params.Limit,
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +215,7 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
|||
if request.Params.Sort != nil {
|
||||
params.SortBy = string(*request.Params.Sort)
|
||||
if request.Params.Cursor != nil {
|
||||
// here we set CursorYear CursorID CursorRating fields
|
||||
err := ParseCursorInto(string(*request.Params.Sort), string(*request.Params.Cursor), ¶ms)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
|
|
@ -328,7 +237,30 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
|||
|
||||
for _, title := range titles {
|
||||
|
||||
t, err := s.mapTitle(ctx, title)
|
||||
_title := sqlc.GetTitleByIDRow{
|
||||
ID: title.ID,
|
||||
// StudioID: title.StudioID,
|
||||
PosterID: title.PosterID,
|
||||
TitleStatus: title.TitleStatus,
|
||||
Rating: title.Rating,
|
||||
RatingCount: title.RatingCount,
|
||||
ReleaseYear: title.ReleaseYear,
|
||||
ReleaseSeason: title.ReleaseSeason,
|
||||
Season: title.Season,
|
||||
EpisodesAired: title.EpisodesAired,
|
||||
EpisodesAll: title.EpisodesAll,
|
||||
// EpisodesLen: title.EpisodesLen,
|
||||
TitleStorageType: title.TitleStorageType,
|
||||
TitleImagePath: title.TitleImagePath,
|
||||
TagNames: title.TitleNames,
|
||||
StudioName: title.StudioName,
|
||||
// StudioIllustID: title.StudioIllustID,
|
||||
// StudioDesc: title.StudioDesc,
|
||||
// StudioStorageType: title.StudioStorageType,
|
||||
// StudioImagePath: title.StudioImagePath,
|
||||
}
|
||||
|
||||
t, err := s.mapTitle(ctx, _title)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetTitles500Response{}, nil
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
oapi "nyanimedb/api"
|
||||
sqlc "nyanimedb/sql"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/oapi-codegen/runtime/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// type Server struct {
|
||||
|
|
@ -50,34 +54,199 @@ func (s Server) GetUsersUserId(ctx context.Context, req oapi.GetUsersUserIdReque
|
|||
return oapi.GetUsersUserId200JSONResponse(mapUser(user)), nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsersUserIdTitles(ctx context.Context, request oapi.GetUsersUserIdTitlesRequestObject) (oapi.GetUsersUserIdTitlesResponseObject, error) {
|
||||
func sqlDate2oapi(p_date pgtype.Timestamptz) *time.Time {
|
||||
if p_date.Valid {
|
||||
t := p_date.Time
|
||||
return &t
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var rate int32 = 9
|
||||
var review_id int64 = 3
|
||||
time := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC)
|
||||
type SqlcUserStatus struct {
|
||||
dropped string
|
||||
finished string
|
||||
planned string
|
||||
in_progress string
|
||||
}
|
||||
|
||||
var userTitles = []oapi.UserTitle{
|
||||
{
|
||||
UserId: 101,
|
||||
TitleId: 2001,
|
||||
Status: oapi.UserTitleStatusFinished,
|
||||
Rate: &rate,
|
||||
Ctime: &time,
|
||||
},
|
||||
{
|
||||
UserId: 102,
|
||||
TitleId: 2002,
|
||||
Status: oapi.UserTitleStatusInProgress,
|
||||
ReviewId: &review_id,
|
||||
Ctime: &time,
|
||||
},
|
||||
{
|
||||
UserId: 103,
|
||||
TitleId: 2003,
|
||||
Status: oapi.UserTitleStatusDropped,
|
||||
Ctime: &time,
|
||||
},
|
||||
// func UserTitleStatus2Sqlc(s *[]oapi.UserTitleStatus) (*SqlcUserStatus, error) {
|
||||
// var sqlc_status SqlcUserStatus
|
||||
// if s == nil {
|
||||
// return &sqlc_status, nil
|
||||
// }
|
||||
// for _, t := range *s {
|
||||
// switch t {
|
||||
// case oapi.UserTitleStatusFinished:
|
||||
// sqlc_status.finished = "finished"
|
||||
// case oapi.UserTitleStatusDropped:
|
||||
// sqlc_status.dropped = "dropped"
|
||||
// case oapi.UserTitleStatusPlanned:
|
||||
// sqlc_status.planned = "planned"
|
||||
// case oapi.UserTitleStatusInProgress:
|
||||
// sqlc_status.in_progress = "in-progress"
|
||||
// default:
|
||||
// return nil, fmt.Errorf("unexpected tittle status: %s", t)
|
||||
// }
|
||||
// }
|
||||
// return &sqlc_status, nil
|
||||
// }
|
||||
|
||||
func sql2usertitlestatus(s sqlc.UsertitleStatusT) (oapi.UserTitleStatus, error) {
|
||||
var status oapi.UserTitleStatus
|
||||
|
||||
switch status {
|
||||
case "finished":
|
||||
status = oapi.UserTitleStatusFinished
|
||||
case "dropped":
|
||||
status = oapi.UserTitleStatusDropped
|
||||
case "planned":
|
||||
status = oapi.UserTitleStatusPlanned
|
||||
case "in-progress":
|
||||
status = oapi.UserTitleStatusInProgress
|
||||
default:
|
||||
return status, fmt.Errorf("unexpected tittle status: %s", s)
|
||||
}
|
||||
|
||||
return oapi.GetUsersUserIdTitles200JSONResponse(userTitles), nil
|
||||
return status, nil
|
||||
}
|
||||
|
||||
func (s Server) mapUsertitle(ctx context.Context, t sqlc.SearchUserTitlesRow) (oapi.UserTitle, error) {
|
||||
|
||||
oapi_usertitle := oapi.UserTitle{
|
||||
Ctime: sqlDate2oapi(t.UserCtime),
|
||||
Rate: t.UserRate,
|
||||
ReviewId: t.ReviewID,
|
||||
// Status: ,
|
||||
// Title: ,
|
||||
UserId: t.UserID,
|
||||
}
|
||||
|
||||
status, err := sql2usertitlestatus(t.UsertitleStatus)
|
||||
if err != nil {
|
||||
return oapi_usertitle, fmt.Errorf("mapUsertitle: %v", err)
|
||||
}
|
||||
oapi_usertitle.Status = status
|
||||
|
||||
_title := sqlc.GetTitleByIDRow{
|
||||
ID: t.ID,
|
||||
// StudioID: title.StudioID,
|
||||
PosterID: t.PosterID,
|
||||
TitleStatus: t.TitleStatus,
|
||||
Rating: t.Rating,
|
||||
RatingCount: t.RatingCount,
|
||||
ReleaseYear: t.ReleaseYear,
|
||||
ReleaseSeason: t.ReleaseSeason,
|
||||
Season: t.Season,
|
||||
EpisodesAired: t.EpisodesAired,
|
||||
EpisodesAll: t.EpisodesAll,
|
||||
// EpisodesLen: title.EpisodesLen,
|
||||
TitleStorageType: t.TitleStorageType,
|
||||
TitleImagePath: t.TitleImagePath,
|
||||
TagNames: t.TitleNames,
|
||||
StudioName: t.StudioName,
|
||||
// StudioIllustID: title.StudioIllustID,
|
||||
// StudioDesc: title.StudioDesc,
|
||||
// StudioStorageType: title.StudioStorageType,
|
||||
// StudioImagePath: title.StudioImagePath,
|
||||
}
|
||||
|
||||
oapi_title, err := s.mapTitle(ctx, _title)
|
||||
if err != nil {
|
||||
return oapi_usertitle, fmt.Errorf("mapUsertitle: %v", err)
|
||||
}
|
||||
oapi_usertitle.Title = &oapi_title
|
||||
|
||||
return oapi_usertitle, nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsersUserIdTitles(ctx context.Context, request oapi.GetUsersUserIdTitlesRequestObject) (oapi.GetUsersUserIdTitlesResponseObject, error) {
|
||||
|
||||
oapi_usertitles := make([]oapi.UserTitle, 0)
|
||||
|
||||
word := Word2Sqlc(request.Params.Word)
|
||||
|
||||
season, err := ReleaseSeason2sqlc(request.Params.ReleaseSeason)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetUsersUserIdTitles400Response{}, err
|
||||
}
|
||||
|
||||
var statuses_sort []string
|
||||
if request.Params.Status != nil {
|
||||
for _, s := range *request.Params.Status {
|
||||
ss := string(s) // s type is alias for string
|
||||
statuses_sort = append(statuses_sort, ss)
|
||||
}
|
||||
}
|
||||
|
||||
var watch_status []string
|
||||
if request.Params.WatchStatus != nil {
|
||||
for _, s := range *request.Params.WatchStatus {
|
||||
ss := string(s) // s type is alias for string
|
||||
watch_status = append(statuses_sort, ss)
|
||||
}
|
||||
}
|
||||
|
||||
params := sqlc.SearchUserTitlesParams{
|
||||
Word: word,
|
||||
TitleStatuses: statuses_sort,
|
||||
UsertitleStatuses: watch_status,
|
||||
Rating: request.Params.Rating,
|
||||
Rate: request.Params.MyRate,
|
||||
ReleaseYear: request.Params.ReleaseYear,
|
||||
ReleaseSeason: season,
|
||||
Forward: true, // default
|
||||
SortBy: "id", // default
|
||||
Limit: request.Params.Limit,
|
||||
}
|
||||
|
||||
if request.Params.SortForward != nil {
|
||||
params.Forward = *request.Params.SortForward
|
||||
}
|
||||
if request.Params.Sort != nil {
|
||||
params.SortBy = string(*request.Params.Sort)
|
||||
if request.Params.Cursor != nil {
|
||||
// here we set CursorYear CursorID CursorRating fields
|
||||
err := ParseCursorInto(string(*request.Params.Sort), string(*request.Params.Cursor), ¶ms)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetUsersUserIdTitles400Response{}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// param = nil means it will not be used
|
||||
titles, err := s.db.SearchUserTitles(ctx, params)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetUsersUserIdTitles500Response{}, nil
|
||||
}
|
||||
if len(titles) == 0 {
|
||||
return oapi.GetUsersUserIdTitles204Response{}, nil
|
||||
}
|
||||
|
||||
var new_cursor oapi.CursorObj
|
||||
|
||||
for _, title := range titles {
|
||||
|
||||
t, err := s.mapUsertitle(ctx, title)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
return oapi.GetUsersUserIdTitles500Response{}, nil
|
||||
}
|
||||
oapi_usertitles = append(oapi_usertitles, t)
|
||||
|
||||
new_cursor.Id = t.Title.Id
|
||||
if request.Params.Sort != nil {
|
||||
switch string(*request.Params.Sort) {
|
||||
case "year":
|
||||
tmp := fmt.Sprint(*t.Title.ReleaseYear)
|
||||
new_cursor.Param = &tmp
|
||||
case "rating":
|
||||
tmp := strconv.FormatFloat(*t.Title.Rating, 'f', -1, 64)
|
||||
new_cursor.Param = &tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oapi.GetUsersUserIdTitles200JSONResponse{Cursor: new_cursor, Data: oapi_usertitles}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,31 +95,36 @@ LEFT JOIN tags as g ON (tt.tag_id = g.id)
|
|||
LEFT JOIN studios as s ON (t.studio_id = s.id)
|
||||
LEFT JOIN images as si ON (s.illust_id = si.id)
|
||||
|
||||
WHERE id = sqlc.arg('title_id')::bigint
|
||||
WHERE t.id = sqlc.arg('title_id')::bigint
|
||||
GROUP BY
|
||||
t.id, i.id, s.id, si.id;
|
||||
|
||||
-- name: SearchTitles :many
|
||||
SELECT
|
||||
t.*,
|
||||
t.id as id,
|
||||
t.title_names as title_names,
|
||||
t.poster_id as poster_id,
|
||||
t.title_status as title_status,
|
||||
t.rating as rating,
|
||||
t.rating_count as rating_count,
|
||||
t.release_year as release_year,
|
||||
t.release_season as release_season,
|
||||
t.season as season,
|
||||
t.episodes_aired as episodes_aired,
|
||||
t.episodes_all as episodes_all,
|
||||
i.storage_type::text as title_storage_type,
|
||||
i.image_path as title_image_path,
|
||||
COALESCE(
|
||||
jsonb_agg(g.tag_names) FILTER (WHERE g.tag_names IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
)::jsonb as tag_names,
|
||||
s.studio_name as studio_name,
|
||||
s.illust_id as studio_illust_id,
|
||||
s.studio_desc as studio_desc,
|
||||
si.storage_type::text as studio_storage_type,
|
||||
si.image_path as studio_image_path
|
||||
s.studio_name as studio_name
|
||||
|
||||
FROM titles as t
|
||||
LEFT JOIN images as i ON (t.poster_id = i.id)
|
||||
LEFT JOIN title_tags as tt ON (t.id = tt.title_id)
|
||||
LEFT JOIN tags as g ON (tt.tag_id = g.id)
|
||||
LEFT JOIN studios as s ON (t.studio_id = s.id)
|
||||
LEFT JOIN images as si ON (s.illust_id = si.id)
|
||||
|
||||
WHERE
|
||||
CASE
|
||||
|
|
@ -187,13 +192,19 @@ WHERE
|
|||
END
|
||||
)
|
||||
|
||||
AND (t.title_status::text IN (sqlc.arg('ongoing')::text, sqlc.arg('finished')::text, sqlc.arg('planned')::text))
|
||||
AND (
|
||||
-- Если массив пуст (NULL или []) — не фильтруем
|
||||
cardinality(sqlc.arg('title_statuses')::text[]) = 0
|
||||
OR
|
||||
-- Иначе: статус есть в списке
|
||||
t.title_status = ANY(sqlc.arg('title_statuses')::text[])
|
||||
)
|
||||
AND (sqlc.narg('rating')::float IS NULL OR t.rating >= sqlc.narg('rating')::float)
|
||||
AND (sqlc.narg('release_year')::int IS NULL OR t.release_year = sqlc.narg('release_year')::int)
|
||||
AND (sqlc.narg('release_season')::release_season_t IS NULL OR t.release_season = sqlc.narg('release_season')::release_season_t)
|
||||
|
||||
GROUP BY
|
||||
t.id, i.id, s.id, si.id
|
||||
t.id, i.id, s.id
|
||||
|
||||
ORDER BY
|
||||
CASE WHEN sqlc.arg('forward')::boolean THEN
|
||||
|
|
@ -216,37 +227,142 @@ ORDER BY
|
|||
LIMIT COALESCE(sqlc.narg('limit')::int, 100); -- 100 is default limit
|
||||
|
||||
-- name: SearchUserTitles :many
|
||||
SELECT
|
||||
*
|
||||
FROM usertitles as u
|
||||
JOIN titles as t ON (u.title_id = t.id)
|
||||
WHERE
|
||||
CASE
|
||||
WHEN sqlc.narg('word')::text IS NOT NULL THEN
|
||||
(
|
||||
SELECT bool_and(
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM jsonb_each_text(t.title_names) AS t(key, val)
|
||||
WHERE val ILIKE pattern
|
||||
)
|
||||
)
|
||||
FROM unnest(
|
||||
ARRAY(
|
||||
SELECT '%' || trim(w) || '%'
|
||||
FROM unnest(string_to_array(sqlc.narg('word')::text, ' ')) AS w
|
||||
WHERE trim(w) <> ''
|
||||
)
|
||||
) AS pattern
|
||||
)
|
||||
ELSE true
|
||||
SELECT
|
||||
t.id as id,
|
||||
t.title_names as title_names,
|
||||
t.poster_id as poster_id,
|
||||
t.title_status as title_status,
|
||||
t.rating as rating,
|
||||
t.rating_count as rating_count,
|
||||
t.release_year as release_year,
|
||||
t.release_season as release_season,
|
||||
t.season as season,
|
||||
t.episodes_aired as episodes_aired,
|
||||
t.episodes_all as episodes_all,
|
||||
u.user_id as user_id,
|
||||
u.status as usertitle_status,
|
||||
u.rate as user_rate,
|
||||
u.review_id as review_id,
|
||||
u.ctime as user_ctime,
|
||||
i.storage_type::text as title_storage_type,
|
||||
i.image_path as title_image_path,
|
||||
COALESCE(
|
||||
jsonb_agg(g.tag_names) FILTER (WHERE g.tag_names IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
)::jsonb as tag_names,
|
||||
s.studio_name as studio_name
|
||||
|
||||
FROM usertitles as u
|
||||
JOIN titles as t ON (u.title_id = t.id)
|
||||
LEFT JOIN images as i ON (t.poster_id = i.id)
|
||||
LEFT JOIN title_tags as tt ON (t.id = tt.title_id)
|
||||
LEFT JOIN tags as g ON (tt.tag_id = g.id)
|
||||
LEFT JOIN studios as s ON (t.studio_id = s.id)
|
||||
|
||||
WHERE
|
||||
CASE
|
||||
WHEN sqlc.arg('forward')::boolean THEN
|
||||
-- forward: greater than cursor (next page)
|
||||
CASE sqlc.arg('sort_by')::text
|
||||
WHEN 'year' THEN
|
||||
(sqlc.narg('cursor_year')::int IS NULL) OR
|
||||
(t.release_year > sqlc.narg('cursor_year')::int) OR
|
||||
(t.release_year = sqlc.narg('cursor_year')::int AND t.id > sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
WHEN 'rating' THEN
|
||||
(sqlc.narg('cursor_rating')::float IS NULL) OR
|
||||
(t.rating > sqlc.narg('cursor_rating')::float) OR
|
||||
(t.rating = sqlc.narg('cursor_rating')::float AND t.id > sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
WHEN 'id' THEN
|
||||
(sqlc.narg('cursor_id')::bigint IS NULL) OR
|
||||
(t.id > sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
ELSE true -- fallback
|
||||
END
|
||||
|
||||
ELSE
|
||||
-- backward: less than cursor (prev page)
|
||||
CASE sqlc.arg('sort_by')::text
|
||||
WHEN 'year' THEN
|
||||
(sqlc.narg('cursor_year')::int IS NULL) OR
|
||||
(t.release_year < sqlc.narg('cursor_year')::int) OR
|
||||
(t.release_year = sqlc.narg('cursor_year')::int AND t.id < sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
WHEN 'rating' THEN
|
||||
(sqlc.narg('cursor_rating')::float IS NULL) OR
|
||||
(t.rating < sqlc.narg('cursor_rating')::float) OR
|
||||
(t.rating = sqlc.narg('cursor_rating')::float AND t.id < sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
WHEN 'id' THEN
|
||||
(sqlc.narg('cursor_id')::bigint IS NULL) OR
|
||||
(t.id < sqlc.narg('cursor_id')::bigint)
|
||||
|
||||
ELSE true
|
||||
END
|
||||
END
|
||||
|
||||
AND (sqlc.narg('status')::title_status_t IS NULL OR t.title_status = sqlc.narg('status')::title_status_t)
|
||||
AND (
|
||||
CASE
|
||||
WHEN sqlc.narg('word')::text IS NOT NULL THEN
|
||||
(
|
||||
SELECT bool_and(
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM jsonb_each_text(t.title_names) AS t(key, val)
|
||||
WHERE val ILIKE pattern
|
||||
)
|
||||
)
|
||||
FROM unnest(
|
||||
ARRAY(
|
||||
SELECT '%' || trim(w) || '%'
|
||||
FROM unnest(string_to_array(sqlc.narg('word')::text, ' ')) AS w
|
||||
WHERE trim(w) <> ''
|
||||
)
|
||||
) AS pattern
|
||||
)
|
||||
ELSE true
|
||||
END
|
||||
)
|
||||
|
||||
AND (
|
||||
-- Если массив пуст (NULL или []) — не фильтруем
|
||||
cardinality(sqlc.arg('title_statuses')::text[]) = 0
|
||||
OR
|
||||
t.title_status = ANY(sqlc.arg('title_statuses')::text[])
|
||||
)
|
||||
AND (
|
||||
cardinality(sqlc.arg('usertitle_statuses')::text[]) = 0
|
||||
OR
|
||||
u.status = ANY(sqlc.arg('usertitle_statuses')::text[])
|
||||
)
|
||||
AND (sqlc.narg('rate')::int IS NULL OR u.rate >= sqlc.narg('rate')::int)
|
||||
AND (sqlc.narg('rating')::float IS NULL OR t.rating >= sqlc.narg('rating')::float)
|
||||
AND (sqlc.narg('release_year')::int IS NULL OR t.release_year = sqlc.narg('release_year')::int)
|
||||
AND (sqlc.narg('release_season')::release_season_t IS NULL OR t.release_season = sqlc.narg('release_season')::release_season_t)
|
||||
AND (sqlc.narg('usertitle_status')::usertitle_status_t IS NULL OR u.usertitle_status = sqlc.narg('usertitle_status')::usertitle_status_t)
|
||||
|
||||
GROUP BY
|
||||
t.id, i.id, s.id
|
||||
|
||||
ORDER BY
|
||||
CASE WHEN sqlc.arg('forward')::boolean THEN
|
||||
CASE
|
||||
WHEN sqlc.arg('sort_by')::text = 'id' THEN t.id
|
||||
WHEN sqlc.arg('sort_by')::text = 'year' THEN t.release_year
|
||||
WHEN sqlc.arg('sort_by')::text = 'rating' THEN t.rating
|
||||
WHEN sqlc.arg('sort_by')::text = 'rate' THEN u.rate
|
||||
END
|
||||
END ASC,
|
||||
CASE WHEN NOT sqlc.arg('forward')::boolean THEN
|
||||
CASE
|
||||
WHEN sqlc.arg('sort_by')::text = 'id' THEN t.id
|
||||
WHEN sqlc.arg('sort_by')::text = 'year' THEN t.release_year
|
||||
WHEN sqlc.arg('sort_by')::text = 'rating' THEN t.rating
|
||||
WHEN sqlc.arg('sort_by')::text = 'rate' THEN u.rate
|
||||
END
|
||||
END DESC,
|
||||
|
||||
CASE WHEN sqlc.arg('sort_by')::text <> 'id' THEN t.id END ASC
|
||||
|
||||
LIMIT COALESCE(sqlc.narg('limit')::int, 100); -- 100 is default limit
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue