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.035000';
3             # ABSTRACT: Combine ResultSet searches with OR's
4              
5 56     56   29184 use strict;
  56         150  
  56         1665  
6 56     56   283 use warnings;
  56         141  
  56         1641  
7              
8 56     56   310 use parent 'DBIx::Class::ResultSet';
  56         123  
  56         305  
9              
10 56     56   3944 use List::Util 'first';
  56         157  
  56         4295  
11 56     56   27891 use Carp::Clan;
  56         102071  
  56         409  
12 56     56   6641 use namespace::clean;
  56         166  
  56         392  
13              
14             sub search_or {
15 2     2 1 2889 my $self = shift;
16 2         5 my @others = @{shift @_ };
  2         8  
17              
18             croak 'All ResultSets passed to search_or must have the same result_source ' .
19 2 100   4   13 'as the invocant!' if first { $self->result_source != $_->result_source } @others;
  4         24  
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) 2020 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