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.034002';
3             # ABSTRACT: Efficiently reuse ResultSet methods from results with fallback
4              
5 55     55   128652 use strict;
  55         123  
  55         1396  
6 55     55   258 use warnings;
  55         125  
  55         1341  
7              
8 55     55   314 use parent 'DBIx::Class::Helper::Row::SelfResultSet', 'DBIx::Class::Row';
  55         105  
  55         286  
9              
10 55     55   2861 use Sub::Name ();
  55         106  
  55         809  
11              
12 55     55   246 use DBIx::Class::Candy::Exports;
  55         113  
  55         389  
13              
14             export_methods [qw( proxy_resultset_method )];
15              
16             __PACKAGE__->mk_group_accessors(inherited => '_proxy_slots');
17              
18             sub proxy_resultset_method {
19 110     110 1 331107 my ($self, $name, $attr) = @_;
20              
21 110   66     567 my $rs_method = $attr->{resultset_method} || "with_$name";
22 110   66     412 my $slot = $attr->{slot} || $name;
23              
24 110 100       2045 $self->_proxy_slots([]) unless $self->_proxy_slots;
25 110         9915 push @{$self->_proxy_slots}, $slot;
  110         1774  
26              
27 55     55   25969 no strict 'refs';
  55         2395  
  55         3208  
28 110         1465 my $method = $self . '::' . $name;
29 110         574 *{$method} = Sub::Name::subname $method, sub {
30 6     6   10199 my ($self) = @_;
        6      
        6      
31 55     55   322 use strict 'refs';
  55         107  
  55         11137  
32              
33 6 100       29 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         52 $self->{_column_data}{$slot} = undef;
37 4         22 $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         325 return $self->get_column($slot)
48             }
49 110         806 }
50              
51             sub copy {
52 2 100   2 1 3212 delete local @{$_[0]->{_column_data}}{@{$_[0]->_proxy_slots||[]}};
  2         203  
  2         50  
53              
54 2         9 shift->next::method(@_);
55             }
56              
57             sub update {
58 1 50   1 1 589 delete local @{$_[0]->{_dirty_columns}}{@{$_[0]->_proxy_slots||[]}};
  1         28  
  1         22  
59              
60 1         5 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) 2019 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