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   71965 use 5.014002;
  30         106  
3              
4 30     30   514 use namespace::autoclean;
  30         20450  
  30         172  
5 30     30   2333 use Mouse v2.4.5;
  30         24975  
  30         170  
6 30     30   20833 use Aniki::Schema::Relationship::Fetcher;
  30         3046  
  30         1220  
7 30     30   21258 use Lingua::EN::Inflect qw/PL/;
  30         782691  
  30         4010  
8 30     30   19852 use Hash::Util::FieldHash qw/fieldhash/;
  30         24773  
  30         23530  
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   2900 my $self = shift;
58              
59 125         261 my @src_columns = @{ $self->src_columns };
  125         559  
60 125         282 my @dest_columns = @{ $self->dest_columns };
  125         447  
61 125         447 my $src_table_name = $self->src_table_name;
62 125         354 my $dest_table_name = $self->dest_table_name;
63              
64 125 50 33     4362 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       730 my $name = $self->has_many ? _to_plural($dest_table_name) : $dest_table_name;
69 125         112430 return $prefix . $name;
70             }
71              
72             sub _to_plural {
73 67     67   9549 my $words = shift;
74 67         487 my $sep = join '|', map quotemeta, @WORD_SEPARATORS;
75 67 100       1080 return $words =~ s/(?<=$sep)(.+?)$/PL($1)/er if $words =~ /$sep/;
  2         14  
76 65         428 return PL($words);
77             }
78              
79             sub get_inverse_relationships {
80 143     143 0 268 my $self = shift;
81 143 100       562 return @{ $self->{__inverse_relationships} } if exists $self->{__inverse_relationships};
  25         77  
82              
83 118         309 my @inverse_relationships = $self->_get_inverse_relationships;
84 118         324 $self->{__inverse_relationships} = \@inverse_relationships;
85 118         504 return @inverse_relationships;
86             }
87              
88             sub _get_inverse_relationships {
89 118     118   214 my $self = shift;
90              
91 118         204 my @relationships;
92 118         557 for my $dest ($self->schema->get_table($self->dest_table_name)->get_relationships->all) {
93 180 100       780 next if $dest->dest_table_name ne $self->src_table_name;
94 118 50       467 next if not _cmp_deeply($dest->dest_columns, $self->src_columns);
95 118 50       487 next if not _cmp_deeply($dest->src_columns, $self->dest_columns);
96 118         309 push @relationships => $dest;
97             }
98              
99 118         405 return @relationships;
100             }
101              
102             sub _cmp_deeply {
103 472     472   926 my ($l, $r) = @_;
104 472 100 66     2206 return $l eq $r if not ref $l or not ref $r;
105 236 50       731 return !!0 if ref $l ne ref $r;
106              
107 236 50       808 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       643 return !!0 if @$l != @$r;
119 236         382 for my $i (0..$#{$l}) {
  236         575  
120 236 50       682 return !!0 if not _cmp_deeply($l->[$i], $r->[$i]);
121             }
122 236         726 return !!1;
123             }
124              
125 0           die "Unknwon case: $l cmp $r";
126             }
127              
128             __PACKAGE__->meta->make_immutable();
129             __END__