github.com/go-kivik/kivik/v4@v4.3.2/x/mango/selector.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 // Package mango provides a Mango query language parser and evaluator. 14 package mango 15 16 import ( 17 "fmt" 18 "regexp" 19 "strings" 20 21 "github.com/go-kivik/kivik/v4/x/collate" 22 ) 23 24 // Node represents a node in the Mango Selector. 25 type Node interface { 26 Op() Operator 27 Value() interface{} 28 String() string 29 Match(interface{}) bool 30 } 31 32 type notNode struct { 33 sel Node 34 } 35 36 var _ Node = (*notNode)(nil) 37 38 func (*notNode) Op() Operator { 39 return OpNot 40 } 41 42 func (n *notNode) Value() interface{} { 43 return n.sel 44 } 45 46 func (n *notNode) String() string { 47 return fmt.Sprintf("%s %s", OpNot, n.sel) 48 } 49 50 func (n *notNode) Match(doc interface{}) bool { 51 return !n.sel.Match(doc) 52 } 53 54 type combinationNode struct { 55 op Operator 56 sel []Node 57 } 58 59 var _ Node = (*combinationNode)(nil) 60 61 func (c *combinationNode) Op() Operator { 62 return c.op 63 } 64 65 func (c *combinationNode) Value() interface{} { 66 return c.sel 67 } 68 69 func (c *combinationNode) String() string { 70 var sb strings.Builder 71 sb.WriteString(string(c.op)) 72 sb.WriteString(" [") 73 for i, sel := range c.sel { 74 if i > 0 { 75 sb.WriteString(", ") 76 } 77 sb.WriteString(fmt.Sprintf("%v", sel)) 78 } 79 sb.WriteString("]") 80 return sb.String() 81 } 82 83 func (c *combinationNode) Match(doc interface{}) bool { 84 switch c.op { 85 case OpAnd: 86 for _, sel := range c.sel { 87 if !sel.Match(doc) { 88 return false 89 } 90 } 91 return true 92 case OpOr: 93 for _, sel := range c.sel { 94 if sel.Match(doc) { 95 return true 96 } 97 } 98 return false 99 case OpNor: 100 for _, sel := range c.sel { 101 if sel.Match(doc) { 102 return false 103 } 104 } 105 return true 106 } 107 panic("not implemented") 108 } 109 110 type fieldNode struct { 111 field string 112 cond Node 113 } 114 115 var _ Node = (*fieldNode)(nil) 116 117 func (f *fieldNode) Op() Operator { 118 return f.cond.Op() 119 } 120 121 func (f *fieldNode) Value() interface{} { 122 return f.cond.Value() 123 } 124 125 func (f *fieldNode) String() string { 126 return fmt.Sprintf("%s %s", f.field, f.cond.String()) 127 } 128 129 func (f *fieldNode) Match(doc interface{}) bool { 130 val := doc 131 132 // Traverse nested fields (e.g. "foo.bar.baz") 133 segments := SplitKeys(f.field) 134 for _, segment := range segments { 135 m, ok := val.(map[string]interface{}) 136 if !ok { 137 return false 138 } 139 140 val = m[segment] 141 } 142 143 // Even if the field does not exist we need to pass it to the condition expression because of `$exists` 144 return f.cond.Match(val) 145 } 146 147 type conditionNode struct { 148 op Operator 149 cond interface{} 150 } 151 152 var _ Node = (*conditionNode)(nil) 153 154 func (e *conditionNode) Op() Operator { 155 return e.op 156 } 157 158 func (e *conditionNode) Value() interface{} { 159 return e.cond 160 } 161 162 func (e *conditionNode) String() string { 163 return fmt.Sprintf("%s %v", e.op, e.cond) 164 } 165 166 func (e *conditionNode) Match(doc interface{}) bool { 167 switch e.op { 168 case OpEqual: 169 return collate.CompareObject(doc, e.cond) == 0 170 case OpNotEqual: 171 return collate.CompareObject(doc, e.cond) != 0 172 case OpLessThan: 173 return collate.CompareObject(doc, e.cond) < 0 174 case OpLessThanOrEqual: 175 return collate.CompareObject(doc, e.cond) <= 0 176 case OpGreaterThan: 177 return collate.CompareObject(doc, e.cond) > 0 178 case OpGreaterThanOrEqual: 179 return collate.CompareObject(doc, e.cond) >= 0 180 case OpExists: 181 return (doc != nil) == e.cond.(bool) 182 case OpType: 183 switch tp := e.cond.(string); tp { 184 case "null": 185 return doc == nil 186 case "boolean": 187 _, ok := doc.(bool) 188 return ok 189 case "number": 190 _, ok := doc.(float64) 191 return ok 192 case "string": 193 _, ok := doc.(string) 194 return ok 195 case "array": 196 _, ok := doc.([]interface{}) 197 return ok 198 case "object": 199 _, ok := doc.(map[string]interface{}) 200 return ok 201 default: 202 panic("unexpected $type value: " + tp) 203 } 204 case OpIn: 205 for _, v := range e.cond.([]interface{}) { 206 if collate.CompareObject(doc, v) == 0 { 207 return true 208 } 209 } 210 return false 211 case OpNotIn: 212 for _, v := range e.cond.([]interface{}) { 213 if collate.CompareObject(doc, v) == 0 { 214 return false 215 } 216 } 217 return true 218 case OpSize: 219 array, ok := doc.([]interface{}) 220 if !ok { 221 return false 222 } 223 return float64(len(array)) == e.cond.(float64) 224 case OpMod: 225 num, ok := doc.(float64) 226 if !ok { 227 return false 228 } 229 if num != float64(int(num)) { 230 return false 231 } 232 mod := e.cond.([2]int64) 233 return int64(num)%mod[0] == mod[1] 234 case OpRegex: 235 str, ok := doc.(string) 236 if !ok { 237 return false 238 } 239 return e.cond.(*regexp.Regexp).MatchString(str) 240 case OpAll: 241 array, ok := doc.([]interface{}) 242 if !ok { 243 return false 244 } 245 for _, v := range e.cond.([]interface{}) { 246 if !contains(array, v) { 247 return false 248 } 249 } 250 return true 251 } 252 return false 253 } 254 255 func contains(haystack []interface{}, needle interface{}) bool { 256 for _, v := range haystack { 257 if collate.CompareObject(v, needle) == 0 { 258 return true 259 } 260 } 261 return false 262 } 263 264 type elementNode struct { 265 op Operator 266 cond *conditionNode 267 } 268 269 var _ Node = (*elementNode)(nil) 270 271 func (e *elementNode) Op() Operator { 272 return e.op 273 } 274 275 func (e *elementNode) Value() interface{} { 276 return e.cond 277 } 278 279 func (e *elementNode) String() string { 280 return fmt.Sprintf("%s {%s}", e.op, e.cond) 281 } 282 283 func (e *elementNode) Match(doc interface{}) bool { 284 switch e.op { 285 case OpElemMatch: 286 array, ok := doc.([]interface{}) 287 if !ok { 288 return false 289 } 290 for _, v := range array { 291 if e.cond.Match(v) { 292 return true 293 } 294 } 295 return false 296 case OpAllMatch: 297 array, ok := doc.([]interface{}) 298 if !ok { 299 return false 300 } 301 for _, v := range array { 302 if !e.cond.Match(v) { 303 return false 304 } 305 } 306 return true 307 case OpKeyMapMatch: 308 object, ok := doc.(map[string]interface{}) 309 if !ok { 310 return false 311 } 312 for k := range object { 313 if k == e.cond.cond.(string) { 314 return e.cond.Match(k) 315 } 316 } 317 return false 318 } 319 panic("unready") 320 } 321 322 // cmpValues compares two arbitrary values by converting them to strings. 323 func cmpValues(a, b interface{}) int { 324 return strings.Compare(fmt.Sprintf("%v", a), fmt.Sprintf("%v", b)) 325 } 326 327 // cmpSelectors compares two selectors, for ordering. 328 func cmpSelectors(a, b Node) int { 329 // Naively sort operators alphabetically. 330 if c := strings.Compare(string(a.Op()), string(b.Op())); c != 0 { 331 return c 332 } 333 switch t := a.(type) { 334 case *notNode: 335 u := b.(*notNode) 336 return cmpSelectors(t.sel, u.sel) 337 case *combinationNode: 338 u := b.(*combinationNode) 339 for i := 0; i < len(t.sel) && i < len(u.sel); i++ { 340 if c := cmpSelectors(t.sel[i], u.sel[i]); c != 0 { 341 return c 342 } 343 } 344 return len(t.sel) - len(u.sel) 345 case *fieldNode: 346 u := b.(*fieldNode) 347 if c := strings.Compare(t.field, u.field); c != 0 { 348 return c 349 } 350 return cmpSelectors(t.cond, u.cond) 351 case *conditionNode: 352 u := b.(*conditionNode) 353 switch t.op { 354 case OpIn, OpNotIn: 355 for i := 0; i < len(t.cond.([]interface{})) && i < len(u.cond.([]interface{})); i++ { 356 if c := cmpValues(t.cond.([]interface{})[i], u.cond.([]interface{})[i]); c != 0 { 357 return c 358 } 359 } 360 return len(t.cond.([]interface{})) - len(u.cond.([]interface{})) 361 case OpMod: 362 tm := t.cond.([2]int) 363 um := u.cond.([2]int) 364 if tm[0] != um[0] { 365 return tm[0] - um[0] 366 } 367 return tm[1] - um[1] 368 default: 369 return cmpValues(t.cond, u.cond) 370 } 371 } 372 return 0 373 } 374 375 // SplitKeys splits a field into its component keys. For example, 376 // "foo.bar" is split into `["foo", "bar"]`. Escaped dots are not treated 377 // as separators, so `"foo\\.bar"` becomes `["foo.bar"]`. 378 func SplitKeys(field string) []string { 379 var escaped bool 380 result := []string{} 381 word := make([]byte, 0, len(field)) 382 for _, ch := range field { 383 if escaped { 384 word = append(word, byte(ch)) 385 escaped = false 386 continue 387 } 388 if ch == '\\' { 389 escaped = true 390 continue 391 } 392 if ch == '.' { 393 result = append(result, string(word)) 394 word = word[:0] 395 continue 396 } 397 word = append(word, byte(ch)) 398 } 399 if escaped { 400 word = append(word, '\\') 401 } 402 return append(result, string(word)) 403 }