Example #1
0
func TestEventEqual(t *testing.T) {

	a := ast.NewValueMap()
	a.Put(ast.String("foo"), ast.Number("1"))
	b := ast.NewValueMap()
	b.Put(ast.String("foo"), ast.Number("2"))

	tests := []struct {
		a     *Event
		b     *Event
		equal bool
	}{
		{&Event{}, &Event{}, true},
		{&Event{Op: EvalOp}, &Event{Op: EnterOp}, false},
		{&Event{QueryID: 1}, &Event{QueryID: 2}, false},
		{&Event{ParentID: 1}, &Event{ParentID: 2}, false},
		{&Event{Node: ast.MustParseBody("true")}, &Event{Node: ast.MustParseBody("false")}, false},
		{&Event{Node: ast.MustParseBody("true")[0]}, &Event{Node: ast.MustParseBody("false")[0]}, false},
		{&Event{Node: ast.MustParseRule("p :- true")}, &Event{Node: ast.MustParseRule("p :- false")}, false},
		{&Event{Node: "foo"}, &Event{Node: "foo"}, false}, // test some unsupported node type
	}

	for _, tc := range tests {
		if tc.a.Equal(tc.b) != tc.equal {
			var s string
			if tc.equal {
				s = "=="
			} else {
				s = "!="
			}
			t.Errorf("Expected %v %v %v", tc.a, s, tc.b)
		}
	}

}
Example #2
0
func evalSubstring(t *Topdown, expr *ast.Expr, iter Iterator) error {
	ops := expr.Terms.([]*ast.Term)

	base, err := ValueToString(ops[1].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: base value must be a string", ast.Substring.Name)
	}

	startIndex, err := ValueToInt(ops[2].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: start index must be a number", ast.Substring.Name)
	}

	l, err := ValueToInt(ops[3].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: length must be a number", ast.Substring.Name)
	}

	var s ast.String
	if l < 0 {
		s = ast.String(base[startIndex:])
	} else {
		s = ast.String(base[startIndex : startIndex+l])
	}

	undo, err := evalEqUnify(t, s, ops[4].Value, nil, iter)
	t.Unbind(undo)
	return err
}
Example #3
0
func evalFormatInt(t *Topdown, expr *ast.Expr, iter Iterator) error {
	ops := expr.Terms.([]*ast.Term)

	input, err := ValueToJSONNumber(ops[1].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: input must be a number", ast.FormatInt.Name)
	}

	i, _ := jsonNumberToFloat(input).Int(nil)

	base, err := ValueToInt(ops[2].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: base must be an integer", ast.FormatInt.Name)
	}

	var format string
	switch base {
	case 2:
		format = "%b"
	case 8:
		format = "%o"
	case 10:
		format = "%d"
	case 16:
		format = "%x"
	default:
		return errors.Wrapf(err, "%v: base must be one of 2, 8, 10, 16", ast.FormatInt.Name)
	}

	s := ast.String(fmt.Sprintf(format, i))

	undo, err := evalEqUnify(t, s, ops[3].Value, nil, iter)
	t.Unbind(undo)
	return err
}
Example #4
0
func evalUpper(t *Topdown, expr *ast.Expr, iter Iterator) error {
	ops := expr.Terms.([]*ast.Term)

	orig, err := ValueToString(ops[1].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: original value must be a string", ast.Upper.Name)
	}

	s := ast.String(strings.ToUpper(orig))

	undo, err := evalEqUnify(t, s, ops[2].Value, nil, iter)
	t.Unbind(undo)
	return err
}
Example #5
0
func evalConcat(t *Topdown, expr *ast.Expr, iter Iterator) error {
	ops := expr.Terms.([]*ast.Term)

	join, err := ValueToString(ops[1].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: join value must be a string", ast.Concat.Name)
	}

	sl, err := ValueToStrings(ops[2].Value, t)
	if err != nil {
		return errors.Wrapf(err, "%v: input value must be array of strings", ast.Concat.Name)
	}

	s := ast.String(strings.Join(sl, join))

	undo, err := evalEqUnify(t, s, ops[3].Value, nil, iter)
	t.Unbind(undo)
	return err
}
Example #6
0
func loadExpectedBindings(input string) []*ast.ValueMap {
	var data []map[string]interface{}
	if err := util.UnmarshalJSON([]byte(input), &data); err != nil {
		panic(err)
	}
	var expected []*ast.ValueMap
	for _, bindings := range data {
		buf := ast.NewValueMap()
		for k, v := range bindings {
			switch v := v.(type) {
			case string:
				buf.Put(ast.Var(k), ast.String(v))
			case json.Number:
				buf.Put(ast.Var(k), ast.Number(v))
			default:
				panic("unreachable")
			}
		}
		expected = append(expected, buf)
	}
	return expected
}
Example #7
0
func iterStorage(ctx context.Context, store Store, txn Transaction, nonGround, ground ast.Ref, bindings *ast.ValueMap, iter func(*ast.ValueMap, interface{})) error {

	if len(nonGround) == 0 {
		path, err := NewPathForRef(ground)
		if err != nil {
			return err
		}
		node, err := store.Read(ctx, txn, path)
		if err != nil {
			if IsNotFound(err) {
				return nil
			}
			return err
		}
		iter(bindings, node)
		return nil
	}

	head := nonGround[0]
	tail := nonGround[1:]

	headVar, isVar := head.Value.(ast.Var)

	if !isVar || len(ground) == 0 {
		ground = append(ground, head)
		return iterStorage(ctx, store, txn, tail, ground, bindings, iter)
	}

	path, err := NewPathForRef(ground)
	if err != nil {
		return err
	}

	node, err := store.Read(ctx, txn, path)
	if err != nil {
		if IsNotFound(err) {
			return nil
		}
		return err
	}

	switch node := node.(type) {
	case map[string]interface{}:
		for key := range node {
			ground = append(ground, ast.StringTerm(key))
			cpy := bindings.Copy()
			cpy.Put(headVar, ast.String(key))
			err := iterStorage(ctx, store, txn, tail, ground, cpy, iter)
			if err != nil {
				return err
			}
			ground = ground[:len(ground)-1]
		}
	case []interface{}:
		for i := range node {
			idx := ast.IntNumberTerm(i)
			ground = append(ground, idx)
			cpy := bindings.Copy()
			cpy.Put(headVar, idx.Value)
			err := iterStorage(ctx, store, txn, tail, ground, cpy, iter)
			if err != nil {
				return err
			}
			ground = ground[:len(ground)-1]
		}
	}

	return nil
}