File Coverage

blib/lib/Aniki/Schema/Relationship/Fetcher.pm
Criterion Covered Total %
statement 82 93 88.1
branch 16 34 47.0
condition 1 3 33.3
subroutine 14 16 87.5
pod 0 1 0.0
total 113 147 76.8


line stmt bran cond sub pod time code
1             package Aniki::Schema::Relationship::Fetcher;
2 30     30   467 use 5.014002;
  30         98  
3              
4 30     30   162 use namespace::autoclean;
  30         146  
  30         189  
5 30     30   1911 use Mouse v2.4.5;
  30         385  
  30         163  
6              
7             has relationship => (
8             is => 'ro',
9             weak_ref => 1,
10             required => 1,
11             );
12              
13 30     30   24999 use List::MoreUtils qw/pairwise notall/;
  30         209656  
  30         320  
14 30     30   35723 use List::UtilsBy qw/partition_by/;
  30         38267  
  30         2086  
15 30     30   228 use Scalar::Util qw/weaken/;
  30         88  
  30         1337  
16 30     30   12157 use SQL::QueryMaker;
  30         60878  
  30         24593  
17              
18             sub execute {
19 32     32 0 73 my ($self, $handler, $rows, $prefetch) = @_;
20 32 50       79 return unless @$rows;
21              
22 32         64 my %where;
23 32 100       85 if (ref $prefetch eq 'HASH') {
24 2         6 my %prefetch;
25 2         7 for my $key (keys %$prefetch) {
26 2 100       12 if ($key =~ /^\./) {
27 1         5 my $column = $key =~ s/^\.//r;
28 1         4 $where{$column} = $prefetch->{$key};
29             }
30             else {
31 1         4 $prefetch{$key} = $prefetch->{$key};
32             }
33             }
34 2         4 $prefetch = \%prefetch;
35             }
36              
37 32         87 my $relationship = $self->relationship;
38 32         86 my $name = $relationship->name;
39 32         75 my $table_name = $relationship->dest_table_name;
40 32         72 my $has_many = $relationship->has_many;
41 32         46 my @src_columns = @{ $relationship->src_columns };
  32         99  
42 32         52 my @dest_columns = @{ $relationship->dest_columns };
  32         84  
43              
44 32 50 33     155 if (@src_columns == 1 and @dest_columns == 1) {
45 32         52 my $src_column = $src_columns[0];
46 32         51 my $dest_column = $dest_columns[0];
47              
48 32         60 my @src_values = grep defined, map { $_->get_column($src_column) } @$rows;
  57         149  
49 32 50       90 unless (@src_values) {
50             # set empty value
51 0         0 for my $row (@$rows) {
52 0 0       0 $row->relay_data->{$name} = $has_many ? [] : undef;
53             }
54 0         0 return;
55             }
56              
57 32         126 my @related_rows = $handler->select($table_name => {
58             %where,
59             $dest_column => sql_in(\@src_values),
60             }, { prefetch => $prefetch })->all;
61              
62 32     72   206 my %related_rows_map = partition_by { $_->get_column($dest_column) } @related_rows;
  72         472  
63 32         263 for my $row (@$rows) {
64 57         136 my $src_value = $row->get_column($src_column);
65 57 50       131 unless (defined $src_value) {
66             # set empty value
67 0 0       0 $row->relay_data->{$name} = $has_many ? [] : undef;
68 0         0 next;
69             }
70              
71 57         98 my $related_rows = $related_rows_map{$src_value};
72 57 50       190 $row->relay_data->{$name} = $has_many ? $related_rows : $related_rows->[0];
73             }
74              
75 32         94 $self->_execute_inverse(\@related_rows => $rows);
76             }
77             else {
78             # follow slow case...
79 0         0 for my $row (@$rows) {
80 0 0   0   0 next if notall { defined $row->get_column($_) } @src_columns;
  0         0  
81             my @related_rows = $handler->select($table_name => {
82             %where,
83 0     0   0 pairwise { $a => $row->get_column($b) } @dest_columns, @src_columns
  0         0  
84             }, { prefetch => $prefetch })->all;
85 0 0       0 $row->relay_data->{$name} = $has_many ? \@related_rows : $related_rows[0];
86             }
87             }
88             }
89              
90             sub _execute_inverse {
91 32     32   65 my ($self, $src_rows, $dest_rows) = @_;
92 32 100       102 return unless @$src_rows;
93 25 50       59 return unless @$dest_rows;
94              
95 25         100 for my $relationship ($self->relationship->get_inverse_relationships) {
96 25         65 my $name = $relationship->name;
97 25         56 my $has_many = $relationship->has_many;
98 25         43 my @src_columns = @{ $relationship->src_columns };
  25         76  
99 25         39 my @dest_columns = @{ $relationship->dest_columns };
  25         62  
100              
101             my $src_keygen = sub {
102 72     72   115 my $src_row = shift;
103 72 50       117 return join '|', map { defined $_ ? quotemeta $_ : '(NULL)' } map { $src_row->get_column($_) } @src_columns;
  72         250  
  72         157  
104 25         88 };
105             my $dest_keygen = sub {
106 48     48   66 my $dest_row = shift;
107 48 50       84 return join '|', map { defined $_ ? quotemeta $_ : '(NULL)' } map { $dest_row->get_column($_) } @dest_columns;
  48         241  
  48         107  
108 25         61 };
109              
110 25     48   84 my %dest_rows_map = partition_by { $dest_keygen->($_) } @$dest_rows;
  48         264  
111 25         195 for my $src_row (@$src_rows) {
112 72 50   72   269 next if notall { defined $src_row->get_column($_) } @src_columns;
  72         467  
113 72         413 my $dest_rows = $dest_rows_map{$src_keygen->($src_row)};
114 72 50       240 $src_row->relay_data->{$name} = $has_many ? $dest_rows : $dest_rows->[0];
115 72         416 weaken($src_row->relay_data->{$name});
116             }
117             }
118             }
119              
120             __PACKAGE__->meta->make_immutable();
121             __END__