mirror of
https://github.com/rancher/steve.git
synced 2025-09-08 18:59:58 +00:00
SQLite backed cache: Support sorting mgmt clusters on value in a specific condition (#447)
* Replace primary/secondary sort fields with an array of sort directives. * Allow more than 2 sort-params in a search query. * Add a virtual 'status.ready' field to clusters. * Rename status.ready -> status.connected * Set virtual field 'spec.internal' <- spec.displayName == 'local' * Need to declare all virtual fields to index. * Ready clusters have condition[type==Ready && status=True] * Update the README to reflect generalized sorting. * Bump lasso to get revised sort directives. * Review-driven changes, mostly comments and drop unneeded code. * Add unit tests to verify sort-order stringification. * Ignore empty-string sort components. * Fix a rebase mishap. * Drop unneeded commented-out code. * Clusters have a 'spec.internal' field, no need to synthesize one. * Added a note on square-brackets for label references. This should be added to the README for filter queries in the PR for 46333. * Bump to latest sqlcache-free lasso
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/rancher/apiserver/pkg/types"
|
||||
"github.com/rancher/steve/pkg/sqlcache/informer"
|
||||
"github.com/rancher/steve/pkg/sqlcache/partition"
|
||||
"github.com/rancher/steve/pkg/stores/queryhelper"
|
||||
"github.com/rancher/wrangler/v3/pkg/schemas/validation"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
@@ -88,27 +89,19 @@ func ParseQuery(apiOp *types.APIRequest, namespaceCache Cache) (informer.ListOpt
|
||||
sortOpts := informer.Sort{}
|
||||
sortKeys := q.Get(sortParam)
|
||||
if sortKeys != "" {
|
||||
sortParts := strings.SplitN(sortKeys, ",", 2)
|
||||
primaryField := sortParts[0]
|
||||
if primaryField != "" {
|
||||
if primaryField[0] == '-' {
|
||||
sortOpts.Orders = append(sortOpts.Orders, informer.DESC)
|
||||
primaryField = primaryField[1:]
|
||||
} else {
|
||||
sortOpts.Orders = append(sortOpts.Orders, informer.ASC)
|
||||
}
|
||||
sortOpts.Fields = append(sortOpts.Fields, strings.Split(primaryField, "."))
|
||||
}
|
||||
if len(sortParts) > 1 {
|
||||
secondaryField := sortParts[1]
|
||||
if secondaryField != "" {
|
||||
if secondaryField[0] == '-' {
|
||||
sortOpts.Orders = append(sortOpts.Orders, informer.DESC)
|
||||
secondaryField = secondaryField[1:]
|
||||
} else {
|
||||
sortOpts.Orders = append(sortOpts.Orders, informer.ASC)
|
||||
sortParts := strings.Split(sortKeys, ",")
|
||||
for _, sortPart := range sortParts {
|
||||
field := sortPart
|
||||
if len(field) > 0 {
|
||||
sortOrder := informer.ASC
|
||||
if field[0] == '-' {
|
||||
sortOrder = informer.DESC
|
||||
field = field[1:]
|
||||
}
|
||||
if len(field) > 0 {
|
||||
sortOpts.Fields = append(sortOpts.Fields, queryhelper.SafeSplit(field))
|
||||
sortOpts.Orders = append(sortOpts.Orders, sortOrder)
|
||||
}
|
||||
sortOpts.Fields = append(sortOpts.Fields, strings.Split(secondaryField, "."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -342,7 +342,7 @@ func TestParseQuery(t *testing.T) {
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with no errors returned should returned no errors. If one sort param is given, primary field" +
|
||||
description: "ParseQuery() with no errors returned should returned no errors. It should sort on the one given" +
|
||||
" sort option should be set",
|
||||
req: &types.APIRequest{
|
||||
Request: &http.Request{
|
||||
@@ -353,11 +353,8 @@ func TestParseQuery(t *testing.T) {
|
||||
ChunkSize: defaultLimit,
|
||||
Sort: informer.Sort{
|
||||
Fields: [][]string{
|
||||
{"metadata", "name"},
|
||||
},
|
||||
Orders: []informer.SortOrder{
|
||||
informer.ASC,
|
||||
},
|
||||
{"metadata", "name"}},
|
||||
Orders: []informer.SortOrder{informer.ASC},
|
||||
},
|
||||
Filters: make([]informer.OrFilter, 0),
|
||||
Pagination: informer.Pagination{
|
||||
@@ -420,6 +417,32 @@ func TestParseQuery(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
tests = append(tests, testCase{
|
||||
description: "sorting can parse bracketed field names correctly",
|
||||
req: &types.APIRequest{
|
||||
Request: &http.Request{
|
||||
URL: &url.URL{RawQuery: "sort=-metadata.labels[beef.cattle.io/snort],metadata.labels.steer,metadata.labels[bossie.cattle.io/moo],spec.something"},
|
||||
},
|
||||
},
|
||||
expectedLO: informer.ListOptions{
|
||||
ChunkSize: defaultLimit,
|
||||
Sort: informer.Sort{
|
||||
Fields: [][]string{{"metadata", "labels", "beef.cattle.io/snort"},
|
||||
{"metadata", "labels", "steer"},
|
||||
{"metadata", "labels", "bossie.cattle.io/moo"},
|
||||
{"spec", "something"}},
|
||||
Orders: []informer.SortOrder{informer.DESC, informer.ASC, informer.ASC, informer.ASC},
|
||||
},
|
||||
Filters: make([]informer.OrFilter, 0),
|
||||
Pagination: informer.Pagination{
|
||||
Page: 1,
|
||||
},
|
||||
},
|
||||
setupNSCache: func() Cache {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
description: "ParseQuery() with no errors returned should returned no errors. If continue params is given, resume" +
|
||||
" should be set with assigned value.",
|
||||
@@ -522,6 +545,9 @@ func TestParseQuery(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
test.nsc = test.setupNSCache()
|
||||
if test.description == "sorting can parse bracketed field names correctly" {
|
||||
fmt.Printf("stop here")
|
||||
}
|
||||
lo, err := ParseQuery(test.req, test.nsc)
|
||||
if test.errExpected {
|
||||
assert.NotNil(t, err)
|
||||
|
Reference in New Issue
Block a user