File Coverage

blib/lib/Aniki/Schema/Relationship.pm
Criterion Covered Total %
statement 55 62 88.7
branch 19 34 55.8
condition 4 9 44.4
subroutine 11 11 100.0
pod 0 1 0.0
total 89 117 76.0


line stmt bran cond sub pod time code
1             package Aniki::Schema::Relationship;
2 30     30   55977 use 5.014002;
  30         98  
3              
4 30     30   584 use namespace::autoclean;
  30         16223  
  30         173  
5 30     30   2264 use Mouse v2.4.5;
  30         21329  
  30         169  
6 30     30   20719 use Aniki::Schema::Relationship::Fetcher;
  30         2728  
  30         1208  
7 30     30   20984 use Lingua::EN::Inflect qw/PL/;
  30         756747  
  30         4038  
8 30     30   18533 use Hash::Util::FieldHash qw/fieldhash/;
  30         23688  
  30         22038  
9              
10             our @WORD_SEPARATORS = ('-', '_', ' ');
11              
12             has schema => (
13             is => 'ro',
14             required => 1,
15             weak_ref => 1,
16             );
17              
18             has src_table_name => (
19             is => 'ro',
20             required => 1,
21             );
22              
23             has src_columns => (
24             is => 'ro',
25             required => 1,
26             );
27              
28             has dest_table_name => (
29             is => 'ro',
30             required => 1,
31             );
32              
33             has dest_columns => (
34             is => 'ro',
35             required => 1,
36             );
37              
38             has has_many => (
39             is => 'ro',
40             default => sub {
41             my $self = shift;
42             return $self->schema->has_many($self->dest_table_name, $self->dest_columns);
43             },
44             );
45              
46             has name => (
47             is => 'ro',
48             default => \&_guess_name,
49             );
50              
51             has fetcher => (
52             is => 'ro',
53             default => sub { Aniki::Schema::Relationship::Fetcher->new(relationship => $_[0]) },
54             );
55              
56             sub _guess_name {
57 125     125   2682 my $self = shift;
58              
59 125         241 my @src_columns = @{ $self->src_columns };
  125         482  
60 125         259 my @dest_columns = @{ $self->dest_columns };
  125         388  
61 125         361 my $src_table_name = $self->src_table_name;
62 125         365 my $dest_table_name = $self->dest_table_name;
63              
64 125 50 33     4265 my $prefix = (@src_columns == 1 && $src_columns[0] =~ /^(.+)_\Q$dest_table_name/) ? $1.'_' :
    50 33        
65             (@dest_columns == 1 && $dest_columns[0] =~ /^(.+)_\Q$src_table_name/) ? $1.'_' :
66             '';
67              
68 125 100       628 my $name = $self->has_many ? _to_plural($dest_table_name) : $dest_table_name;
69 125         105488 return $prefix . $name;
70             }
71              
72             sub _to_plural {
73 67     67   5996 my $words = shift;
74 67         426 my $sep = join '|', map quotemeta, @WORD_SEPARATORS;
75 67 100       1045 return $words =~ s/(?<=$sep)(.+?)$/PL($1)/er if $words =~ /$sep/;
  2         10  
76 65         374 return PL($words);
77             }
78              
79             sub get_inverse_relationships {
80 143     143 0 251 my $self = shift;
81 143 100       516 return @{ $self->{__inverse_relationships} } if exists $self->{__inverse_relationships};
  25         71  
82              
83 118         295 my @inverse_relationships = $self->_get_inverse_relationships;
84 118         279 $self->{__inverse_relationships} = \@inverse_relationships;
85 118         416 return @inverse_relationships;
86             }
87              
88             sub _get_inverse_relationships {
89 118     118   196 my $self = shift;
90              
91 118         198 my @relationships;
92 118         516 for my $dest ($self->schema->get_table($self->dest_table_name)->get_relationships->all) {
93 180 100       776 next if $dest->dest_table_name ne $self->src_table_name;
94 118 50       465 next if not _cmp_deeply($dest->dest_columns, $self->src_columns);
95 118 50       449 next if not _cmp_deeply($dest->src_columns, $self->dest_columns);
96 118         269 push @relationships => $dest;
97             }
98              
99 118         337 return @relationships;
100             }
101              
102             sub _cmp_deeply {
103 472     472   882 my ($l, $r) = @_;
104 472 100 66     2036 return $l eq $r if not ref $l or not ref $r;
105 236 50       658 return !!0 if ref $l ne ref $r;
106              
107 236 50       792 if (ref $l eq 'HASH') {
    50          
108 0         0 for my $k (keys %$l) {
109 0 0       0 return !!0 if not exists $r->{$k};
110 0 0       0 return !!0 if not _cmp_deeply($l->{$k}, $r->{$k});
111             }
112 0         0 for my $k (keys %$r) {
113 0 0       0 return !!0 if not exists $l->{$k};
114             }
115 0         0 return !!1;
116             }
117             elsif (ref $l eq 'ARRAY') {
118 236 50       573 return !!0 if @$l != @$r;
119 236         367 for my $i (0..$#{$l}) {
  236         541  
120 236 50       617 return !!0 if not _cmp_deeply($l->[$i], $r->[$i]);
121             }
122 236         692 return !!1;
123             }
124              
125 0           die "Unknwon case: $l cmp $r";
126             }
127              
128             __PACKAGE__->meta->make_immutable();
129             __END__