X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=7b659ef3bb6658db789baf6d1104cb069218d2f6;hb=43da768fcaf3e4ad27f8ad87bcd7ce3a6a596a32;hp=0a6963b3a74faad96792ac19fbd98023bf5ecbc7;hpb=9f2baadf578157afd2130127f76ae07b17fbbdc5;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 0a6963b..7b659ef 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -9,13 +9,17 @@ use Data::Page; use Storable; use DBIx::Class::ResultSetColumn; use DBIx::Class::ResultSourceHandle; -use List::Util (); use Hash::Merge (); use Scalar::Util qw/blessed weaken/; use Try::Tiny; use Storable qw/nfreeze thaw/; + +# not importing first() as it will clash with our own method +use List::Util (); + use namespace::clean; + BEGIN { # De-duplication in _merge_attr() is disabled, but left in for reference *__HM_DEDUP = sub () { 0 }; @@ -267,15 +271,22 @@ sub search { my $self = shift; my $rs = $self->search_rs( @_ ); - my $want = wantarray; - if ($want) { + if (wantarray) { return $rs->all; } - elsif (defined $want) { + elsif (defined wantarray) { return $rs; } else { - $self->throw_exception ('->search is *not* a mutator, calling it in void context makes no sense'); + # we can be called by a relationship helper, which in + # turn may be called in void context due to some braindead + # overload or whatever else the user decided to be clever + # at this particular day. Thus limit the exception to + # external code calls only + $self->throw_exception ('->search is *not* a mutator, calling it in void context makes no sense') + if (caller)[0] !~ /^\QDBIx::Class::/; + + return (); } } @@ -294,6 +305,7 @@ always return a resultset, even in list context. =cut +my $callsites_warned; sub search_rs { my $self = shift; @@ -359,8 +371,17 @@ sub search_rs { } if @_; - carp 'search( %condition ) is deprecated, use search( \%condition ) instead' - if (@_ > 1 and ! $self->result_source->result_class->isa('DBIx::Class::CDBICompat') ); + if( @_ > 1 and ! $self->result_source->result_class->isa('DBIx::Class::CDBICompat') ) { + # determine callsite obeying Carp::Clan rules (fucking ugly but don't have better ideas) + my $callsite = do { + my $w; + local $SIG{__WARN__} = sub { $w = shift }; + carp; + $w + }; + carp 'search( %condition ) is deprecated, use search( \%condition ) instead' + unless $callsites_warned->{$callsite}++; + } for ($old_where, $call_cond) { if (defined $_) { @@ -1302,10 +1323,42 @@ sub _count_subq_rs { if (ref $sel eq 'HASH' and $sel->{-as}); } - for my $g_part (@$g) { - my $colpiece = $sel_index->{$g_part} || $g_part; + # anything from the original select mentioned on the group-by needs to make it to the inner selector + # also look for named aggregates referred in the having clause + # having often contains scalarrefs - thus parse it out entirely + my @parts = @$g; + if ($attrs->{having}) { + local $sql_maker->{having_bind}; + local $sql_maker->{quote_char} = $sql_maker->{quote_char}; + local $sql_maker->{name_sep} = $sql_maker->{name_sep}; + unless (defined $sql_maker->{quote_char} and length $sql_maker->{quote_char}) { + $sql_maker->{quote_char} = [ "\x00", "\xFF" ]; + # if we don't unset it we screw up retarded but unfortunately working + # 'MAX(foo.bar)' => { '>', 3 } + $sql_maker->{name_sep} = ''; + } + + my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep); + + my $sql = $sql_maker->_parse_rs_attrs ({ having => $attrs->{having} }); + + # search for both a proper quoted qualified string, for a naive unquoted scalarref + # and if all fails for an utterly naive quoted scalar-with-function + while ($sql =~ / + $rquote $sep $lquote (.+?) $rquote + | + [\s,] \w+ \. (\w+) [\s,] + | + [\s,] $lquote (.+?) $rquote [\s,] + /gx) { + push @parts, ($1 || $2 || $3); # one of them matched if we got here + } + } + + for (@parts) { + my $colpiece = $sel_index->{$_} || $_; - # disqualify join-based group_by's. Arcane but possible query + # unqualify join-based group_by's. Arcane but possible query # also horrible horrible hack to alias a column (not a func.) # (probably need to introduce SQLA syntax) if ($colpiece =~ /\./ && $colpiece !~ /^$attrs->{alias}\./) { @@ -2709,7 +2762,7 @@ sub is_paged { sub is_ordered { my ($self) = @_; - return scalar $self->result_source->storage->_extract_order_columns($self->{attrs}{order_by}); + return scalar $self->result_source->storage->_extract_order_criteria($self->{attrs}{order_by}); } =head2 related_resultset @@ -3152,16 +3205,6 @@ sub _resolved_attrs { $_->{as} = [ map { $_ =~ /^\Q$alias.\E(.+)$/ ? $1 : $_ } @{$_->{as}} ]; } - # FIXME !!! - # Blatant bugwardness encoded into multiple tests. - # While columns behaves sensibly, +columns is expected - # to dump *any* foreign columns into the main object - # /me vomits - $selection_pieces->{'+columns'}{as} = [ map - { (split /\./, $_)[-1] } - @{$selection_pieces->{'+columns'}{as}} - ]; - # merge everything for (@sel_pairs) { $attrs->{select} = $self->_merge_attr ($attrs->{select}, $selection_pieces->{$_}{select}); @@ -3961,7 +4004,11 @@ HAVING is a select statement attribute that is applied between GROUP BY and ORDER BY. It is applied to the after the grouping calculations have been done. - having => { 'count(employee)' => { '>=', 100 } } + having => { 'count_employee' => { '>=', 100 } } + +or with an in-place function in which case literal SQL is required: + + having => \[ 'count(employee) >= ?', [ count => 100 ] ] =head2 distinct