diff --git a/internal/domain/main-entities/district/dto.go b/internal/domain/main-entities/district/dto.go index ee81aeec..7205c2b0 100644 --- a/internal/domain/main-entities/district/dto.go +++ b/internal/domain/main-entities/district/dto.go @@ -16,6 +16,7 @@ type ReadListDto struct { Includes string `json:"includes"` Preloads []string `json:"-"` Search string `json:"search"` + Sort string `json:"sort"` Pagination ecore.Pagination } diff --git a/internal/domain/main-entities/province/dto.go b/internal/domain/main-entities/province/dto.go index 595db5a4..b4b13cfe 100644 --- a/internal/domain/main-entities/province/dto.go +++ b/internal/domain/main-entities/province/dto.go @@ -15,6 +15,7 @@ type ReadListDto struct { Includes string `json:"includes"` Preloads []string `json:"-"` Search string `json:"search"` + Sort string `json:"sort"` Pagination ecore.Pagination } diff --git a/internal/domain/main-entities/regency/dto.go b/internal/domain/main-entities/regency/dto.go index 9408096b..09e44e66 100644 --- a/internal/domain/main-entities/regency/dto.go +++ b/internal/domain/main-entities/regency/dto.go @@ -16,6 +16,7 @@ type ReadListDto struct { Includes string `json:"includes"` Preloads []string `json:"-"` Search string `json:"search"` + Sort string `json:"sort"` Pagination ecore.Pagination } diff --git a/internal/domain/main-entities/village/dto.go b/internal/domain/main-entities/village/dto.go index 85448959..f8bc7ab1 100644 --- a/internal/domain/main-entities/village/dto.go +++ b/internal/domain/main-entities/village/dto.go @@ -15,6 +15,7 @@ type ReadListDto struct { Includes string `json:"includes"` Preloads []string `json:"-"` Search string `json:"search"` + Sort string `json:"sort"` Pagination ecore.Pagination } diff --git a/internal/use-case/main-use-case/district/lib.go b/internal/use-case/main-use-case/district/lib.go index b0454716..18cadab7 100644 --- a/internal/use-case/main-use-case/district/lib.go +++ b/internal/use-case/main-use-case/district/lib.go @@ -53,7 +53,9 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di } } - plh.SearchCodeOrName(input.Search, tx) + tx = plh.SearchCodeOrName(input.Search, tx) + + tx = plh.Sort(input.Sort, tx) tx = tx. Model(&e.District{}). diff --git a/internal/use-case/main-use-case/province/lib.go b/internal/use-case/main-use-case/province/lib.go index e4ca32cd..311cdad7 100644 --- a/internal/use-case/main-use-case/province/lib.go +++ b/internal/use-case/main-use-case/province/lib.go @@ -55,6 +55,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr tx = plh.SearchCodeOrName(input.Search, tx) + tx = plh.Sort(input.Sort, tx) + tx = tx. Model(&e.Province{}). Scopes(gh.Filter(input.FilterDto)). diff --git a/internal/use-case/main-use-case/regency/lib.go b/internal/use-case/main-use-case/regency/lib.go index 91c8007a..df2bb790 100644 --- a/internal/use-case/main-use-case/regency/lib.go +++ b/internal/use-case/main-use-case/regency/lib.go @@ -55,6 +55,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Re tx = plh.SearchCodeOrName(input.Search, tx) + tx = plh.Sort(input.Sort, tx) + tx = tx. Model(&e.Regency{}). Scopes(gh.Filter(input.FilterDto)). diff --git a/internal/use-case/main-use-case/village/lib.go b/internal/use-case/main-use-case/village/lib.go index 0e29ff17..059aa6d3 100644 --- a/internal/use-case/main-use-case/village/lib.go +++ b/internal/use-case/main-use-case/village/lib.go @@ -55,6 +55,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Vi tx = plh.SearchCodeOrName(input.Search, tx) + tx = plh.Sort(input.Sort, tx) + tx = tx. Model(&e.Village{}). Scopes(gh.Filter(input.FilterDto)). diff --git a/pkg/lib-helper/lib-helper.go b/pkg/lib-helper/lib-helper.go index 1131447a..1453e1b4 100644 --- a/pkg/lib-helper/lib-helper.go +++ b/pkg/lib-helper/lib-helper.go @@ -3,6 +3,8 @@ package libhelper import ( "fmt" pl "simrs-vx/pkg/logger" + "strings" + "unicode" "github.com/jackc/pgx/v5/pgconn" "gorm.io/gorm" @@ -16,6 +18,59 @@ func SearchCodeOrName(search string, tx *gorm.DB) *gorm.DB { return tx } +func Sort(sort string, tx *gorm.DB) *gorm.DB { + if sort == "" { + return tx + } + + pairs := strings.Split(sort, ",") + for _, pair := range pairs { + parts := strings.Split(strings.TrimSpace(pair), "=") + if len(parts) != 2 { + continue // skip invalid format + } + + field := strings.TrimSpace(parts[0]) + direction := strings.ToUpper(strings.TrimSpace(parts[1])) + + if direction != "ASC" && direction != "DESC" { + continue + } + + field = normalizeColumnName(field) + + tx = tx.Order(fmt.Sprintf("\"%s\" %s", field, direction)) + } + + return tx +} + +func normalizeColumnName(input string) string { + if input == "" { + return input + } + + input = strings.ReplaceAll(input, "-", "_") + + runes := []rune(input) + var out []rune + upperNext := true + for _, r := range runes { + if r == '_' { + out = append(out, r) + upperNext = true + continue + } + if upperNext { + out = append(out, unicode.ToUpper(r)) + upperNext = false + } else { + out = append(out, r) + } + } + return string(out) +} + func HandleCreateError(input any, event *pl.Event, err error) error { e, ok := err.(*pgconn.PgError) if !ok {