File Coverage

blib/lib/Aniki/Row.pm
Criterion Covered Total %
statement 74 77 96.1
branch 23 28 82.1
condition 5 10 50.0
subroutine 22 23 95.6
pod 13 14 92.8
total 137 152 90.1


line stmt bran cond sub pod time code
1             package Aniki::Row;
2 27     27   481 use 5.014002;
  27         98  
3              
4 27     27   147 use namespace::autoclean;
  27         55  
  27         166  
5 27     27   2063 use Mouse v2.4.5;
  27         303  
  27         180  
6 27     27   10599 use Carp qw/croak/;
  27         57  
  27         25240  
7              
8             has table_name => (
9             is => 'ro',
10             required => 1,
11             );
12              
13             has row_data => (
14             is => 'ro',
15             required => 1,
16             );
17              
18             has is_new => (
19             is => 'rw',
20             default => 0,
21             );
22              
23             has relay_data => (
24             is => 'ro',
25             default => sub { +{} },
26             );
27              
28             my %handler;
29              
30             sub BUILD {
31 168     168 1 318 my ($self, $args) = @_;
32 168         1147 $handler{0+$self} = delete $args->{handler};
33             }
34              
35 220     220 1 2835 sub handler { $handler{0+shift} }
36 0     0 1 0 sub schema { shift->handler->schema }
37 162     162 1 375 sub filter { shift->handler->filter }
38              
39             sub table {
40 28     28 1 60 my $self = shift;
41 28         101 return $self->handler->schema->get_table($self->table_name);
42             }
43              
44             sub get {
45 179     179 1 415 my ($self, $column) = @_;
46 179 100       657 return $self->{__instance_cache}{get}{$column} if exists $self->{__instance_cache}{get}{$column};
47              
48 162 50       511 return undef unless exists $self->row_data->{$column}; ## no critic
49              
50 162         529 my $data = $self->get_column($column);
51 162         488 return $self->{__instance_cache}{get}{$column} = $self->filter->inflate_column($self->table_name, $column, $data);
52             }
53              
54             sub relay {
55 108     108 1 187 my ($self, $key) = @_;
56 108 100       299 unless (exists $self->relay_data->{$key}) {
57 24         63 $self->relay_data->{$key} = $self->relay_fetch($key);
58             }
59              
60 108         211 my $relay_data = $self->relay_data->{$key};
61 108 100       265 return unless defined $relay_data;
62 90 100       373 return wantarray ? @$relay_data : $relay_data if ref $relay_data eq 'ARRAY';
    100          
63 24         93 return $relay_data;
64             }
65              
66             sub relay_fetch {
67 24     24 1 43 my ($self, $key) = @_;
68 24         46 $self->handler->fetch_and_attach_relay_data($self->table_name, [$key], [$self]);
69 24         97 return $self->relay_data->{$key};
70             }
71              
72             sub is_prefetched {
73 51     51 1 15168 my ($self, $key) = @_;
74 51         237 return exists $self->relay_data->{$key};
75             }
76              
77             sub get_column {
78 556     556 1 4695 my ($self, $column) = @_;
79 556 50       1499 return undef unless exists $self->row_data->{$column}; ## no critic
80 556         1611 return $self->row_data->{$column};
81             }
82              
83             sub get_columns {
84 7     7 1 2524 my $self = shift;
85              
86 7         13 my %row;
87 7         14 for my $column (keys %{ $self->row_data }) {
  7         42  
88 35         94 $row{$column} = $self->row_data->{$column};
89             }
90 7         55 return \%row;
91             }
92              
93             sub refetch {
94 3     3 1 5062 my ($self, $opts) = @_;
95 3   50     22 $opts //= +{};
96 3         6 $opts->{limit} = 1;
97              
98 3         11 my $where = $self->handler->_where_row_cond($self->table, $self->row_data);
99 3         10 return $self->handler->select($self->table_name => $where, $opts)->first;
100             }
101              
102             my %accessor_method_cache;
103             sub _accessor_method_cache {
104 293     293   420 my $self = shift;
105 293   100     1174 return $accessor_method_cache{$self->table_name} //= {};
106             }
107              
108             sub _guess_accessor_method {
109 293     293   560 my ($invocant, $method) = @_;
110              
111 293 50       638 if (ref $invocant) {
112 293         414 my $self = $invocant;
113 293         406 my $column = $method;
114              
115 293         591 my $cache = $self->_accessor_method_cache();
116 293 100       906 return $cache->{$column} if exists $cache->{$column};
117              
118 40 100   179   294 return $cache->{$column} = sub { shift->get($column) } if exists $self->row_data->{$column};
  179         461  
119              
120 10         40 my $relationships = $self->table->get_relationships;
121 10 100 66 108   90 return $cache->{$column} = sub { shift->relay($column) } if $relationships && $relationships->get($column);
  108         257  
122             }
123              
124 4         39 return undef; ## no critic
125             }
126              
127             sub can {
128 37     37 0 5979 my ($invocant, $method) = @_;
129 37         293 my $code = $invocant->SUPER::can($method);
130 37 100       171 return $code if defined $code;
131 6         21 return $invocant->_guess_accessor_method($method);
132             }
133              
134             our $AUTOLOAD;
135             sub AUTOLOAD {
136 287     287   41840 my $invocant = shift;
137 287         1198 my $column = $AUTOLOAD =~ s/^.+://r;
138              
139 287 50       776 if (ref $invocant) {
140 287         414 my $self = $invocant;
141 287         615 my $method = $self->_guess_accessor_method($column);
142 287 50       881 return $self->$method(@_) if defined $method;
143             }
144              
145 0   0     0 my $msg = sprintf q{Can't locate object method "%s" via package "%s"}, $column, ref $invocant || $invocant;
146 0         0 croak $msg;
147             }
148              
149             sub DEMOLISH {
150 168     168 1 9790 my $self = shift;
151 168         983 delete $handler{0+$self};
152             }
153              
154             __PACKAGE__->meta->make_immutable();
155             __END__
156              
157             =pod
158              
159             =encoding utf-8
160              
161             =head1 NAME
162              
163             Aniki::Row - Row class
164              
165             =head1 SYNOPSIS
166              
167             my $result = $db->select(foo => { bar => 1 });
168             for my $row ($result->all) {
169             print $row->id, "\n";
170             }
171              
172             =head1 DESCRIPTION
173              
174             This is row class.
175              
176             =head1 INSTANCE METHODS
177              
178             =head2 C<$column()>
179              
180             Autoload column name method to C<< $row->get($column) >>.
181              
182             =head2 C<$relay()>
183              
184             Autoload relationship name method to C<< $row->relay($column) >>.
185              
186             =head2 C<get($column)>
187              
188             Returns column data.
189              
190             =head2 C<relay($name)>
191              
192             Returns related data.
193             If not yet cached, call C<relay_fetch>.
194              
195             =head2 C<relay_fetch($name)>
196              
197             Fetch related data, and returns related data.
198              
199             =head2 C<is_prefetched($name)>
200              
201             If a pre-fetch has been executed, it return a true value.
202              
203             =head2 C<get_column($column)>
204              
205             Returns column data without inflate filters.
206              
207             =head2 C<get_columns()>
208              
209             Returns columns data as hash reference.
210              
211             =head2 C<refetch()>
212              
213             =head1 ACCESSORS
214              
215             =over 4
216              
217             =item C<handler : Aniki>
218              
219             =item C<schema : Aniki::Schema>
220              
221             =item C<table : Aniki::Schema::Table>
222              
223             =item C<filter : Aniki::Filter>
224              
225             =item C<table_name : Str>
226              
227             =item C<is_new : Bool>
228              
229             =item C<row_data : HashRef>
230              
231             =item C<relay_data : HashRef>
232              
233             =back
234              
235             =head1 LICENSE
236              
237             Copyright (C) karupanerura.
238              
239             This library is free software; you can redistribute it and/or modify
240             it under the same terms as Perl itself.
241              
242             =head1 AUTHOR
243              
244             karupanerura E<lt>karupa@cpan.orgE<gt>
245              
246             =cut