diff --git a/api/_build/oapi-codegen.yaml b/api/_build/oapi-codegen.yaml deleted file mode 100644 index 32e029a..0000000 --- a/api/_build/oapi-codegen.yaml +++ /dev/null @@ -1,6 +0,0 @@ -package: oapi -generate: - strict-server: true - gin-server: true - models: true -output: api/api.gen.go \ No newline at end of file diff --git a/api/_build/openapi.yaml b/api/_build/openapi.yaml deleted file mode 100644 index 5ff77e0..0000000 --- a/api/_build/openapi.yaml +++ /dev/null @@ -1,436 +0,0 @@ -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 diff --git a/api/api.gen.go b/api/api.gen.go index f252a5a..74a2d52 100644 --- a/api/api.gen.go +++ b/api/api.gen.go @@ -24,14 +24,6 @@ const ( Winter ReleaseSeason = "winter" ) -// Defines values for TitleSort. -const ( - Id TitleSort = "id" - Rating TitleSort = "rating" - Views TitleSort = "views" - Year TitleSort = "year" -) - // Defines values for TitleStatus. const ( TitleStatusFinished TitleStatus = "finished" @@ -47,12 +39,6 @@ const ( 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. type Image struct { Id *int64 `json:"id,omitempty"` @@ -105,16 +91,13 @@ type Title struct { AdditionalProperties map[string]interface{} `json:"-"` } -// TitleSort Title sort order -type TitleSort string - // TitleStatus Title status type TitleStatus string // User defines model for User. type User struct { // AvatarId ID of the user avatar (references images table) - AvatarId *int64 `json:"avatar_id,omitempty"` + AvatarId *int64 `json:"avatar_id"` // CreationDate Timestamp when the user was created CreationDate *time.Time `json:"creation_date,omitempty"` @@ -156,9 +139,6 @@ type Cursor = string // GetTitlesParams defines parameters for GetTitles. type GetTitlesParams struct { - Cursor *Cursor `form:"cursor,omitempty" json:"cursor,omitempty"` - Sort *TitleSort `form:"sort,omitempty" json:"sort,omitempty"` - SortForward *bool `form:"sort_forward,omitempty" json:"sort_forward,omitempty"` Word *string `form:"word,omitempty" json:"word,omitempty"` Status *TitleStatus `form:"status,omitempty" json:"status,omitempty"` Rating *float64 `form:"rating,omitempty" json:"rating,omitempty"` @@ -181,15 +161,11 @@ type GetUsersUserIdParams struct { // GetUsersUserIdTitlesParams defines parameters for GetUsersUserIdTitles. type GetUsersUserIdTitlesParams struct { - Cursor *Cursor `form:"cursor,omitempty" json:"cursor,omitempty"` - Word *string `form:"word,omitempty" json:"word,omitempty"` - Status *TitleStatus `form:"status,omitempty" json:"status,omitempty"` - WatchStatus *UserTitleStatus `form:"watch_status,omitempty" json:"watch_status,omitempty"` - Rating *float64 `form:"rating,omitempty" json:"rating,omitempty"` - ReleaseYear *int32 `form:"release_year,omitempty" json:"release_year,omitempty"` - ReleaseSeason *ReleaseSeason `form:"release_season,omitempty" json:"release_season,omitempty"` - Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"` - Fields *string `form:"fields,omitempty" json:"fields,omitempty"` + Cursor *Cursor `form:"cursor,omitempty" json:"cursor,omitempty"` + Query *string `form:"query,omitempty" json:"query,omitempty"` + Limit *int `form:"limit,omitempty" json:"limit,omitempty"` + Offset *int `form:"offset,omitempty" json:"offset,omitempty"` + Fields *string `form:"fields,omitempty" json:"fields,omitempty"` } // Getter for additional properties for Title. Returns the specified @@ -604,30 +580,6 @@ func (siw *ServerInterfaceWrapper) GetTitles(c *gin.Context) { // Parameter object where we will unmarshal all parameters from the context var params GetTitlesParams - // ------------- Optional query parameter "cursor" ------------- - - err = runtime.BindQueryParameter("form", true, false, "cursor", c.Request.URL.Query(), ¶ms.Cursor) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter cursor: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "sort" ------------- - - err = runtime.BindQueryParameter("form", true, false, "sort", c.Request.URL.Query(), ¶ms.Sort) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter sort: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "sort_forward" ------------- - - err = runtime.BindQueryParameter("form", true, false, "sort_forward", c.Request.URL.Query(), ¶ms.SortForward) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter sort_forward: %w", err), http.StatusBadRequest) - return - } - // ------------- Optional query parameter "word" ------------- err = runtime.BindQueryParameter("form", true, false, "word", c.Request.URL.Query(), ¶ms.Word) @@ -797,51 +749,11 @@ func (siw *ServerInterfaceWrapper) GetUsersUserIdTitles(c *gin.Context) { return } - // ------------- Optional query parameter "word" ------------- + // ------------- Optional query parameter "query" ------------- - err = runtime.BindQueryParameter("form", true, false, "word", c.Request.URL.Query(), ¶ms.Word) + err = runtime.BindQueryParameter("form", true, false, "query", c.Request.URL.Query(), ¶ms.Query) if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter word: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "status" ------------- - - err = runtime.BindQueryParameter("form", true, false, "status", c.Request.URL.Query(), ¶ms.Status) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter status: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "watch_status" ------------- - - err = runtime.BindQueryParameter("form", true, false, "watch_status", c.Request.URL.Query(), ¶ms.WatchStatus) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter watch_status: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "rating" ------------- - - err = runtime.BindQueryParameter("form", true, false, "rating", c.Request.URL.Query(), ¶ms.Rating) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter rating: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "release_year" ------------- - - err = runtime.BindQueryParameter("form", true, false, "release_year", c.Request.URL.Query(), ¶ms.ReleaseYear) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter release_year: %w", err), http.StatusBadRequest) - return - } - - // ------------- Optional query parameter "release_season" ------------- - - err = runtime.BindQueryParameter("form", true, false, "release_season", c.Request.URL.Query(), ¶ms.ReleaseSeason) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter release_season: %w", err), http.StatusBadRequest) + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter query: %w", err), http.StatusBadRequest) return } @@ -853,6 +765,14 @@ func (siw *ServerInterfaceWrapper) GetUsersUserIdTitles(c *gin.Context) { return } + // ------------- Optional query parameter "offset" ------------- + + err = runtime.BindQueryParameter("form", true, false, "offset", c.Request.URL.Query(), ¶ms.Offset) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter offset: %w", err), http.StatusBadRequest) + return + } + // ------------- Optional query parameter "fields" ------------- err = runtime.BindQueryParameter("form", true, false, "fields", c.Request.URL.Query(), ¶ms.Fields) @@ -912,12 +832,7 @@ type GetTitlesResponseObject interface { VisitGetTitlesResponse(w http.ResponseWriter) error } -type GetTitles200JSONResponse struct { - Cursor CursorObj `json:"cursor"` - - // Data List of titles - Data []Title `json:"data"` -} +type GetTitles200JSONResponse []Title func (response GetTitles200JSONResponse) VisitGetTitlesResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") diff --git a/api/openapi.yaml b/api/openapi.yaml index 281fe82..a33fe89 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.4 +openapi: 3.1.1 info: title: Titles, Users, Reviews, Tags, and Media API version: 1.0.0 @@ -8,15 +8,788 @@ servers: paths: /titles: - $ref: "./paths/titles.yaml" + get: + summary: Get titles + parameters: + - 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}: - $ref: "./paths/titles-id.yaml" + 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' + '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}: - $ref: "./paths/users-id.yaml" + 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' + '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/: - $ref: "./paths/users-id-titles.yaml" + get: + summary: Get user titles + parameters: + - $ref: '#/components/parameters/cursor' + - in: path + name: user_id + required: true + schema: + type: string + - in: query + name: query + schema: + type: string + - 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 + 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: parameters: - $ref: "./parameters/_index.yaml" + cursor: + in: query + name: cursor + required: false + schema: + type: string + schemas: - $ref: "./schemas/_index.yaml" + 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 diff --git a/api/parameters/_index.yaml b/api/parameters/_index.yaml deleted file mode 100644 index 6249e7d..0000000 --- a/api/parameters/_index.yaml +++ /dev/null @@ -1,4 +0,0 @@ -cursor: - $ref: "./cursor.yaml" -title_sort: - $ref: "./title_sort.yaml" \ No newline at end of file diff --git a/api/parameters/cursor.yaml b/api/parameters/cursor.yaml deleted file mode 100644 index 1730f18..0000000 --- a/api/parameters/cursor.yaml +++ /dev/null @@ -1,5 +0,0 @@ -in: query -name: cursor -required: false -schema: - type: string diff --git a/api/parameters/title_sort.yaml b/api/parameters/title_sort.yaml deleted file mode 100644 index 615294b..0000000 --- a/api/parameters/title_sort.yaml +++ /dev/null @@ -1,5 +0,0 @@ -in: query -name: sort -required: false -schema: - $ref: '../schemas/TitleSort.yaml' diff --git a/api/paths/titles-id.yaml b/api/paths/titles-id.yaml deleted file mode 100644 index 01fa504..0000000 --- a/api/paths/titles-id.yaml +++ /dev/null @@ -1,29 +0,0 @@ -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 diff --git a/api/paths/titles.yaml b/api/paths/titles.yaml deleted file mode 100644 index e868ed6..0000000 --- a/api/paths/titles.yaml +++ /dev/null @@ -1,73 +0,0 @@ -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 diff --git a/api/paths/users-id-titles.yaml b/api/paths/users-id-titles.yaml deleted file mode 100644 index 0cde5af..0000000 --- a/api/paths/users-id-titles.yaml +++ /dev/null @@ -1,61 +0,0 @@ -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 diff --git a/api/paths/users-id.yaml b/api/paths/users-id.yaml deleted file mode 100644 index 0acdb81..0000000 --- a/api/paths/users-id.yaml +++ /dev/null @@ -1,26 +0,0 @@ -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 diff --git a/api/schemas/CursorObj.yaml b/api/schemas/CursorObj.yaml deleted file mode 100644 index 5a3c96c..0000000 --- a/api/schemas/CursorObj.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: object -required: - - id -properties: - id: - type: integer - format: int64 - param: - type: string diff --git a/api/schemas/Image.yaml b/api/schemas/Image.yaml deleted file mode 100644 index 7226b29..0000000 --- a/api/schemas/Image.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: object -properties: - id: - type: integer - format: int64 - storage_type: - type: string - image_path: - type: string diff --git a/api/schemas/Review.yaml b/api/schemas/Review.yaml deleted file mode 100644 index a116dde..0000000 --- a/api/schemas/Review.yaml +++ /dev/null @@ -1,2 +0,0 @@ -type: object -additionalProperties: true diff --git a/api/schemas/Studio.yaml b/api/schemas/Studio.yaml deleted file mode 100644 index 35b40a8..0000000 --- a/api/schemas/Studio.yaml +++ /dev/null @@ -1,14 +0,0 @@ -type: object -required: - - id - - name -properties: - id: - type: integer - format: int64 - name: - type: string - poster: - $ref: ./Image.yaml - description: - type: string diff --git a/api/schemas/Tag.yaml b/api/schemas/Tag.yaml deleted file mode 100644 index 7239b10..0000000 --- a/api/schemas/Tag.yaml +++ /dev/null @@ -1,8 +0,0 @@ -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: 少女 diff --git a/api/schemas/Tags.yaml b/api/schemas/Tags.yaml deleted file mode 100644 index ca8c4fd..0000000 --- a/api/schemas/Tags.yaml +++ /dev/null @@ -1,11 +0,0 @@ -type: array -description: Array of localized tags -items: - $ref: ./Tag.yaml -example: -- en: Shojo - ru: Сёдзё - ja: 少女 -- en: Shounen - ru: Сёнен - ja: 少年 diff --git a/api/schemas/Title.yaml b/api/schemas/Title.yaml deleted file mode 100644 index 7497d1f..0000000 --- a/api/schemas/Title.yaml +++ /dev/null @@ -1,63 +0,0 @@ -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 diff --git a/api/schemas/TitleSort.yaml b/api/schemas/TitleSort.yaml deleted file mode 100644 index d8ce8f7..0000000 --- a/api/schemas/TitleSort.yaml +++ /dev/null @@ -1,8 +0,0 @@ -type: string -description: Title sort order -default: id -enum: - - id - - year - - rating - - views diff --git a/api/schemas/User.yaml b/api/schemas/User.yaml deleted file mode 100644 index 8b4d88d..0000000 --- a/api/schemas/User.yaml +++ /dev/null @@ -1,40 +0,0 @@ -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 diff --git a/api/schemas/UserTitle.yaml b/api/schemas/UserTitle.yaml deleted file mode 100644 index 658e350..0000000 --- a/api/schemas/UserTitle.yaml +++ /dev/null @@ -1,24 +0,0 @@ -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 diff --git a/api/schemas/_index.yaml b/api/schemas/_index.yaml deleted file mode 100644 index ac49f37..0000000 --- a/api/schemas/_index.yaml +++ /dev/null @@ -1,26 +0,0 @@ -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" diff --git a/api/schemas/enums/ReleaseSeason.yaml b/api/schemas/enums/ReleaseSeason.yaml deleted file mode 100644 index 5cf988d..0000000 --- a/api/schemas/enums/ReleaseSeason.yaml +++ /dev/null @@ -1,7 +0,0 @@ -type: string -description: Title release season -enum: - - winter - - spring - - summer - - fall diff --git a/api/schemas/enums/TitleStatus.yaml b/api/schemas/enums/TitleStatus.yaml deleted file mode 100644 index 0bfce7d..0000000 --- a/api/schemas/enums/TitleStatus.yaml +++ /dev/null @@ -1,6 +0,0 @@ -type: string -description: Title status -enum: - - finished - - ongoing - - planned diff --git a/api/schemas/enums/UserTitleStatus.yaml b/api/schemas/enums/UserTitleStatus.yaml deleted file mode 100644 index 0b1a90d..0000000 --- a/api/schemas/enums/UserTitleStatus.yaml +++ /dev/null @@ -1,7 +0,0 @@ -type: string -description: User's title status -enum: - - finished - - planned - - dropped - - in-progress diff --git a/modules/backend/handlers/titles.go b/modules/backend/handlers/titles.go index e8a3bff..46ff982 100644 --- a/modules/backend/handlers/titles.go +++ b/modules/backend/handlers/titles.go @@ -218,9 +218,6 @@ func (s Server) GetTitlesTitleId(ctx context.Context, request oapi.GetTitlesTitl func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObject) (oapi.GetTitlesResponseObject, error) { opai_titles := make([]oapi.Title, 0) - cursor := oapi.CursorObj{ - Id: 1, - } word := Word2Sqlc(request.Params.Word) status, err := TitleStatus2Sqlc(request.Params.Status) @@ -240,6 +237,7 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje Rating: request.Params.Rating, ReleaseYear: request.Params.ReleaseYear, ReleaseSeason: season, + Offset: request.Params.Offset, Limit: request.Params.Limit, }) if err != nil { @@ -260,5 +258,5 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje opai_titles = append(opai_titles, t) } - return oapi.GetTitles200JSONResponse{Cursor: cursor, Data: opai_titles}, nil + return oapi.GetTitles200JSONResponse(opai_titles), nil } diff --git a/modules/backend/queries.sql b/modules/backend/queries.sql index 8962895..423be37 100644 --- a/modules/backend/queries.sql +++ b/modules/backend/queries.sql @@ -107,67 +107,9 @@ WHERE 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_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 = 'name' THEN name - 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 = 'name' THEN name - 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, - -- Вторичный ключ: id — только если НЕ сортируем по id - 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 +LIMIT COALESCE(sqlc.narg('limit')::int, 100) -- 100 is default limit +OFFSET sqlc.narg('offset')::int; -- -- name: ListTitles :many -- SELECT title_id, title_names, studio_id, poster_id, signal_ids, diff --git a/sql/migrations/000001_init.up.sql b/sql/migrations/000001_init.up.sql index e6ed628..49cca3d 100644 --- a/sql/migrations/000001_init.up.sql +++ b/sql/migrations/000001_init.up.sql @@ -59,7 +59,7 @@ CREATE TABLE studios ( ); CREATE TABLE titles ( - -- // TODO: anime type (film, season etc) + // TODO: anime type (film, season etc) id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- example {"ru": ["Атака титанов", "Атака Титанов"],"en": ["Attack on Titan", "AoT"],"ja": ["進撃の巨人", "しんげきのきょじん"]} title_names jsonb NOT NULL, diff --git a/sql/models.go b/sql/models.go index 93cecca..a593504 100644 --- a/sql/models.go +++ b/sql/models.go @@ -212,6 +212,7 @@ type Review struct { ID int64 `json:"id"` Data string `json:"data"` Rating *int32 `json:"rating"` + IllustID *int64 `json:"illust_id"` UserID *int64 `json:"user_id"` TitleID *int64 `json:"title_id"` CreatedAt pgtype.Timestamptz `json:"created_at"` @@ -276,10 +277,10 @@ type User struct { } type Usertitle 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"` + UserID int64 `json:"user_id"` + TitleID int64 `json:"title_id"` + Status UsertitleStatusT `json:"status"` + Rate *int32 `json:"rate"` + ReviewText *string `json:"review_text"` + ReviewDate pgtype.Timestamptz `json:"review_date"` } diff --git a/sql/queries.sql.go b/sql/queries.sql.go index 4e28f40..c5e6f8a 100644 --- a/sql/queries.sql.go +++ b/sql/queries.sql.go @@ -8,8 +8,6 @@ package sqlc import ( "context" "time" - - "github.com/jackc/pgx/v5/pgtype" ) const createImage = `-- name: CreateImage :one @@ -33,7 +31,7 @@ func (q *Queries) CreateImage(ctx context.Context, arg CreateImageParams) (Image const getImageByID = `-- name: GetImageByID :one SELECT id, storage_type, image_path FROM images -WHERE id = $1::bigint +WHERE id = $1 ` func (q *Queries) GetImageByID(ctx context.Context, illustID int64) (Image, error) { @@ -46,13 +44,11 @@ func (q *Queries) GetImageByID(ctx context.Context, illustID int64) (Image, erro const getReviewByID = `-- name: GetReviewByID :one - -SELECT id, data, rating, user_id, title_id, created_at +SELECT id, data, rating, illust_id, user_id, title_id, created_at FROM reviews WHERE review_id = $1::bigint ` -// 100 is default limit // -- name: ListTitles :many // SELECT title_id, title_names, studio_id, poster_id, signal_ids, // @@ -86,6 +82,7 @@ func (q *Queries) GetReviewByID(ctx context.Context, reviewID int64) (Review, er &i.ID, &i.Data, &i.Rating, + &i.IllustID, &i.UserID, &i.TitleID, &i.CreatedAt, @@ -315,18 +312,9 @@ WHERE AND ($3::float IS NULL OR rating >= $3::float) AND ($4::int IS NULL OR release_year = $4::int) AND ($5::release_season_t IS NULL OR release_season = $5::release_season_t) -ORDER BY CASE - WHEN $6::boolean AND $7::text = 'name' THEN name - WHEN $8::boolean AND $7::text = 'id' THEN id - WHEN $8::boolean AND $7::text = 'name' THEN name - WHEN $8::boolean AND $7::text = 'id' THEN id -END ASC, CASE - WHEN NOT $8::boolean AND $7::text = 'name' THEN name - WHEN NOT $8::boolean AND $7::text = 'id' THEN id - WHEN NOT $8::boolean AND $7::text = 'name' THEN name - WHEN NOT $8::boolean AND $7::text = 'id' THEN id -END DESC -LIMIT COALESCE($9::int, 100) + +LIMIT COALESCE($7::int, 100) -- 100 is default limit +OFFSET $6::int ` type SearchTitlesParams struct { @@ -335,9 +323,7 @@ type SearchTitlesParams struct { Rating *float64 `json:"rating"` ReleaseYear *int32 `json:"release_year"` ReleaseSeason *ReleaseSeasonT `json:"release_season"` - Forward bool `json:"forward"` - OrderBy string `json:"order_by"` - Reverse bool `json:"reverse"` + Offset *int32 `json:"offset"` Limit *int32 `json:"limit"` } @@ -348,9 +334,7 @@ func (q *Queries) SearchTitles(ctx context.Context, arg SearchTitlesParams) ([]T arg.Rating, arg.ReleaseYear, arg.ReleaseSeason, - arg.Forward, - arg.OrderBy, - arg.Reverse, + arg.Offset, arg.Limit, ) if err != nil { @@ -384,122 +368,3 @@ func (q *Queries) SearchTitles(ctx context.Context, arg SearchTitlesParams) ([]T } 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 -}