File Coverage

blib/lib/Aniki/Result/Collection/Joined.pm
Criterion Covered Total %
statement 75 79 94.9
branch 9 10 90.0
condition 4 6 66.6
subroutine 16 17 94.1
pod 1 3 33.3
total 105 115 91.3


line stmt bran cond sub pod time code
1             package Aniki::Result::Collection::Joined;
2 2     2   3048 use 5.014002;
  2         8  
3              
4 2     2   10 use namespace::autoclean;
  2         5  
  2         13  
5 2     2   127 use Mouse v2.4.5;
  2         22  
  2         14  
6             extends qw/Aniki::Result::Collection/;
7              
8 2     2   954 use Carp qw/croak/;
  2         6  
  2         145  
9 2     2   803 use Aniki::Row::Joined;
  2         6  
  2         73  
10 2     2   16 use List::MoreUtils qw/none/;
  2         6  
  2         23  
11 2     2   1326 use List::UtilsBy qw/uniq_by/;
  2         5  
  2         93  
12 2     2   13 use Scalar::Util qw/refaddr/;
  2         5  
  2         1789  
13              
14             has '+table_name' => (
15             required => 0,
16             lazy => 1,
17             default => sub { join ',', @{ $_[0]->table_names } }
18             );
19              
20             has '+row_class' => (
21             lazy => 1,
22             default => sub { croak 'Cannot get row class of '.__PACKAGE__.'. Use row_classes instead of row_class.' },
23             );
24              
25             has table_names => (
26             is => 'ro',
27             required => 1,
28             );
29              
30             has _compact_row_datas => (
31             is => 'ro',
32             lazy => 1,
33             builder => '_compress',
34             );
35              
36             has _subresult_cache => (
37             is => 'ro',
38             default => sub {
39             my $self = shift;
40             return +{
41             map { $_ => undef } @{ $self->table_names },
42             };
43             },
44             );
45              
46             sub row_classes {
47 0     0 0 0 my $self = shift;
48 0         0 return map { $self->handler->guess_row_class($_) } @{ $self->table_names };
  0         0  
  0         0  
49             }
50              
51             sub rows {
52 11     11 1 36 my $self = shift;
53 11 100       47 if (@_ == 1) {
54 8         27 my $table_name = shift;
55 8         29 return $self->subresult($table_name)->rows();
56             }
57 3         31 return $self->SUPER::rows();
58             }
59              
60             sub subresult {
61 8     8 0 30 my ($self, $table_name) = @_;
62 8 100       60 return $self->_subresult_cache->{$table_name} if $self->_subresult_cache->{$table_name};
63              
64 6         35 my $result_class = $self->handler->guess_result_class($table_name);
65             return $self->_subresult_cache->{$table_name} = $result_class->new(
66             table_name => $table_name,
67             handler => $self->handler,
68 30     30   311 row_datas => [uniq_by { refaddr $_ } map { $_->{$table_name} } @{ $self->_compact_row_datas() }],
  30         103  
  6         51  
69             !$self->suppress_row_objects ? (
70 6 50   30   30 inflated_rows => [uniq_by { refaddr $_ } map { $_->$table_name } @{ $self->inflated_rows() }],
  30         294  
  30         190  
  6         81  
71             ) : (),
72             suppress_row_objects => $self->suppress_row_objects,
73             );
74             }
75              
76             sub _uniq_key {
77 30     30   84 my ($row_data, $pk) = @_;
78 30 100   30   198 return if none { defined $row_data->{$_} } @$pk;
  30         323  
79 27         209 return join '|', map { quotemeta $row_data->{$_} } @$pk;
  27         159  
80             }
81              
82             sub _compress {
83 3     3   11 my $self = shift;
84 3         21 my $handler = $self->handler;
85              
86 3         10 my @table_names = @{ $self->table_names };
  3         19  
87             my %pk = map {
88 3         14 $_ => [map { $_->name } $handler->schema->get_table($_)->primary_key->fields]
  6         37  
  6         56  
89             } @table_names;
90              
91 3         13 my @rows;
92             my %cache;
93 3         10 for my $row (@{ $self->row_datas }) {
  3         25  
94 15         40 my %rows;
95              
96 15         47 for my $table_name (@table_names) {
97 30         83 my $row_data = $row->{$table_name};
98 30         94 my $uniq_key = _uniq_key($row_data, $pk{$table_name});
99 30 100 66     255 $rows{$table_name} = defined $uniq_key ? ($cache{$table_name}{$uniq_key} //= $row_data) : $row_data;
100             }
101              
102 15         69 push @rows => \%rows;
103             }
104              
105 3         34 return \@rows;
106             }
107              
108             sub _inflate {
109 3     3   11 my $self = shift;
110 3         14 my $handler = $self->handler;
111              
112 3         11 my @table_names = @{ $self->table_names };
  3         22  
113 3         13 my %row_class = map { $_ => $handler->guess_row_class($_) } @table_names;
  6         71  
114              
115 3         15 my @rows;
116             my %cache;
117 3         9 for my $row (@{ $self->_compact_row_datas }) {
  3         20  
118 15         39 my %rows;
119              
120             # inflate to row class
121 15         45 for my $table_name (@table_names) {
122 30         80 my $row_data = $row->{$table_name};
123 30   66     480 $rows{$table_name} = $cache{$table_name}{refaddr $row_data} //= $row_class{$table_name}->new(
124             table_name => $table_name,
125             handler => $handler,
126             row_data => $row_data,
127             );
128             }
129              
130 15         83 push @rows => Aniki::Row::Joined->new(values %rows);
131             }
132              
133 3         32 return \@rows;
134             }
135              
136             __PACKAGE__->meta->make_immutable();
137             __END__