package DX::Predicate::MemberAt;
-use DX::Utils qw(step INDICES_OF EXISTENCE_OF CONTENTS_OF string);
+use DX::Utils qw(:builders :dep_types);
+use DX::ActionBuilder::ProxySetToAdd;
+use DX::ActionBuilder::Null;
use DX::Class;
with 'DX::Role::Predicate';
-# Thing I've ignored for the moment: set key, unset value
-# which for an add should result in an _make_equal style
-# bind-with-add-action I suspect, but I don't have a current use
-# case so punting while I get everything-the-fuck-else done
-
sub _possible_resolution_list {
- my ($self, $coll, $key, $value) = @_;
- die "First argument to member_at must be a structured value"
- unless $coll->does('DX::Role::StructuredValue');
- return (
- ($key->is_set
- ? map $_->but_with_dependencies_on(
- [ undef ,=>
- [ EXISTENCE_OF ,=> $coll, $key->string_value ],
- [ CONTENTS_OF ,=> $key ],
- ]
- ), do {
- if (my $cur_val = $coll->get_member_at($key)) {
- $self->_make_equal($cur_val, $value);
- } elsif (
- $value->is_set
- and my $add = $coll->action_for_add_member($key, $value)
- ) {
+ my ($self, @args) = @_;
+ my $rspace = $self->_resolution_space_for(@args);
+ return () unless my @members = @{$rspace->members};
+ return map {
+ $_->isa('DX::Resolution')
+ ? step(
+ actions => $_->actions,
+ depends_on => $_->veracity_depends_on,
+ )
+ : do {
+ my ($db, @ap) = (
+ $_->veracity_depends_on_builder, @{$_->action_prototypes}
+ );
+ map {
+ my @cand = @{$_};
step(
- actions => [ $add ],
- depends_on => [
- [ $value =>
- [ CONTENTS_OF ,=> $coll, $key->string_value ],
- [ CONTENTS_OF ,=> $value ],
- ],
+ actions => [
+ map {
+ my ($inv, $type, @args) = @{$ap[$_]};
+ $inv->${\"action_for_${type}"}(@args, @{$cand[$_]});
+ } 0..$#ap
],
- );
- } else {
- ()
- }
+ depends_on => $db->(@cand),
+ )
+ } @{$_->implementation_candidates};
}
- : ()
- ),
- ($key->can_set_value
- ? map {
- my $set_key = $key->action_for_set_value(string(my $kstr = $_));
- map $_->but_first($set_key)
- ->but_with_dependencies_on(
- [ undef ,=>
- [ EXISTENCE_OF ,=> $coll, $kstr ]
- ]
- ),
- $self->_make_equal($coll->get_member_at($_), $value);
- } $coll->index_list
- : ()
- ),
- );
+ } @members;
}
-sub selection_depends_on {
- my ($self, $coll, $key, $value) = @_;
- die "NEEDS REDOING";
- [ [ $coll => ($key->can_set_value ? INDICES_OF : (EXISTENCE_OF ,=> $key)) ],
- $key,
- $value,
- ]
+# member_at Dict Key Value
+#
+# Dict must be set to a dict (later maybe also an array and Key -> Index)
+#
+# Key bound ->
+#
+# Key exists ->
+#
+# Value bound ->
+#
+# Dict.Key = Value ->
+#
+# Trivial resolution
+#
+# Dict.Key != Value ->
+#
+# Failure
+#
+# Value unbound ->
+#
+# Set value to Dict.Key
+#
+# Key does not exist ->
+#
+# Dict allows add ->
+#
+# Value bound ->
+#
+# Failure on (exists Dict.Key, Value)
+#
+# Value unbound ->
+#
+# Set value to ProxySetToAdd value
+#
+# Dict disallows add ->
+#
+# Failure on (exists Dict.Key)
+#
+# Key unbound ->
+#
+# Value must also be unbound, because seriously?
+#
+# Set [Key, Value] to each pair in turn
+
+sub _resolution_space_for {
+ my ($self, $dict, $key, $value) = @_;
+
+ die "Fucked" unless $dict->does('DX::Role::StructuredValue');
+
+ if ($key->is_set) {
+
+ if (my $cur_val = $dict->get_member_at($key)) {
+
+ my $deps = [
+ [ CONTENTS_OF ,=> $dict, $key->string_value ],
+ [ CONTENTS_OF ,=> $value ],
+ ];
+
+ if ($value->is_set) {
+
+ my @members = (
+ $cur_val->equals($value)
+ # Trivial resolution, D.K = V
+ ? res(
+ actions => [],
+ veracity_depends_on => $deps,
+ )
+ # Failure
+ : ()
+ );
+
+ return rspace(
+ geometry_depends_on => $deps,
+ members => \@members
+ );
+
+ }
+
+ return rspace(
+ geometry_depends_on => [
+ [ CONTENTS_OF ,=> $dict, $key->string_value ],
+ [ TYPE_OF ,=> $value ],
+ ],
+ members => [
+ res(
+ actions => [ $value->action_for_set_value($cur_val) ],
+ veracity_depends_on => $deps,
+ ),
+ ]
+ );
+
+ }
+
+ if ($dict->can_add_member) {
+
+ my $deps = [
+ [ EXISTENCE_OF ,=> $dict, $key->string_value ],
+ [ TYPE_OF ,=> $value ],
+ ];
+
+ if ($value->is_set) {
+
+ # If we get here, it means (currently) that we entered recheck
+ # due to the deletion of the key from the dict and should fail
+ # (or there's a bug in the compiler but let's hope not)
+ return rspace(
+ geometry_depends_on => $deps,
+ members => [],
+ );
+ }
+
+ my @path = (@{$dict->value_path}, $key->string_value);
+ my $ab = DX::ActionBuilder::ProxySetToAdd->new(
+ target_path => \@path,
+ proxy_to => $dict->action_builder,
+ );
+
+ return rspace(
+ geometry_depends_on => $deps,
+ members => [
+ res(
+ actions => [
+ $value->action_for_set_value(
+ $value->but(action_builder => $ab),
+ ),
+ ],
+ # Veracity only depends on EXISTENCE_OF at this stage - if the
+ # $value is later set, recheck will lead us down a different path
+ # that will update those dependencies to include CONTENTS_OF
+ veracity_depends_on => $deps,
+ ),
+ ],
+ );
+
+ }
+
+ # Dict doesn't allow adding keys and key doesn't exist, so
+ # the contents of the value is completely irrelevant to the failure
+ return rspace(
+ geometry_depends_on => [
+ [ EXISTENCE_OF ,=> $dict, $key->string_value ],
+ ],
+ members => [],
+ );
+
+ }
+
+ die "Fucked" if $value->is_set; # +D -K +V ? seriously ?
+
+ # Laaater we may need to look at autovivifying an additional key/index
+ # ala ProxySetToAdd but I'm not 100% sure how that will make sense and
+ # premature generalisation is the root of all eval.
+
+ my @cand = map [
+ [ $_ ],
+ [ $dict->get_member_at($_) ],
+ ], map string($_), $dict->index_list;
+
+ return rspace(
+ geometry_depends_on => [
+ [ INDICES_OF ,=> $dict ],
+ [ TYPE_OF ,=> $key ],
+ [ TYPE_OF ,=> $value ],
+ ],
+ members => [
+ rstrat(
+ action_prototypes => [
+ [ $key => 'set_value' ],
+ [ $value => 'set_value' ],
+ ],
+ veracity_depends_on_builder => sub {
+ my ($this_key, $this_val) = map @$_, @_;
+ return [
+ [ CONTENTS_OF ,=> $dict, $this_key->string_value ],
+ [ CONTENTS_OF ,=> $key ],
+ [ CONTENTS_OF ,=> $value ],
+ ];
+ },
+ implementation_candidates => \@cand,
+ ),
+ ],
+ );
}
1;