value_path will work fine for new-value binding, identity_path not required
[scpubgit/DX.git] / lib / DX / Predicate / MemberAt.pm
1 package DX::Predicate::MemberAt;
2
3 use DX::Utils qw(step INDICES_OF EXISTENCE_OF CONTENTS_OF string);
4 use DX::ActionBuilder::ProxySetToAdd;
5 use DX::ActionBuilder::Null;
6 use DX::Class;
7
8 with 'DX::Role::Predicate';
9
10 sub _possible_resolution_list {
11   my ($self, $coll, $key, $value) = @_;
12   die "First argument to member_at must be a structured value"
13     unless $coll->does('DX::Role::StructuredValue');
14   return (
15     ($key->is_set
16       ? map $_->but_with_dependencies_on(
17           [ undef ,=>
18             [ EXISTENCE_OF ,=> $coll, $key->string_value ],
19             [ CONTENTS_OF ,=> $key ],
20           ]
21         ), do {
22           if (my $cur_val = $coll->get_member_at($key)) {
23             $self->_make_equal($cur_val, $value);
24           } elsif (
25             $value->is_set
26             and my $add = $coll->action_for_add_member($key, $value)
27           ) {
28             step(
29               actions => [ $add ],
30               depends_on => [
31                 [ $value =>
32                   [ CONTENTS_OF ,=> $coll, $key->string_value ],
33                   [ CONTENTS_OF ,=> $value ],
34                 ],
35               ],
36             );
37           } elsif (
38             !$value->is_set
39             and $value->action_builder->isa('DX::ActionBuilder::UnsetValue')
40             and my $p = $coll->value_path
41           ) {
42             my @path = (@$p, $key->string_value);
43             my $ab = DX::ActionBuilder::ProxySetToAdd->new(
44               target_path => \@path,
45               proxy_to => $coll->action_builder,
46             );
47             my $set = $value->action_for_set_value(
48                         $value->but(
49                           action_builder => $ab
50                         )
51                       );
52             step(
53               actions => [ $set ],
54               depends_on => [
55                 [ $value =>
56                   [ CONTENTS_OF ,=> $coll, $key->string_value ],
57                   [ CONTENTS_OF ,=> $value ],
58                 ],
59               ],
60             );
61           } else {
62             ()
63           }
64         }
65       : ()
66     ),
67     (!$key->is_set
68      && $key->action_builder->isa('DX::ActionBuilder::UnsetValue')
69       ? map {
70           my $set_key = DX::Action::SetValue->new(
71             target_path => $key->action_builder->target_path,
72             new_value => DX::ActionBuilder::Null->new(
73                            target_path => $key->action_builder->target_path,
74                          )->apply_to_value(string(my $kstr = $_))
75           );
76           map $_->but_first($set_key)
77                 ->but_with_dependencies_on(
78                     [ undef ,=>
79                       [ EXISTENCE_OF ,=> $coll, $kstr ],
80                       [ CONTENTS_OF ,=> $key ],
81                     ]
82                   ),
83             $self->_make_equal($coll->get_member_at($_), $value);
84         } $coll->index_list
85       : ()
86     ),
87   );
88 }
89
90 sub selection_depends_on {
91   my ($self, $coll, $key, $value) = @_;
92   die "NEEDS REDOING";
93   [ [ $coll => ($key->can_set_value ? INDICES_OF : (EXISTENCE_OF ,=> $key)) ],
94     $key,
95     $value,
96   ]
97 }
98
99 1;