...

Source file src/github.com/go-kivik/kivik/v4/x/mango/mango.go

Documentation: github.com/go-kivik/kivik/v4/x/mango

     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, &notNode{
    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  }
   228  

View as plain text