func (this *DNF) VisitFunction(expr expression.Function) (interface{}, error) { var exp expression.Expression = expr switch expr := expr.(type) { case *expression.IsBoolean: exp = expression.NewLE(expr.Operand(), expression.TRUE_EXPR) case *expression.IsNumber: exp = expression.NewAnd( expression.NewGT(expr.Operand(), expression.TRUE_EXPR), expression.NewLT(expr.Operand(), expression.EMPTY_STRING_EXPR)) case *expression.IsString: exp = expression.NewAnd( expression.NewGE(expr.Operand(), expression.EMPTY_STRING_EXPR), expression.NewLT(expr.Operand(), expression.EMPTY_ARRAY_EXPR)) case *expression.IsArray: exp = expression.NewAnd( expression.NewGE(expr.Operand(), expression.EMPTY_ARRAY_EXPR), expression.NewLT(expr.Operand(), _EMPTY_OBJECT_EXPR)) case *expression.IsObject: // Not equivalent to IS OBJECT. Includes BINARY values. exp = expression.NewGE(expr.Operand(), _EMPTY_OBJECT_EXPR) } return exp, exp.MapChildren(this) }
func newSubsetLike(expr expression.BinaryFunction, re *regexp.Regexp) expression.Visitor { if re == nil { // Pattern is not a constant return newSubsetDefault(expr) } prefix, complete := re.LiteralPrefix() if complete { eq := expression.NewEq(expr.First(), expression.NewConstant(prefix)) return newSubsetEq(eq.(*expression.Eq)) } if prefix == "" { return newSubsetDefault(expr) } var and expression.Expression le := expression.NewLE(expression.NewConstant(prefix), expr.First()) last := len(prefix) - 1 if prefix[last] < math.MaxUint8 { bytes := []byte(prefix) bytes[last]++ and = expression.NewAnd(le, expression.NewLT( expr.First(), expression.NewConstant(string(bytes)))) } else { and = expression.NewAnd(le, expression.NewLT( expr.First(), expression.EMPTY_ARRAY_EXPR)) } sand := newSubsetAnd(and.(*expression.And)) rv := &subsetLike{} rv.test = func(expr2 expression.Expression) (bool, error) { if expr.EquivalentTo(expr2) { return true, nil } return sand.test(expr2) } return rv }
func (this *DNF) VisitNot(expr *expression.Not) (interface{}, error) { err := expr.MapChildren(this) if err != nil { return nil, err } var exp expression.Expression = expr switch operand := expr.Operand().(type) { case *expression.Not: exp = operand.Operand() case *expression.And: operands := make(expression.Expressions, len(operand.Operands())) for i, op := range operand.Operands() { operands[i] = expression.NewNot(op) } exp = expression.NewOr(operands...) case *expression.Or: operands := make(expression.Expressions, len(operand.Operands())) for i, op := range operand.Operands() { operands[i] = expression.NewNot(op) } and := expression.NewAnd(operands...) return this.VisitAnd(and) case *expression.Eq: exp = expression.NewOr(expression.NewLT(operand.First(), operand.Second()), expression.NewLT(operand.Second(), operand.First())) case *expression.LT: exp = expression.NewLE(operand.Second(), operand.First()) case *expression.LE: exp = expression.NewLT(operand.Second(), operand.First()) default: return expr, nil } return exp, exp.MapChildren(this) }
func (this *DNF) VisitLike(expr *expression.Like) (interface{}, error) { err := expr.MapChildren(this) if err != nil { return nil, err } re := expr.Regexp() if re == nil { return expr, nil } prefix, complete := re.LiteralPrefix() if complete { eq := expression.NewEq(expr.First(), expression.NewConstant(prefix)) return eq, nil } if prefix == "" { return expr, nil } var and expression.Expression le := expression.NewLE(expression.NewConstant(prefix), expr.First()) last := len(prefix) - 1 if prefix[last] < math.MaxUint8 { bytes := []byte(prefix) bytes[last]++ and = expression.NewAnd(le, expression.NewLT( expr.First(), expression.NewConstant(string(bytes)))) } else { and = expression.NewAnd(le, expression.NewLT( expr.First(), expression.EMPTY_ARRAY_EXPR)) } return and, nil }
func TestConverter(t *testing.T) { s1 := NewJSConverter().Visit( expression.NewLT(constant("a"), constant("b"))) s2 := "(\"a\" < \"b\")" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit( expression.NewBetween(constant("a"), constant("b"), constant("c"))) s2 = "(\"a\" > \"b\" && \"a\" < \"c\")" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewAdd( expression.NewSub(constant("a"), constant("b")), expression.NewDiv(constant("a"), constant("b")))) s2 = "((\"a\" - \"b\") + (\"a\" / \"b\"))" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewLength(constant("abc"))) s2 = "\"abc\".length" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewUpper(constant("abc"))) s2 = "\"abc\".toUpperCase()" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewStrToMillis(constant("Wed, 09 Aug 1995 00:00:00"))) s2 = "Date.parse(\"Wed, 09 Aug 1995 00:00:00\")" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewContains(constant("dfgabc"), constant("abc"))) s2 = "\"dfgabc\".indexOf(\"abc\")" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewSubstr(constant("dfgabc"), constant(1), constant(4))) s2 = "\"dfgabc\".substring(1,4)" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewAdd(expression.NewContains(constant("dfgabc"), constant("abc")), expression.NewSubstr(constant("dfgabc"), constant(1), constant(4)))) s2 = "(\"dfgabc\".indexOf(\"abc\") + \"dfgabc\".substring(1,4))" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } doc := expression.NewIdentifier("bucket") m1 := expression.NewField(doc, expression.NewFieldName("id", false)) m2 := expression.NewField(doc, expression.NewFieldName("type", false)) s1 = NewJSConverter().Visit(expression.NewOr( expression.NewUpper(m1), expression.NewLower(m2))) s2 = "(`bucket`.`id`.toUpperCase() || `bucket`.`type`.toLowerCase())" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } doc = expression.NewIdentifier("bucket") m1 = expression.NewField(doc, expression.NewFieldName("geo", false)) m2 = expression.NewField(m1, expression.NewFieldName("accuracy", false)) s1 = NewJSConverter().Visit(m2) s2 = "`bucket`.`geo`.`accuracy`" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } doc = expression.NewIdentifier("bucket") m1 = expression.NewField(doc, expression.NewElement(expression.NewFieldName("address", false), constant(0))) s1 = NewJSConverter().Visit(m1) s2 = "`bucket`.`address`[0]" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } s1 = NewJSConverter().Visit(expression.NewLength(expression.NewElement(doc, expression.NewFieldName("type", false)))) s2 = "`bucket`[`type`].length" if s1 != s2 { t.Errorf(" mismatch s1 %s s2 %s", s1, s2) } }