Fix busted get_column when using +select (and friends)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSetColumn.pm
CommitLineData
2bb7b40b 1package DBIx::Class::ResultSetColumn;
2use strict;
3use warnings;
4use base 'DBIx::Class';
66521001 5use List::Util;
2bb7b40b 6
7=head1 NAME
8
9 DBIx::Class::ResultSetColumn - helpful methods for messing
10 with a single column of the resultset
11
12=head1 SYNOPSIS
13
14 $rs = $schema->resultset('CD')->search({ artist => 'Tool' });
15 $rs_column = $rs->get_column('year');
16 $max_year = $rs_column->max; #returns latest year
17
18=head1 DESCRIPTION
19
eb98561c 20A convenience class used to perform operations on a specific column of
21a resultset.
2bb7b40b 22
23=cut
24
25=head1 METHODS
26
27=head2 new
28
29 my $obj = DBIx::Class::ResultSetColumn->new($rs, $column);
30
eb98561c 31Creates a new resultset column object from the resultset and column
32passed as params. Used internally by L<DBIx::Class::ResultSet/get_column>.
2bb7b40b 33
34=cut
35
36sub new {
37 my ($class, $rs, $column) = @_;
38 $class = ref $class if ref $class;
3f6cc7e4 39 my $new_parent_rs = $rs->search_rs; # we don't want to mess up the original, so clone it
5d1fc7dc 40 my $attrs = $new_parent_rs->_resolved_attrs;
121068ec 41 $new_parent_rs->{attrs}->{prefetch} = undef; # prefetch cause additional columns to be fetched
b6e85b48 42
152002c4 43 # If $column can be found in the 'as' list of the parent resultset, use the
44 # corresponding element of its 'select' list (to keep any custom column
45 # definition set up with 'select' or '+select' attrs), otherwise use $column
46 # (to create a new column definition on-the-fly).
b6e85b48 47 my $as_list = $attrs->{as} || [];
48 my $select_list = $attrs->{select} || [];
49 my $as_index = List::Util::first { ($as_list->[$_] || "") eq $column } 0..$#$as_list;
b6e85b48 50 my $select = defined $as_index ? $select_list->[$as_index] : $column;
51
52 my $new = bless { _select => $select, _as => $column, _parent_resultset => $new_parent_rs }, $class;
6b051e14 53 $new->throw_exception("column must be supplied") unless $column;
2bb7b40b 54 return $new;
55}
56
70bb942d 57=head2 as_query (EXPERIMENTAL)
658fa250 58
59=over 4
60
61=item Arguments: none
62
4dc99a01 63=item Return Value: \[ $sql, @bind ]
658fa250 64
65=back
66
67Returns the SQL query and bind vars associated with the invocant.
68
03834f77 69This is generally used as the RHS for a subquery.
c7a9d102 70
6a9530d1 71B<NOTE>: This feature is still experimental.
72
c7a9d102 73=cut
74
03834f77 75sub as_query { return shift->_resultset->as_query }
c7a9d102 76
2bb7b40b 77=head2 next
78
79=over 4
80
81=item Arguments: none
82
83=item Return Value: $value
84
85=back
86
eb98561c 87Returns the next value of the column in the resultset (or C<undef> if
88there is none).
2bb7b40b 89
eb98561c 90Much like L<DBIx::Class::ResultSet/next> but just returning the
91one value.
2bb7b40b 92
93=cut
94
95sub next {
96 my $self = shift;
66521001 97 my ($row) = $self->_resultset->cursor->next;
2bb7b40b 98 return $row;
99}
100
101=head2 all
102
103=over 4
104
105=item Arguments: none
106
107=item Return Value: @values
108
109=back
110
eb98561c 111Returns all values of the column in the resultset (or C<undef> if
112there are none).
2bb7b40b 113
eb98561c 114Much like L<DBIx::Class::ResultSet/all> but returns values rather
115than row objects.
2bb7b40b 116
117=cut
118
119sub all {
120 my $self = shift;
66521001 121 return map { $_->[0] } $self->_resultset->cursor->all;
122}
123
124=head2 reset
125
126=over 4
127
128=item Arguments: none
129
130=item Return Value: $self
131
132=back
133
134Resets the underlying resultset's cursor, so you can iterate through the
135elements of the column again.
136
137Much like L<DBIx::Class::ResultSet/reset>.
138
139=cut
140
141sub reset {
142 my $self = shift;
143 $self->_resultset->cursor->reset;
144 return $self;
145}
146
147=head2 first
148
149=over 4
150
151=item Arguments: none
152
153=item Return Value: $value
154
155=back
156
157Resets the underlying resultset and returns the next value of the column in the
158resultset (or C<undef> if there is none).
159
160Much like L<DBIx::Class::ResultSet/first> but just returning the one value.
161
162=cut
163
164sub first {
165 my $self = shift;
3484603a 166 my ($row) = $self->_resultset->cursor->reset->next;
66521001 167 return $row;
2bb7b40b 168}
169
170=head2 min
171
172=over 4
173
174=item Arguments: none
175
176=item Return Value: $lowest_value
177
178=back
179
eb98561c 180 my $first_year = $year_col->min();
181
182Wrapper for ->func. Returns the lowest value of the column in the
183resultset (or C<undef> if there are none).
2bb7b40b 184
185=cut
186
187sub min {
6b051e14 188 return shift->func('MIN');
2bb7b40b 189}
190
4fa7bc22 191=head2 min_rs
192
193=over 4
194
195=item Arguments: none
196
197=item Return Value: $resultset
198
199=back
200
201 my $rs = $year_col->min_rs();
202
203Wrapper for ->func_rs for function MIN().
204
205=cut
206
207sub min_rs { return shift->func_rs('MIN') }
208
2bb7b40b 209=head2 max
210
211=over 4
212
213=item Arguments: none
214
215=item Return Value: $highest_value
216
217=back
218
eb98561c 219 my $last_year = $year_col->max();
220
221Wrapper for ->func. Returns the highest value of the column in the
222resultset (or C<undef> if there are none).
2bb7b40b 223
224=cut
225
226sub max {
6b051e14 227 return shift->func('MAX');
2bb7b40b 228}
229
4fa7bc22 230=head2 max_rs
231
232=over 4
233
234=item Arguments: none
235
236=item Return Value: $resultset
237
238=back
239
240 my $rs = $year_col->max_rs();
241
242Wrapper for ->func_rs for function MAX().
243
244=cut
245
246sub max_rs { return shift->func_rs('MAX') }
247
2bb7b40b 248=head2 sum
249
250=over 4
251
252=item Arguments: none
253
254=item Return Value: $sum_of_values
255
256=back
257
eb98561c 258 my $total = $prices_col->sum();
259
260Wrapper for ->func. Returns the sum of all the values in the column of
261the resultset. Use on varchar-like columns at your own risk.
2bb7b40b 262
263=cut
264
265sub sum {
6b051e14 266 return shift->func('SUM');
2bb7b40b 267}
268
4fa7bc22 269=head2 sum_rs
270
271=over 4
272
273=item Arguments: none
274
275=item Return Value: $resultset
276
277=back
278
279 my $rs = $year_col->sum_rs();
280
281Wrapper for ->func_rs for function SUM().
282
283=cut
284
285sub sum_rs { return shift->func_rs('SUM') }
286
2bb7b40b 287=head2 func
288
289=over 4
290
291=item Arguments: $function
292
293=item Return Value: $function_return_value
294
295=back
296
e8419341 297 $rs = $schema->resultset("CD")->search({});
298 $length = $rs->get_column('title')->func('LENGTH');
2bb7b40b 299
eb98561c 300Runs a query using the function on the column and returns the
301value. Produces the following SQL:
302
303 SELECT LENGTH( title ) FROM cd me
2bb7b40b 304
305=cut
306
307sub func {
6b051e14 308 my ($self,$function) = @_;
4fa7bc22 309 my $cursor = $self->func_rs($function)->cursor;
5d62876f 310
311 if( wantarray ) {
312 return map { $_->[ 0 ] } $cursor->all;
313 }
314
315 return ( $cursor->next )[ 0 ];
2bb7b40b 316}
317
4fa7bc22 318=head2 func_rs
319
320=over 4
321
322=item Arguments: $function
323
324=item Return Value: $resultset
325
326=back
327
328Creates the resultset that C<func()> uses to run its query.
329
330=cut
331
332sub func_rs {
333 my ($self,$function) = @_;
334 return $self->{_parent_resultset}->search(
335 undef, {
336 select => {$function => $self->{_select}},
337 as => [$self->{_as}],
338 },
339 );
340}
341
5d1fc7dc 342=head2 throw_exception
343
344See L<DBIx::Class::Schema/throw_exception> for details.
345
346=cut
347
348sub throw_exception {
349 my $self=shift;
350 if (ref $self && $self->{_parent_resultset}) {
351 $self->{_parent_resultset}->throw_exception(@_)
352 } else {
353 croak(@_);
354 }
355}
356
b6e85b48 357# _resultset
358#
359# Arguments: none
360#
361# Return Value: $resultset
362#
363# $year_col->_resultset->next
364#
365# Returns the underlying resultset. Creates it from the parent resultset if
366# necessary.
367#
66521001 368sub _resultset {
369 my $self = shift;
370
371 return $self->{_resultset} ||= $self->{_parent_resultset}->search(undef,
372 {
373 select => [$self->{_select}],
374 as => [$self->{_as}]
375 }
376 );
377}
378
2bb7b40b 3791;
380
381=head1 AUTHORS
382
383Luke Saunders <luke.saunders@gmail.com>
384
eb98561c 385Jess Robinson
386
2bb7b40b 387=head1 LICENSE
388
389You may distribute this code under the same terms as Perl itself.
390
391=cut