github.com/cayleygraph/cayley@v0.7.7/graph/iterator/value_comparison.go (about)

     1  // Copyright 2014 The Cayley Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package iterator
    16  
    17  // "Value Comparison" is a unary operator -- a filter across the values in the
    18  // relevant subiterator.
    19  //
    20  // This is hugely useful for things like label, but value ranges in general
    21  // come up from time to time. At *worst* we're as big as our underlying iterator.
    22  // At best, we're the null iterator.
    23  //
    24  // This is ripe for backend-side optimization. If you can run a value iterator,
    25  // from a sorted set -- some sort of value index, then go for it.
    26  //
    27  // In MQL terms, this is the [{"age>=": 21}] concept.
    28  
    29  import (
    30  	"fmt"
    31  	"time"
    32  
    33  	"github.com/cayleygraph/cayley/graph"
    34  	"github.com/cayleygraph/quad"
    35  )
    36  
    37  type Operator int
    38  
    39  func (op Operator) String() string {
    40  	switch op {
    41  	case CompareLT:
    42  		return "<"
    43  	case CompareLTE:
    44  		return "<="
    45  	case CompareGT:
    46  		return ">"
    47  	case CompareGTE:
    48  		return ">="
    49  	default:
    50  		return fmt.Sprintf("op(%d)", int(op))
    51  	}
    52  }
    53  
    54  const (
    55  	CompareLT Operator = iota
    56  	CompareLTE
    57  	CompareGT
    58  	CompareGTE
    59  	// Why no Equals? Because that's usually an AndIterator.
    60  )
    61  
    62  func NewComparison(sub graph.Iterator, op Operator, val quad.Value, qs graph.Namer) graph.Iterator {
    63  	return NewValueFilter(qs, sub, func(qval quad.Value) (bool, error) {
    64  		switch cVal := val.(type) {
    65  		case quad.Int:
    66  			if cVal2, ok := qval.(quad.Int); ok {
    67  				return RunIntOp(cVal2, op, cVal), nil
    68  			}
    69  			return false, nil
    70  		case quad.Float:
    71  			if cVal2, ok := qval.(quad.Float); ok {
    72  				return RunFloatOp(cVal2, op, cVal), nil
    73  			}
    74  			return false, nil
    75  		case quad.String:
    76  			if cVal2, ok := qval.(quad.String); ok {
    77  				return RunStrOp(string(cVal2), op, string(cVal)), nil
    78  			}
    79  			return false, nil
    80  		case quad.BNode:
    81  			if cVal2, ok := qval.(quad.BNode); ok {
    82  				return RunStrOp(string(cVal2), op, string(cVal)), nil
    83  			}
    84  			return false, nil
    85  		case quad.IRI:
    86  			if cVal2, ok := qval.(quad.IRI); ok {
    87  				return RunStrOp(string(cVal2), op, string(cVal)), nil
    88  			}
    89  			return false, nil
    90  		case quad.Time:
    91  			if cVal2, ok := qval.(quad.Time); ok {
    92  				return RunTimeOp(time.Time(cVal2), op, time.Time(cVal)), nil
    93  			}
    94  			return false, nil
    95  		default:
    96  			return RunStrOp(quad.StringOf(qval), op, quad.StringOf(val)), nil
    97  		}
    98  	})
    99  }
   100  
   101  func RunIntOp(a quad.Int, op Operator, b quad.Int) bool {
   102  	switch op {
   103  	case CompareLT:
   104  		return a < b
   105  	case CompareLTE:
   106  		return a <= b
   107  	case CompareGT:
   108  		return a > b
   109  	case CompareGTE:
   110  		return a >= b
   111  	default:
   112  		panic("Unknown operator type")
   113  	}
   114  }
   115  
   116  func RunFloatOp(a quad.Float, op Operator, b quad.Float) bool {
   117  	switch op {
   118  	case CompareLT:
   119  		return a < b
   120  	case CompareLTE:
   121  		return a <= b
   122  	case CompareGT:
   123  		return a > b
   124  	case CompareGTE:
   125  		return a >= b
   126  	default:
   127  		panic("Unknown operator type")
   128  	}
   129  }
   130  
   131  func RunStrOp(a string, op Operator, b string) bool {
   132  	switch op {
   133  	case CompareLT:
   134  		return a < b
   135  	case CompareLTE:
   136  		return a <= b
   137  	case CompareGT:
   138  		return a > b
   139  	case CompareGTE:
   140  		return a >= b
   141  	default:
   142  		panic("Unknown operator type")
   143  	}
   144  }
   145  
   146  func RunTimeOp(a time.Time, op Operator, b time.Time) bool {
   147  	switch op {
   148  	case CompareLT:
   149  		return a.Before(b)
   150  	case CompareLTE:
   151  		return !a.After(b)
   152  	case CompareGT:
   153  		return a.After(b)
   154  	case CompareGTE:
   155  		return !a.Before(b)
   156  	default:
   157  		panic("Unknown operator type")
   158  	}
   159  }