github.com/Axway/agent-sdk@v1.1.101/pkg/apic/apiserver/clients/api/v1/query.go (about)

     1  package v1
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
     9  )
    10  
    11  // QueryStringer helps print a query
    12  type QueryStringer struct {
    13  	QueryNode
    14  }
    15  
    16  func (qs QueryStringer) String() string {
    17  	v := rsqlVisitor{strings.Builder{}}
    18  	v.Visit(qs)
    19  
    20  	return v.String()
    21  }
    22  
    23  // Visitor visits a QueryNode
    24  type Visitor interface {
    25  	Visit(QueryNode)
    26  }
    27  
    28  type andNode []QueryNode
    29  
    30  func (n andNode) Accept(v Visitor) {
    31  	v.Visit(n)
    32  }
    33  
    34  type orNode []QueryNode
    35  
    36  func (n orNode) Accept(v Visitor) {
    37  	v.Visit(n)
    38  }
    39  
    40  type attrNode struct {
    41  	key    string
    42  	values []string
    43  }
    44  
    45  type tagNode []string
    46  
    47  type namesNode []string
    48  
    49  func (n namesNode) Accept(v Visitor) {
    50  	v.Visit(n)
    51  }
    52  
    53  func (n *attrNode) Accept(v Visitor) {
    54  	v.Visit(n)
    55  }
    56  
    57  func (n tagNode) Accept(v Visitor) {
    58  	v.Visit(n)
    59  }
    60  
    61  type referenceNode struct {
    62  	gvk  apiv1.GroupVersionKind
    63  	name string
    64  }
    65  
    66  func (r *referenceNode) Accept(v Visitor) {
    67  	v.Visit(r)
    68  }
    69  
    70  // AttrIn creates a query that matches resources with attribute key and  any of values
    71  func AttrIn(key string, values ...string) QueryNode {
    72  	return &attrNode{
    73  		key,
    74  		values,
    75  	}
    76  }
    77  
    78  // TagsIn creates a query that matches resources with any of the tag values
    79  func TagsIn(values ...string) QueryNode {
    80  	return tagNode(values)
    81  }
    82  
    83  func AllTags(values ...string) QueryNode {
    84  	subNodes := make([]QueryNode, len(values))
    85  	for i, value := range values {
    86  		subNodes[i] = TagsIn(value)
    87  	}
    88  
    89  	return andNode(subNodes)
    90  }
    91  
    92  // AnyAttr creates a query that matches resources with any of the attributes
    93  func AnyAttr(attrs map[string]string) QueryNode {
    94  	nodes := make([]QueryNode, len(attrs))
    95  	i := 0
    96  
    97  	keys := make([]string, 0, len(attrs))
    98  	for k := range attrs {
    99  		keys = append(keys, k)
   100  	}
   101  	sort.Strings(keys)
   102  
   103  	for _, key := range keys {
   104  		nodes[i] = AttrIn(key, attrs[key])
   105  		i++
   106  	}
   107  	return orNode(nodes)
   108  }
   109  
   110  // AllAttr creates a query that matches resources with all of the attributes
   111  func AllAttr(attrs map[string]string) QueryNode {
   112  	nodes := make([]QueryNode, len(attrs))
   113  	i := 0
   114  
   115  	keys := make([]string, 0, len(attrs))
   116  	for k := range attrs {
   117  		keys = append(keys, k)
   118  	}
   119  	sort.Strings(keys)
   120  
   121  	for _, key := range keys {
   122  		nodes[i] = AttrIn(key, attrs[key])
   123  		i++
   124  	}
   125  	return andNode(nodes)
   126  }
   127  
   128  // Names creates a query that matches any of the passed names
   129  func Names(names ...string) QueryNode {
   130  	return namesNode(names)
   131  }
   132  
   133  // Or creates a query that ors two or more subqueries
   134  func Or(first, second QueryNode, rest ...QueryNode) QueryNode {
   135  	nodes := make([]QueryNode, len(rest)+2)
   136  	nodes[0] = first
   137  	nodes[1] = second
   138  
   139  	return orNode(append(nodes, rest...))
   140  }
   141  
   142  // And creates a query that ands two or more subqueries
   143  func And(first, second QueryNode, rest ...QueryNode) QueryNode {
   144  	nodes := make([]QueryNode, len(rest)+2)
   145  	nodes[0] = first
   146  	nodes[1] = second
   147  
   148  	return andNode(append(nodes, rest...))
   149  }
   150  
   151  // Reference create a query by reference to resource kind and name
   152  func Reference(gvk apiv1.GroupVersionKind, name string) QueryNode {
   153  	return &referenceNode{
   154  		gvk:  gvk,
   155  		name: name,
   156  	}
   157  }
   158  
   159  // rsqlVisitor builds an RSQL string by visiting QueryNodes
   160  type rsqlVisitor struct {
   161  	b strings.Builder
   162  }
   163  
   164  func newRSQLVisitor() *rsqlVisitor {
   165  	return &rsqlVisitor{
   166  		b: strings.Builder{},
   167  	}
   168  }
   169  
   170  func (rv *rsqlVisitor) String() string {
   171  	return rv.b.String()
   172  }
   173  
   174  func (rv *rsqlVisitor) Visit(node QueryNode) {
   175  
   176  	switch n := node.(type) {
   177  
   178  	case andNode:
   179  		rv.b.WriteString("(")
   180  		children := []QueryNode(n)
   181  		for i, child := range children {
   182  			child.Accept(rv)
   183  			if i < len(children)-1 {
   184  				rv.b.WriteString(";")
   185  			}
   186  		}
   187  		rv.b.WriteString(")")
   188  	case orNode:
   189  		rv.b.WriteString("(")
   190  		children := []QueryNode(n)
   191  		for i, child := range children {
   192  			child.Accept(rv)
   193  			if i < len(children)-1 {
   194  				rv.b.WriteString(",")
   195  			}
   196  		}
   197  		rv.b.WriteString(")")
   198  	case namesNode:
   199  		switch len(n) {
   200  		case 0:
   201  			rv.b.WriteString(`name==""`)
   202  		case 1:
   203  			rv.b.WriteString(fmt.Sprintf(`name=="%s"`, n[0]))
   204  		default:
   205  			rv.b.WriteString(fmt.Sprintf(`name=in=("%s")`, strings.Join(n, `","`)))
   206  		}
   207  	case tagNode:
   208  		switch len(n) {
   209  		case 0:
   210  			rv.b.WriteString(`tags==""`)
   211  		case 1:
   212  			rv.b.WriteString(fmt.Sprintf(`tags=="%s"`, n[0]))
   213  		default:
   214  			rv.b.WriteString(fmt.Sprintf(`tags=in=("%s")`, strings.Join(n, `","`)))
   215  		}
   216  	case *attrNode:
   217  		switch len(n.values) {
   218  		case 0:
   219  			rv.b.WriteString(fmt.Sprintf(`attributes.%s==""`, n.key))
   220  		case 1:
   221  			rv.b.WriteString(fmt.Sprintf(`attributes.%s=="%s"`, n.key, n.values[0]))
   222  		default:
   223  			rv.b.WriteString(fmt.Sprintf(`attributes.%s=in=("%s")`, n.key, strings.Join(n.values, `","`)))
   224  		}
   225  	case *referenceNode:
   226  		rv.b.WriteString(fmt.Sprintf(`metadata.references.name==%s;metadata.references.kind==%s`, n.name, n.gvk.GroupKind.Kind))
   227  	default:
   228  		panic(fmt.Sprintf("unknown node type %v", n))
   229  	}
   230  }