Beispiel #1
0
func reduceCount(x interface{}) (ast.Value, error) {
	switch x := x.(type) {
	case []interface{}:
		return ast.IntNumberTerm(len(x)).Value, nil
	case map[string]interface{}:
		return ast.IntNumberTerm(len(x)).Value, nil
	case string:
		return ast.IntNumberTerm(len(x)).Value, nil
	default:
		return nil, fmt.Errorf("count: source must be array, object, or string")
	}
}
Beispiel #2
0
// Ref returns a ref that represents p rooted at head.
func (p Path) Ref(head *ast.Term) (ref ast.Ref) {
	ref = make(ast.Ref, len(p)+1)
	ref[0] = head
	for i := range p {
		idx, err := strconv.ParseInt(p[i], 10, 64)
		if err == nil {
			ref[i+1] = ast.IntNumberTerm(int(idx))
		} else {
			ref[i+1] = ast.StringTerm(p[i])
		}
	}
	return ref
}
Beispiel #3
0
func stringPathToRef(s string) (r ast.Ref) {
	if len(s) == 0 {
		return r
	}
	p := strings.Split(s, "/")
	for _, x := range p {
		if x == "" {
			continue
		}
		i, err := strconv.Atoi(x)
		if err != nil {
			r = append(r, ast.StringTerm(x))
		} else {
			r = append(r, ast.IntNumberTerm(i))
		}
	}
	return r
}
Beispiel #4
0
func evalIndexOf(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.IndexOf.Name)
	}

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

	index := ast.IntNumberTerm(strings.Index(base, search))

	undo, err := evalEqUnify(t, index.Value, ops[3].Value, nil, iter)
	t.Unbind(undo)
	return err
}
Beispiel #5
0
func evalEqUnifyArrayRef(t *Topdown, a ast.Array, b ast.Ref, prev *Undo, iter Iterator) (*Undo, error) {

	r, err := t.Resolve(b)
	if err != nil {
		return prev, err
	}

	slice, ok := r.([]interface{})
	if !ok {
		return prev, nil
	}

	if len(a) != len(slice) {
		return prev, nil
	}

	for i := range a {
		var tmp *Topdown
		child := make(ast.Ref, len(b), len(b)+1)
		copy(child, b)
		child = append(child, ast.IntNumberTerm(i))
		p, err := evalEqUnify(t, a[i].Value, child, prev, func(t *Topdown) error {
			tmp = t
			return nil
		})
		prev = p
		if err != nil {
			return nil, err
		}
		if tmp == nil {
			return nil, nil
		}
		t = tmp
	}
	return prev, iter(t)
}
Beispiel #6
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
}