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.036000';
3             # ABSTRACT: Efficiently reuse ResultSet methods from results with fallback
4              
5 56     56   90803 use strict;
  56         130  
  56         1545  
6 56     56   312 use warnings;
  56         176  
  56         3213  
7              
8 56     56   279 use parent 'DBIx::Class::Helper::Row::SelfResultSet', 'DBIx::Class::Row';
  56         115  
  56         293  
9              
10 56     56   4734 use Sub::Name ();
  56         126  
  56         926  
11              
12 56     56   267 use DBIx::Class::Candy::Exports;
  56         113  
  56         430  
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 376966 my ($self, $name, $attr) = @_;
20              
21 112   66     701 my $rs_method = $attr->{resultset_method} || "with_$name";
22 112   66     456 my $slot = $attr->{slot} || $name;
23              
24 112 100       2302 $self->_proxy_slots([]) unless $self->_proxy_slots;
25 112         11082 push @{$self->_proxy_slots}, $slot;
  112         2000  
26              
27 56     56   27190 no strict 'refs';
  56         126  
  56         3585  
28 112         1670 my $method = $self . '::' . $name;
29 112         640 *{$method} = Sub::Name::subname $method, sub {
30 6     6   12581 my ($self) = @_;
        6      
        6      
31 56     56   455 use strict 'refs';
  56         128  
  56         12974  
32              
33 6 100       35 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         64 $self->{_column_data}{$slot} = undef;
37 4         28 $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         385 return $self->get_column($slot)
48             }
49 112         880 }
50              
51             sub copy {
52 2 100   2 1 4097 delete local @{$_[0]->{_column_data}}{@{$_[0]->_proxy_slots||[]}};
  2         257  
  2         62  
53              
54 2         10 shift->next::method(@_);
55             }
56              
57             sub update {
58 1 50   1 1 915 delete local @{$_[0]->{_dirty_columns}}{@{$_[0]->_proxy_slots||[]}};
  1         36  
  1         34  
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