github.com/MontFerret/ferret@v0.18.0/pkg/runtime/expressions/operators/array.go (about)

     1  package operators
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"github.com/MontFerret/ferret/pkg/runtime/core"
     8  	"github.com/MontFerret/ferret/pkg/runtime/values"
     9  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
    10  )
    11  
    12  type (
    13  	ArrayOperatorVariant int
    14  
    15  	ArrayOperator struct {
    16  		*baseOperator
    17  		variant    ArrayOperatorVariant
    18  		comparator core.Predicate
    19  	}
    20  )
    21  
    22  const (
    23  	ArrayOperatorVariantAll ArrayOperatorVariant = iota
    24  	ArrayOperatorVariantAny
    25  	ArrayOperatorVariantNone
    26  )
    27  
    28  func ToArrayOperatorVariant(name string) (ArrayOperatorVariant, error) {
    29  	switch strings.ToUpper(name) {
    30  	case "ALL":
    31  		return ArrayOperatorVariantAll, nil
    32  	case "ANY":
    33  		return ArrayOperatorVariantAny, nil
    34  	case "NONE":
    35  		return ArrayOperatorVariantNone, nil
    36  	default:
    37  		return ArrayOperatorVariant(-1), core.Error(core.ErrInvalidArgument, name)
    38  	}
    39  }
    40  
    41  func NewArrayOperator(
    42  	src core.SourceMap,
    43  	left core.Expression,
    44  	right core.Expression,
    45  	variantStr string,
    46  	comparator core.Predicate,
    47  ) (*ArrayOperator, error) {
    48  	if left == nil {
    49  		return nil, core.Error(core.ErrMissedArgument, "left expression")
    50  	}
    51  
    52  	if right == nil {
    53  		return nil, core.Error(core.ErrMissedArgument, "right expression")
    54  	}
    55  
    56  	variant, err := ToArrayOperatorVariant(variantStr)
    57  
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	if comparator == nil {
    63  		return nil, core.Error(core.ErrMissedArgument, "comparator expression")
    64  	}
    65  
    66  	base := &baseOperator{src, left, right}
    67  
    68  	return &ArrayOperator{base, variant, comparator}, nil
    69  }
    70  
    71  func (operator *ArrayOperator) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) {
    72  	left, err := operator.left.Exec(ctx, scope)
    73  
    74  	if err != nil {
    75  		return values.False, core.SourceError(operator.src, err)
    76  	}
    77  
    78  	right, err := operator.right.Exec(ctx, scope)
    79  
    80  	if err != nil {
    81  		return values.False, core.SourceError(operator.src, err)
    82  	}
    83  
    84  	return operator.Eval(ctx, left, right)
    85  }
    86  
    87  func (operator *ArrayOperator) Eval(ctx context.Context, left, right core.Value) (core.Value, error) {
    88  	err := core.ValidateType(left, types.Array)
    89  
    90  	if err != nil {
    91  		// TODO: Return the error? AQL just returns false
    92  		return values.False, nil
    93  	}
    94  
    95  	arr := left.(*values.Array)
    96  
    97  	switch operator.variant {
    98  	case ArrayOperatorVariantAll:
    99  		return operator.all(ctx, arr, right)
   100  	case ArrayOperatorVariantAny:
   101  		return operator.any(ctx, arr, right)
   102  	default:
   103  		return operator.none(ctx, arr, right)
   104  	}
   105  }
   106  
   107  func (operator *ArrayOperator) all(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) {
   108  	result := values.False
   109  	var err error
   110  
   111  	arr.ForEach(func(el core.Value, _ int) bool {
   112  		out, e := operator.comparator.Eval(ctx, el, value)
   113  
   114  		if e != nil {
   115  			err = e
   116  			return false
   117  		}
   118  
   119  		if out == values.True {
   120  			result = values.True
   121  		} else {
   122  			result = values.False
   123  			return false
   124  		}
   125  
   126  		return true
   127  	})
   128  
   129  	if err != nil {
   130  		return values.False, err
   131  	}
   132  
   133  	return result, nil
   134  }
   135  
   136  func (operator *ArrayOperator) any(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) {
   137  	result := values.False
   138  	var err error
   139  
   140  	arr.ForEach(func(el core.Value, _ int) bool {
   141  		out, e := operator.comparator.Eval(ctx, el, value)
   142  
   143  		if e != nil {
   144  			err = e
   145  			return false
   146  		}
   147  
   148  		if out == values.True {
   149  			result = values.True
   150  			return false
   151  		}
   152  
   153  		return true
   154  	})
   155  
   156  	if err != nil {
   157  		return values.False, err
   158  	}
   159  
   160  	return result, nil
   161  }
   162  
   163  func (operator *ArrayOperator) none(ctx context.Context, arr *values.Array, value core.Value) (core.Value, error) {
   164  	result := values.False
   165  	var err error
   166  
   167  	arr.ForEach(func(el core.Value, _ int) bool {
   168  		out, e := operator.comparator.Eval(ctx, el, value)
   169  
   170  		if e != nil {
   171  			err = e
   172  			return false
   173  		}
   174  
   175  		if out == values.False {
   176  			result = values.True
   177  		} else {
   178  			result = values.False
   179  			return false
   180  		}
   181  
   182  		return true
   183  	})
   184  
   185  	if err != nil {
   186  		return values.False, err
   187  	}
   188  
   189  	return result, nil
   190  }