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   56200 use 5.014002;
  30         113  
3              
4 30     30   533 use namespace::autoclean;
  30         13634  
  30         192  
5 30     30   2331 use Mouse v2.4.5;
  30         22804  
  30         198  
6 30     30   22416 use Aniki::Schema::Relationship::Fetcher;
  30         3377  
  30         1603  
7 30     30   24137 use Lingua::EN::Inflect qw/PL/;
  30         843499  
  30         5143  
8 30     30   23236 use Hash::Util::FieldHash qw/fieldhash/;
  30         28248  
  30         26203  
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   3372 my $self = shift;
58              
59 125         393 my @src_columns = @{ $self->src_columns };
  125         617  
60 125         318 my @dest_columns = @{ $self->dest_columns };
  125         496  
61 125         421 my $src_table_name = $self->src_table_name;
62 125         384 my $dest_table_name = $self->dest_table_name;
63              
64 125 50 33     5513 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       795 my $name = $self->has_many ? _to_plural($dest_table_name) : $dest_table_name;
69 125         128675 return $prefix . $name;
70             }
71              
72             sub _to_plural {
73 67     67   5233 my $words = shift;
74 67         570 my $sep = join '|', map quotemeta, @WORD_SEPARATORS;
75 67 100       1307 return $words =~ s/(?<=$sep)(.+?)$/PL($1)/er if $words =~ /$sep/;
  2         8  
76 65         450 return PL($words);
77             }
78              
79             sub get_inverse_relationships {
80 143     143 0 266 my $self = shift;
81 143 100       618 return @{ $self->{__inverse_relationships} } if exists $self->{__inverse_relationships};
  25         73  
82              
83 118         341 my @inverse_relationships = $self->_get_inverse_relationships;
84 118         325 $self->{__inverse_relationships} = \@inverse_relationships;
85 118         491 return @inverse_relationships;
86             }
87              
88             sub _get_inverse_relationships {
89 118     118   295 my $self = shift;
90              
91 118         196 my @relationships;
92 118         705 for my $dest ($self->schema->get_table($self->dest_table_name)->get_relationships->all) {
93 180 100       909 next if $dest->dest_table_name ne $self->src_table_name;
94 118 50       490 next if not _cmp_deeply($dest->dest_columns, $self->src_columns);
95 118 50       491 next if not _cmp_deeply($dest->src_columns, $self->dest_columns);
96 118         311 push @relationships => $dest;
97             }
98              
99 118         368 return @relationships;
100             }
101              
102             sub _cmp_deeply {
103 472     472   980 my ($l, $r) = @_;
104 472 100 66     2390 return $l eq $r if not ref $l or not ref $r;
105 236 50       750 return !!0 if ref $l ne ref $r;
106              
107 236 50       837 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       614 return !!0 if @$l != @$r;
119 236         423 for my $i (0..$#{$l}) {
  236         619  
120 236 50       686 return !!0 if not _cmp_deeply($l->[$i], $r->[$i]);
121             }
122 236         751 return !!1;
123             }
124              
125 0           die "Unknwon case: $l cmp $r";
126             }
127              
128             __PACKAGE__->meta->make_immutable();
129             __END__