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 }