github.com/go-kivik/kivik/v4@v4.3.2/x/mango/mango.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 14 15 import ( 16 "encoding/json" 17 "errors" 18 "fmt" 19 "regexp" 20 "sort" 21 ) 22 23 // Selector represents a Mango Selector tree. 24 type Selector struct { 25 root Node 26 } 27 28 // Match returns true if doc matches the selector. 29 func (s *Selector) Match(doc interface{}) bool { 30 return s.root.Match(doc) 31 } 32 33 // UnmarshalJSON parses the JSON-encoded data and stores the result in s. 34 func (s *Selector) UnmarshalJSON(data []byte) error { 35 node, err := Parse(data) 36 if err != nil { 37 return err 38 } 39 s.root = node 40 return nil 41 } 42 43 // Parse parses s into a Mango Selector tree. 44 func Parse(input []byte) (Node, error) { 45 var tmp map[string]json.RawMessage 46 if err := json.Unmarshal(input, &tmp); err != nil { 47 return nil, err 48 } 49 if len(tmp) == 0 { 50 // Empty object is an implicit $and 51 return &combinationNode{ 52 op: OpAnd, 53 sel: nil, 54 }, nil 55 } 56 sels := make([]Node, 0, len(tmp)) 57 for k, v := range tmp { 58 switch op := Operator(k); op { 59 case OpAnd, OpOr, OpNor: 60 var sel []json.RawMessage 61 if err := json.Unmarshal(v, &sel); err != nil { 62 return nil, fmt.Errorf("%s: %w", k, err) 63 } 64 subsels := make([]Node, 0, len(sel)) 65 for _, s := range sel { 66 sel, err := Parse(s) 67 if err != nil { 68 return nil, fmt.Errorf("%s: %w", k, err) 69 } 70 subsels = append(subsels, sel) 71 } 72 73 sels = append(sels, &combinationNode{ 74 op: op, 75 sel: subsels, 76 }) 77 case OpNot: 78 sel, err := Parse(v) 79 if err != nil { 80 return nil, fmt.Errorf("%s: %w", k, err) 81 } 82 sels = append(sels, ¬Node{ 83 sel: sel, 84 }) 85 case OpEqual, OpLessThan, OpLessThanOrEqual, OpNotEqual, 86 OpGreaterThan, OpGreaterThanOrEqual: 87 op, value, err := opAndValue(v) 88 if err != nil { 89 return nil, err 90 } 91 sels = append(sels, &conditionNode{ 92 op: op, 93 cond: value, 94 }) 95 default: 96 if op[0] == '$' { 97 return nil, fmt.Errorf("unknown operator %s", op) 98 } 99 op, value, err := opAndValue(v) 100 if err != nil { 101 return nil, err 102 } 103 104 switch op { 105 case OpElemMatch, OpAllMatch, OpKeyMapMatch: 106 sels = append(sels, &fieldNode{ 107 field: k, 108 cond: &elementNode{ 109 op: op, 110 cond: value.(*conditionNode), 111 }, 112 }) 113 default: 114 sels = append(sels, &fieldNode{ 115 field: k, 116 cond: &conditionNode{ 117 op: op, 118 cond: value, 119 }, 120 }) 121 } 122 } 123 } 124 if len(sels) == 1 { 125 return sels[0], nil 126 } 127 128 // Sort the selectors to ensure deterministic output. 129 sort.Slice(sels, func(i, j int) bool { 130 return cmpSelectors(sels[i], sels[j]) < 0 131 }) 132 133 return &combinationNode{ 134 op: OpAnd, 135 sel: sels, 136 }, nil 137 } 138 139 // opAndValue is called when the input is an object in a context where a 140 // comparison operator is expected. It returns the operator and value, 141 // defaulting to [OpEqual] if no operator is specified. 142 func opAndValue(input json.RawMessage) (Operator, interface{}, error) { 143 if input[0] != '{' { 144 var value interface{} 145 if err := json.Unmarshal(input, &value); err != nil { 146 return "", nil, err 147 } 148 return OpEqual, value, nil 149 } 150 var tmp map[string]json.RawMessage 151 if err := json.Unmarshal(input, &tmp); err != nil { 152 return "", nil, err 153 } 154 switch len(tmp) { 155 case 0: 156 return OpEqual, map[string]interface{}{}, nil 157 case 1: 158 for k, v := range tmp { 159 switch op := Operator(k); op { 160 case OpEqual, OpLessThan, OpLessThanOrEqual, OpNotEqual, 161 OpGreaterThan, OpGreaterThanOrEqual: 162 var value interface{} 163 err := json.Unmarshal(v, &value) 164 return op, value, err 165 case OpExists: 166 var value bool 167 if err := json.Unmarshal(v, &value); err != nil { 168 return "", nil, fmt.Errorf("%s: %w", k, err) 169 } 170 return OpExists, value, nil 171 case OpType: 172 var value string 173 if err := json.Unmarshal(v, &value); err != nil { 174 return "", nil, fmt.Errorf("%s: %w", k, err) 175 } 176 return OpType, value, nil 177 case OpIn, OpNotIn: 178 var value []interface{} 179 if err := json.Unmarshal(v, &value); err != nil { 180 return "", nil, fmt.Errorf("%s: %w", k, err) 181 } 182 return op, value, nil 183 case OpSize: 184 var value uint 185 if err := json.Unmarshal(v, &value); err != nil { 186 return "", nil, fmt.Errorf("%s: %w", k, err) 187 } 188 return OpSize, float64(value), nil 189 case OpMod: 190 var value [2]int64 191 if err := json.Unmarshal(v, &value); err != nil { 192 return "", nil, fmt.Errorf("%s: %w", k, err) 193 } 194 if value[0] == 0 { 195 return "", nil, errors.New("$mod: divisor must be non-zero") 196 } 197 return OpMod, value, nil 198 case OpRegex: 199 var pattern string 200 if err := json.Unmarshal(v, &pattern); err != nil { 201 return "", nil, fmt.Errorf("%s: %w", k, err) 202 } 203 re, err := regexp.Compile(pattern) 204 if err != nil { 205 return "", nil, fmt.Errorf("%s: %w", k, err) 206 } 207 return OpRegex, re, nil 208 case OpAll: 209 var value []interface{} 210 if err := json.Unmarshal(v, &value); err != nil { 211 return "", nil, fmt.Errorf("%s: %w", k, err) 212 } 213 return OpAll, value, nil 214 case OpElemMatch, OpAllMatch, OpKeyMapMatch: 215 sel, err := Parse(v) 216 if err != nil { 217 return "", nil, fmt.Errorf("%s: %w", k, err) 218 } 219 return op, sel, nil 220 } 221 return "", nil, fmt.Errorf("invalid operator %s", k) 222 } 223 default: 224 return "", nil, errors.New("too many keys in object") 225 } 226 panic("impossible") 227 }