Skip to content

Commit

Permalink
Support multiple field selectors
Browse files Browse the repository at this point in the history
Signed-off-by: Tamal Saha <tamal@appscode.com>
  • Loading branch information
tamalsaha committed Mar 11, 2022
1 parent 9ee63fc commit a74b910
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 15 deletions.
64 changes: 50 additions & 14 deletions pkg/cache/internal/cache_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,55 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli
listOpts.ApplyOptions(opts)

switch {
case listOpts.FieldSelector != nil:
case listOpts.FieldSelector != nil && !listOpts.FieldSelector.Empty():
// TODO(directxman12): support more complicated field selectors by
// combining multiple indices, GetIndexers, etc
field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector)
requiresExact := requiresExactMatch(listOpts.FieldSelector)
if !requiresExact {
return fmt.Errorf("non-exact field matches are not supported by the cache")
}
// list all objects by the field selector. If this is namespaced and we have one, ask for the
// namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces"
// namespace.
objs, err = c.indexer.ByIndex(FieldIndexName(field), KeyToNamespacedKey(listOpts.Namespace, val))

reqs := listOpts.FieldSelector.Requirements()
// len(reqs) == 0 means, select nothing
if len(reqs) > 0 {
req := reqs[0]
// list all objects by the field selector. If this is namespaced and we have one, ask for the
// namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces"
// namespace.
list, err := c.indexer.ByIndex(FieldIndexName(req.Field), KeyToNamespacedKey(listOpts.Namespace, req.Value))
if err != nil {
return err
}
if len(reqs) > 1 {
objmap := make(map[client.ObjectKey]interface{}, len(list))
for i := range list {
obj := list[i].(client.Object)
objmap[client.ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}] = obj
}
for _, req := range reqs[1:] {
list, err := c.indexer.ByIndex(FieldIndexName(req.Field), KeyToNamespacedKey(listOpts.Namespace, req.Value))
if err != nil {
return err
}

numap := make(map[client.ObjectKey]interface{}, len(list))
for i := range list {
obj := list[i].(client.Object)
key := client.ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}
if _, exists := objmap[key]; exists {
numap[key] = obj
}
}
objmap = numap
}
objs = make([]interface{}, 0, len(objmap))
for _, obj := range objmap {
objs = append(objs, obj)
}
} else {
objs = list
}
}
case listOpts.Namespace != "":
objs, err = c.indexer.ByIndex(cache.NamespaceIndex, listOpts.Namespace)
default:
Expand Down Expand Up @@ -187,16 +225,14 @@ func objectKeyToStoreKey(k client.ObjectKey) string {
}

// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.
func requiresExactMatch(sel fields.Selector) (field, val string, required bool) {
func requiresExactMatch(sel fields.Selector) (required bool) {
reqs := sel.Requirements()
if len(reqs) != 1 {
return "", "", false
}
req := reqs[0]
if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
return "", "", false
for _, req := range reqs {
if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
return false
}
}
return req.Field, req.Value, true
return true
}

// FieldIndexName constructs the name of the index over the given field,
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ type ListOptions struct {
LabelSelector labels.Selector
// FieldSelector filters results by a particular field. In order
// to use this with cache-based implementations, restrict usage to
// a single field-value pair that's been added to the indexers.
// field-value pair exact matches that's been added to the indexers.
FieldSelector fields.Selector

// Namespace represents the namespace to list for, or empty for
Expand Down

0 comments on commit a74b910

Please sign in to comment.