From 046903c7a1c47a9bcda5e6a16fe1a0d81e8c486a Mon Sep 17 00:00:00 2001 From: renaldybrada Date: Mon, 2 Feb 2026 15:21:32 +0700 Subject: [PATCH] update doc list api antrian + pagination --- docs/docs.go | 14 +++++ docs/swagger.json | 14 +++++ docs/swagger.yaml | 10 ++++ internal/domain/antrian_operasi/handler.go | 7 ++- internal/domain/antrian_operasi/model.go | 10 +++- internal/domain/antrian_operasi/repository.go | 34 ++++++++--- internal/shared/baseResponse.go | 17 ++++++ internal/shared/pagination.go | 57 +++++++++++++++++++ 8 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 internal/shared/pagination.go diff --git a/docs/docs.go b/docs/docs.go index 2104ebe..9f3b6ec 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -33,6 +33,20 @@ const docTemplate = `{ "description": "Type antrian : all, kategori, spesialis, sub-spesialis", "name": "type", "in": "query" + }, + { + "type": "string", + "default": "10", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "0", + "description": "Offset", + "name": "offset", + "in": "query" } ], "responses": { diff --git a/docs/swagger.json b/docs/swagger.json index d3e17db..fd3ae10 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -27,6 +27,20 @@ "description": "Type antrian : all, kategori, spesialis, sub-spesialis", "name": "type", "in": "query" + }, + { + "type": "string", + "default": "10", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "0", + "description": "Offset", + "name": "offset", + "in": "query" } ], "responses": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 039ee1a..f2b82f3 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -219,6 +219,16 @@ paths: in: query name: type type: string + - default: "10" + description: Limit + in: query + name: limit + type: string + - default: "0" + description: Offset + in: query + name: offset + type: string responses: "200": description: OK diff --git a/internal/domain/antrian_operasi/handler.go b/internal/domain/antrian_operasi/handler.go index e9c7d7a..6b5142c 100644 --- a/internal/domain/antrian_operasi/handler.go +++ b/internal/domain/antrian_operasi/handler.go @@ -81,6 +81,8 @@ func (h AntrianOperasiHandler) CreateAntrianOperasi(c *gin.Context) { // @Tags Antrian Operasi // @Param search query string false "Search Keyword" // @Param type query string false "Type antrian : all, kategori, spesialis, sub-spesialis" +// @Param limit query string false "Limit" default(10) +// @Param offset query string false "Offset" default(0) // @Success 200 {object} []PasienOperasi // @Failure 500 {object} shared.BaseErrorResponse // @Router /antrian-operasi/ [get] @@ -95,5 +97,8 @@ func (h AntrianOperasiHandler) GetListAntrianOperasi(c *gin.Context) { return } - c.JSON(200, shared.ToBaseResponse(res, true, 200, "success get list antrian operasi")) + c.JSON(200, + shared.ToBaseResponsePaginate( + res.Data, res.Paging, true, 200, "success get list antrian operasi", + )) } diff --git a/internal/domain/antrian_operasi/model.go b/internal/domain/antrian_operasi/model.go index f8cde3b..e59fe6a 100644 --- a/internal/domain/antrian_operasi/model.go +++ b/internal/domain/antrian_operasi/model.go @@ -1,6 +1,9 @@ package antrianoperasi -import "time" +import ( + "antrian-operasi/internal/shared" + "time" +) type PasienOperasi struct { ID string `db:"id" json:"id"` @@ -17,3 +20,8 @@ type PasienOperasi struct { NoUrutSpesialis int `db:"no_urut_spesialis"` NoUrutSubSpesialis int `db:"no_urut_sub_spesialis"` } + +type ListPasienOperasiPaginate struct { + Data []PasienOperasi + Paging shared.PaginationInfo +} diff --git a/internal/domain/antrian_operasi/repository.go b/internal/domain/antrian_operasi/repository.go index b4d4002..b6fb3cd 100644 --- a/internal/domain/antrian_operasi/repository.go +++ b/internal/domain/antrian_operasi/repository.go @@ -2,6 +2,7 @@ package antrianoperasi import ( "antrian-operasi/internal/database" + "antrian-operasi/internal/shared" queryUtils "antrian-operasi/internal/utils/query" "log" "slices" @@ -16,7 +17,7 @@ const TBL_NAME = "data_pasien_operasi" type IAntrianOperasiRepository interface { CreateAntrianOperasi(c *gin.Context, req CreatePasienOperasiRequest) (CreatePasienOperasiRequest, error) - SearchableListAntrianOperasi(c *gin.Context) ([]PasienOperasi, error) + SearchableListAntrianOperasi(c *gin.Context) (ListPasienOperasiPaginate, error) } type antrianOperasiRepo struct { @@ -267,8 +268,8 @@ func (r antrianOperasiRepo) CreateAntrianOperasi(c *gin.Context, req CreatePasie return req, nil } -func (r antrianOperasiRepo) SearchableListAntrianOperasi(c *gin.Context) ([]PasienOperasi, error) { - var result []PasienOperasi +func (r antrianOperasiRepo) SearchableListAntrianOperasi(c *gin.Context) (ListPasienOperasiPaginate, error) { + var result ListPasienOperasiPaginate search := c.Query("search") availableType := []string{"all", "kategori", "spesialis", "sub-spesialis"} antrianType := c.Query("type") @@ -277,6 +278,9 @@ func (r antrianOperasiRepo) SearchableListAntrianOperasi(c *gin.Context) ([]Pasi antrianType = "all" } + limit := shared.ParseQueryLimit(c) + offset := shared.ParseQueryOffset(c) + query := queryUtils.DynamicQuery{ From: TBL_NAME, Aliases: "dpo", @@ -292,7 +296,6 @@ func (r antrianOperasiRepo) SearchableListAntrianOperasi(c *gin.Context) ([]Pasi {Expression: "ddpo.Diagnosa", Alias: "diagnosa"}, {Expression: "dko.Kategori", Alias: "kategori"}, }, - Limit: 10, Sort: []queryUtils.SortField{ {Column: "dpo.Tanggal_daftar", Order: "ASC"}}, } @@ -390,16 +393,33 @@ func (r antrianOperasiRepo) SearchableListAntrianOperasi(c *gin.Context) ([]Pasi query.Filters = append(query.Filters, queryUtils.FilterGroup{Filters: searchFilters, LogicOp: "OR"}) } + // TODO Filtering status + dbconn, err := r.db.GetSQLXDB(DB_NAME) if err != nil { log.Printf("Unable to connect db : %s", err) return result, err } - err = r.queryBuilder.ExecuteQuery( - c, dbconn, query, &result) + // query count + countData, err := r.queryBuilder.ExecuteCount(c, dbconn, query) if err != nil { - log.Printf("Unable to execute query : %s", err) + log.Printf("Unable to execute query count : %s ", err) + return result, err + } + result.Paging.Limit = limit + result.Paging.Offset = offset + result.Paging.Total = int(countData) + result.Paging.CalculatePagingInfo() + + // query data + queryData := query + queryData.Limit = limit + queryData.Offset = offset + err = r.queryBuilder.ExecuteQuery( + c, dbconn, queryData, &result.Data) + if err != nil { + log.Printf("Unable to execute query data : %s", err) return result, err } diff --git a/internal/shared/baseResponse.go b/internal/shared/baseResponse.go index 0c93785..f7c3df7 100644 --- a/internal/shared/baseResponse.go +++ b/internal/shared/baseResponse.go @@ -14,6 +14,11 @@ type BaseResponse[T any] struct { Data T `json:"data" swaggertype:"object"` } +type BaseResponsePaginate[T any] struct { + BaseResponse[T] + Paginate PaginationInfo +} + func ToBaseResponse[T any](data T, isSuccess bool, code int, message string) BaseResponse[T] { return BaseResponse[T]{ Success: true, @@ -22,3 +27,15 @@ func ToBaseResponse[T any](data T, isSuccess bool, code int, message string) Bas Data: data, } } + +func ToBaseResponsePaginate[T any](data T, paginate PaginationInfo, isSuccess bool, code int, message string) BaseResponsePaginate[T] { + return BaseResponsePaginate[T]{ + BaseResponse: BaseResponse[T]{ + Success: true, + Code: 200, + Message: message, + Data: data, + }, + Paginate: paginate, + } +} diff --git a/internal/shared/pagination.go b/internal/shared/pagination.go new file mode 100644 index 0000000..10df96c --- /dev/null +++ b/internal/shared/pagination.go @@ -0,0 +1,57 @@ +package shared + +import ( + "strconv" + + "github.com/gin-gonic/gin" +) + +type PaginationInfo struct { + Limit int + Offset int + Total int + TotalPages int + CurrentPage int + HasNext bool + HasPrev bool +} + +func ParseQueryLimit(c *gin.Context) int { + limit := 10 // default + l, err := strconv.Atoi(c.Query("limit")) + if err == nil { + if l > 100 { + limit = 100 // max limit default + } else if l < 100 && l > 0 { + limit = l + } + } + + return limit +} + +func ParseQueryOffset(c *gin.Context) int { + offset := 0 + o, err := strconv.Atoi(c.Query("offset")) + if err == nil { + if o > 0 { + offset = o + } + } + return offset +} + +func (source *PaginationInfo) CalculatePagingInfo() *PaginationInfo { + result := source + + result.TotalPages, result.CurrentPage = 0, 1 + if result.Limit > 0 { + result.TotalPages = (result.Total + result.Limit - 1) / result.Limit + result.CurrentPage = (result.Offset / result.Limit) + 1 + } + + result.HasNext = result.Offset+result.Limit < result.Total + result.HasPrev = result.Offset > 0 + + return result +}