query/solve/ensure
[scpubgit/DKit.git] / lib / DX / Role / Op / FindIsh.pm
1 package DX::Role::Op::FindIsh;
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::Role;
9
10 with 'DX::Role::Op';
11
12 has var_name => (is => 'ro', required => 1);
13
14 has body => (is => 'ro', required => 1);
15
16 requires 'make_result_handler';
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 $allow = $state->allow_actions;
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->but(allow_actions => $allow)
51               ->then($self->next);
52       },
53       next => $self->make_result_handler($coll),
54     )
55   );
56   $state->assign_vars($self->var_name => {})
57         ->but(allow_actions => 0)
58         ->push_return_then($ret, $invoke)->mark_choice($var);
59 }
60
61 1;