diff --git a/internal/company/form.go b/internal/company/form.go index 6b367c0..181b1dd 100644 --- a/internal/company/form.go +++ b/internal/company/form.go @@ -76,7 +76,7 @@ type SearchForm struct { FoundedYearMax *int `query:"founded_year_max" valid:"optional,range(1800|2100)"` Limit *int `query:"limit" valid:"optional,range(1|100)"` Offset *int `query:"offset" valid:"optional,range(0|1000000)"` - SortBy *string `query:"sort_by" valid:"optional,in(name|type|industry|created_at|updated_at|status|employee_count|annual_revenue)"` + SortBy *string `query:"sort_by" valid:"optional,in(name|type|industry|created_at|updated_at|status|employee_count|annual_revenue|email|phone|country|state|language|currency)"` SortOrder *string `query:"sort_order" valid:"optional,in(asc|desc)"` } diff --git a/internal/company/handler.go b/internal/company/handler.go index 62b7fb7..c7ad89e 100644 --- a/internal/company/handler.go +++ b/internal/company/handler.go @@ -212,6 +212,8 @@ func (h *Handler) Delete(c echo.Context) error { // @Param is_compliant query boolean false "Compliance status" // @Param limit query integer false "Limit" default(20) // @Param offset query integer false "Offset" default(0) +// @Param sort_by query string false "Field to sort by" Enums(name, type, industry, created_at, updated_at, status, employee_count, annual_revenue, email, phone, country, state, language, currency) default(created_at) +// @Param sort_order query string false "Sort order" Enums(asc, desc) default(desc) // @Success 200 {object} response.APIResponse{data=CompanyListResponse} "Companies search completed" // @Failure 400 {object} response.APIResponse "Bad request - Invalid query parameters" // @Failure 422 {object} response.APIResponse "Validation error - Invalid query parameters" diff --git a/internal/company/repository.go b/internal/company/repository.go index a7c04c2..85ec6dc 100644 --- a/internal/company/repository.go +++ b/internal/company/repository.go @@ -56,6 +56,17 @@ func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Re } } +func mapCompanySortField(sortBy string) string { + switch sortBy { + case "country": + return "address.country" + case "state": + return "address.state" + default: + return sortBy + } +} + // Create creates a new company func (r *companyRepository) Create(ctx context.Context, company *Company) error { // Set created/updated timestamps using Unix timestamps @@ -285,7 +296,7 @@ func (r *companyRepository) Search(ctx context.Context, form *SearchForm, pagina pagination.Limit, pagination.Offset, pagination.Cursor, - pagination.SortBy, + mapCompanySortField(pagination.SortBy), pagination.SortOrder, filter, orm.ListPaginationOptions{}, diff --git a/internal/company_category/form.go b/internal/company_category/form.go index 5cdacf2..0b371e0 100644 --- a/internal/company_category/form.go +++ b/internal/company_category/form.go @@ -15,7 +15,7 @@ type SearchForm struct { Published *bool `query:"published" valid:"optional"` Limit *int `query:"limit" valid:"optional,range(1|100)"` Offset *int `query:"offset" valid:"optional,range(0|1000000)"` - SortBy *string `query:"sort_by" valid:"optional,in(name|created_at|updated_at|published_at)"` + SortBy *string `query:"sort_by" valid:"optional,in(name|description|published|created_at|updated_at|published_at)"` SortOrder *string `query:"sort_order" valid:"optional,in(asc|desc)"` } diff --git a/internal/company_category/handler.go b/internal/company_category/handler.go index 1e7a578..89ad585 100644 --- a/internal/company_category/handler.go +++ b/internal/company_category/handler.go @@ -155,7 +155,7 @@ func (h *Handler) Delete(c echo.Context) error { // @Param published query boolean false "Published status filter" // @Param limit query integer false "Limit" default(20) // @Param offset query integer false "Offset" default(0) -// @Param sort_by query string false "Sort by field" Enums(name,created_at,updated_at,published_at) +// @Param sort_by query string false "Sort by field" Enums(name,description,published,created_at,updated_at,published_at) // @Param sort_order query string false "Sort order" Enums(asc,desc) // @Success 200 {object} response.APIResponse{data=CategoryListResponse} "Categories search completed" // @Failure 400 {object} response.APIResponse "Bad request - Invalid query parameters" diff --git a/pkg/mongo/cursor.go b/pkg/mongo/cursor.go index 6cb0c38..37366a6 100644 --- a/pkg/mongo/cursor.go +++ b/pkg/mongo/cursor.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strconv" + "strings" "go.mongodb.org/mongo-driver/v2/bson" ) @@ -189,6 +190,10 @@ func documentSortValue(docMap bson.M, sortField string) (interface{}, error) { return id, nil } + if strings.Contains(sortField, ".") { + return nestedDocumentValue(docMap, sortField) + } + sortValue, exists := docMap[sortField] if !exists { return nil, fmt.Errorf("sort field %s not found in document", sortField) @@ -196,6 +201,30 @@ func documentSortValue(docMap bson.M, sortField string) (interface{}, error) { return sortValue, nil } +func nestedDocumentValue(docMap bson.M, path string) (interface{}, error) { + parts := strings.Split(path, ".") + var current interface{} = docMap + + for _, part := range parts { + nested, ok := current.(bson.M) + if !ok { + if nestedMap, ok := current.(map[string]interface{}); ok { + nested = bson.M(nestedMap) + } else { + return nil, fmt.Errorf("sort field %s not found in document", path) + } + } + + value, exists := nested[part] + if !exists { + return nil, fmt.Errorf("sort field %s not found in document", path) + } + current = value + } + + return current, nil +} + func documentIDHex(docMap bson.M) (string, error) { id, exists := docMap["_id"] if !exists {