diff --git a/api/api.gen.go b/api/api.gen.go index a235db8..24aebd3 100644 --- a/api/api.gen.go +++ b/api/api.gen.go @@ -16,59 +16,13 @@ import ( openapi_types "github.com/oapi-codegen/runtime/types" ) -// Defines values for ReleaseSeason. -const ( - Fall ReleaseSeason = "fall" - Spring ReleaseSeason = "spring" - Summer ReleaseSeason = "summer" - Winter ReleaseSeason = "winter" -) - -// Defines values for TitleStatus. -const ( - Finished TitleStatus = "finished" - Ongoing TitleStatus = "ongoing" - Planned TitleStatus = "planned" -) - -// ReleaseSeason Title release season -type ReleaseSeason string - -// Title defines model for Title. -type Title struct { - EpisodesAired *int32 `json:"episodes_aired,omitempty"` - EpisodesAll *int32 `json:"episodes_all,omitempty"` - EpisodesLen *map[string]float64 `json:"episodes_len,omitempty"` - - // Id Unique title ID (primary key) - Id *int64 `json:"id,omitempty"` - PosterId *int64 `json:"poster_id,omitempty"` - Rating *float64 `json:"rating,omitempty"` - RatingCount *int32 `json:"rating_count,omitempty"` - - // ReleaseSeason Title release season - ReleaseSeason *ReleaseSeason `json:"release_season,omitempty"` - ReleaseYear *int32 `json:"release_year,omitempty"` - StudioId *int64 `json:"studio_id,omitempty"` - - // TitleNames Localized titles. Key = language (ISO 639-1), value = list of names - TitleNames *map[string][]string `json:"title_names,omitempty"` - - // TitleStatus Title status - TitleStatus *TitleStatus `json:"title_status,omitempty"` - AdditionalProperties map[string]interface{} `json:"-"` -} - -// 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"` // CreationDate Timestamp when the user was created - CreationDate *time.Time `json:"creation_date,omitempty"` + CreationDate time.Time `json:"creation_date"` // DispName Display name DispName *string `json:"disp_name,omitempty"` @@ -86,267 +40,13 @@ type User struct { UserDesc *string `json:"user_desc,omitempty"` } -// GetTitleParams defines parameters for GetTitle. -type GetTitleParams struct { - Word *string `form:"word,omitempty" json:"word,omitempty"` - Status *TitleStatus `form:"status,omitempty" json:"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 *int `form:"limit,omitempty" json:"limit,omitempty"` - Offset *int `form:"offset,omitempty" json:"offset,omitempty"` - Fields *string `form:"fields,omitempty" json:"fields,omitempty"` -} - // GetUsersUserIdParams defines parameters for GetUsersUserId. type GetUsersUserIdParams struct { Fields *string `form:"fields,omitempty" json:"fields,omitempty"` } -// PostUsersJSONRequestBody defines body for PostUsers for application/json ContentType. -type PostUsersJSONRequestBody = User - -// Getter for additional properties for Title. Returns the specified -// element and whether it was found -func (a Title) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for Title -func (a *Title) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for Title to handle AdditionalProperties -func (a *Title) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["episodes_aired"]; found { - err = json.Unmarshal(raw, &a.EpisodesAired) - if err != nil { - return fmt.Errorf("error reading 'episodes_aired': %w", err) - } - delete(object, "episodes_aired") - } - - if raw, found := object["episodes_all"]; found { - err = json.Unmarshal(raw, &a.EpisodesAll) - if err != nil { - return fmt.Errorf("error reading 'episodes_all': %w", err) - } - delete(object, "episodes_all") - } - - if raw, found := object["episodes_len"]; found { - err = json.Unmarshal(raw, &a.EpisodesLen) - if err != nil { - return fmt.Errorf("error reading 'episodes_len': %w", err) - } - delete(object, "episodes_len") - } - - if raw, found := object["id"]; found { - err = json.Unmarshal(raw, &a.Id) - if err != nil { - return fmt.Errorf("error reading 'id': %w", err) - } - delete(object, "id") - } - - if raw, found := object["poster_id"]; found { - err = json.Unmarshal(raw, &a.PosterId) - if err != nil { - return fmt.Errorf("error reading 'poster_id': %w", err) - } - delete(object, "poster_id") - } - - if raw, found := object["rating"]; found { - err = json.Unmarshal(raw, &a.Rating) - if err != nil { - return fmt.Errorf("error reading 'rating': %w", err) - } - delete(object, "rating") - } - - if raw, found := object["rating_count"]; found { - err = json.Unmarshal(raw, &a.RatingCount) - if err != nil { - return fmt.Errorf("error reading 'rating_count': %w", err) - } - delete(object, "rating_count") - } - - if raw, found := object["release_season"]; found { - err = json.Unmarshal(raw, &a.ReleaseSeason) - if err != nil { - return fmt.Errorf("error reading 'release_season': %w", err) - } - delete(object, "release_season") - } - - if raw, found := object["release_year"]; found { - err = json.Unmarshal(raw, &a.ReleaseYear) - if err != nil { - return fmt.Errorf("error reading 'release_year': %w", err) - } - delete(object, "release_year") - } - - if raw, found := object["studio_id"]; found { - err = json.Unmarshal(raw, &a.StudioId) - if err != nil { - return fmt.Errorf("error reading 'studio_id': %w", err) - } - delete(object, "studio_id") - } - - if raw, found := object["title_names"]; found { - err = json.Unmarshal(raw, &a.TitleNames) - if err != nil { - return fmt.Errorf("error reading 'title_names': %w", err) - } - delete(object, "title_names") - } - - if raw, found := object["title_status"]; found { - err = json.Unmarshal(raw, &a.TitleStatus) - if err != nil { - return fmt.Errorf("error reading 'title_status': %w", err) - } - delete(object, "title_status") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]interface{}) - for fieldName, fieldBuf := range object { - var fieldVal interface{} - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for Title to handle AdditionalProperties -func (a Title) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.EpisodesAired != nil { - object["episodes_aired"], err = json.Marshal(a.EpisodesAired) - if err != nil { - return nil, fmt.Errorf("error marshaling 'episodes_aired': %w", err) - } - } - - if a.EpisodesAll != nil { - object["episodes_all"], err = json.Marshal(a.EpisodesAll) - if err != nil { - return nil, fmt.Errorf("error marshaling 'episodes_all': %w", err) - } - } - - if a.EpisodesLen != nil { - object["episodes_len"], err = json.Marshal(a.EpisodesLen) - if err != nil { - return nil, fmt.Errorf("error marshaling 'episodes_len': %w", err) - } - } - - if a.Id != nil { - object["id"], err = json.Marshal(a.Id) - if err != nil { - return nil, fmt.Errorf("error marshaling 'id': %w", err) - } - } - - if a.PosterId != nil { - object["poster_id"], err = json.Marshal(a.PosterId) - if err != nil { - return nil, fmt.Errorf("error marshaling 'poster_id': %w", err) - } - } - - if a.Rating != nil { - object["rating"], err = json.Marshal(a.Rating) - if err != nil { - return nil, fmt.Errorf("error marshaling 'rating': %w", err) - } - } - - if a.RatingCount != nil { - object["rating_count"], err = json.Marshal(a.RatingCount) - if err != nil { - return nil, fmt.Errorf("error marshaling 'rating_count': %w", err) - } - } - - if a.ReleaseSeason != nil { - object["release_season"], err = json.Marshal(a.ReleaseSeason) - if err != nil { - return nil, fmt.Errorf("error marshaling 'release_season': %w", err) - } - } - - if a.ReleaseYear != nil { - object["release_year"], err = json.Marshal(a.ReleaseYear) - if err != nil { - return nil, fmt.Errorf("error marshaling 'release_year': %w", err) - } - } - - if a.StudioId != nil { - object["studio_id"], err = json.Marshal(a.StudioId) - if err != nil { - return nil, fmt.Errorf("error marshaling 'studio_id': %w", err) - } - } - - if a.TitleNames != nil { - object["title_names"], err = json.Marshal(a.TitleNames) - if err != nil { - return nil, fmt.Errorf("error marshaling 'title_names': %w", err) - } - } - - if a.TitleStatus != nil { - object["title_status"], err = json.Marshal(a.TitleStatus) - if err != nil { - return nil, fmt.Errorf("error marshaling 'title_status': %w", err) - } - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) - } - } - return json.Marshal(object) -} - // ServerInterface represents all server handlers. type ServerInterface interface { - // Get titles - // (GET /title) - GetTitle(c *gin.Context, params GetTitleParams) - // Add new user - // (POST /users) - PostUsers(c *gin.Context) // Get user info // (GET /users/{user_id}) GetUsersUserId(c *gin.Context, userId string, params GetUsersUserIdParams) @@ -361,101 +61,6 @@ type ServerInterfaceWrapper struct { type MiddlewareFunc func(c *gin.Context) -// GetTitle operation middleware -func (siw *ServerInterfaceWrapper) GetTitle(c *gin.Context) { - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetTitleParams - - // ------------- Optional query parameter "word" ------------- - - err = runtime.BindQueryParameter("form", true, false, "word", c.Request.URL.Query(), ¶ms.Word) - 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 "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) - return - } - - // ------------- Optional query parameter "limit" ------------- - - err = runtime.BindQueryParameter("form", true, false, "limit", c.Request.URL.Query(), ¶ms.Limit) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter limit: %w", err), http.StatusBadRequest) - 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) - if err != nil { - siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter fields: %w", err), http.StatusBadRequest) - return - } - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.GetTitle(c, params) -} - -// PostUsers operation middleware -func (siw *ServerInterfaceWrapper) PostUsers(c *gin.Context) { - - for _, middleware := range siw.HandlerMiddlewares { - middleware(c) - if c.IsAborted() { - return - } - } - - siw.Handler.PostUsers(c) -} - // GetUsersUserId operation middleware func (siw *ServerInterfaceWrapper) GetUsersUserId(c *gin.Context) { @@ -518,73 +123,9 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options ErrorHandler: errorHandler, } - router.GET(options.BaseURL+"/title", wrapper.GetTitle) - router.POST(options.BaseURL+"/users", wrapper.PostUsers) router.GET(options.BaseURL+"/users/:user_id", wrapper.GetUsersUserId) } -type GetTitleRequestObject struct { - Params GetTitleParams -} - -type GetTitleResponseObject interface { - VisitGetTitleResponse(w http.ResponseWriter) error -} - -type GetTitle200JSONResponse []Title - -func (response GetTitle200JSONResponse) VisitGetTitleResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -type GetTitle204Response struct { -} - -func (response GetTitle204Response) VisitGetTitleResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} - -type GetTitle400Response struct { -} - -func (response GetTitle400Response) VisitGetTitleResponse(w http.ResponseWriter) error { - w.WriteHeader(400) - return nil -} - -type GetTitle500Response struct { -} - -func (response GetTitle500Response) VisitGetTitleResponse(w http.ResponseWriter) error { - w.WriteHeader(500) - return nil -} - -type PostUsersRequestObject struct { - Body *PostUsersJSONRequestBody -} - -type PostUsersResponseObject interface { - VisitPostUsersResponse(w http.ResponseWriter) error -} - -type PostUsers200JSONResponse struct { - Error *string `json:"error,omitempty"` - Success *bool `json:"success,omitempty"` - UserJson *User `json:"user_json,omitempty"` -} - -func (response PostUsers200JSONResponse) VisitPostUsersResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - type GetUsersUserIdRequestObject struct { UserId string `json:"user_id"` Params GetUsersUserIdParams @@ -603,14 +144,6 @@ func (response GetUsersUserId200JSONResponse) VisitGetUsersUserIdResponse(w http return json.NewEncoder(w).Encode(response) } -type GetUsersUserId400Response struct { -} - -func (response GetUsersUserId400Response) VisitGetUsersUserIdResponse(w http.ResponseWriter) error { - w.WriteHeader(400) - return nil -} - type GetUsersUserId404Response struct { } @@ -619,22 +152,8 @@ func (response GetUsersUserId404Response) VisitGetUsersUserIdResponse(w http.Res return nil } -type GetUsersUserId500Response struct { -} - -func (response GetUsersUserId500Response) VisitGetUsersUserIdResponse(w http.ResponseWriter) error { - w.WriteHeader(500) - return nil -} - // StrictServerInterface represents all server handlers. type StrictServerInterface interface { - // Get titles - // (GET /title) - GetTitle(ctx context.Context, request GetTitleRequestObject) (GetTitleResponseObject, error) - // Add new user - // (POST /users) - PostUsers(ctx context.Context, request PostUsersRequestObject) (PostUsersResponseObject, error) // Get user info // (GET /users/{user_id}) GetUsersUserId(ctx context.Context, request GetUsersUserIdRequestObject) (GetUsersUserIdResponseObject, error) @@ -652,66 +171,6 @@ type strictHandler struct { middlewares []StrictMiddlewareFunc } -// GetTitle operation middleware -func (sh *strictHandler) GetTitle(ctx *gin.Context, params GetTitleParams) { - var request GetTitleRequestObject - - request.Params = params - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.GetTitle(ctx, request.(GetTitleRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetTitle") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(GetTitleResponseObject); ok { - if err := validResponse.VisitGetTitleResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} - -// PostUsers operation middleware -func (sh *strictHandler) PostUsers(ctx *gin.Context) { - var request PostUsersRequestObject - - var body PostUsersJSONRequestBody - if err := ctx.ShouldBindJSON(&body); err != nil { - ctx.Status(http.StatusBadRequest) - ctx.Error(err) - return - } - request.Body = &body - - handler := func(ctx *gin.Context, request interface{}) (interface{}, error) { - return sh.ssi.PostUsers(ctx, request.(PostUsersRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "PostUsers") - } - - response, err := handler(ctx, request) - - if err != nil { - ctx.Error(err) - ctx.Status(http.StatusInternalServerError) - } else if validResponse, ok := response.(PostUsersResponseObject); ok { - if err := validResponse.VisitPostUsersResponse(ctx.Writer); err != nil { - ctx.Error(err) - } - } else if response != nil { - ctx.Error(fmt.Errorf("unexpected response type: %T", response)) - } -} - // GetUsersUserId operation middleware func (sh *strictHandler) GetUsersUserId(ctx *gin.Context, userId string, params GetUsersUserIdParams) { var request GetUsersUserIdRequestObject diff --git a/api/openapi.yaml b/api/openapi.yaml index 4187ebb..6439c86 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -5,62 +5,41 @@ info: servers: - url: /api/v1 paths: - /title: - 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 - 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 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 + # /title: + # get: + # summary: Get titles + # parameters: + # - 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 titles + # content: + # application/json: + # schema: + # type: array + # items: + # $ref: '#/components/schemas/Title' + # '204': + # description: No titles found + # /title/{title_id}: # get: # summary: Get title description @@ -168,10 +147,6 @@ paths: $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 @@ -560,81 +535,8 @@ paths: components: schemas: - 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 Title: type: object - 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_id: - type: integer - format: int64 - poster_id: - type: integer - format: int64 - 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 diff --git a/go.mod b/go.mod index 7c34aeb..b7a66f2 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/quic-go/qpack v0.5.1 // 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/ugorji/go/codec v1.3.0 // indirect go.uber.org/mock v0.5.0 // indirect diff --git a/go.sum b/go.sum index 121ca40..1af1a7c 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,6 @@ github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -97,7 +95,6 @@ golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/modules/backend/handlers/titles.go b/modules/backend/handlers/titles.go deleted file mode 100644 index 85f9f45..0000000 --- a/modules/backend/handlers/titles.go +++ /dev/null @@ -1,135 +0,0 @@ -package handlers - -import ( - "context" - "encoding/json" - "fmt" - oapi "nyanimedb/api" - sqlc "nyanimedb/sql" - - log "github.com/sirupsen/logrus" -) - -func Word2Sqlc(s *string) *string { - if s == nil { - return nil - } - if *s == "" { - return nil - } - return s -} - -func TitleStatus2Sqlc(s *oapi.TitleStatus) (*sqlc.TitleStatusT, error) { - if s == nil { - return nil, nil - } - var t sqlc.TitleStatusT - if *s == "finished" { - t = "finished" - } else if *s == "ongoing" { - t = "ongoing" - } else if *s == "planned" { - t = "planned" - } else { - return nil, fmt.Errorf("unexpected tittle status: %s", *s) - } - return &t, nil -} - -func ReleaseSeason2sqlc(s *oapi.ReleaseSeason) (*sqlc.ReleaseSeasonT, error) { - if s == nil { - return nil, nil - } - //TODO - var t sqlc.ReleaseSeasonT - if *s == oapi.Winter { - t = sqlc.ReleaseSeasonTWinter - } else if *s == "spring" { - t = "spring" - } else if *s == "summer" { - t = "summer" - } else if *s == "fall" { - t = "fall" - } else { - return nil, fmt.Errorf("unexpected release season: %s", *s) - } - return &t, nil -} - -// unmarshall jsonb to map[string][]string -func jsonb2map4names(b []byte) (*map[string][]string, error) { - var t map[string][]string - if err := json.Unmarshal(b, &t); err != nil { - return nil, fmt.Errorf("invalid title_names JSON for title: %w", err) - } - return &t, nil -} - -func jsonb2map4len(b []byte) (*map[string]float64, error) { - var t map[string]float64 - if err := json.Unmarshal(b, &t); err != nil { - return nil, fmt.Errorf("invalid episodes_len JSON for title: %w", err) - } - return &t, nil -} - -func (s Server) GetTitle(ctx context.Context, request oapi.GetTitleRequestObject) (oapi.GetTitleResponseObject, error) { - var result []oapi.Title - - word := Word2Sqlc(request.Params.Word) - status, err := TitleStatus2Sqlc(request.Params.Status) - if err != nil { - log.Errorf("%v", err) - return oapi.GetTitle400Response{}, err - } - season, err := ReleaseSeason2sqlc(request.Params.ReleaseSeason) - if err != nil { - log.Errorf("%v", err) - return oapi.GetTitle400Response{}, err - } - // param = nil means it will not be used - titles, err := s.db.SearchTitles(ctx, sqlc.SearchTitlesParams{ - Word: word, - Status: status, - Rating: request.Params.Rating, - ReleaseYear: request.Params.ReleaseYear, - ReleaseSeason: season, - }) - if err != nil { - return oapi.GetTitle500Response{}, nil - } - if len(titles) == 0 { - return oapi.GetTitle204Response{}, nil - } - - for _, title := range titles { - title_names, err := jsonb2map4names(title.TitleNames) - if err != nil { - log.Errorf("%v", err) - return oapi.GetTitle500Response{}, err - } - episodes_lens, err := jsonb2map4len(title.EpisodesLen) - if err != nil { - log.Errorf("%v", err) - return oapi.GetTitle500Response{}, err - } - t := oapi.Title{ - Id: &title.ID, - PosterId: title.PosterID, - Rating: title.Rating, - RatingCount: title.RatingCount, - ReleaseSeason: (*oapi.ReleaseSeason)(title.ReleaseSeason), - ReleaseYear: title.ReleaseYear, - StudioId: &title.StudioID, - TitleNames: title_names, - TitleStatus: (*oapi.TitleStatus)(&title.TitleStatus), - EpisodesAired: title.EpisodesAired, - EpisodesAll: title.EpisodesAll, - EpisodesLen: episodes_lens, - } - result = append(result, t) - } - - return oapi.GetTitle200JSONResponse(result), nil -} diff --git a/modules/backend/queries.sql b/modules/backend/queries.sql index b90ec6a..b1dd8af 100644 --- a/modules/backend/queries.sql +++ b/modules/backend/queries.sql @@ -38,39 +38,12 @@ WHERE id = $1; -- DELETE FROM users -- WHERE user_id = $1; --- name: SearchTitles :many -SELECT - * -FROM titles -WHERE - CASE - WHEN sqlc.narg('word')::text IS NOT NULL THEN - ( - SELECT bool_and( - EXISTS ( - SELECT 1 - FROM jsonb_each_text(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 title_status = sqlc.narg('status')::title_status_t) - 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) - -LIMIT COALESCE(sqlc.narg('limit')::int, 100) -- 100 is default limit -OFFSET sqlc.narg('offset')::int; +-- -- name: GetTitleByID :one +-- SELECT title_id, title_names, studio_id, poster_id, signal_ids, +-- title_status, rating, rating_count, release_year, release_season, +-- season, episodes_aired, episodes_all, episodes_len +-- FROM titles +-- WHERE title_id = $1; -- -- name: ListTitles :many -- SELECT title_id, title_names, studio_id, poster_id, signal_ids, diff --git a/sql/migrations/000001_init.up.sql b/sql/migrations/000001_init.up.sql index c325dc8..abecd32 100644 --- a/sql/migrations/000001_init.up.sql +++ b/sql/migrations/000001_init.up.sql @@ -44,7 +44,6 @@ CREATE TABLE studios ( CREATE TABLE titles ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - -- example {"ru": ["Атака титанов", "Атака Титанов"],"en": ["Attack on Titan", "AoT"],"ja": ["進撃の巨人", "しんげきのきょじん"]} title_names jsonb NOT NULL, studio_id bigint NOT NULL REFERENCES studios (id), poster_id bigint REFERENCES images (id), @@ -56,7 +55,6 @@ CREATE TABLE titles ( season int CHECK (season >= 0), episodes_aired int CHECK (episodes_aired >= 0), episodes_all int CHECK (episodes_all >= 0), - -- example { "1": "50.50", "2": "23.23"} episodes_len jsonb, CHECK ((episodes_aired IS NULL AND episodes_all IS NULL) OR (episodes_aired IS NOT NULL AND episodes_all IS NOT NULL @@ -88,14 +86,9 @@ CREATE TABLE signals ( ); CREATE TABLE external_ids ( - user_id bigint NOT NULL REFERENCES users (id), - service_id bigint REFERENCES external_services (id), - external_id text NOT NULL -); - -CREATE TABLE external_services ( - id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - name text UNIQUE NOT NULL + user_id NOT NULL REFERENCES users (id), + service_id text NOT NULL, + external_ids text NOT NULL ); -- Functions diff --git a/sql/models.go b/sql/models.go index 6583b71..928d5ac 100644 --- a/sql/models.go +++ b/sql/models.go @@ -185,17 +185,6 @@ func (ns NullUsertitleStatusT) Value() (driver.Value, error) { return string(ns.UsertitleStatusT), nil } -type ExternalID struct { - UserID int64 `json:"user_id"` - ServiceID *int64 `json:"service_id"` - ExternalID string `json:"external_id"` -} - -type ExternalService struct { - ID int64 `json:"id"` - Name string `json:"name"` -} - type Image struct { ID int64 `json:"id"` StorageType StorageTypeT `json:"storage_type"` @@ -229,19 +218,19 @@ type Tag struct { } type Title struct { - 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"` + 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 NullReleaseSeasonT `json:"release_season"` + Season *int32 `json:"season"` + EpisodesAired *int32 `json:"episodes_aired"` + EpisodesAll *int32 `json:"episodes_all"` + EpisodesLen []byte `json:"episodes_len"` } type TitleTag struct { diff --git a/sql/queries.sql.go b/sql/queries.sql.go index 2ef4178..8f92c2a 100644 --- a/sql/queries.sql.go +++ b/sql/queries.sql.go @@ -71,117 +71,3 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (GetUserByIDRow, er ) return i, err } - -const searchTitles = `-- name: SearchTitles :many - - - - -SELECT - id, title_names, studio_id, poster_id, title_status, rating, rating_count, release_year, release_season, season, episodes_aired, episodes_all, episodes_len -FROM titles -WHERE - CASE - WHEN $1::text IS NOT NULL THEN - ( - SELECT bool_and( - EXISTS ( - SELECT 1 - FROM jsonb_each_text(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 title_status = $2::title_status_t) - 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) - -LIMIT COALESCE($7::int, 100) -- 100 is default limit -OFFSET $6::int -` - -type SearchTitlesParams struct { - Word *string `json:"word"` - Status *TitleStatusT `json:"status"` - Rating *float64 `json:"rating"` - ReleaseYear *int32 `json:"release_year"` - ReleaseSeason *ReleaseSeasonT `json:"release_season"` - Offset *int32 `json:"offset"` - Limit *int32 `json:"limit"` -} - -// -- name: ListUsers :many -// SELECT user_id, avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date -// FROM users -// ORDER BY user_id -// LIMIT $1 OFFSET $2; -// -- name: CreateUser :one -// INSERT INTO users (avatar_id, passhash, mail, nickname, disp_name, user_desc, creation_date) -// VALUES ($1, $2, $3, $4, $5, $6, $7) -// RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date; -// -- name: UpdateUser :one -// UPDATE users -// SET -// -// avatar_id = COALESCE(sqlc.narg('avatar_id'), avatar_id), -// disp_name = COALESCE(sqlc.narg('disp_name'), disp_name), -// user_desc = COALESCE(sqlc.narg('user_desc'), user_desc), -// passhash = COALESCE(sqlc.narg('passhash'), passhash) -// -// WHERE user_id = sqlc.arg('user_id') -// RETURNING user_id, avatar_id, nickname, disp_name, user_desc, creation_date; -// -- name: DeleteUser :exec -// DELETE FROM users -// WHERE user_id = $1; -func (q *Queries) SearchTitles(ctx context.Context, arg SearchTitlesParams) ([]Title, error) { - rows, err := q.db.Query(ctx, searchTitles, - arg.Word, - arg.Status, - arg.Rating, - arg.ReleaseYear, - arg.ReleaseSeason, - arg.Offset, - arg.Limit, - ) - if err != nil { - return nil, err - } - defer rows.Close() - var items []Title - for rows.Next() { - var i Title - if err := rows.Scan( - &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 -} diff --git a/sql/sqlc.yaml b/sql/sqlc.yaml index f74d2ad..f44761e 100644 --- a/sql/sqlc.yaml +++ b/sql/sqlc.yaml @@ -24,14 +24,4 @@ sql: nullable: false go_type: import: "time" - type: "Time" - - db_type: "title_status_t" - nullable: true - go_type: - pointer: true - type: "TitleStatusT" - - db_type: "release_season_t" - nullable: true - go_type: - pointer: true - type: "ReleaseSeasonT" \ No newline at end of file + type: "Time" \ No newline at end of file