File Coverage

blib/lib/DBIx/Class/Helper/ResultSet/SearchOr.pm
Criterion Covered Total %
statement 24 24 100.0
branch 2 2 100.0
condition n/a
subroutine 8 8 100.0
pod 1 1 100.0
total 35 35 100.0


line stmt bran cond sub pod time code
1             package DBIx::Class::Helper::ResultSet::SearchOr;
2             $DBIx::Class::Helper::ResultSet::SearchOr::VERSION = '2.034002';
3             # ABSTRACT: Combine ResultSet searches with OR's
4              
5 55     55   21632 use strict;
  55         115  
  55         1236  
6 55     55   227 use warnings;
  55         95  
  55         1192  
7              
8 55     55   230 use parent 'DBIx::Class::ResultSet';
  55         93  
  55         228  
9              
10 55     55   3069 use List::Util 'first';
  55         104  
  55         3949  
11 55     55   21364 use Carp::Clan;
  55         79220  
  55         336  
12 55     55   4819 use namespace::clean;
  55         110  
  55         303  
13              
14             sub search_or {
15 2     2 1 2380 my $self = shift;
16 2         5 my @others = @{shift @_ };
  2         6  
17              
18             croak 'All ResultSets passed to search_or must have the same result_source ' .
19 2 100   4   12 'as the invocant!' if first { $self->result_source != $_->result_source } @others;
  4         21  
20              
21             $self->search({
22             -or => [
23             map $_->_resolved_attrs->{where}, @others
24 1         8 ],
25             });
26             }
27              
28             1;
29              
30             __END__
31              
32             =pod
33              
34             =head1 NAME
35              
36             DBIx::Class::Helper::ResultSet::SearchOr - Combine ResultSet searches with OR's
37              
38             =head1 SYNOPSIS
39              
40             package MyApp::Schema::ResultSet::Tests;
41              
42             use parent 'DBIx::Class::ResultSet';
43              
44             __PACKAGE__->load_components(qw(Helper::ResultSet::IgnoreWantarray Helper::ResultSet::SearchOr));
45              
46             sub failed {
47             my $self = shift;
48              
49             my $me = $self->current_source_alias;
50              
51             $self->search({ "$me.passed" => '0' });
52             }
53              
54             sub untested {
55             my $self = shift;
56              
57             my $me = $self->current_source_alias;
58              
59             $self->search({ "$me.passed" => undef });
60             }
61              
62             sub not_passed {
63             my $self = shift;
64              
65             my $me = $self->current_source_alias;
66              
67             $self->search_or([$self->failed, $self->untested]);
68             }
69              
70             1;
71              
72             =head1 DESCRIPTION
73              
74             I would argue that the most important feature of L<DBIx::Class> is the fact
75             that you can "chain" ResultSet searches. Unfortunately this can cause problems
76             when you need to reuse multiple ResultSet methods as... well as or's. In the
77             past I got around this by doing:
78              
79             $rs->foo->union([ $rs->bar]);
80              
81             While this works, it can generate some hairy SQL pretty fast. This Helper is
82             supposed to basically be a lightweight union. Note that it therefor has a
83             number of L</LIMITATIONS>. The thing that makes this module special is that
84             the ResultSet that is doing the "search_or" ing still limits everything
85             correctly. To be clear, the following only returns C<$user>'s friends that
86             match either of the following criteria:
87              
88             my $friend_rs = $schema->resultset('Friend');
89             my @internet_friends = $user->friends->search_or([
90             $friend_rs->on_facebook,
91             $friend_rs->on_twitter,
92             ])->all;
93              
94             With a union, you'd have to implement it like this:
95              
96             $user->friends->on_facebook->union([ $user->friends->on_twitter ]);
97              
98             The union will work, but it will generate more complex SQL that may have lower
99             performance on your database.
100              
101             See L<DBIx::Class::Helper::ResultSet/NOTE> for a nice way to apply it to
102             your entire schema.
103              
104             =head1 METHODS
105              
106             =head2 search_or
107              
108             my $new_rs = $rs->search_or([ $rs->foo, $rs->bar ]);
109              
110             C<search_or> takes a single arrayref of ResultSets. The ResultSets B<must>
111             point to the same source or you will get an error message. Additionally, no
112             check is made to ensure that more than one ResultSet is in the ArrayRef, but
113             only passing one ResultSet would not make any sense.
114              
115             =head1 LIMITATIONS
116              
117             Because this module us basically an expression union and not a true union,
118             C<JOIN>'s won't Just Work. If you have a ResultSet method that uses a C<JOIN>
119             and you want to C<OR> it with another method, you'll need to do something like
120             this:
121              
122             my @authors = $authors->search(undef, { join => 'books' })->search_or([
123             $authors->wrote_good_books,
124             $authors->wrote_bestselling_books,
125             ])->all;
126              
127             Furthermore, if you want to C<OR> two methods that C<JOIN> in the same
128             relationship via alternate paths you B<must> use
129             L<union|DBIx::Class::Helper::ResultSet::SetOperations/union>.
130              
131             =head1 AUTHOR
132              
133             Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
134              
135             =head1 COPYRIGHT AND LICENSE
136              
137             This software is copyright (c) 2019 by Arthur Axel "fREW" Schmidt.
138              
139             This is free software; you can redistribute it and/or modify it under
140             the same terms as the Perl 5 programming language system itself.
141              
142             =cut