File Coverage

blib/lib/Aniki/Row.pm
Criterion Covered Total %
statement 72 75 96.0
branch 23 28 82.1
condition 5 10 50.0
subroutine 21 22 95.4
pod 12 13 92.3
total 133 148 89.8


line stmt bran cond sub pod time code
1             package Aniki::Row;
2 27     27   612 use 5.014002;
  27         119  
3              
4 27     27   160 use namespace::autoclean;
  27         62  
  27         205  
5 27     27   2515 use Mouse v2.4.5;
  27         369  
  27         235  
6 27     27   12799 use Carp qw/croak/;
  27         62  
  27         28207  
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 161     161 1 343 my ($self, $args) = @_;
32 161         1344 $handler{0+$self} = delete $args->{handler};
33             }
34              
35 212     212 1 1059 sub handler { $handler{0+shift} }
36 0     0 1 0 sub schema { shift->handler->schema }
37 157     157 1 415 sub filter { shift->handler->filter }
38              
39             sub table {
40 28     28 1 65 my $self = shift;
41 28         90 return $self->handler->schema->get_table($self->table_name);
42             }
43              
44             sub get {
45 174     174 1 530 my ($self, $column) = @_;
46 174 100       657 return $self->{__instance_cache}{get}{$column} if exists $self->{__instance_cache}{get}{$column};
47              
48 157 50       574 return undef unless exists $self->row_data->{$column}; ## no critic
49              
50 157         522 my $data = $self->get_column($column);
51 157         557 return $self->{__instance_cache}{get}{$column} = $self->filter->inflate_column($self->table_name, $column, $data);
52             }
53              
54             sub relay {
55 86     86 1 150 my ($self, $key) = @_;
56 86 100       237 unless (exists $self->relay_data->{$key}) {
57 21         59 $self->relay_data->{$key} = $self->relay_fetch($key);
58             }
59              
60 86         172 my $relay_data = $self->relay_data->{$key};
61 86 100       183 return unless defined $relay_data;
62 80 100       312 return wantarray ? @$relay_data : $relay_data if ref $relay_data eq 'ARRAY';
    100          
63 24         84 return $relay_data;
64             }
65              
66             sub relay_fetch {
67 21     21 1 36 my ($self, $key) = @_;
68 21         40 $self->handler->fetch_and_attach_relay_data($self->table_name, [$key], [$self]);
69 21         79 return $self->relay_data->{$key};
70             }
71              
72             sub get_column {
73 533     533 1 5376 my ($self, $column) = @_;
74 533 50       1529 return undef unless exists $self->row_data->{$column}; ## no critic
75 533         1632 return $self->row_data->{$column};
76             }
77              
78             sub get_columns {
79 7     7 1 3667 my $self = shift;
80              
81 7         18 my %row;
82 7         17 for my $column (keys %{ $self->row_data }) {
  7         57  
83 35         119 $row{$column} = $self->row_data->{$column};
84             }
85 7         74 return \%row;
86             }
87              
88             sub refetch {
89 3     3 1 5394 my ($self, $opts) = @_;
90 3   50     33 $opts //= +{};
91 3         12 $opts->{limit} = 1;
92              
93 3         17 my $where = $self->handler->_where_row_cond($self->table, $self->row_data);
94 3         17 return $self->handler->select($self->table_name => $where, $opts)->first;
95             }
96              
97             my %accessor_method_cache;
98             sub _accessor_method_cache {
99 266     266   408 my $self = shift;
100 266   100     1199 return $accessor_method_cache{$self->table_name} //= {};
101             }
102              
103             sub _guess_accessor_method {
104 266     266   570 my ($invocant, $method) = @_;
105              
106 266 50       632 if (ref $invocant) {
107 266         401 my $self = $invocant;
108 266         416 my $column = $method;
109              
110 266         597 my $cache = $self->_accessor_method_cache();
111 266 100       902 return $cache->{$column} if exists $cache->{$column};
112              
113 40 100   174   387 return $cache->{$column} = sub { shift->get($column) } if exists $self->row_data->{$column};
  174         509  
114              
115 10         38 my $relationships = $self->table->get_relationships;
116 10 100 66 86   99 return $cache->{$column} = sub { shift->relay($column) } if $relationships && $relationships->get($column);
  86         204  
117             }
118              
119 4         60 return undef; ## no critic
120             }
121              
122             sub can {
123 37     37 0 6369 my ($invocant, $method) = @_;
124 37         387 my $code = $invocant->SUPER::can($method);
125 37 100       244 return $code if defined $code;
126 6         27 return $invocant->_guess_accessor_method($method);
127             }
128              
129             our $AUTOLOAD;
130             sub AUTOLOAD {
131 260     260   62568 my $invocant = shift;
132 260         1157 my $column = $AUTOLOAD =~ s/^.+://r;
133              
134 260 50       741 if (ref $invocant) {
135 260         404 my $self = $invocant;
136 260         638 my $method = $self->_guess_accessor_method($column);
137 260 50       830 return $self->$method(@_) if defined $method;
138             }
139              
140 0   0     0 my $msg = sprintf q{Can't locate object method "%s" via package "%s"}, $column, ref $invocant || $invocant;
141 0         0 croak $msg;
142             }
143              
144             sub DEMOLISH {
145 161     161 1 19651 my $self = shift;
146 161         1286 delete $handler{0+$self};
147             }
148              
149             __PACKAGE__->meta->make_immutable();
150             __END__
151              
152             =pod
153              
154             =encoding utf-8
155              
156             =head1 NAME
157              
158             Aniki::Row - Row class
159              
160             =head1 SYNOPSIS
161              
162             my $result = $db->select(foo => { bar => 1 });
163             for my $row ($result->all) {
164             print $row->id, "\n";
165             }
166              
167             =head1 DESCRIPTION
168              
169             This is row class.
170              
171             =head1 INSTANCE METHODS
172              
173             =head2 C<$column()>
174              
175             Autoload column name method to C<< $row->get($column) >>.
176              
177             =head2 C<$relay()>
178              
179             Autoload relationship name method to C<< $row->relay($column) >>.
180              
181             =head2 C<get($column)>
182              
183             Returns column data.
184              
185             =head2 C<relay($name)>
186              
187             Returns related data.
188             If not yet cached, call C<relay_fetch>.
189              
190             =head2 C<relay_fetch($name)>
191              
192             Fetch related data, and returns related data.
193              
194             =head2 C<get_column($column)>
195              
196             Returns column data without inflate filters.
197              
198             =head2 C<get_columns()>
199              
200             Returns columns data as hash reference.
201              
202             =head2 C<refetch()>
203              
204             =head1 ACCESSORS
205              
206             =over 4
207              
208             =item C<handler : Aniki>
209              
210             =item C<schema : Aniki::Schema>
211              
212             =item C<table : Aniki::Schema::Table>
213              
214             =item C<filter : Aniki::Filter>
215              
216             =item C<table_name : Str>
217              
218             =item C<is_new : Bool>
219              
220             =item C<row_data : HashRef>
221              
222             =item C<relay_data : HashRef>
223              
224             =back
225              
226             =head1 LICENSE
227              
228             Copyright (C) karupanerura.
229              
230             This library is free software; you can redistribute it and/or modify
231             it under the same terms as Perl itself.
232              
233             =head1 AUTHOR
234              
235             karupanerura E<lt>karupa@cpan.orgE<gt>
236              
237             =cut