File Coverage

blib/lib/DBIx/Class/Helper/Row/ProxyResultSetMethod.pm
Criterion Covered Total %
statement 43 43 100.0
branch 7 8 87.5
condition 4 6 66.6
subroutine 13 13 100.0
pod 3 3 100.0
total 70 73 95.8


line stmt bran cond sub pod time code
1             package DBIx::Class::Helper::Row::ProxyResultSetMethod;
2             $DBIx::Class::Helper::Row::ProxyResultSetMethod::VERSION = '2.035000';
3             # ABSTRACT: Efficiently reuse ResultSet methods from results with fallback
4              
5 56     56   136437 use strict;
  56         147  
  56         1798  
6 56     56   347 use warnings;
  56         1320  
  56         3004  
7              
8 56     56   304 use parent 'DBIx::Class::Helper::Row::SelfResultSet', 'DBIx::Class::Row';
  56         121  
  56         1544  
9              
10 56     56   3676 use Sub::Name ();
  56         137  
  56         971  
11              
12 56     56   332 use DBIx::Class::Candy::Exports;
  56         120  
  56         414  
13              
14             export_methods [qw( proxy_resultset_method )];
15              
16             __PACKAGE__->mk_group_accessors(inherited => '_proxy_slots');
17              
18             sub proxy_resultset_method {
19 112     112 1 420652 my ($self, $name, $attr) = @_;
20              
21 112   66     671 my $rs_method = $attr->{resultset_method} || "with_$name";
22 112   66     476 my $slot = $attr->{slot} || $name;
23              
24 112 100       2541 $self->_proxy_slots([]) unless $self->_proxy_slots;
25 112         12132 push @{$self->_proxy_slots}, $slot;
  112         2133  
26              
27 56     56   29841 no strict 'refs';
  56         169  
  56         3992  
28 112         1817 my $method = $self . '::' . $name;
29 112         687 *{$method} = Sub::Name::subname $method, sub {
30 6     6   12127 my ($self) = @_;
        6      
        6      
31 56     56   429 use strict 'refs';
  56         136  
  56         14059  
32              
33 6 100       37 unless ($self->has_column_loaded($slot)) {
34             # boo. The accessor checks that there's an actual column defined, so we
35             # skip it so we can cache results.
36 4         66 $self->{_column_data}{$slot} = undef;
37 4         31 $self->set_column(
38             $slot,
39             $self->self_rs
40             ->search(undef, { columns => [] })
41             ->$rs_method
42             ->get_column($slot)
43             ->next,
44             );
45             }
46              
47 6         395 return $self->get_column($slot)
48             }
49 112         970 }
50              
51             sub copy {
52 2 100   2 1 3995 delete local @{$_[0]->{_column_data}}{@{$_[0]->_proxy_slots||[]}};
  2         261  
  2         63  
53              
54 2         12 shift->next::method(@_);
55             }
56              
57             sub update {
58 1 50   1 1 719 delete local @{$_[0]->{_dirty_columns}}{@{$_[0]->_proxy_slots||[]}};
  1         34  
  1         28  
59              
60 1         6 shift->next::method(@_);
61             }
62              
63             1;
64              
65             __END__
66              
67             =pod
68              
69             =head1 NAME
70              
71             DBIx::Class::Helper::Row::ProxyResultSetMethod - Efficiently reuse ResultSet methods from results with fallback
72              
73             =head1 SYNOPSIS
74              
75             ResultSet:
76              
77             package MyApp::Schema::ResultSet::Foo;
78              
79             use parent 'DBIx::Class::ResultSet';
80              
81             __PACKAGE__->load_components(qw(
82             Helper::ResultSet::CorrelateRelationship
83             ));
84              
85             ...;
86              
87             sub with_friend_count {
88             shift->search(undef, {
89             '+columns' => {
90             'friend_count' => $self->correlate('friends')->count_rs->as_query,
91             },
92             })
93             }
94              
95             Result:
96              
97             package MyApp::Schema::Result::Foo;
98              
99             use parent 'DBIx::Class::Core';
100              
101             __PACKAGE__->load_components(qw( Helper::Row::ProxyResultSetMethod ));
102              
103             __PACKAGE__->proxy_resultset_method('friend_count');
104              
105             or with L<DBIx::Class::Candy>:
106              
107             package MyApp::Schema::Result::Foo;
108              
109             use DBIx::Class::Candy -components => ['Helper::Row::ProxyResultSetMethod'];
110              
111             proxy_resultset_method 'friend_count';
112              
113             Elsewhere:
114              
115             my $row = $foo_rs->first;
116             say $row->friend_count . ' friends';
117              
118             =head1 DESCRIPTION
119              
120             This module makes reusing resultset methods from a result trivially easy. You
121             should be using it.
122              
123             =head1 METHODS
124              
125             =head2 proxy_resultset_method
126              
127             __PACKAGE__->proxy_resultset_method( $name => {
128             slot => $slot,
129             resultset_method => $rs_method
130             });
131              
132             C<proxy_resultset_method>'s first argument is the name of the method to
133             generate and is required. The other two arguments, C<$slot>, and
134             C<$resultset_method> are optional. If unspecified C<$slot> will default to
135             C<$name> and C<$resultset_method> will default to C<"with_$name">. C<$slot>
136             is the column that the data being retrieved is stored as in the ResultSet
137             method being proxied to. C<$resultset_method> is (duh) the ResultSet method
138             being proxied to.
139              
140             If you did not call the C<with_*> method on your ResultSet, and call the
141             proxy method, it will transparently B<fallback> and do the call and fetch
142             the needed data. E.g.:
143              
144             my $foo = $schema->resultset('Foo')->first; ## did not call with_friend_count
145             print $foo->friend_count; ## will produce desired result magically
146              
147             =head1 CANDY EXPORTS
148              
149             If used in conjunction with L<DBIx::Class::Candy> this component will export:
150              
151             =over
152              
153             =item proxy_resultset_method
154              
155             =back
156              
157             =head1 DEDICATION
158              
159             This module is dedicated to Ray Bradbury, who wrote Something Wicked This Way
160             Comes, Dandelion Wine, and numerous short stories, plays, etc etc. Read this
161             author's books.
162              
163             =head1 AUTHOR
164              
165             Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
166              
167             =head1 COPYRIGHT AND LICENSE
168              
169             This software is copyright (c) 2020 by Arthur Axel "fREW" Schmidt.
170              
171             This is free software; you can redistribute it and/or modify it under
172             the same terms as the Perl 5 programming language system itself.
173              
174             =cut