Compare commits
13 commits
397d2bcf70
...
fd8ecbeaca
| Author | SHA1 | Date | |
|---|---|---|---|
| fd8ecbeaca | |||
| 9c0fada00e | |||
| e2ac80610c | |||
| 7e6520c931 | |||
| 34d9341e75 | |||
| fbf3f1d3a2 | |||
| 2025bb451f | |||
| 9ed09500ed | |||
| c0be58ba07 | |||
| a9391c18b9 | |||
| 8504746d27 | |||
| ecccc29aa8 | |||
| 7e41b6b9ce |
35 changed files with 1133 additions and 851 deletions
6
api/_build/oapi-codegen.yaml
Normal file
6
api/_build/oapi-codegen.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package: oapi
|
||||||
|
generate:
|
||||||
|
strict-server: true
|
||||||
|
gin-server: true
|
||||||
|
models: true
|
||||||
|
output: api/api.gen.go
|
||||||
436
api/_build/openapi.yaml
Normal file
436
api/_build/openapi.yaml
Normal file
|
|
@ -0,0 +1,436 @@
|
||||||
|
openapi: 3.0.4
|
||||||
|
info:
|
||||||
|
title: 'Titles, Users, Reviews, Tags, and Media API'
|
||||||
|
version: 1.0.0
|
||||||
|
servers:
|
||||||
|
- url: /api/v1
|
||||||
|
paths:
|
||||||
|
/titles:
|
||||||
|
get:
|
||||||
|
summary: Get titles
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/cursor'
|
||||||
|
- $ref: '#/components/parameters/title_sort'
|
||||||
|
- in: query
|
||||||
|
name: sort_forward
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
- in: query
|
||||||
|
name: word
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: status
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TitleStatus'
|
||||||
|
- in: query
|
||||||
|
name: rating
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
- in: query
|
||||||
|
name: release_year
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
- in: query
|
||||||
|
name: release_season
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ReleaseSeason'
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 10
|
||||||
|
- in: query
|
||||||
|
name: offset
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 0
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of titles with cursor
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Title'
|
||||||
|
description: List of titles
|
||||||
|
cursor:
|
||||||
|
$ref: '#/components/schemas/CursorObj'
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
- cursor
|
||||||
|
'204':
|
||||||
|
description: No titles found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
|
'/titles/{title_id}':
|
||||||
|
get:
|
||||||
|
summary: Get title description
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: title_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Title description
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Title'
|
||||||
|
'204':
|
||||||
|
description: No title found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'404':
|
||||||
|
description: Title not found
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
|
'/users/{user_id}':
|
||||||
|
get:
|
||||||
|
summary: Get user info
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: User info
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'404':
|
||||||
|
description: User not found
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
|
'/users/{user_id}/titles/':
|
||||||
|
get:
|
||||||
|
summary: Get user titles
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/cursor'
|
||||||
|
- in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: word
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: status
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TitleStatus'
|
||||||
|
- in: query
|
||||||
|
name: watch_status
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserTitleStatus'
|
||||||
|
- in: query
|
||||||
|
name: rating
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
- in: query
|
||||||
|
name: release_year
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
- in: query
|
||||||
|
name: release_season
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ReleaseSeason'
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 10
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of user titles
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserTitle'
|
||||||
|
'204':
|
||||||
|
description: No titles found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
|
components:
|
||||||
|
parameters:
|
||||||
|
cursor:
|
||||||
|
in: query
|
||||||
|
name: cursor
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
title_sort:
|
||||||
|
in: query
|
||||||
|
name: sort
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TitleSort'
|
||||||
|
schemas:
|
||||||
|
CursorObj:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
param:
|
||||||
|
type: string
|
||||||
|
TitleSort:
|
||||||
|
type: string
|
||||||
|
description: Title sort order
|
||||||
|
default: id
|
||||||
|
enum:
|
||||||
|
- id
|
||||||
|
- year
|
||||||
|
- rating
|
||||||
|
- views
|
||||||
|
Image:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
storage_type:
|
||||||
|
type: string
|
||||||
|
image_path:
|
||||||
|
type: string
|
||||||
|
TitleStatus:
|
||||||
|
type: string
|
||||||
|
description: Title status
|
||||||
|
enum:
|
||||||
|
- finished
|
||||||
|
- ongoing
|
||||||
|
- planned
|
||||||
|
ReleaseSeason:
|
||||||
|
type: string
|
||||||
|
description: Title release season
|
||||||
|
enum:
|
||||||
|
- winter
|
||||||
|
- spring
|
||||||
|
- summer
|
||||||
|
- fall
|
||||||
|
UserTitleStatus:
|
||||||
|
type: string
|
||||||
|
description: User's title status
|
||||||
|
enum:
|
||||||
|
- finished
|
||||||
|
- planned
|
||||||
|
- dropped
|
||||||
|
- in-progress
|
||||||
|
Review:
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
Tag:
|
||||||
|
type: object
|
||||||
|
description: 'A localized tag: keys are language codes (ISO 639-1), values are tag names'
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
en: Shojo
|
||||||
|
ru: Сёдзё
|
||||||
|
ja: 少女
|
||||||
|
Tags:
|
||||||
|
type: array
|
||||||
|
description: Array of localized tags
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Tag'
|
||||||
|
example:
|
||||||
|
- en: Shojo
|
||||||
|
ru: Сёдзё
|
||||||
|
ja: 少女
|
||||||
|
- en: Shounen
|
||||||
|
ru: Сёнен
|
||||||
|
ja: 少年
|
||||||
|
Studio:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
poster:
|
||||||
|
$ref: '#/components/schemas/Image'
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
Title:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title_names
|
||||||
|
- tags
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Unique title ID (primary key)
|
||||||
|
example: 1
|
||||||
|
title_names:
|
||||||
|
type: object
|
||||||
|
description: 'Localized titles. Key = language (ISO 639-1), value = list of names'
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example: Attack on Titan
|
||||||
|
minItems: 1
|
||||||
|
example:
|
||||||
|
- Attack on Titan
|
||||||
|
- AoT
|
||||||
|
example:
|
||||||
|
en:
|
||||||
|
- Attack on Titan
|
||||||
|
- AoT
|
||||||
|
ru:
|
||||||
|
- Атака титанов
|
||||||
|
- Титаны
|
||||||
|
ja:
|
||||||
|
- 進撃の巨人
|
||||||
|
studio:
|
||||||
|
$ref: '#/components/schemas/Studio'
|
||||||
|
tags:
|
||||||
|
$ref: '#/components/schemas/Tags'
|
||||||
|
poster:
|
||||||
|
$ref: '#/components/schemas/Image'
|
||||||
|
title_status:
|
||||||
|
$ref: '#/components/schemas/TitleStatus'
|
||||||
|
rating:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
rating_count:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
release_year:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
release_season:
|
||||||
|
$ref: '#/components/schemas/ReleaseSeason'
|
||||||
|
episodes_aired:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
episodes_all:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
episodes_len:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
additionalProperties: true
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Unique user ID (primary key)
|
||||||
|
example: 1
|
||||||
|
avatar_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: ID of the user avatar (references images table)
|
||||||
|
example: null
|
||||||
|
mail:
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
description: User email
|
||||||
|
example: john.doe@example.com
|
||||||
|
nickname:
|
||||||
|
type: string
|
||||||
|
description: Username (alphanumeric + _ or -)
|
||||||
|
maxLength: 16
|
||||||
|
example: john_doe_42
|
||||||
|
disp_name:
|
||||||
|
type: string
|
||||||
|
description: Display name
|
||||||
|
maxLength: 32
|
||||||
|
example: John Doe
|
||||||
|
user_desc:
|
||||||
|
type: string
|
||||||
|
description: User description
|
||||||
|
maxLength: 512
|
||||||
|
example: Just a regular user.
|
||||||
|
creation_date:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: Timestamp when the user was created
|
||||||
|
example: '2025-10-10T23:45:47.908073Z'
|
||||||
|
required:
|
||||||
|
- user_id
|
||||||
|
- nickname
|
||||||
|
UserTitle:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- user_id
|
||||||
|
- title_id
|
||||||
|
- status
|
||||||
|
properties:
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
title_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
status:
|
||||||
|
$ref: '#/components/schemas/UserTitleStatus'
|
||||||
|
rate:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
review_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
ctime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
additionalProperties: true
|
||||||
|
|
@ -47,6 +47,12 @@ const (
|
||||||
UserTitleStatusPlanned UserTitleStatus = "planned"
|
UserTitleStatusPlanned UserTitleStatus = "planned"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CursorObj defines model for CursorObj.
|
||||||
|
type CursorObj struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Param *string `json:"param,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Image defines model for Image.
|
// Image defines model for Image.
|
||||||
type Image struct {
|
type Image struct {
|
||||||
Id *int64 `json:"id,omitempty"`
|
Id *int64 `json:"id,omitempty"`
|
||||||
|
|
@ -108,7 +114,7 @@ type TitleStatus string
|
||||||
// User defines model for User.
|
// User defines model for User.
|
||||||
type User struct {
|
type User struct {
|
||||||
// AvatarId ID of the user avatar (references images table)
|
// AvatarId ID of the user avatar (references images table)
|
||||||
AvatarId *int64 `json:"avatar_id"`
|
AvatarId *int64 `json:"avatar_id,omitempty"`
|
||||||
|
|
||||||
// CreationDate Timestamp when the user was created
|
// CreationDate Timestamp when the user was created
|
||||||
CreationDate *time.Time `json:"creation_date,omitempty"`
|
CreationDate *time.Time `json:"creation_date,omitempty"`
|
||||||
|
|
@ -906,7 +912,12 @@ type GetTitlesResponseObject interface {
|
||||||
VisitGetTitlesResponse(w http.ResponseWriter) error
|
VisitGetTitlesResponse(w http.ResponseWriter) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetTitles200JSONResponse []Title
|
type GetTitles200JSONResponse struct {
|
||||||
|
Cursor CursorObj `json:"cursor"`
|
||||||
|
|
||||||
|
// Data List of titles
|
||||||
|
Data []Title `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
func (response GetTitles200JSONResponse) VisitGetTitlesResponse(w http.ResponseWriter) error {
|
func (response GetTitles200JSONResponse) VisitGetTitlesResponse(w http.ResponseWriter) error {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
|
||||||
829
api/openapi.yaml
829
api/openapi.yaml
|
|
@ -1,4 +1,4 @@
|
||||||
openapi: 3.1.1
|
openapi: 3.0.4
|
||||||
info:
|
info:
|
||||||
title: Titles, Users, Reviews, Tags, and Media API
|
title: Titles, Users, Reviews, Tags, and Media API
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|
@ -8,830 +8,15 @@ servers:
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/titles:
|
/titles:
|
||||||
get:
|
$ref: "./paths/titles.yaml"
|
||||||
summary: Get titles
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/cursor'
|
|
||||||
- $ref: '#/components/parameters/title_sort'
|
|
||||||
- in: query
|
|
||||||
name: sort_forward
|
|
||||||
default: true
|
|
||||||
schema:
|
|
||||||
type: boolean
|
|
||||||
- in: query
|
|
||||||
name: word
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: status
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/TitleStatus'
|
|
||||||
- in: query
|
|
||||||
name: rating
|
|
||||||
schema:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
- in: query
|
|
||||||
name: release_year
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
- in: query
|
|
||||||
name: release_season
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/ReleaseSeason'
|
|
||||||
- in: query
|
|
||||||
name: limit
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
default: 10
|
|
||||||
- in: query
|
|
||||||
name: offset
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
default: 0
|
|
||||||
- in: query
|
|
||||||
name: fields
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
default: all
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: List of titles
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/Title'
|
|
||||||
'204':
|
|
||||||
description: No titles found
|
|
||||||
'400':
|
|
||||||
description: Request params are not correct
|
|
||||||
'500':
|
|
||||||
description: Unknown server error
|
|
||||||
|
|
||||||
/titles/{title_id}:
|
/titles/{title_id}:
|
||||||
get:
|
$ref: "./paths/titles-id.yaml"
|
||||||
summary: Get title description
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: title_id
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
- in: query
|
|
||||||
name: fields
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
default: all
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Title description
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/Title'
|
|
||||||
'404':
|
|
||||||
description: Title not found
|
|
||||||
'400':
|
|
||||||
description: Request params are not correct
|
|
||||||
'500':
|
|
||||||
description: Unknown server error
|
|
||||||
'204':
|
|
||||||
description: No title found
|
|
||||||
|
|
||||||
# patch:
|
|
||||||
# summary: Update title info
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: title_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/Title'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Update result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
# user_json:
|
|
||||||
# $ref: '#/components/schemas/User'
|
|
||||||
|
|
||||||
# /titles/{title_id}/reviews:
|
|
||||||
# get:
|
|
||||||
# summary: Get title reviews
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: title_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# - in: query
|
|
||||||
# name: limit
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 10
|
|
||||||
# - in: query
|
|
||||||
# name: offset
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 0
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: List of reviews
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: '#/components/schemas/Review'
|
|
||||||
# '204':
|
|
||||||
# description: No reviews found
|
|
||||||
|
|
||||||
/users/{user_id}:
|
/users/{user_id}:
|
||||||
get:
|
$ref: "./paths/users-id.yaml"
|
||||||
summary: Get user info
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: user_id
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: fields
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
default: all
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: User info
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/User'
|
|
||||||
'404':
|
|
||||||
description: User not found
|
|
||||||
'400':
|
|
||||||
description: Request params are not correct
|
|
||||||
'500':
|
|
||||||
description: Unknown server error
|
|
||||||
|
|
||||||
# patch:
|
|
||||||
# summary: Update user
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/User'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Update result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# delete:
|
|
||||||
# summary: Delete user
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Delete result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# /users:
|
|
||||||
# get:
|
|
||||||
# summary: Search user
|
|
||||||
# parameters:
|
|
||||||
# - in: query
|
|
||||||
# name: query
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# - in: query
|
|
||||||
# name: fields
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: List of users
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: '#/components/schemas/User'
|
|
||||||
|
|
||||||
# post:
|
|
||||||
# summary: Add new user
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/User'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Add result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
# user_json:
|
|
||||||
# $ref: '#/components/schemas/User'
|
|
||||||
|
|
||||||
/users/{user_id}/titles/:
|
/users/{user_id}/titles/:
|
||||||
get:
|
$ref: "./paths/users-id-titles.yaml"
|
||||||
summary: Get user titles
|
|
||||||
parameters:
|
|
||||||
- $ref: '#/components/parameters/cursor'
|
|
||||||
- in: path
|
|
||||||
name: user_id
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: word
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: status
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/TitleStatus'
|
|
||||||
- in: query
|
|
||||||
name: watch_status
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/UserTitleStatus'
|
|
||||||
- in: query
|
|
||||||
name: rating
|
|
||||||
schema:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
- in: query
|
|
||||||
name: release_year
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
- in: query
|
|
||||||
name: release_season
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/ReleaseSeason'
|
|
||||||
- in: query
|
|
||||||
name: limit
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
default: 10
|
|
||||||
- in: query
|
|
||||||
name: fields
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
default: all
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: List of user titles
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/UserTitle'
|
|
||||||
'204':
|
|
||||||
description: No titles found
|
|
||||||
'400':
|
|
||||||
description: Request params are not correct
|
|
||||||
'500':
|
|
||||||
description: Unknown server error
|
|
||||||
|
|
||||||
# post:
|
|
||||||
# summary: Add user title
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# title_id:
|
|
||||||
# type: string
|
|
||||||
# status:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Add result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# patch:
|
|
||||||
# summary: Update user title
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/UserTitle'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Update result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# delete:
|
|
||||||
# summary: Delete user title
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# - in: query
|
|
||||||
# name: title_id
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Delete result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# /users/{user_id}/reviews:
|
|
||||||
# get:
|
|
||||||
# summary: Get user reviews
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: user_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# - in: query
|
|
||||||
# name: limit
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 10
|
|
||||||
# - in: query
|
|
||||||
# name: offset
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 0
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: List of reviews
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: '#/components/schemas/Review'
|
|
||||||
|
|
||||||
# /reviews:
|
|
||||||
# post:
|
|
||||||
# summary: Add review
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/Review'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Add result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# /reviews/{review_id}:
|
|
||||||
# patch:
|
|
||||||
# summary: Update review
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: review_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# requestBody:
|
|
||||||
# required: true
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# $ref: '#/components/schemas/Review'
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Update result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
# delete:
|
|
||||||
# summary: Delete review
|
|
||||||
# parameters:
|
|
||||||
# - in: path
|
|
||||||
# name: review_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Delete result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# /tags:
|
|
||||||
# get:
|
|
||||||
# summary: Get tags
|
|
||||||
# parameters:
|
|
||||||
# - in: query
|
|
||||||
# name: limit
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 10
|
|
||||||
# - in: query
|
|
||||||
# name: offset
|
|
||||||
# schema:
|
|
||||||
# type: integer
|
|
||||||
# default: 0
|
|
||||||
# - in: query
|
|
||||||
# name: fields
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: List of tags
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: array
|
|
||||||
# items:
|
|
||||||
# $ref: '#/components/schemas/Tag'
|
|
||||||
|
|
||||||
# /media:
|
|
||||||
# post:
|
|
||||||
# summary: Upload image
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Upload result
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
# image_id:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# get:
|
|
||||||
# summary: Get image path
|
|
||||||
# parameters:
|
|
||||||
# - in: query
|
|
||||||
# name: image_id
|
|
||||||
# required: true
|
|
||||||
# schema:
|
|
||||||
# type: string
|
|
||||||
# responses:
|
|
||||||
# '200':
|
|
||||||
# description: Image path
|
|
||||||
# content:
|
|
||||||
# application/json:
|
|
||||||
# schema:
|
|
||||||
# type: object
|
|
||||||
# properties:
|
|
||||||
# success:
|
|
||||||
# type: boolean
|
|
||||||
# error:
|
|
||||||
# type: string
|
|
||||||
# image_path:
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
components:
|
components:
|
||||||
parameters:
|
parameters:
|
||||||
cursor: # example base64( {id: 1, param: 2019})
|
$ref: "./parameters/_index.yaml"
|
||||||
in: query
|
|
||||||
name: cursor
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
|
|
||||||
title_sort:
|
|
||||||
in: query
|
|
||||||
name: sort
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/TitleSort'
|
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
TitleSort:
|
$ref: "./schemas/_index.yaml"
|
||||||
type: string
|
|
||||||
description: Title sort order
|
|
||||||
default: id
|
|
||||||
enum:
|
|
||||||
- id
|
|
||||||
- year
|
|
||||||
- rating
|
|
||||||
- views
|
|
||||||
|
|
||||||
Image:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
storage_type:
|
|
||||||
type: string
|
|
||||||
image_path:
|
|
||||||
type: string
|
|
||||||
|
|
||||||
TitleStatus:
|
|
||||||
type: string
|
|
||||||
description: Title status
|
|
||||||
enum:
|
|
||||||
- finished
|
|
||||||
- ongoing
|
|
||||||
- planned
|
|
||||||
|
|
||||||
ReleaseSeason:
|
|
||||||
type: string
|
|
||||||
description: Title release season
|
|
||||||
enum:
|
|
||||||
- winter
|
|
||||||
- spring
|
|
||||||
- summer
|
|
||||||
- fall
|
|
||||||
|
|
||||||
UserTitleStatus:
|
|
||||||
type: string
|
|
||||||
description: User's title status
|
|
||||||
enum:
|
|
||||||
- finished
|
|
||||||
- planned
|
|
||||||
- dropped
|
|
||||||
- in-progress
|
|
||||||
|
|
||||||
Review:
|
|
||||||
type: object
|
|
||||||
additionalProperties: true
|
|
||||||
|
|
||||||
Tag:
|
|
||||||
type: object
|
|
||||||
description: "A localized tag: keys are language codes (ISO 639-1), values are tag names"
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
example:
|
|
||||||
en: "Shojo"
|
|
||||||
ru: "Сёдзё"
|
|
||||||
ja: "少女"
|
|
||||||
|
|
||||||
Tags:
|
|
||||||
type: array
|
|
||||||
description: "Array of localized tags"
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/Tag'
|
|
||||||
example:
|
|
||||||
- en: "Shojo"
|
|
||||||
ru: "Сёдзё"
|
|
||||||
ja: "少女"
|
|
||||||
- en: "Shounen"
|
|
||||||
ru: "Сёнен"
|
|
||||||
ja: "少年"
|
|
||||||
|
|
||||||
Studio:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- id
|
|
||||||
- name
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
poster:
|
|
||||||
$ref: '#/components/schemas/Image'
|
|
||||||
description:
|
|
||||||
type: string
|
|
||||||
|
|
||||||
|
|
||||||
Title:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- id
|
|
||||||
- title_names
|
|
||||||
- tags
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
description: Unique title ID (primary key)
|
|
||||||
example: 1
|
|
||||||
title_names:
|
|
||||||
type: object
|
|
||||||
description: "Localized titles. Key = language (ISO 639-1), value = list of names"
|
|
||||||
additionalProperties:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
example: "Attack on Titan"
|
|
||||||
minItems: 1
|
|
||||||
example: ["Attack on Titan", "AoT"]
|
|
||||||
example:
|
|
||||||
en: ["Attack on Titan", "AoT"]
|
|
||||||
ru: ["Атака титанов", "Титаны"]
|
|
||||||
ja: ["進撃の巨人"]
|
|
||||||
studio:
|
|
||||||
$ref: '#/components/schemas/Studio'
|
|
||||||
tags:
|
|
||||||
$ref: '#/components/schemas/Tags'
|
|
||||||
poster:
|
|
||||||
$ref: '#/components/schemas/Image'
|
|
||||||
title_status:
|
|
||||||
$ref: '#/components/schemas/TitleStatus'
|
|
||||||
rating:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
rating_count:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
release_year:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
release_season:
|
|
||||||
$ref: '#/components/schemas/ReleaseSeason'
|
|
||||||
episodes_aired:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
episodes_all:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
episodes_len:
|
|
||||||
type: object
|
|
||||||
additionalProperties:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
additionalProperties: true
|
|
||||||
|
|
||||||
User:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
description: Unique user ID (primary key)
|
|
||||||
example: 1
|
|
||||||
avatar_id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
description: ID of the user avatar (references images table)
|
|
||||||
nullable: true
|
|
||||||
example: null
|
|
||||||
mail:
|
|
||||||
type: string
|
|
||||||
format: email
|
|
||||||
description: User email
|
|
||||||
example: "john.doe@example.com"
|
|
||||||
nickname:
|
|
||||||
type: string
|
|
||||||
description: Username (alphanumeric + _ or -)
|
|
||||||
maxLength: 16
|
|
||||||
example: "john_doe_42"
|
|
||||||
disp_name:
|
|
||||||
type: string
|
|
||||||
description: Display name
|
|
||||||
maxLength: 32
|
|
||||||
example: "John Doe"
|
|
||||||
user_desc:
|
|
||||||
type: string
|
|
||||||
description: User description
|
|
||||||
maxLength: 512
|
|
||||||
example: "Just a regular user."
|
|
||||||
creation_date:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
description: Timestamp when the user was created
|
|
||||||
example: "2025-10-10T23:45:47.908073Z"
|
|
||||||
required:
|
|
||||||
- user_id
|
|
||||||
- nickname
|
|
||||||
# - creation_date
|
|
||||||
|
|
||||||
UserTitle:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- user_id
|
|
||||||
- title_id
|
|
||||||
- status
|
|
||||||
properties:
|
|
||||||
user_id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
title_id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
status:
|
|
||||||
$ref: '#/components/schemas/UserTitleStatus'
|
|
||||||
rate:
|
|
||||||
type: integer
|
|
||||||
format: int32
|
|
||||||
review_id:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
ctime:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
additionalProperties: true
|
|
||||||
|
|
|
||||||
4
api/parameters/_index.yaml
Normal file
4
api/parameters/_index.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
cursor:
|
||||||
|
$ref: "./cursor.yaml"
|
||||||
|
title_sort:
|
||||||
|
$ref: "./title_sort.yaml"
|
||||||
5
api/parameters/cursor.yaml
Normal file
5
api/parameters/cursor.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
in: query
|
||||||
|
name: cursor
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
5
api/parameters/title_sort.yaml
Normal file
5
api/parameters/title_sort.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
in: query
|
||||||
|
name: sort
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/TitleSort.yaml'
|
||||||
29
api/paths/titles-id.yaml
Normal file
29
api/paths/titles-id.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
get:
|
||||||
|
summary: Get title description
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: title_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Title description
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "../schemas/Title.yaml"
|
||||||
|
'404':
|
||||||
|
description: Title not found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
|
'204':
|
||||||
|
description: No title found
|
||||||
73
api/paths/titles.yaml
Normal file
73
api/paths/titles.yaml
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
get:
|
||||||
|
summary: Get titles
|
||||||
|
parameters:
|
||||||
|
- $ref: "../parameters/cursor.yaml"
|
||||||
|
- $ref: "../parameters/title_sort.yaml"
|
||||||
|
- in: query
|
||||||
|
name: sort_forward
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
- in: query
|
||||||
|
name: word
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: status
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/enums/TitleStatus.yaml'
|
||||||
|
- in: query
|
||||||
|
name: rating
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
- in: query
|
||||||
|
name: release_year
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
- in: query
|
||||||
|
name: release_season
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/enums/ReleaseSeason.yaml'
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 10
|
||||||
|
- in: query
|
||||||
|
name: offset
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 0
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of titles with cursor
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '../schemas/Title.yaml'
|
||||||
|
description: List of titles
|
||||||
|
cursor:
|
||||||
|
$ref: '../schemas/CursorObj.yaml'
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
- cursor
|
||||||
|
'204':
|
||||||
|
description: No titles found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
61
api/paths/users-id-titles.yaml
Normal file
61
api/paths/users-id-titles.yaml
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
get:
|
||||||
|
summary: Get user titles
|
||||||
|
parameters:
|
||||||
|
- $ref: '../parameters/cursor.yaml'
|
||||||
|
- in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: word
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: status
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/enums/TitleStatus.yaml'
|
||||||
|
- in: query
|
||||||
|
name: watch_status
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/enums/UserTitleStatus.yaml'
|
||||||
|
- in: query
|
||||||
|
name: rating
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
- in: query
|
||||||
|
name: release_year
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
- in: query
|
||||||
|
name: release_season
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/enums/ReleaseSeason.yaml'
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
default: 10
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of user titles
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '../schemas/UserTitle.yaml'
|
||||||
|
'204':
|
||||||
|
description: No titles found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
26
api/paths/users-id.yaml
Normal file
26
api/paths/users-id.yaml
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
get:
|
||||||
|
summary: Get user info
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: fields
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: all
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: User info
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '../schemas/User.yaml'
|
||||||
|
'404':
|
||||||
|
description: User not found
|
||||||
|
'400':
|
||||||
|
description: Request params are not correct
|
||||||
|
'500':
|
||||||
|
description: Unknown server error
|
||||||
9
api/schemas/CursorObj.yaml
Normal file
9
api/schemas/CursorObj.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
param:
|
||||||
|
type: string
|
||||||
9
api/schemas/Image.yaml
Normal file
9
api/schemas/Image.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
storage_type:
|
||||||
|
type: string
|
||||||
|
image_path:
|
||||||
|
type: string
|
||||||
2
api/schemas/Review.yaml
Normal file
2
api/schemas/Review.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
14
api/schemas/Studio.yaml
Normal file
14
api/schemas/Studio.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
poster:
|
||||||
|
$ref: ./Image.yaml
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
8
api/schemas/Tag.yaml
Normal file
8
api/schemas/Tag.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
type: object
|
||||||
|
description: 'A localized tag: keys are language codes (ISO 639-1), values are tag names'
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
en: Shojo
|
||||||
|
ru: Сёдзё
|
||||||
|
ja: 少女
|
||||||
11
api/schemas/Tags.yaml
Normal file
11
api/schemas/Tags.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
type: array
|
||||||
|
description: Array of localized tags
|
||||||
|
items:
|
||||||
|
$ref: ./Tag.yaml
|
||||||
|
example:
|
||||||
|
- en: Shojo
|
||||||
|
ru: Сёдзё
|
||||||
|
ja: 少女
|
||||||
|
- en: Shounen
|
||||||
|
ru: Сёнен
|
||||||
|
ja: 少年
|
||||||
63
api/schemas/Title.yaml
Normal file
63
api/schemas/Title.yaml
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title_names
|
||||||
|
- tags
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Unique title ID (primary key)
|
||||||
|
example: 1
|
||||||
|
title_names:
|
||||||
|
type: object
|
||||||
|
description: Localized titles. Key = language (ISO 639-1), value = list of names
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example: Attack on Titan
|
||||||
|
minItems: 1
|
||||||
|
example:
|
||||||
|
- Attack on Titan
|
||||||
|
- AoT
|
||||||
|
example:
|
||||||
|
en:
|
||||||
|
- Attack on Titan
|
||||||
|
- AoT
|
||||||
|
ru:
|
||||||
|
- Атака титанов
|
||||||
|
- Титаны
|
||||||
|
ja:
|
||||||
|
- 進撃の巨人
|
||||||
|
studio:
|
||||||
|
$ref: ./Studio.yaml
|
||||||
|
tags:
|
||||||
|
$ref: ./Tags.yaml
|
||||||
|
poster:
|
||||||
|
$ref: ./Image.yaml
|
||||||
|
title_status:
|
||||||
|
$ref: ./enums/TitleStatus.yaml
|
||||||
|
rating:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
rating_count:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
release_year:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
release_season:
|
||||||
|
$ref: ./enums/ReleaseSeason.yaml
|
||||||
|
episodes_aired:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
episodes_all:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
episodes_len:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
additionalProperties: true
|
||||||
8
api/schemas/TitleSort.yaml
Normal file
8
api/schemas/TitleSort.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
type: string
|
||||||
|
description: Title sort order
|
||||||
|
default: id
|
||||||
|
enum:
|
||||||
|
- id
|
||||||
|
- year
|
||||||
|
- rating
|
||||||
|
- views
|
||||||
40
api/schemas/User.yaml
Normal file
40
api/schemas/User.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Unique user ID (primary key)
|
||||||
|
example: 1
|
||||||
|
avatar_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: ID of the user avatar (references images table)
|
||||||
|
example: null
|
||||||
|
mail:
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
description: User email
|
||||||
|
example: john.doe@example.com
|
||||||
|
nickname:
|
||||||
|
type: string
|
||||||
|
description: Username (alphanumeric + _ or -)
|
||||||
|
maxLength: 16
|
||||||
|
example: john_doe_42
|
||||||
|
disp_name:
|
||||||
|
type: string
|
||||||
|
description: Display name
|
||||||
|
maxLength: 32
|
||||||
|
example: John Doe
|
||||||
|
user_desc:
|
||||||
|
type: string
|
||||||
|
description: User description
|
||||||
|
maxLength: 512
|
||||||
|
example: Just a regular user.
|
||||||
|
creation_date:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: Timestamp when the user was created
|
||||||
|
example: '2025-10-10T23:45:47.908073Z'
|
||||||
|
required:
|
||||||
|
- user_id
|
||||||
|
- nickname
|
||||||
24
api/schemas/UserTitle.yaml
Normal file
24
api/schemas/UserTitle.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- user_id
|
||||||
|
- title_id
|
||||||
|
- status
|
||||||
|
properties:
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
title_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
status:
|
||||||
|
$ref: ./enums/UserTitleStatus.yaml
|
||||||
|
rate:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
review_id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
ctime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
additionalProperties: true
|
||||||
26
api/schemas/_index.yaml
Normal file
26
api/schemas/_index.yaml
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
CursorObj:
|
||||||
|
$ref: ./CursorObj.yaml
|
||||||
|
TitleSort:
|
||||||
|
$ref: "./TitleSort.yaml"
|
||||||
|
Image:
|
||||||
|
$ref: "./Image.yaml"
|
||||||
|
TitleStatus:
|
||||||
|
$ref: "./enums/TitleStatus.yaml"
|
||||||
|
ReleaseSeason:
|
||||||
|
$ref: "./enums/ReleaseSeason.yaml"
|
||||||
|
UserTitleStatus:
|
||||||
|
$ref: "./enums/UserTitleStatus.yaml"
|
||||||
|
Review:
|
||||||
|
$ref: "./Review.yaml"
|
||||||
|
Tag:
|
||||||
|
$ref: "./Tag.yaml"
|
||||||
|
Tags:
|
||||||
|
$ref: "./Tags.yaml"
|
||||||
|
Studio:
|
||||||
|
$ref: "./Studio.yaml"
|
||||||
|
Title:
|
||||||
|
$ref: "./Title.yaml"
|
||||||
|
User:
|
||||||
|
$ref: "./User.yaml"
|
||||||
|
UserTitle:
|
||||||
|
$ref: "./UserTitle.yaml"
|
||||||
7
api/schemas/enums/ReleaseSeason.yaml
Normal file
7
api/schemas/enums/ReleaseSeason.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
type: string
|
||||||
|
description: Title release season
|
||||||
|
enum:
|
||||||
|
- winter
|
||||||
|
- spring
|
||||||
|
- summer
|
||||||
|
- fall
|
||||||
6
api/schemas/enums/TitleStatus.yaml
Normal file
6
api/schemas/enums/TitleStatus.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
type: string
|
||||||
|
description: Title status
|
||||||
|
enum:
|
||||||
|
- finished
|
||||||
|
- ongoing
|
||||||
|
- planned
|
||||||
7
api/schemas/enums/UserTitleStatus.yaml
Normal file
7
api/schemas/enums/UserTitleStatus.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
type: string
|
||||||
|
description: User's title status
|
||||||
|
enum:
|
||||||
|
- finished
|
||||||
|
- planned
|
||||||
|
- dropped
|
||||||
|
- in-progress
|
||||||
5
go.mod
5
go.mod
|
|
@ -8,7 +8,7 @@ require (
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
github.com/jackc/pgx/v5 v5.7.6
|
||||||
github.com/oapi-codegen/runtime v1.1.2
|
github.com/oapi-codegen/runtime v1.1.2
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4
|
github.com/pelletier/go-toml/v2 v2.2.4
|
||||||
golang.org/x/crypto v0.40.0
|
github.com/sirupsen/logrus v1.9.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
@ -26,6 +26,7 @@ require (
|
||||||
github.com/google/uuid v1.5.0 // indirect
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
|
@ -34,11 +35,11 @@ require (
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
github.com/quic-go/quic-go v0.54.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
go.uber.org/mock v0.5.0 // indirect
|
go.uber.org/mock v0.5.0 // indirect
|
||||||
golang.org/x/arch v0.20.0 // indirect
|
golang.org/x/arch v0.20.0 // indirect
|
||||||
|
golang.org/x/crypto v0.40.0 // indirect
|
||||||
golang.org/x/mod v0.25.0 // indirect
|
golang.org/x/mod v0.25.0 // indirect
|
||||||
golang.org/x/net v0.42.0 // indirect
|
golang.org/x/net v0.42.0 // indirect
|
||||||
golang.org/x/sync v0.16.0 // indirect
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,9 @@ func (s Server) GetTitlesTitleId(ctx context.Context, request oapi.GetTitlesTitl
|
||||||
|
|
||||||
func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObject) (oapi.GetTitlesResponseObject, error) {
|
func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObject) (oapi.GetTitlesResponseObject, error) {
|
||||||
opai_titles := make([]oapi.Title, 0)
|
opai_titles := make([]oapi.Title, 0)
|
||||||
|
cursor := oapi.CursorObj{
|
||||||
|
Id: 1,
|
||||||
|
}
|
||||||
|
|
||||||
word := Word2Sqlc(request.Params.Word)
|
word := Word2Sqlc(request.Params.Word)
|
||||||
status, err := TitleStatus2Sqlc(request.Params.Status)
|
status, err := TitleStatus2Sqlc(request.Params.Status)
|
||||||
|
|
@ -237,7 +240,8 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
||||||
Rating: request.Params.Rating,
|
Rating: request.Params.Rating,
|
||||||
ReleaseYear: request.Params.ReleaseYear,
|
ReleaseYear: request.Params.ReleaseYear,
|
||||||
ReleaseSeason: season,
|
ReleaseSeason: season,
|
||||||
Offset: request.Params.Offset,
|
Forward: true,
|
||||||
|
SortBy: "id",
|
||||||
Limit: request.Params.Limit,
|
Limit: request.Params.Limit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -258,5 +262,5 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
|
||||||
opai_titles = append(opai_titles, t)
|
opai_titles = append(opai_titles, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
return oapi.GetTitles200JSONResponse(opai_titles), nil
|
return oapi.GetTitles200JSONResponse{Cursor: cursor, Data: opai_titles}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -31,17 +31,17 @@ func main() {
|
||||||
// log.Fatalf("Failed to init config: %v\n", err)
|
// log.Fatalf("Failed to init config: %v\n", err)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
pool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer conn.Close(context.Background())
|
defer pool.Close()
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
queries := sqlc.New(conn)
|
queries := sqlc.New(pool)
|
||||||
|
|
||||||
server := handlers.NewServer(queries)
|
server := handlers.NewServer(queries)
|
||||||
// r.LoadHTMLGlob("templates/*")
|
// r.LoadHTMLGlob("templates/*")
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,65 @@ WHERE
|
||||||
AND (sqlc.narg('rating')::float IS NULL OR rating >= sqlc.narg('rating')::float)
|
AND (sqlc.narg('rating')::float IS NULL OR rating >= sqlc.narg('rating')::float)
|
||||||
AND (sqlc.narg('release_year')::int IS NULL OR release_year = sqlc.narg('release_year')::int)
|
AND (sqlc.narg('release_year')::int IS NULL OR release_year = sqlc.narg('release_year')::int)
|
||||||
AND (sqlc.narg('release_season')::release_season_t IS NULL OR release_season = sqlc.narg('release_season')::release_season_t)
|
AND (sqlc.narg('release_season')::release_season_t IS NULL OR release_season = sqlc.narg('release_season')::release_season_t)
|
||||||
|
ORDER BY
|
||||||
|
-- Основной ключ: выбранное поле
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'id' THEN id
|
||||||
|
WHEN sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'year' THEN release_year
|
||||||
|
WHEN sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'rating' THEN rating
|
||||||
|
-- WHEN sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'views' THEN views
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN NOT sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'id' THEN id
|
||||||
|
WHEN NOT sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'year' THEN release_year
|
||||||
|
WHEN NOT sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'rating' THEN rating
|
||||||
|
-- WHEN NOT sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'views' THEN views
|
||||||
|
END DESC,
|
||||||
|
|
||||||
LIMIT COALESCE(sqlc.narg('limit')::int, 100) -- 100 is default limit
|
-- Вторичный ключ: id — только если НЕ сортируем по id
|
||||||
OFFSET sqlc.narg('offset')::int;
|
CASE
|
||||||
|
WHEN sqlc.arg(sort_by)::text != 'id' AND sqlc.arg(forward)::boolean THEN id
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.arg(sort_by)::text != 'id' AND NOT sqlc.arg(forward)::boolean THEN id
|
||||||
|
END DESC
|
||||||
|
LIMIT COALESCE(sqlc.narg('limit')::int, 100); -- 100 is default limit
|
||||||
|
-- OFFSET sqlc.narg('offset')::int;
|
||||||
|
|
||||||
|
-- name: SearchUserTitles :many
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM usertitles as u
|
||||||
|
JOIN titles as t ON (u.title_id = t.id)
|
||||||
|
WHERE
|
||||||
|
CASE
|
||||||
|
WHEN sqlc.narg('word')::text IS NOT NULL THEN
|
||||||
|
(
|
||||||
|
SELECT bool_and(
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM jsonb_each_text(t.title_names) AS t(key, val)
|
||||||
|
WHERE val ILIKE pattern
|
||||||
|
)
|
||||||
|
)
|
||||||
|
FROM unnest(
|
||||||
|
ARRAY(
|
||||||
|
SELECT '%' || trim(w) || '%'
|
||||||
|
FROM unnest(string_to_array(sqlc.narg('word')::text, ' ')) AS w
|
||||||
|
WHERE trim(w) <> ''
|
||||||
|
)
|
||||||
|
) AS pattern
|
||||||
|
)
|
||||||
|
ELSE true
|
||||||
|
END
|
||||||
|
|
||||||
|
AND (sqlc.narg('status')::title_status_t IS NULL OR t.title_status = sqlc.narg('status')::title_status_t)
|
||||||
|
AND (sqlc.narg('rating')::float IS NULL OR t.rating >= sqlc.narg('rating')::float)
|
||||||
|
AND (sqlc.narg('release_year')::int IS NULL OR t.release_year = sqlc.narg('release_year')::int)
|
||||||
|
AND (sqlc.narg('release_season')::release_season_t IS NULL OR t.release_season = sqlc.narg('release_season')::release_season_t)
|
||||||
|
AND (sqlc.narg('usertitle_status')::usertitle_status_t IS NULL OR u.usertitle_status = sqlc.narg('usertitle_status')::usertitle_status_t)
|
||||||
|
|
||||||
|
LIMIT COALESCE(sqlc.narg('limit')::int, 100); -- 100 is default limit
|
||||||
|
|
||||||
-- -- name: ListTitles :many
|
-- -- name: ListTitles :many
|
||||||
-- SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
-- SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,8 @@
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.45.0",
|
"typescript-eslint": "^8.45.0",
|
||||||
"vite": "^7.1.7"
|
"vite": "^7.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": false,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": false,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ CREATE TABLE studios (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE titles (
|
CREATE TABLE titles (
|
||||||
// TODO: anime type (film, season etc)
|
-- // TODO: anime type (film, season etc)
|
||||||
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
-- example {"ru": ["Атака титанов", "Атака Титанов"],"en": ["Attack on Titan", "AoT"],"ja": ["進撃の巨人", "しんげきのきょじん"]}
|
-- example {"ru": ["Атака титанов", "Атака Титанов"],"en": ["Attack on Titan", "AoT"],"ja": ["進撃の巨人", "しんげきのきょじん"]}
|
||||||
title_names jsonb NOT NULL,
|
title_names jsonb NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,6 @@ type Review struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Rating *int32 `json:"rating"`
|
Rating *int32 `json:"rating"`
|
||||||
IllustID *int64 `json:"illust_id"`
|
|
||||||
UserID *int64 `json:"user_id"`
|
UserID *int64 `json:"user_id"`
|
||||||
TitleID *int64 `json:"title_id"`
|
TitleID *int64 `json:"title_id"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
|
@ -281,6 +280,6 @@ type Usertitle struct {
|
||||||
TitleID int64 `json:"title_id"`
|
TitleID int64 `json:"title_id"`
|
||||||
Status UsertitleStatusT `json:"status"`
|
Status UsertitleStatusT `json:"status"`
|
||||||
Rate *int32 `json:"rate"`
|
Rate *int32 `json:"rate"`
|
||||||
ReviewText *string `json:"review_text"`
|
ReviewID *int64 `json:"review_id"`
|
||||||
ReviewDate pgtype.Timestamptz `json:"review_date"`
|
Ctime pgtype.Timestamptz `json:"ctime"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ package sqlc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const createImage = `-- name: CreateImage :one
|
const createImage = `-- name: CreateImage :one
|
||||||
|
|
@ -31,7 +33,7 @@ func (q *Queries) CreateImage(ctx context.Context, arg CreateImageParams) (Image
|
||||||
const getImageByID = `-- name: GetImageByID :one
|
const getImageByID = `-- name: GetImageByID :one
|
||||||
SELECT id, storage_type, image_path
|
SELECT id, storage_type, image_path
|
||||||
FROM images
|
FROM images
|
||||||
WHERE id = $1
|
WHERE id = $1::bigint
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetImageByID(ctx context.Context, illustID int64) (Image, error) {
|
func (q *Queries) GetImageByID(ctx context.Context, illustID int64) (Image, error) {
|
||||||
|
|
@ -44,11 +46,13 @@ func (q *Queries) GetImageByID(ctx context.Context, illustID int64) (Image, erro
|
||||||
const getReviewByID = `-- name: GetReviewByID :one
|
const getReviewByID = `-- name: GetReviewByID :one
|
||||||
|
|
||||||
|
|
||||||
SELECT id, data, rating, illust_id, user_id, title_id, created_at
|
|
||||||
|
SELECT id, data, rating, user_id, title_id, created_at
|
||||||
FROM reviews
|
FROM reviews
|
||||||
WHERE review_id = $1::bigint
|
WHERE review_id = $1::bigint
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// 100 is default limit
|
||||||
// -- name: ListTitles :many
|
// -- name: ListTitles :many
|
||||||
// SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
// SELECT title_id, title_names, studio_id, poster_id, signal_ids,
|
||||||
//
|
//
|
||||||
|
|
@ -82,7 +86,6 @@ func (q *Queries) GetReviewByID(ctx context.Context, reviewID int64) (Review, er
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.Data,
|
&i.Data,
|
||||||
&i.Rating,
|
&i.Rating,
|
||||||
&i.IllustID,
|
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.TitleID,
|
&i.TitleID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|
@ -312,9 +315,29 @@ WHERE
|
||||||
AND ($3::float IS NULL OR rating >= $3::float)
|
AND ($3::float IS NULL OR rating >= $3::float)
|
||||||
AND ($4::int IS NULL OR release_year = $4::int)
|
AND ($4::int IS NULL OR release_year = $4::int)
|
||||||
AND ($5::release_season_t IS NULL OR release_season = $5::release_season_t)
|
AND ($5::release_season_t IS NULL OR release_season = $5::release_season_t)
|
||||||
|
ORDER BY
|
||||||
|
-- Основной ключ: выбранное поле
|
||||||
|
CASE
|
||||||
|
WHEN $6::boolean AND $7::text = 'id' THEN id
|
||||||
|
WHEN $6::boolean AND $7::text = 'year' THEN release_year
|
||||||
|
WHEN $6::boolean AND $7::text = 'rating' THEN rating
|
||||||
|
-- WHEN sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'views' THEN views
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN NOT $6::boolean AND $7::text = 'id' THEN id
|
||||||
|
WHEN NOT $6::boolean AND $7::text = 'year' THEN release_year
|
||||||
|
WHEN NOT $6::boolean AND $7::text = 'rating' THEN rating
|
||||||
|
-- WHEN NOT sqlc.arg(forward)::boolean AND sqlc.arg(sort_by)::text = 'views' THEN views
|
||||||
|
END DESC,
|
||||||
|
|
||||||
LIMIT COALESCE($7::int, 100) -- 100 is default limit
|
-- Вторичный ключ: id — только если НЕ сортируем по id
|
||||||
OFFSET $6::int
|
CASE
|
||||||
|
WHEN $7::text != 'id' AND $6::boolean THEN id
|
||||||
|
END ASC,
|
||||||
|
CASE
|
||||||
|
WHEN $7::text != 'id' AND NOT $6::boolean THEN id
|
||||||
|
END DESC
|
||||||
|
LIMIT COALESCE($8::int, 100)
|
||||||
`
|
`
|
||||||
|
|
||||||
type SearchTitlesParams struct {
|
type SearchTitlesParams struct {
|
||||||
|
|
@ -323,7 +346,8 @@ type SearchTitlesParams struct {
|
||||||
Rating *float64 `json:"rating"`
|
Rating *float64 `json:"rating"`
|
||||||
ReleaseYear *int32 `json:"release_year"`
|
ReleaseYear *int32 `json:"release_year"`
|
||||||
ReleaseSeason *ReleaseSeasonT `json:"release_season"`
|
ReleaseSeason *ReleaseSeasonT `json:"release_season"`
|
||||||
Offset *int32 `json:"offset"`
|
Forward bool `json:"forward"`
|
||||||
|
SortBy string `json:"sort_by"`
|
||||||
Limit *int32 `json:"limit"`
|
Limit *int32 `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,7 +358,8 @@ func (q *Queries) SearchTitles(ctx context.Context, arg SearchTitlesParams) ([]T
|
||||||
arg.Rating,
|
arg.Rating,
|
||||||
arg.ReleaseYear,
|
arg.ReleaseYear,
|
||||||
arg.ReleaseSeason,
|
arg.ReleaseSeason,
|
||||||
arg.Offset,
|
arg.Forward,
|
||||||
|
arg.SortBy,
|
||||||
arg.Limit,
|
arg.Limit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -368,3 +393,122 @@ func (q *Queries) SearchTitles(ctx context.Context, arg SearchTitlesParams) ([]T
|
||||||
}
|
}
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const searchUserTitles = `-- name: SearchUserTitles :many
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
user_id, title_id, status, rate, review_id, ctime, id, title_names, studio_id, poster_id, title_status, rating, rating_count, release_year, release_season, season, episodes_aired, episodes_all, episodes_len
|
||||||
|
FROM usertitles as u
|
||||||
|
JOIN titles as t ON (u.title_id = t.id)
|
||||||
|
WHERE
|
||||||
|
CASE
|
||||||
|
WHEN $1::text IS NOT NULL THEN
|
||||||
|
(
|
||||||
|
SELECT bool_and(
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM jsonb_each_text(t.title_names) AS t(key, val)
|
||||||
|
WHERE val ILIKE pattern
|
||||||
|
)
|
||||||
|
)
|
||||||
|
FROM unnest(
|
||||||
|
ARRAY(
|
||||||
|
SELECT '%' || trim(w) || '%'
|
||||||
|
FROM unnest(string_to_array($1::text, ' ')) AS w
|
||||||
|
WHERE trim(w) <> ''
|
||||||
|
)
|
||||||
|
) AS pattern
|
||||||
|
)
|
||||||
|
ELSE true
|
||||||
|
END
|
||||||
|
|
||||||
|
AND ($2::title_status_t IS NULL OR t.title_status = $2::title_status_t)
|
||||||
|
AND ($3::float IS NULL OR t.rating >= $3::float)
|
||||||
|
AND ($4::int IS NULL OR t.release_year = $4::int)
|
||||||
|
AND ($5::release_season_t IS NULL OR t.release_season = $5::release_season_t)
|
||||||
|
AND ($6::usertitle_status_t IS NULL OR u.usertitle_status = $6::usertitle_status_t)
|
||||||
|
|
||||||
|
LIMIT COALESCE($7::int, 100)
|
||||||
|
`
|
||||||
|
|
||||||
|
type SearchUserTitlesParams struct {
|
||||||
|
Word *string `json:"word"`
|
||||||
|
Status *TitleStatusT `json:"status"`
|
||||||
|
Rating *float64 `json:"rating"`
|
||||||
|
ReleaseYear *int32 `json:"release_year"`
|
||||||
|
ReleaseSeason *ReleaseSeasonT `json:"release_season"`
|
||||||
|
UsertitleStatus NullUsertitleStatusT `json:"usertitle_status"`
|
||||||
|
Limit *int32 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchUserTitlesRow struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
TitleID int64 `json:"title_id"`
|
||||||
|
Status UsertitleStatusT `json:"status"`
|
||||||
|
Rate *int32 `json:"rate"`
|
||||||
|
ReviewID *int64 `json:"review_id"`
|
||||||
|
Ctime pgtype.Timestamptz `json:"ctime"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
TitleNames []byte `json:"title_names"`
|
||||||
|
StudioID int64 `json:"studio_id"`
|
||||||
|
PosterID *int64 `json:"poster_id"`
|
||||||
|
TitleStatus TitleStatusT `json:"title_status"`
|
||||||
|
Rating *float64 `json:"rating"`
|
||||||
|
RatingCount *int32 `json:"rating_count"`
|
||||||
|
ReleaseYear *int32 `json:"release_year"`
|
||||||
|
ReleaseSeason *ReleaseSeasonT `json:"release_season"`
|
||||||
|
Season *int32 `json:"season"`
|
||||||
|
EpisodesAired *int32 `json:"episodes_aired"`
|
||||||
|
EpisodesAll *int32 `json:"episodes_all"`
|
||||||
|
EpisodesLen []byte `json:"episodes_len"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 100 is default limit
|
||||||
|
// OFFSET sqlc.narg('offset')::int;
|
||||||
|
func (q *Queries) SearchUserTitles(ctx context.Context, arg SearchUserTitlesParams) ([]SearchUserTitlesRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, searchUserTitles,
|
||||||
|
arg.Word,
|
||||||
|
arg.Status,
|
||||||
|
arg.Rating,
|
||||||
|
arg.ReleaseYear,
|
||||||
|
arg.ReleaseSeason,
|
||||||
|
arg.UsertitleStatus,
|
||||||
|
arg.Limit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []SearchUserTitlesRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i SearchUserTitlesRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.UserID,
|
||||||
|
&i.TitleID,
|
||||||
|
&i.Status,
|
||||||
|
&i.Rate,
|
||||||
|
&i.ReviewID,
|
||||||
|
&i.Ctime,
|
||||||
|
&i.ID,
|
||||||
|
&i.TitleNames,
|
||||||
|
&i.StudioID,
|
||||||
|
&i.PosterID,
|
||||||
|
&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
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue