Example #1
0
/*
Apply constant folding. Remove any constant terms.
*/
func (this *DNF) VisitOr(expr *expression.Or) (interface{}, error) {
	err := expr.MapChildren(this)
	if err != nil {
		return nil, err
	}

	// Constant folding
	var terms expression.Expressions
	for _, term := range expr.Operands() {
		val := term.Value()
		if val == nil {
			if terms == nil {
				terms = make(expression.Expressions, 0, len(expr.Operands()))
			}

			terms = append(terms, term)
			continue
		}

		if val.Truth() {
			return expression.TRUE_EXPR, nil
		}
	}

	if len(terms) == 0 {
		return expression.FALSE_EXPR, nil
	}

	if len(terms) < len(expr.Operands()) {
		expr = expression.NewOr(terms...)
	}

	return expr, nil
}
Example #2
0
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)
}
Example #3
0
func (this *DNF) VisitIn(expr *expression.In) (interface{}, error) {
	err := expr.MapChildren(this)
	if err != nil {
		return nil, err
	}

	a, ok := expr.Second().(*expression.ArrayConstruct)
	if !ok {
		return expr, nil
	}

	first := expr.First()
	operands := make(expression.Expressions, len(a.Operands()))
	for i, op := range a.Operands() {
		operands[i] = expression.NewEq(first, op)
	}

	return expression.NewOr(operands...), nil
}
Example #4
0
/*
Bounded DNF, to mitigate combinatorial worst-case.

Internally apply Disjunctive Normal Form.

Convert ANDs of ORs to ORs of ANDs. For example:

(A OR B) AND C => (A AND C) OR (B AND C)
*/
func applyDNF(expr *expression.And, level int) expression.Expression {
	na := len(expr.Operands())
	if na > 4 {
		return expr
	}

	for i, aterm := range expr.Operands() {
		switch aterm := aterm.(type) {
		case *expression.Or:
			no := len(aterm.Operands())
			if no*na > 8 {
				return expr
			}

			oterms := make(expression.Expressions, no)

			for j, oterm := range aterm.Operands() {
				aterms := make(expression.Expressions, na)
				for ii, atrm := range expr.Operands() {
					if ii == i {
						aterms[ii] = oterm
					} else {
						aterms[ii] = atrm
					}
				}

				if level > 2 {
					oterms[j] = expression.NewAnd(aterms...)
				} else {
					oterms[j] = applyDNF(expression.NewAnd(aterms...), level+1)
				}
			}

			rv := expression.NewOr(oterms...)
			return rv
		}
	}

	return expr
}
Example #5
0
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)
	}

}