mirror of
https://github.com/rancher/steve.git
synced 2025-09-08 18:59:58 +00:00
Add support for OR filters
Currently, multiple filters can be appended on the query string, and each subsequent filter is ANDed with the set. Items that pass through the filter set must match every filter in the set. This change adds support for OR filters. A single filter key can specify multiple filters, separated by ','. An item that passes this filter can match any filter in the set. For example, this filter matches items that have either "name" or "namespace" that match "example": ?filter=metadata.name=example,metadata.namespace=example This filter matches items that have "name" that matches either "foo" or "bar": ?filter=metadata.name=foo,metadata.name=bar Specifying more than one filter key in the query still ANDs each inner filter set together. This set of filters can match either a name of "foo" or "bar", but must in all cases match namespace "abc": ?filter=metadata.name=foo,metadata.name=bar&filter=metadata.namespace=abc
This commit is contained in:
@@ -278,6 +278,9 @@ func TestList(t *testing.T) {
|
||||
apiOps: []*types.APIRequest{
|
||||
newRequest("filter=data.color=green", "user1"),
|
||||
newRequest("filter=data.color=green&filter=metadata.name=bramley", "user1"),
|
||||
newRequest("filter=data.color=green,data.color=pink", "user1"),
|
||||
newRequest("filter=data.color=green,data.color=pink&filter=metadata.name=fuji", "user1"),
|
||||
newRequest("filter=data.color=green,data.color=pink&filter=metadata.name=crispin", "user1"),
|
||||
},
|
||||
access: []map[string]string{
|
||||
{
|
||||
@@ -286,6 +289,15 @@ func TestList(t *testing.T) {
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
},
|
||||
partitions: map[string][]Partition{
|
||||
"user1": {
|
||||
@@ -318,6 +330,23 @@ func TestList(t *testing.T) {
|
||||
newApple("bramley").toObj(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Count: 3,
|
||||
Objects: []types.APIObject{
|
||||
newApple("fuji").toObj(),
|
||||
newApple("granny-smith").toObj(),
|
||||
newApple("bramley").toObj(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Count: 1,
|
||||
Objects: []types.APIObject{
|
||||
newApple("fuji").toObj(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Count: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1739,6 +1768,133 @@ func TestList(t *testing.T) {
|
||||
{"green": 2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pagination with or filters",
|
||||
apiOps: []*types.APIRequest{
|
||||
newRequest("filter=metadata.name=el,data.color=el&pagesize=2", "user1"),
|
||||
newRequest("filter=metadata.name=el,data.color=el&pagesize=2&page=2&revision=42", "user1"),
|
||||
newRequest("filter=metadata.name=el,data.color=el&pagesize=2&page=3&revision=42", "user1"),
|
||||
},
|
||||
access: []map[string]string{
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
{
|
||||
"user1": "roleA",
|
||||
},
|
||||
},
|
||||
partitions: map[string][]Partition{
|
||||
"user1": {
|
||||
mockPartition{
|
||||
name: "all",
|
||||
},
|
||||
},
|
||||
},
|
||||
objects: map[string]*unstructured.UnstructuredList{
|
||||
"all": {
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"resourceVersion": "42",
|
||||
},
|
||||
},
|
||||
Items: []unstructured.Unstructured{
|
||||
newApple("fuji").Unstructured,
|
||||
newApple("granny-smith").Unstructured,
|
||||
newApple("red-delicious").Unstructured,
|
||||
newApple("golden-delicious").Unstructured,
|
||||
newApple("crispin").Unstructured,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.APIObjectList{
|
||||
{
|
||||
Count: 3,
|
||||
Pages: 2,
|
||||
Revision: "42",
|
||||
Objects: []types.APIObject{
|
||||
newApple("red-delicious").toObj(),
|
||||
newApple("golden-delicious").toObj(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Count: 3,
|
||||
Pages: 2,
|
||||
Revision: "42",
|
||||
Objects: []types.APIObject{
|
||||
newApple("crispin").toObj(),
|
||||
},
|
||||
},
|
||||
{
|
||||
Count: 3,
|
||||
Pages: 2,
|
||||
Revision: "42",
|
||||
},
|
||||
},
|
||||
wantCache: []mockCache{
|
||||
{
|
||||
contents: map[cacheKey]*unstructured.UnstructuredList{
|
||||
{
|
||||
chunkSize: 100000,
|
||||
filters: "data.color=el,metadata.name=el",
|
||||
pageSize: 2,
|
||||
accessID: getAccessID("user1", "roleA"),
|
||||
resourcePath: "/apples",
|
||||
revision: "42",
|
||||
}: {
|
||||
Items: []unstructured.Unstructured{
|
||||
newApple("red-delicious").Unstructured,
|
||||
newApple("golden-delicious").Unstructured,
|
||||
newApple("crispin").Unstructured,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
contents: map[cacheKey]*unstructured.UnstructuredList{
|
||||
{
|
||||
chunkSize: 100000,
|
||||
filters: "data.color=el,metadata.name=el",
|
||||
pageSize: 2,
|
||||
accessID: getAccessID("user1", "roleA"),
|
||||
resourcePath: "/apples",
|
||||
revision: "42",
|
||||
}: {
|
||||
Items: []unstructured.Unstructured{
|
||||
newApple("red-delicious").Unstructured,
|
||||
newApple("golden-delicious").Unstructured,
|
||||
newApple("crispin").Unstructured,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
contents: map[cacheKey]*unstructured.UnstructuredList{
|
||||
{
|
||||
chunkSize: 100000,
|
||||
filters: "data.color=el,metadata.name=el",
|
||||
pageSize: 2,
|
||||
accessID: getAccessID("user1", "roleA"),
|
||||
resourcePath: "/apples",
|
||||
revision: "42",
|
||||
}: {
|
||||
Items: []unstructured.Unstructured{
|
||||
newApple("red-delicious").Unstructured,
|
||||
newApple("golden-delicious").Unstructured,
|
||||
newApple("crispin").Unstructured,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantListCalls: []map[string]int{
|
||||
{"all": 1},
|
||||
{"all": 1},
|
||||
{"all": 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user