From 7e1a6e1f3ff98f45a24bd5104d3ca8b35b4a4d6c Mon Sep 17 00:00:00 2001 From: Emilia Grant Date: Wed, 14 Jan 2026 11:27:17 -0500 Subject: [PATCH] add SortBy and SortDirection parsing --- internal/clientcache/internal/cache/search.go | 9 ++- .../internal/daemon/search_handler.go | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/internal/clientcache/internal/cache/search.go b/internal/clientcache/internal/cache/search.go index 16078cabf7..2399ce5c24 100644 --- a/internal/clientcache/internal/cache/search.go +++ b/internal/clientcache/internal/cache/search.go @@ -20,8 +20,9 @@ import ( type SortBy string const ( - SortByDefault SortBy = "" - SortByName SortBy = "name" + SortByDefault SortBy = "" + SortByName SortBy = "name" + SortByCreatedAt SortBy = "created_at" ) type SortDirection string @@ -76,6 +77,10 @@ type SearchParams struct { Filter string // Max result set size is an override to the default max result set size MaxResultSetSize int + // Which column to sort results by, defaultis resource specific + SortBy SortBy + // Which direction to sort results by (asc, desc), default is resource specific + SortDirection SortDirection } // SearchResult returns the results from searching the cache. diff --git a/internal/clientcache/internal/daemon/search_handler.go b/internal/clientcache/internal/daemon/search_handler.go index 97dffa5cc2..9ced1c4522 100644 --- a/internal/clientcache/internal/daemon/search_handler.go +++ b/internal/clientcache/internal/daemon/search_handler.go @@ -10,6 +10,7 @@ import ( "fmt" "net/http" "strconv" + "strings" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/aliases" @@ -57,6 +58,8 @@ const ( forceRefreshKey = "force_refresh" authTokenIdKey = "auth_token_id" maxResultSetSizeKey = "max_result_set_size" + sortByKey = "sort_by" + sortDirectionKey = "sort_direction" ) func newSearchHandlerFunc(ctx context.Context, repo *cache.Repository, refreshService *cache.RefreshService, logger hclog.Logger) (http.HandlerFunc, error) { @@ -84,6 +87,8 @@ func newSearchHandlerFunc(ctx context.Context, repo *cache.Repository, refreshSe maxResultSetSizeInt, maxResultSetSizeIntErr := strconv.Atoi(maxResultSetSizeStr) query := q.Get(queryKey) filter := q.Get(filterKey) + sb := q.Get(sortByKey) + sd := q.Get(sortDirectionKey) searchableResource := cache.ToSearchableResource(resource) switch { @@ -121,6 +126,20 @@ func newSearchHandlerFunc(ctx context.Context, repo *cache.Repository, refreshSe return } + sortBy, valid := parseSortBy(sb, searchableResource) + if !valid { + event.WriteError(ctx, op, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("sort_by parameter %q not valid for resource %q", sb, searchableResource))) + writeError(w, fmt.Sprintf("sort_by parameter %q not valid for resource %q", sb, searchableResource), http.StatusBadRequest) + return + } + + sortDirection, valid := parseSortDirection(sd) + if !valid { + event.WriteError(ctx, op, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("sort_direction parameter %q not valid", sb))) + writeError(w, fmt.Sprintf("sort_direction parameter %q not valid ", sb), http.StatusBadRequest) + return + } + t, err := repo.LookupToken(reqCtx, authTokenId, cache.WithUpdateLastAccessedTime(true)) if err != nil || t == nil { if err != nil { @@ -175,6 +194,8 @@ func newSearchHandlerFunc(ctx context.Context, repo *cache.Repository, refreshSe Query: query, Filter: filter, MaxResultSetSize: maxResultSetSizeInt, + SortBy: sortBy, + SortDirection: sortDirection, }) if err != nil { event.WriteError(ctx, op, err, event.WithInfoMsg("when performing search", "auth_token_id", authTokenId, "resource", searchableResource, "query", query, "filter", filter)) @@ -237,3 +258,41 @@ func writeUnsupportedError(w http.ResponseWriter) { } http.Error(w, string(b), http.StatusBadRequest) } + +func parseSortDirection(sd string) (cache.SortDirection, bool) { + sd = strings.ToLower(sd) + switch sd { + case "asc", "ascending": + return cache.Ascending, true + case "desc", "descending": + return cache.Ascending, true + case "": + return cache.SortDirectionDefault, true + default: + return cache.SortDirectionDefault, false + } +} + +func parseSortBy(sb string, sr cache.SearchableResource) (cache.SortBy, bool) { + sb = strings.ToLower(sb) + by := cache.SortBy(sb) + + if by == cache.SortByDefault { + return cache.SortByDefault, true + } + + switch sr { + case cache.Targets: + if by != cache.SortByName { + return cache.SortByDefault, false + } + return by, true + case cache.Sessions: + if by != cache.SortByCreatedAt { + return cache.SortByDefault, false + } + return by, true + default: + return cache.SortByDefault, false + } +}