Compare commits
11 commits
de1479c995
...
102d15c5fd
| Author | SHA1 | Date | |
|---|---|---|---|
| 102d15c5fd | |||
| eda59c68d3 | |||
| e239c0ca04 | |||
| 80285ba7da | |||
| 31a09037cb | |||
| 2d2d97ec27 | |||
| 03f5b3b3db | |||
| 29c034bd1a | |||
| 18722db340 | |||
| 8b317ae655 | |||
| cbbb135a72 |
18 changed files with 6994 additions and 25 deletions
1958
api/gen.go
Normal file
1958
api/gen.go
Normal file
File diff suppressed because it is too large
Load diff
6
api/oapi-codegen.yaml
Normal file
6
api/oapi-codegen.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package: api
|
||||
generate:
|
||||
strict-server: true
|
||||
gin-server: true
|
||||
models: true
|
||||
output: gen.go
|
||||
1958
modules/backend/api/gen.go
Normal file
1958
modules/backend/api/gen.go
Normal file
File diff suppressed because it is too large
Load diff
718
modules/backend/api/impl.go
Normal file
718
modules/backend/api/impl.go
Normal file
|
|
@ -0,0 +1,718 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"nyanimedb-server/db"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
db *db.Queries
|
||||
}
|
||||
|
||||
func NewServer(db *db.Queries) Server {
|
||||
return Server{db: db}
|
||||
}
|
||||
|
||||
// —————————————————————————————————————————————
|
||||
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
|
||||
// —————————————————————————————————————————————
|
||||
|
||||
func parseInt32(s string) (int32, error) {
|
||||
i, err := strconv.ParseInt(s, 10, 32)
|
||||
return int32(i), err
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
|
||||
func pgInt4ToPtr(v pgtype.Int4) *int32 {
|
||||
if v.Valid {
|
||||
return &v.Int32
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pgTextToPtr(v pgtype.Text) *string {
|
||||
if v.Valid {
|
||||
return &v.String
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pgFloat8ToPtr(v pgtype.Float8) *float64 {
|
||||
if v.Valid {
|
||||
return &v.Float64
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func jsonbToInterface(data []byte) interface{} {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
var out interface{}
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return string(data) // fallback
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// —————————————————————————————————————————————
|
||||
// ХЕНДЛЕРЫ
|
||||
// —————————————————————————————————————————————
|
||||
|
||||
func (s Server) GetMedia(ctx context.Context, req GetMediaRequestObject) (GetMediaResponseObject, error) {
|
||||
id, err := parseInt32(req.Params.ImageId)
|
||||
if err != nil {
|
||||
return GetMedia200JSONResponse{Success: ptr(false), Error: ptr("invalid image_id")}, nil
|
||||
}
|
||||
img, err := s.db.GetImageByID(ctx, id)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return GetMedia200JSONResponse{Success: ptr(false), Error: ptr("image not found")}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return GetMedia200JSONResponse{
|
||||
Success: ptr(true),
|
||||
ImagePath: ptr(img.ImagePath),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s Server) PostMedia(ctx context.Context, req PostMediaRequestObject) (PostMediaResponseObject, error) {
|
||||
// ❗ Не реализовано: OpenAPI не определяет тело запроса для загрузки
|
||||
return PostMedia200JSONResponse{
|
||||
Success: ptr(false),
|
||||
Error: ptr("upload not implemented: request body not defined in spec"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsers(ctx context.Context, req GetUsersRequestObject) (GetUsersResponseObject, error) {
|
||||
users, err := s.db.ListUsers(ctx, db.ListUsersParams{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp []User
|
||||
for _, u := range users {
|
||||
resp = append(resp, mapUser(u))
|
||||
}
|
||||
return GetUsers200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) PostUsers(ctx context.Context, req PostUsersRequestObject) (PostUsersResponseObject, error) {
|
||||
if req.Body == nil {
|
||||
return PostUsers200JSONResponse{
|
||||
Success: ptr(false),
|
||||
Error: ptr("request body is required"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
body := *req.Body
|
||||
|
||||
// Обязательные поля
|
||||
nickname, ok := body["nickname"].(string)
|
||||
if !ok || nickname == "" {
|
||||
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("nickname is required")}, nil
|
||||
}
|
||||
|
||||
mail, ok := body["mail"].(string)
|
||||
if !ok || mail == "" {
|
||||
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("mail is required")}, nil
|
||||
}
|
||||
|
||||
password, ok := body["password"].(string)
|
||||
if !ok || password == "" {
|
||||
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("password is required")}, nil
|
||||
}
|
||||
|
||||
// Опциональные поля
|
||||
var avatarID *int32
|
||||
if v, ok := body["avatar_id"].(float64); ok {
|
||||
id := int32(v)
|
||||
avatarID = &id
|
||||
}
|
||||
|
||||
dispName, _ := body["disp_name"].(string)
|
||||
userDesc, _ := body["user_desc"].(string)
|
||||
|
||||
// 🔐 Хешируем пароль
|
||||
passhashBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("failed to hash password")}, nil
|
||||
}
|
||||
passhash := string(passhashBytes)
|
||||
|
||||
// Сохраняем в БД
|
||||
_, err = s.db.CreateUser(ctx, db.CreateUserParams{
|
||||
AvatarID: pgtype.Int4{
|
||||
Int32: 0,
|
||||
Valid: avatarID != nil,
|
||||
},
|
||||
Passhash: passhash,
|
||||
Mail: pgtype.Text{
|
||||
String: mail,
|
||||
Valid: true,
|
||||
},
|
||||
Nickname: nickname,
|
||||
DispName: pgtype.Text{
|
||||
String: dispName,
|
||||
Valid: dispName != "",
|
||||
},
|
||||
UserDesc: pgtype.Text{
|
||||
String: userDesc,
|
||||
Valid: userDesc != "",
|
||||
},
|
||||
CreationDate: pgtype.Timestamp{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
// Проверяем нарушение уникальности (например, дубль mail или nickname)
|
||||
if err.Error() == "ERROR: duplicate key value violates unique constraint \"users_mail_key\"" ||
|
||||
err.Error() == "ERROR: duplicate key value violates unique constraint \"users_nickname_key\"" {
|
||||
return PostUsers200JSONResponse{
|
||||
Success: ptr(false),
|
||||
Error: ptr("user with this email or nickname already exists"),
|
||||
}, nil
|
||||
}
|
||||
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("database error")}, nil
|
||||
}
|
||||
|
||||
// Получаем созданного пользователя (без passhash и mail!)
|
||||
// Предположим, что у вас есть запрос GetUserByNickname или аналогичный
|
||||
// Но проще — вернуть только ID и nickname
|
||||
|
||||
// ⚠️ Поскольку мы не знаем user_id, можно:
|
||||
// а) добавить RETURNING в CreateUser (рекомендуется),
|
||||
// б) сделать отдельный SELECT.
|
||||
|
||||
// Пока вернём минимальный ответ
|
||||
userResp := User{
|
||||
"nickname": nickname,
|
||||
// "user_id" можно добавить, если обновите query.sql
|
||||
}
|
||||
|
||||
return PostUsers200JSONResponse{
|
||||
Success: ptr(true),
|
||||
UserJson: &userResp,
|
||||
}, nil
|
||||
}
|
||||
func (s Server) DeleteUsersUserId(ctx context.Context, req DeleteUsersUserIdRequestObject) (DeleteUsersUserIdResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return DeleteUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||
}
|
||||
err = s.db.DeleteUser(ctx, userID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return DeleteUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("user not found")}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return DeleteUsersUserId200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsersUserId(ctx context.Context, req GetUsersUserIdRequestObject) (GetUsersUserIdResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return GetUsersUserId404Response{}, nil
|
||||
}
|
||||
user, err := s.db.GetUserByID(ctx, userID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return GetUsersUserId404Response{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return GetUsersUserId200JSONResponse(mapUser(user)), nil
|
||||
}
|
||||
|
||||
func (s Server) PatchUsersUserId(ctx context.Context, req PatchUsersUserIdRequestObject) (PatchUsersUserIdResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||
}
|
||||
if req.Body == nil {
|
||||
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
}
|
||||
|
||||
body := *req.Body
|
||||
args := db.UpdateUserParams{
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
if v, ok := body["avatar_id"].(float64); ok {
|
||||
args.AvatarID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.AvatarIDValid = true
|
||||
}
|
||||
if v, ok := body["disp_name"].(string); ok {
|
||||
args.DispName = pgtype.Text{String: v, Valid: true}
|
||||
// args.DispNameValid = true
|
||||
}
|
||||
if v, ok := body["user_desc"].(string); ok {
|
||||
args.UserDesc = pgtype.Text{String: v, Valid: true}
|
||||
// args.UserDescValid = true
|
||||
}
|
||||
|
||||
_, err = s.db.UpdateUser(ctx, args)
|
||||
if err != nil {
|
||||
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
}
|
||||
return PatchUsersUserId200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsersUserIdReviews(ctx context.Context, req GetUsersUserIdReviewsRequestObject) (GetUsersUserIdReviewsResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return GetUsersUserIdReviews200JSONResponse{}, nil
|
||||
}
|
||||
limit := int32(20)
|
||||
offset := int32(0)
|
||||
// if req.Params.Limit != nil {
|
||||
// limit = int32(*req.Params.Limit)
|
||||
// }
|
||||
// if req.Params.Offset != nil {
|
||||
// offset = int32(*req.Params.Offset)
|
||||
// }
|
||||
|
||||
reviews, err := s.db.ListReviewsByUser(ctx, db.ListReviewsByUserParams{
|
||||
UserID: userID,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []Review
|
||||
for _, r := range reviews {
|
||||
resp = append(resp, mapReview(r))
|
||||
}
|
||||
return GetUsersUserIdReviews200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) DeleteUsersUserIdTitles(ctx context.Context, req DeleteUsersUserIdTitlesRequestObject) (DeleteUsersUserIdTitlesResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||
}
|
||||
|
||||
if req.Params.TitleId != nil {
|
||||
titleID, err := parseInt32(*req.Params.TitleId)
|
||||
if err != nil {
|
||||
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||
}
|
||||
err = s.db.DeleteUserTitle(ctx, db.DeleteUserTitleParams{
|
||||
UserID: userID,
|
||||
Column2: titleID,
|
||||
})
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// err = s.db.DeleteAllUserTitles(ctx, userID)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetUsersUserIdTitles(ctx context.Context, req GetUsersUserIdTitlesRequestObject) (GetUsersUserIdTitlesResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return GetUsersUserIdTitles200JSONResponse{}, nil
|
||||
}
|
||||
limit := int32(100)
|
||||
offset := int32(0)
|
||||
if req.Params.Limit != nil {
|
||||
limit = int32(*req.Params.Limit)
|
||||
}
|
||||
if req.Params.Offset != nil {
|
||||
offset = int32(*req.Params.Offset)
|
||||
}
|
||||
|
||||
titles, err := s.db.ListUserTitles(ctx, db.ListUserTitlesParams{
|
||||
UserID: userID,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []UserTitle
|
||||
for _, t := range titles {
|
||||
resp = append(resp, mapUserTitle(t))
|
||||
}
|
||||
return GetUsersUserIdTitles200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) PatchUsersUserIdTitles(ctx context.Context, req PatchUsersUserIdTitlesRequestObject) (PatchUsersUserIdTitlesResponseObject, error) {
|
||||
// userID, err := parseInt32(req.UserId)
|
||||
// if err != nil {
|
||||
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||
// }
|
||||
// if req.Body == nil {
|
||||
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
// }
|
||||
|
||||
// body := *req.Body
|
||||
// titleID, ok := body["title_id"].(float64)
|
||||
// if !ok {
|
||||
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("title_id required")}, nil
|
||||
// }
|
||||
|
||||
// args := db.UpdateUserTitleParams{
|
||||
// UserID: userID,
|
||||
// TitleID: int32(titleID),
|
||||
// }
|
||||
|
||||
// if v, ok := body["status"].(string); ok {
|
||||
// args.Status = db.UsertitleStatusT(v)
|
||||
// // args.StatusValid = true
|
||||
// }
|
||||
// if v, ok := body["rate"].(float64); ok {
|
||||
// args.Rate = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// // args.RateValid = true
|
||||
// }
|
||||
// if v, ok := body["review_id"].(float64); ok {
|
||||
// args.ReviewID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// // args.ReviewIDValid = true
|
||||
// }
|
||||
|
||||
// _, err = s.db.UpdateUserTitle(ctx, args)
|
||||
// if err != nil {
|
||||
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
// }
|
||||
return PatchUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) PostUsersUserIdTitles(ctx context.Context, req PostUsersUserIdTitlesRequestObject) (PostUsersUserIdTitlesResponseObject, error) {
|
||||
userID, err := parseInt32(req.UserId)
|
||||
if err != nil {
|
||||
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||
}
|
||||
if req.Body == nil {
|
||||
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
}
|
||||
|
||||
body := req.Body
|
||||
titleID, err := parseInt32(*body.TitleId)
|
||||
if err != nil {
|
||||
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||
}
|
||||
|
||||
status := db.UsertitleStatusT("planned")
|
||||
if body.Status != nil {
|
||||
status = db.UsertitleStatusT(*body.Status)
|
||||
}
|
||||
|
||||
_, err = s.db.CreateUserTitle(ctx, db.CreateUserTitleParams{
|
||||
UserID: userID,
|
||||
TitleID: titleID,
|
||||
Status: status,
|
||||
Rate: pgtype.Int4{Valid: false},
|
||||
ReviewID: pgtype.Int4{Valid: false},
|
||||
})
|
||||
if err != nil {
|
||||
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
}
|
||||
return PostUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetTags(ctx context.Context, req GetTagsRequestObject) (GetTagsResponseObject, error) {
|
||||
limit := int32(100)
|
||||
offset := int32(0)
|
||||
if req.Params.Limit != nil {
|
||||
limit = int32(*req.Params.Limit)
|
||||
}
|
||||
if req.Params.Offset != nil {
|
||||
offset = int32(*req.Params.Offset)
|
||||
}
|
||||
tags, err := s.db.ListTags(ctx, db.ListTagsParams{Limit: limit, Offset: offset})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp []Tag
|
||||
for _, t := range tags {
|
||||
resp = append(resp, Tag{
|
||||
"tag_id": t.TagID,
|
||||
"tag_names": jsonbToInterface(t.TagNames),
|
||||
})
|
||||
}
|
||||
return GetTags200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) GetTitle(ctx context.Context, req GetTitleRequestObject) (GetTitleResponseObject, error) {
|
||||
limit := int32(50)
|
||||
offset := int32(0)
|
||||
if req.Params.Limit != nil {
|
||||
limit = int32(*req.Params.Limit)
|
||||
}
|
||||
if req.Params.Offset != nil {
|
||||
offset = int32(*req.Params.Offset)
|
||||
}
|
||||
titles, err := s.db.ListTitles(ctx, db.ListTitlesParams{Limit: limit, Offset: offset})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp []Title
|
||||
for _, t := range titles {
|
||||
resp = append(resp, mapTitle(t))
|
||||
}
|
||||
return GetTitle200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) GetTitleTitleId(ctx context.Context, req GetTitleTitleIdRequestObject) (GetTitleTitleIdResponseObject, error) {
|
||||
titleID, err := parseInt32(req.TitleId)
|
||||
if err != nil {
|
||||
return GetTitleTitleId404Response{}, nil
|
||||
}
|
||||
title, err := s.db.GetTitleByID(ctx, titleID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return GetTitleTitleId404Response{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return GetTitleTitleId200JSONResponse(mapTitle(title)), nil
|
||||
}
|
||||
|
||||
func (s Server) PatchTitleTitleId(ctx context.Context, req PatchTitleTitleIdRequestObject) (PatchTitleTitleIdResponseObject, error) {
|
||||
titleID, err := parseInt32(req.TitleId)
|
||||
if err != nil {
|
||||
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||
}
|
||||
if req.Body == nil {
|
||||
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
}
|
||||
|
||||
body := *req.Body
|
||||
args := db.UpdateTitleParams{
|
||||
TitleID: titleID,
|
||||
}
|
||||
|
||||
if v, ok := body["title_names"].(map[string]interface{}); ok {
|
||||
data, _ := json.Marshal(v)
|
||||
args.TitleNames = data
|
||||
// args.TitleNamesValid = true
|
||||
}
|
||||
if v, ok := body["studio_id"].(float64); ok {
|
||||
args.StudioID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.StudioIDValid = true
|
||||
}
|
||||
if v, ok := body["poster_id"].(float64); ok {
|
||||
args.PosterID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.PosterIDValid = true
|
||||
}
|
||||
// if v, ok := body["title_status"].(string); ok {
|
||||
// args.TitleStatus = db.NullTitleStatusT(v)
|
||||
// // args.TitleStatusValid = true
|
||||
// }
|
||||
if v, ok := body["release_year"].(float64); ok {
|
||||
args.ReleaseYear = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.ReleaseYearValid = true
|
||||
}
|
||||
if v, ok := body["episodes_aired"].(float64); ok {
|
||||
args.EpisodesAired = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.EpisodesAiredValid = true
|
||||
}
|
||||
if v, ok := body["episodes_all"].(float64); ok {
|
||||
args.EpisodesAll = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||
// args.EpisodesAllValid = true
|
||||
}
|
||||
|
||||
_, err = s.db.UpdateTitle(ctx, args)
|
||||
if err != nil {
|
||||
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
}
|
||||
return PatchTitleTitleId200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) GetTitleTitleIdReviews(ctx context.Context, req GetTitleTitleIdReviewsRequestObject) (GetTitleTitleIdReviewsResponseObject, error) {
|
||||
titleID, err := parseInt32(req.TitleId)
|
||||
if err != nil {
|
||||
return GetTitleTitleIdReviews200JSONResponse{}, nil
|
||||
}
|
||||
limit := int32(20)
|
||||
offset := int32(0)
|
||||
if req.Params.Limit != nil {
|
||||
limit = int32(*req.Params.Limit)
|
||||
}
|
||||
if req.Params.Offset != nil {
|
||||
offset = int32(*req.Params.Offset)
|
||||
}
|
||||
|
||||
reviews, err := s.db.ListReviewsByTitle(ctx, db.ListReviewsByTitleParams{
|
||||
TitleID: titleID,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []Review
|
||||
for _, r := range reviews {
|
||||
resp = append(resp, mapReview(r))
|
||||
}
|
||||
return GetTitleTitleIdReviews200JSONResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s Server) PostReviews(ctx context.Context, req PostReviewsRequestObject) (PostReviewsResponseObject, error) {
|
||||
if req.Body == nil {
|
||||
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
}
|
||||
|
||||
body := *req.Body
|
||||
userID, ok1 := body["user_id"].(float64)
|
||||
titleID, ok2 := body["title_id"].(float64)
|
||||
reviewText, ok3 := body["review_text"].(string)
|
||||
if !ok1 || !ok2 || !ok3 {
|
||||
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr("user_id, title_id, review_text required")}, nil
|
||||
}
|
||||
|
||||
var imageIDs []int32
|
||||
if ids, ok := body["image_ids"].([]interface{}); ok {
|
||||
for _, id := range ids {
|
||||
if f, ok := id.(float64); ok {
|
||||
imageIDs = append(imageIDs, int32(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := s.db.CreateReview(ctx, db.CreateReviewParams{
|
||||
UserID: int32(userID),
|
||||
TitleID: int32(titleID),
|
||||
ImageIds: imageIDs,
|
||||
ReviewText: reviewText,
|
||||
CreationDate: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
}
|
||||
|
||||
return PostReviews200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) DeleteReviewsReviewId(ctx context.Context, req DeleteReviewsReviewIdRequestObject) (DeleteReviewsReviewIdResponseObject, error) {
|
||||
reviewID, err := parseInt32(req.ReviewId)
|
||||
if err != nil {
|
||||
return DeleteReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("invalid review_id")}, nil
|
||||
}
|
||||
err = s.db.DeleteReview(ctx, reviewID)
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return DeleteReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("review not found")}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return DeleteReviewsReviewId200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
func (s Server) PatchReviewsReviewId(ctx context.Context, req PatchReviewsReviewIdRequestObject) (PatchReviewsReviewIdResponseObject, error) {
|
||||
reviewID, err := parseInt32(req.ReviewId)
|
||||
if err != nil {
|
||||
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("invalid review_id")}, nil
|
||||
}
|
||||
if req.Body == nil {
|
||||
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||
}
|
||||
|
||||
body := *req.Body
|
||||
args := db.UpdateReviewParams{
|
||||
ReviewID: reviewID,
|
||||
}
|
||||
|
||||
if v, ok := body["review_text"].(string); ok {
|
||||
args.ReviewText = pgtype.Text{String: v, Valid: true}
|
||||
// args.ReviewTextValid = true
|
||||
}
|
||||
if ids, ok := body["image_ids"].([]interface{}); ok {
|
||||
var imageIDs []int32
|
||||
for _, id := range ids {
|
||||
if f, ok := id.(float64); ok {
|
||||
imageIDs = append(imageIDs, int32(f))
|
||||
}
|
||||
}
|
||||
args.ImageIds = imageIDs
|
||||
// args.ImageIdsValid = true
|
||||
}
|
||||
|
||||
_, err = s.db.UpdateReview(ctx, args)
|
||||
if err != nil {
|
||||
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||
}
|
||||
return PatchReviewsReviewId200JSONResponse{Success: ptr(true)}, nil
|
||||
}
|
||||
|
||||
// —————————————————————————————————————————————
|
||||
// МАППИНГИ
|
||||
// —————————————————————————————————————————————
|
||||
|
||||
func mapUser(u db.Users) User {
|
||||
return User{
|
||||
"user_id": u.UserID,
|
||||
"avatar_id": pgInt4ToPtr(u.AvatarID),
|
||||
"nickname": u.Nickname,
|
||||
"disp_name": pgTextToPtr(u.DispName),
|
||||
"user_desc": pgTextToPtr(u.UserDesc),
|
||||
"creation_date": u.CreationDate.Time,
|
||||
// mail и passhash НЕ возвращаем!
|
||||
}
|
||||
}
|
||||
|
||||
func mapTitle(t db.Titles) Title {
|
||||
var releaseSeason interface{}
|
||||
if t.ReleaseSeason.Valid {
|
||||
releaseSeason = string(t.ReleaseSeason.ReleaseSeasonT)
|
||||
}
|
||||
|
||||
return Title{
|
||||
"title_id": t.TitleID,
|
||||
"title_names": jsonbToInterface(t.TitleNames),
|
||||
"studio_id": t.StudioID,
|
||||
"poster_id": pgInt4ToPtr(t.PosterID),
|
||||
"signal_ids": t.SignalIds,
|
||||
"title_status": string(t.TitleStatus),
|
||||
"rating": pgFloat8ToPtr(t.Rating),
|
||||
"rating_count": pgInt4ToPtr(t.RatingCount),
|
||||
"release_year": pgInt4ToPtr(t.ReleaseYear),
|
||||
"release_season": releaseSeason,
|
||||
"season": pgInt4ToPtr(t.Season),
|
||||
"episodes_aired": pgInt4ToPtr(t.EpisodesAired),
|
||||
"episodes_all": pgInt4ToPtr(t.EpisodesAll),
|
||||
"episodes_len": jsonbToInterface(t.EpisodesLen),
|
||||
}
|
||||
}
|
||||
|
||||
func mapReview(r db.Reviews) Review {
|
||||
return Review{
|
||||
"review_id": r.ReviewID,
|
||||
"user_id": r.UserID,
|
||||
"title_id": r.TitleID,
|
||||
"image_ids": r.ImageIds,
|
||||
"review_text": r.ReviewText,
|
||||
"creation_date": r.CreationDate.Time,
|
||||
}
|
||||
}
|
||||
|
||||
func mapUserTitle(ut db.Usertitles) UserTitle {
|
||||
return UserTitle{
|
||||
"usertitle_id": ut.UsertitleID,
|
||||
"user_id": ut.UserID,
|
||||
"title_id": ut.TitleID,
|
||||
"status": string(ut.Status),
|
||||
"rate": pgInt4ToPtr(ut.Rate),
|
||||
"review_id": pgInt4ToPtr(ut.ReviewID),
|
||||
}
|
||||
}
|
||||
32
modules/backend/db/db.go
Normal file
32
modules/backend/db/db.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
||||
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
||||
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
||||
266
modules/backend/db/models.go
Normal file
266
modules/backend/db/models.go
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type ReleaseSeasonT string
|
||||
|
||||
const (
|
||||
ReleaseSeasonTWinter ReleaseSeasonT = "winter"
|
||||
ReleaseSeasonTSpring ReleaseSeasonT = "spring"
|
||||
ReleaseSeasonTSummer ReleaseSeasonT = "summer"
|
||||
ReleaseSeasonTFall ReleaseSeasonT = "fall"
|
||||
)
|
||||
|
||||
func (e *ReleaseSeasonT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = ReleaseSeasonT(s)
|
||||
case string:
|
||||
*e = ReleaseSeasonT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for ReleaseSeasonT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullReleaseSeasonT struct {
|
||||
ReleaseSeasonT ReleaseSeasonT `json:"release_season_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if ReleaseSeasonT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullReleaseSeasonT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.ReleaseSeasonT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.ReleaseSeasonT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullReleaseSeasonT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.ReleaseSeasonT), nil
|
||||
}
|
||||
|
||||
type StorageTypeT string
|
||||
|
||||
const (
|
||||
StorageTypeTLocal StorageTypeT = "local"
|
||||
StorageTypeTS3 StorageTypeT = "s3"
|
||||
)
|
||||
|
||||
func (e *StorageTypeT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = StorageTypeT(s)
|
||||
case string:
|
||||
*e = StorageTypeT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for StorageTypeT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullStorageTypeT struct {
|
||||
StorageTypeT StorageTypeT `json:"storage_type_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if StorageTypeT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullStorageTypeT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.StorageTypeT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.StorageTypeT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullStorageTypeT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.StorageTypeT), nil
|
||||
}
|
||||
|
||||
type TitleStatusT string
|
||||
|
||||
const (
|
||||
TitleStatusTFinished TitleStatusT = "finished"
|
||||
TitleStatusTOngoing TitleStatusT = "ongoing"
|
||||
TitleStatusTPlanned TitleStatusT = "planned"
|
||||
)
|
||||
|
||||
func (e *TitleStatusT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = TitleStatusT(s)
|
||||
case string:
|
||||
*e = TitleStatusT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for TitleStatusT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullTitleStatusT struct {
|
||||
TitleStatusT TitleStatusT `json:"title_status_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if TitleStatusT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullTitleStatusT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.TitleStatusT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.TitleStatusT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullTitleStatusT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.TitleStatusT), nil
|
||||
}
|
||||
|
||||
type UsertitleStatusT string
|
||||
|
||||
const (
|
||||
UsertitleStatusTFinished UsertitleStatusT = "finished"
|
||||
UsertitleStatusTPlanned UsertitleStatusT = "planned"
|
||||
UsertitleStatusTDropped UsertitleStatusT = "dropped"
|
||||
UsertitleStatusTInProgress UsertitleStatusT = "in-progress"
|
||||
)
|
||||
|
||||
func (e *UsertitleStatusT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = UsertitleStatusT(s)
|
||||
case string:
|
||||
*e = UsertitleStatusT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for UsertitleStatusT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullUsertitleStatusT struct {
|
||||
UsertitleStatusT UsertitleStatusT `json:"usertitle_status_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if UsertitleStatusT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullUsertitleStatusT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.UsertitleStatusT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.UsertitleStatusT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullUsertitleStatusT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.UsertitleStatusT), nil
|
||||
}
|
||||
|
||||
type Images struct {
|
||||
ImageID int32 `db:"image_id" json:"image_id"`
|
||||
StorageType StorageTypeT `db:"storage_type" json:"storage_type"`
|
||||
ImagePath string `db:"image_path" json:"image_path"`
|
||||
}
|
||||
|
||||
type Providers struct {
|
||||
ProviderID int32 `db:"provider_id" json:"provider_id"`
|
||||
ProviderName string `db:"provider_name" json:"provider_name"`
|
||||
}
|
||||
|
||||
type Reviews struct {
|
||||
ReviewID int32 `db:"review_id" json:"review_id"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText string `db:"review_text" json:"review_text"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type Signals struct {
|
||||
SignalID int32 `db:"signal_id" json:"signal_id"`
|
||||
RawData []byte `db:"raw_data" json:"raw_data"`
|
||||
ProviderID int32 `db:"provider_id" json:"provider_id"`
|
||||
Dirty bool `db:"dirty" json:"dirty"`
|
||||
}
|
||||
|
||||
type Studios struct {
|
||||
StudioID int32 `db:"studio_id" json:"studio_id"`
|
||||
StudioName pgtype.Text `db:"studio_name" json:"studio_name"`
|
||||
IllustID pgtype.Int4 `db:"illust_id" json:"illust_id"`
|
||||
StudioDesc pgtype.Text `db:"studio_desc" json:"studio_desc"`
|
||||
}
|
||||
|
||||
type Tags struct {
|
||||
TagID int32 `db:"tag_id" json:"tag_id"`
|
||||
TagNames []byte `db:"tag_names" json:"tag_names"`
|
||||
}
|
||||
|
||||
type TitleTags struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
TagID int32 `db:"tag_id" json:"tag_id"`
|
||||
}
|
||||
|
||||
type Titles struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
TitleNames []byte `db:"title_names" json:"title_names"`
|
||||
StudioID int32 `db:"studio_id" json:"studio_id"`
|
||||
PosterID pgtype.Int4 `db:"poster_id" json:"poster_id"`
|
||||
SignalIds []int32 `db:"signal_ids" json:"signal_ids"`
|
||||
TitleStatus TitleStatusT `db:"title_status" json:"title_status"`
|
||||
Rating pgtype.Float8 `db:"rating" json:"rating"`
|
||||
RatingCount pgtype.Int4 `db:"rating_count" json:"rating_count"`
|
||||
ReleaseYear pgtype.Int4 `db:"release_year" json:"release_year"`
|
||||
ReleaseSeason NullReleaseSeasonT `db:"release_season" json:"release_season"`
|
||||
Season pgtype.Int4 `db:"season" json:"season"`
|
||||
EpisodesAired pgtype.Int4 `db:"episodes_aired" json:"episodes_aired"`
|
||||
EpisodesAll pgtype.Int4 `db:"episodes_all" json:"episodes_all"`
|
||||
EpisodesLen []byte `db:"episodes_len" json:"episodes_len"`
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Passhash string `db:"passhash" json:"passhash"`
|
||||
Mail pgtype.Text `db:"mail" json:"mail"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type Usertitles struct {
|
||||
UsertitleID int32 `db:"usertitle_id" json:"usertitle_id"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status UsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
712
modules/backend/db/query.sql.go
Normal file
712
modules/backend/db/query.sql.go
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: query.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const createImage = `-- name: CreateImage :one
|
||||
INSERT INTO images (storage_type, image_path)
|
||||
VALUES ($1, $2)
|
||||
RETURNING image_id, storage_type, image_path
|
||||
`
|
||||
|
||||
type CreateImageParams struct {
|
||||
StorageType StorageTypeT `db:"storage_type" json:"storage_type"`
|
||||
ImagePath string `db:"image_path" json:"image_path"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateImage(ctx context.Context, arg CreateImageParams) (Images, error) {
|
||||
row := q.db.QueryRow(ctx, createImage, arg.StorageType, arg.ImagePath)
|
||||
var i Images
|
||||
err := row.Scan(&i.ImageID, &i.StorageType, &i.ImagePath)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createReview = `-- name: CreateReview :one
|
||||
INSERT INTO reviews (user_id, title_id, image_ids, review_text, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
`
|
||||
|
||||
type CreateReviewParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText string `db:"review_text" json:"review_text"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateReview(ctx context.Context, arg CreateReviewParams) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, createReview,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.ImageIds,
|
||||
arg.ReviewText,
|
||||
arg.CreationDate,
|
||||
)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Passhash string `db:"passhash" json:"passhash"`
|
||||
Mail pgtype.Text `db:"mail" json:"mail"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type CreateUserRow struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
|
||||
row := q.db.QueryRow(ctx, createUser,
|
||||
arg.AvatarID,
|
||||
arg.Passhash,
|
||||
arg.Mail,
|
||||
arg.Nickname,
|
||||
arg.DispName,
|
||||
arg.UserDesc,
|
||||
arg.CreationDate,
|
||||
)
|
||||
var i CreateUserRow
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUserTitle = `-- name: CreateUserTitle :one
|
||||
INSERT INTO usertitles (user_id, title_id, status, rate, review_id)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING usertitle_id, user_id, title_id, status, rate, review_id
|
||||
`
|
||||
|
||||
type CreateUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status UsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUserTitle(ctx context.Context, arg CreateUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, createUserTitle,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.Status,
|
||||
arg.Rate,
|
||||
arg.ReviewID,
|
||||
)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteReview = `-- name: DeleteReview :exec
|
||||
DELETE FROM reviews
|
||||
WHERE review_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteReview(ctx context.Context, reviewID int32) error {
|
||||
_, err := q.db.Exec(ctx, deleteReview, reviewID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUser = `-- name: DeleteUser :exec
|
||||
DELETE FROM users
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUser(ctx context.Context, userID int32) error {
|
||||
_, err := q.db.Exec(ctx, deleteUser, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUserTitle = `-- name: DeleteUserTitle :exec
|
||||
DELETE FROM usertitles
|
||||
WHERE user_id = $1 AND ($2::int IS NULL OR title_id = $2)
|
||||
`
|
||||
|
||||
type DeleteUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Column2 int32 `db:"column_2" json:"column_2"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteUserTitle(ctx context.Context, arg DeleteUserTitleParams) error {
|
||||
_, err := q.db.Exec(ctx, deleteUserTitle, arg.UserID, arg.Column2)
|
||||
return err
|
||||
}
|
||||
|
||||
const getImageByID = `-- name: GetImageByID :one
|
||||
SELECT image_id, storage_type, image_path
|
||||
FROM images
|
||||
WHERE image_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetImageByID(ctx context.Context, imageID int32) (Images, error) {
|
||||
row := q.db.QueryRow(ctx, getImageByID, imageID)
|
||||
var i Images
|
||||
err := row.Scan(&i.ImageID, &i.StorageType, &i.ImagePath)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getReviewByID = `-- name: GetReviewByID :one
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE review_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetReviewByID(ctx context.Context, reviewID int32) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, getReviewByID, reviewID)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTitleByID = `-- name: GetTitleByID :one
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
WHERE title_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTitleByID(ctx context.Context, titleID int32) (Titles, error) {
|
||||
row := q.db.QueryRow(ctx, getTitleByID, titleID)
|
||||
var i Titles
|
||||
err := row.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserByID = `-- name: GetUserByID :one
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByID(ctx context.Context, userID int32) (Users, error) {
|
||||
row := q.db.QueryRow(ctx, getUserByID, userID)
|
||||
var i Users
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Passhash,
|
||||
&i.Mail,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserTitle = `-- name: GetUserTitle :one
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1 AND title_id = $2
|
||||
`
|
||||
|
||||
type GetUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetUserTitle(ctx context.Context, arg GetUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, getUserTitle, arg.UserID, arg.TitleID)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listReviewsByTitle = `-- name: ListReviewsByTitle :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE title_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListReviewsByTitleParams struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReviewsByTitle(ctx context.Context, arg ListReviewsByTitleParams) ([]Reviews, error) {
|
||||
rows, err := q.db.Query(ctx, listReviewsByTitle, arg.TitleID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Reviews
|
||||
for rows.Next() {
|
||||
var i Reviews
|
||||
if err := rows.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listReviewsByUser = `-- name: ListReviewsByUser :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE user_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListReviewsByUserParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReviewsByUser(ctx context.Context, arg ListReviewsByUserParams) ([]Reviews, error) {
|
||||
rows, err := q.db.Query(ctx, listReviewsByUser, arg.UserID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Reviews
|
||||
for rows.Next() {
|
||||
var i Reviews
|
||||
if err := rows.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listTags = `-- name: ListTags :many
|
||||
SELECT tag_id, tag_names
|
||||
FROM tags
|
||||
ORDER BY tag_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListTagsParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListTags(ctx context.Context, arg ListTagsParams) ([]Tags, error) {
|
||||
rows, err := q.db.Query(ctx, listTags, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Tags
|
||||
for rows.Next() {
|
||||
var i Tags
|
||||
if err := rows.Scan(&i.TagID, &i.TagNames); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listTitles = `-- name: ListTitles :many
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
ORDER BY title_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListTitlesParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListTitles(ctx context.Context, arg ListTitlesParams) ([]Titles, error) {
|
||||
rows, err := q.db.Query(ctx, listTitles, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Titles
|
||||
for rows.Next() {
|
||||
var i Titles
|
||||
if err := rows.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUserTitles = `-- name: ListUserTitles :many
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1
|
||||
ORDER BY usertitle_id
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListUserTitlesParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListUserTitles(ctx context.Context, arg ListUserTitlesParams) ([]Usertitles, error) {
|
||||
rows, err := q.db.Query(ctx, listUserTitles, arg.UserID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Usertitles
|
||||
for rows.Next() {
|
||||
var i Usertitles
|
||||
if err := rows.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUsers = `-- name: ListUsers :many
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
ORDER BY user_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListUsersParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, error) {
|
||||
rows, err := q.db.Query(ctx, listUsers, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Users
|
||||
for rows.Next() {
|
||||
var i Users
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Passhash,
|
||||
&i.Mail,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateReview = `-- name: UpdateReview :one
|
||||
UPDATE reviews
|
||||
SET
|
||||
image_ids = COALESCE($1, image_ids),
|
||||
review_text = COALESCE($2, review_text)
|
||||
WHERE review_id = $3
|
||||
RETURNING review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
`
|
||||
|
||||
type UpdateReviewParams struct {
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText pgtype.Text `db:"review_text" json:"review_text"`
|
||||
ReviewID int32 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateReview(ctx context.Context, arg UpdateReviewParams) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, updateReview, arg.ImageIds, arg.ReviewText, arg.ReviewID)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTitle = `-- name: UpdateTitle :one
|
||||
UPDATE titles
|
||||
SET
|
||||
title_names = COALESCE($1, title_names),
|
||||
studio_id = COALESCE($2, studio_id),
|
||||
poster_id = COALESCE($3, poster_id),
|
||||
signal_ids = COALESCE($4, signal_ids),
|
||||
title_status = COALESCE($5, title_status),
|
||||
release_year = COALESCE($6, release_year),
|
||||
release_season = COALESCE($7, release_season),
|
||||
episodes_aired = COALESCE($8, episodes_aired),
|
||||
episodes_all = COALESCE($9, episodes_all),
|
||||
episodes_len = COALESCE($10, episodes_len)
|
||||
WHERE title_id = $11
|
||||
RETURNING title_id, title_names, studio_id, poster_id, signal_ids, title_status, rating, rating_count, release_year, release_season, season, episodes_aired, episodes_all, episodes_len
|
||||
`
|
||||
|
||||
type UpdateTitleParams struct {
|
||||
TitleNames []byte `db:"title_names" json:"title_names"`
|
||||
StudioID pgtype.Int4 `db:"studio_id" json:"studio_id"`
|
||||
PosterID pgtype.Int4 `db:"poster_id" json:"poster_id"`
|
||||
SignalIds []int32 `db:"signal_ids" json:"signal_ids"`
|
||||
TitleStatus NullTitleStatusT `db:"title_status" json:"title_status"`
|
||||
ReleaseYear pgtype.Int4 `db:"release_year" json:"release_year"`
|
||||
ReleaseSeason NullReleaseSeasonT `db:"release_season" json:"release_season"`
|
||||
EpisodesAired pgtype.Int4 `db:"episodes_aired" json:"episodes_aired"`
|
||||
EpisodesAll pgtype.Int4 `db:"episodes_all" json:"episodes_all"`
|
||||
EpisodesLen []byte `db:"episodes_len" json:"episodes_len"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTitle(ctx context.Context, arg UpdateTitleParams) (Titles, error) {
|
||||
row := q.db.QueryRow(ctx, updateTitle,
|
||||
arg.TitleNames,
|
||||
arg.StudioID,
|
||||
arg.PosterID,
|
||||
arg.SignalIds,
|
||||
arg.TitleStatus,
|
||||
arg.ReleaseYear,
|
||||
arg.ReleaseSeason,
|
||||
arg.EpisodesAired,
|
||||
arg.EpisodesAll,
|
||||
arg.EpisodesLen,
|
||||
arg.TitleID,
|
||||
)
|
||||
var i Titles
|
||||
err := row.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUser = `-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
avatar_id = COALESCE($1, avatar_id),
|
||||
disp_name = COALESCE($2, disp_name),
|
||||
user_desc = COALESCE($3, user_desc)
|
||||
WHERE user_id = $4
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date
|
||||
`
|
||||
|
||||
type UpdateUserParams struct {
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
}
|
||||
|
||||
type UpdateUserRow struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (UpdateUserRow, error) {
|
||||
row := q.db.QueryRow(ctx, updateUser,
|
||||
arg.AvatarID,
|
||||
arg.DispName,
|
||||
arg.UserDesc,
|
||||
arg.UserID,
|
||||
)
|
||||
var i UpdateUserRow
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserTitle = `-- name: UpdateUserTitle :one
|
||||
UPDATE usertitles
|
||||
SET
|
||||
status = COALESCE($3, status),
|
||||
rate = COALESCE($4, rate),
|
||||
review_id = COALESCE($5, review_id)
|
||||
WHERE user_id = $1 AND title_id = $2
|
||||
RETURNING usertitle_id, user_id, title_id, status, rate, review_id
|
||||
`
|
||||
|
||||
type UpdateUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status NullUsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserTitle(ctx context.Context, arg UpdateUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, updateUserTitle,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.Status,
|
||||
arg.Rate,
|
||||
arg.ReviewID,
|
||||
)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ module nyanimedb-server
|
|||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
|
|
@ -15,12 +16,17 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.6 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/oapi-codegen/runtime v1.1.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
||||
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
|
|
@ -29,8 +33,17 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
|
|||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
|
|
@ -43,6 +56,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
|
||||
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
|
@ -52,6 +67,7 @@ github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQB
|
|||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
|
|
|||
|
|
@ -1,35 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"nyanimedb-server/api"
|
||||
"nyanimedb-server/db"
|
||||
"os"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var AppConfig Config
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
AppConfig.Mode = "env"
|
||||
} else {
|
||||
AppConfig.Mode = "argv"
|
||||
// if len(os.Args) != 2 {
|
||||
// AppConfig.Mode = "env"
|
||||
// } else {
|
||||
// AppConfig.Mode = "argv"
|
||||
// }
|
||||
|
||||
// err := InitConfig()
|
||||
// if err != nil {
|
||||
// log.Fatalf("Failed to init config: %v\n", err)
|
||||
// }
|
||||
|
||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err := InitConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to init config: %v\n", err)
|
||||
}
|
||||
defer conn.Close(context.Background())
|
||||
|
||||
r := gin.Default()
|
||||
|
||||
r.LoadHTMLGlob("templates/*")
|
||||
queries := db.New(conn)
|
||||
|
||||
server := api.NewServer(queries)
|
||||
// r.LoadHTMLGlob("templates/*")
|
||||
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*"}, // allow all origins, change to specific domains in production
|
||||
|
|
@ -40,22 +53,27 @@ func main() {
|
|||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{
|
||||
"title": "Welcome Page",
|
||||
"message": "Hello, Gin with HTML templates!",
|
||||
})
|
||||
})
|
||||
api.RegisterHandlers(r, api.NewStrictHandler(
|
||||
server,
|
||||
// сюда можно добавить middlewares, если нужно
|
||||
[]api.StrictMiddlewareFunc{},
|
||||
))
|
||||
// r.GET("/", func(c *gin.Context) {
|
||||
// c.HTML(http.StatusOK, "index.html", gin.H{
|
||||
// "title": "Welcome Page",
|
||||
// "message": "Hello, Gin with HTML templates!",
|
||||
// })
|
||||
// })
|
||||
|
||||
r.GET("/api", func(c *gin.Context) {
|
||||
items := []Item{
|
||||
{ID: 1, Title: "First Item", Description: "This is the description of the first item."},
|
||||
{ID: 2, Title: "Second Item", Description: "This is the description of the second item."},
|
||||
{ID: 3, Title: "Third Item", Description: "This is the description of the third item."},
|
||||
}
|
||||
// r.GET("/api", func(c *gin.Context) {
|
||||
// items := []Item{
|
||||
// {ID: 1, Title: "First Item", Description: "This is the description of the first item."},
|
||||
// {ID: 2, Title: "Second Item", Description: "This is the description of the second item."},
|
||||
// {ID: 3, Title: "Third Item", Description: "This is the description of the third item."},
|
||||
// }
|
||||
|
||||
c.JSON(http.StatusOK, items)
|
||||
})
|
||||
// c.JSON(http.StatusOK, items)
|
||||
// })
|
||||
|
||||
r.Run(":8080")
|
||||
}
|
||||
|
|
|
|||
3
modules/sql/go.mod
Normal file
3
modules/sql/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module tutorial.sqlc.dev/app
|
||||
|
||||
go 1.25.2
|
||||
142
modules/sql/query.sql
Normal file
142
modules/sql/query.sql
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
-- name: GetImageByID :one
|
||||
SELECT image_id, storage_type, image_path
|
||||
FROM images
|
||||
WHERE image_id = $1;
|
||||
|
||||
-- name: CreateImage :one
|
||||
INSERT INTO images (storage_type, image_path)
|
||||
VALUES ($1, $2)
|
||||
RETURNING image_id, storage_type, image_path;
|
||||
|
||||
-- name: GetUserByID :one
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: ListUsers :many
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
ORDER BY user_id
|
||||
LIMIT $1 OFFSET $2;
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date;
|
||||
|
||||
-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
avatar_id = COALESCE(sqlc.narg('avatar_id'), avatar_id),
|
||||
disp_name = COALESCE(sqlc.narg('disp_name'), disp_name),
|
||||
user_desc = COALESCE(sqlc.narg('user_desc'), user_desc),
|
||||
passhash = COALESCE(sqlc.narg('passhash'), passhash),
|
||||
WHERE user_id = sqlc.arg('user_id')
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: GetTitleByID :one
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
WHERE title_id = $1;
|
||||
|
||||
-- name: ListTitles :many
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
ORDER BY title_id
|
||||
LIMIT $1 OFFSET $2;
|
||||
|
||||
-- name: UpdateTitle :one
|
||||
UPDATE titles
|
||||
SET
|
||||
title_names = COALESCE(sqlc.narg('title_names'), title_names),
|
||||
studio_id = COALESCE(sqlc.narg('studio_id'), studio_id),
|
||||
poster_id = COALESCE(sqlc.narg('poster_id'), poster_id),
|
||||
signal_ids = COALESCE(sqlc.narg('signal_ids'), signal_ids),
|
||||
title_status = COALESCE(sqlc.narg('title_status'), title_status),
|
||||
release_year = COALESCE(sqlc.narg('release_year'), release_year),
|
||||
release_season = COALESCE(sqlc.narg('release_season'), release_season),
|
||||
episodes_aired = COALESCE(sqlc.narg('episodes_aired'), episodes_aired),
|
||||
episodes_all = COALESCE(sqlc.narg('episodes_all'), episodes_all),
|
||||
episodes_len = COALESCE(sqlc.narg('episodes_len'), episodes_len)
|
||||
WHERE title_id = sqlc.arg('title_id')
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetReviewByID :one
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE review_id = $1;
|
||||
|
||||
-- name: CreateReview :one
|
||||
INSERT INTO reviews (user_id, title_id, image_ids, review_text, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING review_id, user_id, title_id, image_ids, review_text, creation_date;
|
||||
|
||||
-- name: UpdateReview :one
|
||||
UPDATE reviews
|
||||
SET
|
||||
image_ids = COALESCE(sqlc.narg('image_ids'), image_ids),
|
||||
review_text = COALESCE(sqlc.narg('review_text'), review_text)
|
||||
WHERE review_id = sqlc.arg('review_id')
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteReview :exec
|
||||
DELETE FROM reviews
|
||||
WHERE review_id = $1;
|
||||
|
||||
-- name: ListReviewsByTitle :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE title_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3;
|
||||
|
||||
-- name: ListReviewsByUser :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE user_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3;
|
||||
|
||||
-- name: GetUserTitle :one
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1 AND title_id = $2;
|
||||
|
||||
-- name: ListUserTitles :many
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1
|
||||
ORDER BY usertitle_id
|
||||
LIMIT $2 OFFSET $3;
|
||||
|
||||
-- name: CreateUserTitle :one
|
||||
INSERT INTO usertitles (user_id, title_id, status, rate, review_id)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING usertitle_id, user_id, title_id, status, rate, review_id;
|
||||
|
||||
-- name: UpdateUserTitle :one
|
||||
UPDATE usertitles
|
||||
SET
|
||||
status = COALESCE(sqlc.narg('status'), status),
|
||||
rate = COALESCE(sqlc.narg('rate'), rate),
|
||||
review_id = COALESCE(sqlc.narg('review_id'), review_id)
|
||||
WHERE user_id = $1 AND title_id = $2
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUserTitle :exec
|
||||
DELETE FROM usertitles
|
||||
WHERE user_id = $1 AND ($2::int IS NULL OR title_id = $2);
|
||||
|
||||
-- name: ListTags :many
|
||||
SELECT tag_id, tag_names
|
||||
FROM tags
|
||||
ORDER BY tag_id
|
||||
LIMIT $1 OFFSET $2;
|
||||
97
modules/sql/scheme.sql
Normal file
97
modules/sql/scheme.sql
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
-- TODO:
|
||||
-- title table triggers
|
||||
-- maybe jsonb constraints
|
||||
-- actions (delete)
|
||||
BEGIN;
|
||||
|
||||
CREATE TYPE usertitle_status_t AS ENUM ('finished', 'planned', 'dropped', 'in-progress');
|
||||
CREATE TYPE storage_type_t AS ENUM ('local', 's3');
|
||||
CREATE TYPE title_status_t AS ENUM ('finished', 'ongoing', 'planned');
|
||||
CREATE TYPE release_season_t AS ENUM ('winter', 'spring', 'summer', 'fall');
|
||||
|
||||
CREATE TABLE providers (
|
||||
provider_id serial PRIMARY KEY,
|
||||
provider_name varchar(64) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
tag_id serial PRIMARY KEY,
|
||||
tag_names jsonb NOT NULL --mb constraints
|
||||
);
|
||||
|
||||
CREATE TABLE images (
|
||||
image_id serial PRIMARY KEY,
|
||||
storage_type storage_type_t NOT NULL,
|
||||
image_path varchar(256) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
user_id serial PRIMARY KEY,
|
||||
avatar_id int REFERENCES images (image_id),
|
||||
passhash text NOT NULL,
|
||||
mail varchar(64) CHECK (mail ~ '[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+'),
|
||||
nickname varchar(16) NOT NULL CHECK (nickname ~ '^[a-zA-Z0-9_-]+$'),
|
||||
disp_name varchar(32),
|
||||
user_desc varchar(512),
|
||||
creation_date timestamp NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE studios (
|
||||
studio_id serial PRIMARY KEY,
|
||||
studio_name varchar(64) UNIQUE,
|
||||
illust_id int REFERENCES images (image_id),
|
||||
studio_desc text
|
||||
);
|
||||
|
||||
CREATE TABLE titles (
|
||||
title_id serial PRIMARY KEY,
|
||||
title_names jsonb NOT NULL,
|
||||
studio_id int NOT NULL REFERENCES studios,
|
||||
poster_id int REFERENCES images (image_id),
|
||||
signal_ids int[] NOT NULL,
|
||||
title_status title_status_t NOT NULL,
|
||||
rating float CHECK (rating > 0 AND rating <= 10), --by trigger
|
||||
rating_count int CHECK (rating_count >= 0), --by trigger
|
||||
release_year int CHECK (release_year >= 1900),
|
||||
release_season release_season_t,
|
||||
season int CHECK (season >= 0),
|
||||
episodes_aired int CHECK (episodes_aired >= 0),
|
||||
episodes_all int CHECK (episodes_all >= 0),
|
||||
episodes_len jsonb,
|
||||
CHECK ((episodes_aired IS NULL AND episodes_all IS NULL)
|
||||
OR (episodes_aired IS NOT NULL AND episodes_all IS NOT NULL
|
||||
AND episodes_aired <= episodes_all))
|
||||
);
|
||||
|
||||
CREATE TABLE reviews (
|
||||
review_id serial PRIMARY KEY,
|
||||
user_id int NOT NULL REFERENCES users,
|
||||
title_id int NOT NULL REFERENCES titles,
|
||||
image_ids int[],
|
||||
review_text text NOT NULL,
|
||||
creation_date timestamp NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE usertitles (
|
||||
usertitle_id serial PRIMARY KEY,
|
||||
user_id int NOT NULL REFERENCES users,
|
||||
title_id int NOT NULL REFERENCES titles,
|
||||
status usertitle_status_t NOT NULL,
|
||||
rate int CHECK (rate > 0 AND rate <= 10),
|
||||
review_id int REFERENCES reviews
|
||||
);
|
||||
|
||||
CREATE TABLE title_tags (
|
||||
PRIMARY KEY (title_id, tag_id),
|
||||
title_id int NOT NULL REFERENCES titles,
|
||||
tag_id int NOT NULL REFERENCES tags
|
||||
);
|
||||
|
||||
CREATE TABLE signals (
|
||||
signal_id serial PRIMARY KEY,
|
||||
raw_data jsonb NOT NULL,
|
||||
provider_id int NOT NULL REFERENCES providers,
|
||||
dirty bool NOT NULL
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
13
modules/sql/sqlc-generate.yaml
Normal file
13
modules/sql/sqlc-generate.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
version: "2"
|
||||
sql:
|
||||
- engine: "postgresql"
|
||||
queries: "query.sql"
|
||||
schema: "scheme.sql"
|
||||
gen:
|
||||
go:
|
||||
package: "nyanimedb.backend"
|
||||
out: "sqlc"
|
||||
sql_package: "pgx/v5"
|
||||
sql_driver: "github.com/lib/pq"
|
||||
emit_db_tags: true
|
||||
emit_exact_table_names: true
|
||||
14
modules/sql/sqlc.yaml
Normal file
14
modules/sql/sqlc.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
version: "2"
|
||||
sql:
|
||||
- engine: "postgresql"
|
||||
queries: "query.sql"
|
||||
schema: "scheme.sql"
|
||||
gen:
|
||||
go:
|
||||
package: "nyanimedb_backend"
|
||||
out: "sqlc"
|
||||
sql_package: "pgx/v5"
|
||||
sql_driver: "github.com/lib/pq"
|
||||
emit_db_tags: true
|
||||
emit_exact_table_names: true
|
||||
emit_json_tags: true
|
||||
32
modules/sql/sqlc/db.go
Normal file
32
modules/sql/sqlc/db.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
|
||||
package nyanimedb_backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
||||
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
||||
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
||||
266
modules/sql/sqlc/models.go
Normal file
266
modules/sql/sqlc/models.go
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
|
||||
package nyanimedb_backend
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type ReleaseSeasonT string
|
||||
|
||||
const (
|
||||
ReleaseSeasonTWinter ReleaseSeasonT = "winter"
|
||||
ReleaseSeasonTSpring ReleaseSeasonT = "spring"
|
||||
ReleaseSeasonTSummer ReleaseSeasonT = "summer"
|
||||
ReleaseSeasonTFall ReleaseSeasonT = "fall"
|
||||
)
|
||||
|
||||
func (e *ReleaseSeasonT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = ReleaseSeasonT(s)
|
||||
case string:
|
||||
*e = ReleaseSeasonT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for ReleaseSeasonT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullReleaseSeasonT struct {
|
||||
ReleaseSeasonT ReleaseSeasonT `json:"release_season_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if ReleaseSeasonT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullReleaseSeasonT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.ReleaseSeasonT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.ReleaseSeasonT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullReleaseSeasonT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.ReleaseSeasonT), nil
|
||||
}
|
||||
|
||||
type StorageTypeT string
|
||||
|
||||
const (
|
||||
StorageTypeTLocal StorageTypeT = "local"
|
||||
StorageTypeTS3 StorageTypeT = "s3"
|
||||
)
|
||||
|
||||
func (e *StorageTypeT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = StorageTypeT(s)
|
||||
case string:
|
||||
*e = StorageTypeT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for StorageTypeT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullStorageTypeT struct {
|
||||
StorageTypeT StorageTypeT `json:"storage_type_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if StorageTypeT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullStorageTypeT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.StorageTypeT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.StorageTypeT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullStorageTypeT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.StorageTypeT), nil
|
||||
}
|
||||
|
||||
type TitleStatusT string
|
||||
|
||||
const (
|
||||
TitleStatusTFinished TitleStatusT = "finished"
|
||||
TitleStatusTOngoing TitleStatusT = "ongoing"
|
||||
TitleStatusTPlanned TitleStatusT = "planned"
|
||||
)
|
||||
|
||||
func (e *TitleStatusT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = TitleStatusT(s)
|
||||
case string:
|
||||
*e = TitleStatusT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for TitleStatusT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullTitleStatusT struct {
|
||||
TitleStatusT TitleStatusT `json:"title_status_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if TitleStatusT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullTitleStatusT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.TitleStatusT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.TitleStatusT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullTitleStatusT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.TitleStatusT), nil
|
||||
}
|
||||
|
||||
type UsertitleStatusT string
|
||||
|
||||
const (
|
||||
UsertitleStatusTFinished UsertitleStatusT = "finished"
|
||||
UsertitleStatusTPlanned UsertitleStatusT = "planned"
|
||||
UsertitleStatusTDropped UsertitleStatusT = "dropped"
|
||||
UsertitleStatusTInProgress UsertitleStatusT = "in-progress"
|
||||
)
|
||||
|
||||
func (e *UsertitleStatusT) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = UsertitleStatusT(s)
|
||||
case string:
|
||||
*e = UsertitleStatusT(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for UsertitleStatusT: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullUsertitleStatusT struct {
|
||||
UsertitleStatusT UsertitleStatusT `json:"usertitle_status_t"`
|
||||
Valid bool `json:"valid"` // Valid is true if UsertitleStatusT is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullUsertitleStatusT) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.UsertitleStatusT, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.UsertitleStatusT.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullUsertitleStatusT) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.UsertitleStatusT), nil
|
||||
}
|
||||
|
||||
type Images struct {
|
||||
ImageID int32 `db:"image_id" json:"image_id"`
|
||||
StorageType StorageTypeT `db:"storage_type" json:"storage_type"`
|
||||
ImagePath string `db:"image_path" json:"image_path"`
|
||||
}
|
||||
|
||||
type Providers struct {
|
||||
ProviderID int32 `db:"provider_id" json:"provider_id"`
|
||||
ProviderName string `db:"provider_name" json:"provider_name"`
|
||||
}
|
||||
|
||||
type Reviews struct {
|
||||
ReviewID int32 `db:"review_id" json:"review_id"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText string `db:"review_text" json:"review_text"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type Signals struct {
|
||||
SignalID int32 `db:"signal_id" json:"signal_id"`
|
||||
RawData []byte `db:"raw_data" json:"raw_data"`
|
||||
ProviderID int32 `db:"provider_id" json:"provider_id"`
|
||||
Dirty bool `db:"dirty" json:"dirty"`
|
||||
}
|
||||
|
||||
type Studios struct {
|
||||
StudioID int32 `db:"studio_id" json:"studio_id"`
|
||||
StudioName pgtype.Text `db:"studio_name" json:"studio_name"`
|
||||
IllustID pgtype.Int4 `db:"illust_id" json:"illust_id"`
|
||||
StudioDesc pgtype.Text `db:"studio_desc" json:"studio_desc"`
|
||||
}
|
||||
|
||||
type Tags struct {
|
||||
TagID int32 `db:"tag_id" json:"tag_id"`
|
||||
TagNames []byte `db:"tag_names" json:"tag_names"`
|
||||
}
|
||||
|
||||
type TitleTags struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
TagID int32 `db:"tag_id" json:"tag_id"`
|
||||
}
|
||||
|
||||
type Titles struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
TitleNames []byte `db:"title_names" json:"title_names"`
|
||||
StudioID int32 `db:"studio_id" json:"studio_id"`
|
||||
PosterID pgtype.Int4 `db:"poster_id" json:"poster_id"`
|
||||
SignalIds []int32 `db:"signal_ids" json:"signal_ids"`
|
||||
TitleStatus TitleStatusT `db:"title_status" json:"title_status"`
|
||||
Rating pgtype.Float8 `db:"rating" json:"rating"`
|
||||
RatingCount pgtype.Int4 `db:"rating_count" json:"rating_count"`
|
||||
ReleaseYear pgtype.Int4 `db:"release_year" json:"release_year"`
|
||||
ReleaseSeason NullReleaseSeasonT `db:"release_season" json:"release_season"`
|
||||
Season pgtype.Int4 `db:"season" json:"season"`
|
||||
EpisodesAired pgtype.Int4 `db:"episodes_aired" json:"episodes_aired"`
|
||||
EpisodesAll pgtype.Int4 `db:"episodes_all" json:"episodes_all"`
|
||||
EpisodesLen []byte `db:"episodes_len" json:"episodes_len"`
|
||||
}
|
||||
|
||||
type Users struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Passhash string `db:"passhash" json:"passhash"`
|
||||
Mail pgtype.Text `db:"mail" json:"mail"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type Usertitles struct {
|
||||
UsertitleID int32 `db:"usertitle_id" json:"usertitle_id"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status UsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
712
modules/sql/sqlc/query.sql.go
Normal file
712
modules/sql/sqlc/query.sql.go
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: query.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const createImage = `-- name: CreateImage :one
|
||||
INSERT INTO images (storage_type, image_path)
|
||||
VALUES ($1, $2)
|
||||
RETURNING image_id, storage_type, image_path
|
||||
`
|
||||
|
||||
type CreateImageParams struct {
|
||||
StorageType StorageTypeT `db:"storage_type" json:"storage_type"`
|
||||
ImagePath string `db:"image_path" json:"image_path"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateImage(ctx context.Context, arg CreateImageParams) (Images, error) {
|
||||
row := q.db.QueryRow(ctx, createImage, arg.StorageType, arg.ImagePath)
|
||||
var i Images
|
||||
err := row.Scan(&i.ImageID, &i.StorageType, &i.ImagePath)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createReview = `-- name: CreateReview :one
|
||||
INSERT INTO reviews (user_id, title_id, image_ids, review_text, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
`
|
||||
|
||||
type CreateReviewParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText string `db:"review_text" json:"review_text"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateReview(ctx context.Context, arg CreateReviewParams) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, createReview,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.ImageIds,
|
||||
arg.ReviewText,
|
||||
arg.CreationDate,
|
||||
)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Passhash string `db:"passhash" json:"passhash"`
|
||||
Mail pgtype.Text `db:"mail" json:"mail"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
type CreateUserRow struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
|
||||
row := q.db.QueryRow(ctx, createUser,
|
||||
arg.AvatarID,
|
||||
arg.Passhash,
|
||||
arg.Mail,
|
||||
arg.Nickname,
|
||||
arg.DispName,
|
||||
arg.UserDesc,
|
||||
arg.CreationDate,
|
||||
)
|
||||
var i CreateUserRow
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUserTitle = `-- name: CreateUserTitle :one
|
||||
INSERT INTO usertitles (user_id, title_id, status, rate, review_id)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING usertitle_id, user_id, title_id, status, rate, review_id
|
||||
`
|
||||
|
||||
type CreateUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status UsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUserTitle(ctx context.Context, arg CreateUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, createUserTitle,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.Status,
|
||||
arg.Rate,
|
||||
arg.ReviewID,
|
||||
)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteReview = `-- name: DeleteReview :exec
|
||||
DELETE FROM reviews
|
||||
WHERE review_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteReview(ctx context.Context, reviewID int32) error {
|
||||
_, err := q.db.Exec(ctx, deleteReview, reviewID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUser = `-- name: DeleteUser :exec
|
||||
DELETE FROM users
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUser(ctx context.Context, userID int32) error {
|
||||
_, err := q.db.Exec(ctx, deleteUser, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUserTitle = `-- name: DeleteUserTitle :exec
|
||||
DELETE FROM usertitles
|
||||
WHERE user_id = $1 AND ($2::int IS NULL OR title_id = $2)
|
||||
`
|
||||
|
||||
type DeleteUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Column2 int32 `db:"column_2" json:"column_2"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteUserTitle(ctx context.Context, arg DeleteUserTitleParams) error {
|
||||
_, err := q.db.Exec(ctx, deleteUserTitle, arg.UserID, arg.Column2)
|
||||
return err
|
||||
}
|
||||
|
||||
const getImageByID = `-- name: GetImageByID :one
|
||||
SELECT image_id, storage_type, image_path
|
||||
FROM images
|
||||
WHERE image_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetImageByID(ctx context.Context, imageID int32) (Images, error) {
|
||||
row := q.db.QueryRow(ctx, getImageByID, imageID)
|
||||
var i Images
|
||||
err := row.Scan(&i.ImageID, &i.StorageType, &i.ImagePath)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getReviewByID = `-- name: GetReviewByID :one
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE review_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetReviewByID(ctx context.Context, reviewID int32) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, getReviewByID, reviewID)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTitleByID = `-- name: GetTitleByID :one
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
WHERE title_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTitleByID(ctx context.Context, titleID int32) (Titles, error) {
|
||||
row := q.db.QueryRow(ctx, getTitleByID, titleID)
|
||||
var i Titles
|
||||
err := row.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserByID = `-- name: GetUserByID :one
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByID(ctx context.Context, userID int32) (Users, error) {
|
||||
row := q.db.QueryRow(ctx, getUserByID, userID)
|
||||
var i Users
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Passhash,
|
||||
&i.Mail,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserTitle = `-- name: GetUserTitle :one
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1 AND title_id = $2
|
||||
`
|
||||
|
||||
type GetUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetUserTitle(ctx context.Context, arg GetUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, getUserTitle, arg.UserID, arg.TitleID)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listReviewsByTitle = `-- name: ListReviewsByTitle :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE title_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListReviewsByTitleParams struct {
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReviewsByTitle(ctx context.Context, arg ListReviewsByTitleParams) ([]Reviews, error) {
|
||||
rows, err := q.db.Query(ctx, listReviewsByTitle, arg.TitleID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Reviews
|
||||
for rows.Next() {
|
||||
var i Reviews
|
||||
if err := rows.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listReviewsByUser = `-- name: ListReviewsByUser :many
|
||||
SELECT review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
FROM reviews
|
||||
WHERE user_id = $1
|
||||
ORDER BY creation_date DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListReviewsByUserParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReviewsByUser(ctx context.Context, arg ListReviewsByUserParams) ([]Reviews, error) {
|
||||
rows, err := q.db.Query(ctx, listReviewsByUser, arg.UserID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Reviews
|
||||
for rows.Next() {
|
||||
var i Reviews
|
||||
if err := rows.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listTags = `-- name: ListTags :many
|
||||
SELECT tag_id, tag_names
|
||||
FROM tags
|
||||
ORDER BY tag_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListTagsParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListTags(ctx context.Context, arg ListTagsParams) ([]Tags, error) {
|
||||
rows, err := q.db.Query(ctx, listTags, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Tags
|
||||
for rows.Next() {
|
||||
var i Tags
|
||||
if err := rows.Scan(&i.TagID, &i.TagNames); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listTitles = `-- name: ListTitles :many
|
||||
SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||
title_status, rating, rating_count, release_year, release_season,
|
||||
season, episodes_aired, episodes_all, episodes_len
|
||||
FROM titles
|
||||
ORDER BY title_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListTitlesParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListTitles(ctx context.Context, arg ListTitlesParams) ([]Titles, error) {
|
||||
rows, err := q.db.Query(ctx, listTitles, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Titles
|
||||
for rows.Next() {
|
||||
var i Titles
|
||||
if err := rows.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUserTitles = `-- name: ListUserTitles :many
|
||||
SELECT usertitle_id, user_id, title_id, status, rate, review_id
|
||||
FROM usertitles
|
||||
WHERE user_id = $1
|
||||
ORDER BY usertitle_id
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListUserTitlesParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListUserTitles(ctx context.Context, arg ListUserTitlesParams) ([]Usertitles, error) {
|
||||
rows, err := q.db.Query(ctx, listUserTitles, arg.UserID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Usertitles
|
||||
for rows.Next() {
|
||||
var i Usertitles
|
||||
if err := rows.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listUsers = `-- name: ListUsers :many
|
||||
SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date
|
||||
FROM users
|
||||
ORDER BY user_id
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListUsersParams struct {
|
||||
Limit int32 `db:"limit" json:"limit"`
|
||||
Offset int32 `db:"offset" json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, error) {
|
||||
rows, err := q.db.Query(ctx, listUsers, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Users
|
||||
for rows.Next() {
|
||||
var i Users
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Passhash,
|
||||
&i.Mail,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateReview = `-- name: UpdateReview :one
|
||||
UPDATE reviews
|
||||
SET
|
||||
image_ids = COALESCE($1, image_ids),
|
||||
review_text = COALESCE($2, review_text)
|
||||
WHERE review_id = $3
|
||||
RETURNING review_id, user_id, title_id, image_ids, review_text, creation_date
|
||||
`
|
||||
|
||||
type UpdateReviewParams struct {
|
||||
ImageIds []int32 `db:"image_ids" json:"image_ids"`
|
||||
ReviewText pgtype.Text `db:"review_text" json:"review_text"`
|
||||
ReviewID int32 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateReview(ctx context.Context, arg UpdateReviewParams) (Reviews, error) {
|
||||
row := q.db.QueryRow(ctx, updateReview, arg.ImageIds, arg.ReviewText, arg.ReviewID)
|
||||
var i Reviews
|
||||
err := row.Scan(
|
||||
&i.ReviewID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.ImageIds,
|
||||
&i.ReviewText,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTitle = `-- name: UpdateTitle :one
|
||||
UPDATE titles
|
||||
SET
|
||||
title_names = COALESCE($1, title_names),
|
||||
studio_id = COALESCE($2, studio_id),
|
||||
poster_id = COALESCE($3, poster_id),
|
||||
signal_ids = COALESCE($4, signal_ids),
|
||||
title_status = COALESCE($5, title_status),
|
||||
release_year = COALESCE($6, release_year),
|
||||
release_season = COALESCE($7, release_season),
|
||||
episodes_aired = COALESCE($8, episodes_aired),
|
||||
episodes_all = COALESCE($9, episodes_all),
|
||||
episodes_len = COALESCE($10, episodes_len)
|
||||
WHERE title_id = $11
|
||||
RETURNING title_id, title_names, studio_id, poster_id, signal_ids, title_status, rating, rating_count, release_year, release_season, season, episodes_aired, episodes_all, episodes_len
|
||||
`
|
||||
|
||||
type UpdateTitleParams struct {
|
||||
TitleNames []byte `db:"title_names" json:"title_names"`
|
||||
StudioID pgtype.Int4 `db:"studio_id" json:"studio_id"`
|
||||
PosterID pgtype.Int4 `db:"poster_id" json:"poster_id"`
|
||||
SignalIds []int32 `db:"signal_ids" json:"signal_ids"`
|
||||
TitleStatus NullTitleStatusT `db:"title_status" json:"title_status"`
|
||||
ReleaseYear pgtype.Int4 `db:"release_year" json:"release_year"`
|
||||
ReleaseSeason NullReleaseSeasonT `db:"release_season" json:"release_season"`
|
||||
EpisodesAired pgtype.Int4 `db:"episodes_aired" json:"episodes_aired"`
|
||||
EpisodesAll pgtype.Int4 `db:"episodes_all" json:"episodes_all"`
|
||||
EpisodesLen []byte `db:"episodes_len" json:"episodes_len"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTitle(ctx context.Context, arg UpdateTitleParams) (Titles, error) {
|
||||
row := q.db.QueryRow(ctx, updateTitle,
|
||||
arg.TitleNames,
|
||||
arg.StudioID,
|
||||
arg.PosterID,
|
||||
arg.SignalIds,
|
||||
arg.TitleStatus,
|
||||
arg.ReleaseYear,
|
||||
arg.ReleaseSeason,
|
||||
arg.EpisodesAired,
|
||||
arg.EpisodesAll,
|
||||
arg.EpisodesLen,
|
||||
arg.TitleID,
|
||||
)
|
||||
var i Titles
|
||||
err := row.Scan(
|
||||
&i.TitleID,
|
||||
&i.TitleNames,
|
||||
&i.StudioID,
|
||||
&i.PosterID,
|
||||
&i.SignalIds,
|
||||
&i.TitleStatus,
|
||||
&i.Rating,
|
||||
&i.RatingCount,
|
||||
&i.ReleaseYear,
|
||||
&i.ReleaseSeason,
|
||||
&i.Season,
|
||||
&i.EpisodesAired,
|
||||
&i.EpisodesAll,
|
||||
&i.EpisodesLen,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUser = `-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
avatar_id = COALESCE($1, avatar_id),
|
||||
disp_name = COALESCE($2, disp_name),
|
||||
user_desc = COALESCE($3, user_desc)
|
||||
WHERE user_id = $4
|
||||
RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date
|
||||
`
|
||||
|
||||
type UpdateUserParams struct {
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
}
|
||||
|
||||
type UpdateUserRow struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
AvatarID pgtype.Int4 `db:"avatar_id" json:"avatar_id"`
|
||||
Nickname string `db:"nickname" json:"nickname"`
|
||||
DispName pgtype.Text `db:"disp_name" json:"disp_name"`
|
||||
UserDesc pgtype.Text `db:"user_desc" json:"user_desc"`
|
||||
CreationDate pgtype.Timestamp `db:"creation_date" json:"creation_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (UpdateUserRow, error) {
|
||||
row := q.db.QueryRow(ctx, updateUser,
|
||||
arg.AvatarID,
|
||||
arg.DispName,
|
||||
arg.UserDesc,
|
||||
arg.UserID,
|
||||
)
|
||||
var i UpdateUserRow
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.AvatarID,
|
||||
&i.Nickname,
|
||||
&i.DispName,
|
||||
&i.UserDesc,
|
||||
&i.CreationDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserTitle = `-- name: UpdateUserTitle :one
|
||||
UPDATE usertitles
|
||||
SET
|
||||
status = COALESCE($3, status),
|
||||
rate = COALESCE($4, rate),
|
||||
review_id = COALESCE($5, review_id)
|
||||
WHERE user_id = $1 AND title_id = $2
|
||||
RETURNING usertitle_id, user_id, title_id, status, rate, review_id
|
||||
`
|
||||
|
||||
type UpdateUserTitleParams struct {
|
||||
UserID int32 `db:"user_id" json:"user_id"`
|
||||
TitleID int32 `db:"title_id" json:"title_id"`
|
||||
Status NullUsertitleStatusT `db:"status" json:"status"`
|
||||
Rate pgtype.Int4 `db:"rate" json:"rate"`
|
||||
ReviewID pgtype.Int4 `db:"review_id" json:"review_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserTitle(ctx context.Context, arg UpdateUserTitleParams) (Usertitles, error) {
|
||||
row := q.db.QueryRow(ctx, updateUserTitle,
|
||||
arg.UserID,
|
||||
arg.TitleID,
|
||||
arg.Status,
|
||||
arg.Rate,
|
||||
arg.ReviewID,
|
||||
)
|
||||
var i Usertitles
|
||||
err := row.Scan(
|
||||
&i.UsertitleID,
|
||||
&i.UserID,
|
||||
&i.TitleID,
|
||||
&i.Status,
|
||||
&i.Rate,
|
||||
&i.ReviewID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue