File Coverage

blib/lib/DBIx/Class/Schema/Diff/Filter.pm
Criterion Covered Total %
statement 104 105 99.0
branch 78 90 86.6
condition 64 71 90.1
subroutine 15 15 100.0
pod 0 7 0.0
total 261 288 90.6


line stmt bran cond sub pod time code
1             package DBIx::Class::Schema::Diff::Filter;
2 5     5   80 use strict;
  5         14  
  5         174  
3 5     5   28 use warnings;
  5         64  
  5         205  
4              
5             # Further filters diff data produced by DBIx::Class::Schema::Diff
6              
7 5     5   29 use Moo;
  5         11  
  5         37  
8             with 'DBIx::Class::Schema::Diff::Role::Common';
9              
10 5     5   2232 use Types::Standard qw(:all);
  5         20  
  5         45  
11              
12             has 'mode', is => 'ro', isa => Enum[qw(limit ignore)], default => sub{'limit'};
13             has 'match', is => 'ro', isa => Maybe[InstanceOf['Hash::Layout']], default => sub{undef};
14              
15             has 'events', is => 'ro', coerce => \&_coerce_list_hash,
16             isa => Maybe[Map[Enum[qw(added changed deleted)],Bool]];
17              
18             has 'source_events', is => 'ro', coerce => \&_coerce_list_hash,
19             isa => Maybe[Map[Enum[qw(added changed deleted)],Bool]];
20              
21             has 'empty_match', is => 'ro', lazy => 1, default => sub {
22             my $self = shift;
23             return (scalar(keys %{$self->match->Data}) > 0) ? 0 : 1;
24             }, init_arg => undef, isa => Bool;
25              
26             has 'matched_paths', is => 'ro', init_arg => undef, default => sub {[]};
27              
28             sub filter {
29 127     127 0 1534 my ($self, $diff) = @_;
30 127 50       421 return undef unless ($diff);
31            
32 127         279 my $newd = {};
33 127         453 for my $s_name (keys %$diff) {
34 719         1468 my $h = $diff->{$s_name};
35             next if (
36             $self->skip_source($s_name)
37             || $self->_is_skip( source_events => $h->{_event})
38 719 100 100     1754 );
39            
40 520         1379 $newd->{$s_name} = $self->source_filter( $s_name => $h );
41 520 50       1304 delete $newd->{$s_name} unless (defined $newd->{$s_name});
42              
43             # Strip if the event is 'changed' but the diff data has been stripped
44             delete $newd->{$s_name} if (
45             $newd->{$s_name} &&
46             $newd->{$s_name}{_event} &&
47             $newd->{$s_name}{_event} eq 'changed' &&
48 520 100 33     2879 scalar(keys %{$newd->{$s_name}}) == 1
  426   66     1869  
      100        
49             );
50             }
51            
52 127 50       1158 return scalar(keys %$newd) > 0 ? $newd : undef;
53             }
54              
55              
56             sub source_filter {
57 520     520 0 1064 my ($self, $s_name, $diff) = @_;
58 520 50       1179 return undef unless ($diff);
59            
60 520         971 my $newd = {};
61 520         1531 for my $type (keys %$diff) {
62 1221 100 100     3658 next if ($type ne '_event' && $self->skip_type($s_name => $type));
63 1020         2531 my $val = $diff->{$type};
64 1020 100 100     4665 if($type eq 'columns' || $type eq 'relationships' || $type eq 'constraints') {
      100        
65 338         936 $newd->{$type} = $self->_info_filter( $type, $s_name => $val );
66 338 100       1179 delete $newd->{$type} unless (defined $newd->{$type});
67             }
68             else {
69 682         1903 $newd->{$type} = $val
70             }
71             }
72            
73 520 50       2267 return (scalar(keys %$newd) > 0) ? $newd : undef;
74             }
75              
76             sub _should_skip_info_item {
77 707     707   1636 my ($self, $type, $s_name, $name, $data) = @_;
78 707 100       1804 return 1 if ($self->_is_skip( 'events' => $data->{_event} ));
79 701 100       1690 return 1 if ($self->skip_type_id($s_name, $type => $name ));
80 551         2925 return 0
81             }
82              
83             sub _info_filter {
84 338     338   852 my ($self, $type, $s_name, $items) = @_;
85 338 50       898 return undef unless ($items);
86              
87 338         663 my $new_items = {};
88              
89 338         1181 for my $name (keys %$items) {
90            
91             #next if ($self->_should_skip_info_item($type, $s_name, $name, $items->{$name}));
92            
93 567 100       1823 if($items->{$name}{_event} eq 'changed') {
94            
95 280         683 my $check = $self->test_path($s_name, $type, $name);
96 280         59047 my $globmatch = 0;
97 280   100     970 my $filter_deep = ($check && ref($check) eq 'HASH');
98            
99 280 100       706 unless($filter_deep) {
100 233         574 my $diff = $items->{$name}{diff};
101 233         724 for my $k (keys %$diff) {
102            
103 233 100       832 if($self->match->lookup_path_globmatch($s_name, $type, $name, $k)) {
104 14         10945 $globmatch = 1;
105 14         34 last;
106             }
107             }
108             }
109            
110 280   100     120673 $filter_deep = ($check && ref($check) eq 'HASH') || $globmatch;
111            
112 280 100 100     1251 next if (!$globmatch && $self->_should_skip_info_item($type, $s_name, $name, $items->{$name}));
113            
114 215 100       503 if($filter_deep) {
115             my $new_diff = $self->_deep_value_filter(
116 61 100       221 $items->{$name}{diff}, $s_name, $type, $name
117             ) or next;
118            
119 38         200 $new_items->{$name} = {
120             _event => 'changed',
121             diff => $new_diff
122             };
123             }
124             else {
125             # Allow through as-is:
126 154 50       489 $new_items->{$name} = $items->{$name} unless ($self->_should_skip_info_item($type, $s_name, $name, $items->{$name}))
127             }
128             }
129             else {
130             # Allow through as-is:
131 287 100       1150 $new_items->{$name} = $items->{$name} unless ($self->_should_skip_info_item($type, $s_name, $name, $items->{$name}))
132             #if($self->match->lookup_leaf_path($s_name, $type, $name));
133             }
134             }
135            
136 338 100       1595 return scalar(keys %$new_items) > 0 ? $new_items : undef;
137             }
138              
139             sub _deep_value_filter {
140 73     73   231 my ($self, $hash, @path) = @_;
141            
142 73         173 my $new_hash = {};
143 73         259 for my $k (keys %$hash) {
144 73         177 my $val = $hash->{$k};
145 73         192 my $set = $self->test_path(@path,$k);
146              
147 73 100       11065 if($set) {
148 51 100 66     402 if($val && ref($val) eq 'HASH' && ref($set) eq 'HASH' && scalar(keys %$val) > 0) {
      100        
      66        
149 12         53 $new_hash->{$k} = $self->_deep_value_filter($val,@path,$k);
150 12 50       59 delete $new_hash->{$k} unless (defined $new_hash->{$k});
151             }
152             else {
153 39 100       168 next if ($self->mode eq 'ignore');
154 38         151 $new_hash->{$k} = $val;
155             }
156             }
157             else {
158 22 50       114 next if ($self->mode eq 'limit');
159 0         0 $new_hash->{$k} = $val;
160             }
161             }
162            
163 73 100       448 return scalar(keys %$new_hash) > 0 ? $new_hash : undef;
164             }
165              
166              
167             sub _is_skip {
168 1248     1248   3505 my ($self, $meth, $key) = @_;
169 1248         3690 my $h = $self->$meth;
170 1248 100 100     5859 $self->mode eq 'limit' ? $h && ! $h->{$key} : $h && $h->{$key};
      66        
171             }
172              
173              
174             sub skip_source {
175 719     719 0 1516 my ($self, $s_name) = @_;
176 719 50       2162 my $HL = $self->match or return 0;
177 719   100     1674 my $set = $self->test_path($s_name) || 0;
178            
179 719 100       172114 if($self->mode eq 'limit') {
180 602 100       11117 return 0 if ($self->empty_match);
181 562 100       12006 return $set ? 0 : 1;
182             }
183             else {
184 117 100 100     836 return $set && ! ref($set) ? 1 : 0;
185             }
186             }
187              
188             sub skip_type {
189 701     701 0 1479 my ($self, $s_name, $type) = @_;
190 701 50       1913 my $HL = $self->match or return 0;
191 701         1501 my $set = $self->test_path($s_name,$type);
192            
193 701 100       144361 if($self->mode eq 'limit') {
194 586 100       10850 return 0 if ($self->empty_match);
195             # If this source/type is set, OR if the entire source is included:
196 542 100 100     6307 return $set || $self->test_leaf_path($s_name) ? 0 : 1;
197             }
198             else {
199 115 100 100     675 return $set && ! ref($set) ? 1 : 0;
200             }
201             }
202              
203             sub skip_type_id {
204 701     701 0 1455 my ($self, $s_name, $type, $id) = @_;
205              
206 701 50       1921 my $HL = $self->match or return 0;
207 701         1556 my $set = $self->test_path($s_name,$type,$id);
208            
209 701 100       147337 if($self->mode eq 'limit') {
210 561 100       10679 return 0 if ($self->empty_match);
211              
212             # If this source/type is set, OR if the entire source or source/type is included:
213 485 100 100     5155 return $set
214             || $self->test_leaf_path($s_name)
215             || $self->test_leaf_path($s_name,$type) ? 0 : 1;
216             }
217             else {
218 140 100 100     648 return $set && ! ref($set) ? 1 : 0;
219             }
220             }
221              
222             sub test_path {
223 2474     2474 0 5670 my ($self, @path) = @_;
224 2474   100     5145 return $self->test_leaf_path(@path) || $self->match->lookup_path(@path)
225             }
226              
227             sub test_leaf_path {
228 3380     3380 0 7540 my ($self, @path) = @_;
229 3380   100     9799 my $ret = $self->match->lookup_leaf_path(@path) || $self->match->lookup_path_globmatch(@path);
230 3380 100 66     2374358 push @{$self->matched_paths}, \@path if (
  607         2234  
231             $ret
232             # We don't want to record the path as "matched" for empty HashRef {} leafs
233             && ! ref $ret
234             );
235 3380         17736 return $ret;
236             }
237              
238             1;
239              
240              
241             __END__