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 |