findall
[scpubgit/DKit.git] / lib / DX / Op / FindAll.pm
1 package DX::Op::FindAll;
2
3 use DX::Op::FromCode;
4 use DX::Op::FindAllCollect;
5 use DX::Var;
6 use DX::OrderedSet;
7 use DX::Op::Return;
8 use Moo;
9
10 with 'DX::Role::Op';
11
12 has coll_name => (is => 'ro', required => 1);
13
14 has var_name => (is => 'ro', required => 1);
15
16 has body => (is => 'ro', required => 1);
17
18 sub run {
19   my ($self, $state) = @_;
20   my $values = [];
21   my $coll = DX::OrderedSet->new(values => $values);
22   my $collect = DX::Op::FindAllCollect->new(
23     var_name => $self->var_name,
24     into => $values
25   );
26   my $do_body = DX::Op::FromCode->new(
27     code => sub {
28       my ($self, $state) = @_;
29       $state->push_return_then($collect, $self->next);
30     },
31     next => $self->body
32   );
33   my $var = DX::Var->new(id => "rule:findall")
34                    ->with_stream(DX::ArrayStream->from_array(
35                        $do_body, DX::Op::Return->new
36                      ));
37   my $invoke = DX::Op::FromCode->new(
38     code => sub {
39       my ($self, $state) = @_;
40       my $op = $state->resolve_value($var);
41       $state->then($op);
42     }
43   );
44   my $coll_name = $self->coll_name;
45   my $ret = DX::Op::SetScope->new(
46     scope => $state->scope,
47     next => DX::Op::FromCode->new(
48       code => sub {
49         my ($self, $state) = @_;
50         $state->bind_value($state->scope->{$coll_name} => $coll)
51               ->then($self->next);
52       },
53       next => $self->next
54     )
55   );
56   $state->assign_vars($self->var_name => {})
57         ->push_return_then($ret, $invoke)->mark_choice($var);
58 }
59
60 1;