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 }