1 |
3 |
ahitrov@rambler.ru |
package SQL::CommonFilters; |
2 |
|
|
|
3 |
|
|
use strict; |
4 |
|
|
use SQL::Common; |
5 |
|
|
use Contenido::Globals; |
6 |
|
|
|
7 |
|
|
########### FILTERS DESCRIPTION #################################################################################### |
8 |
|
|
sub _status_filter { |
9 |
|
|
my ($self, %opts)=@_; |
10 |
|
|
return undef unless ( exists($opts{status}) ); |
11 |
|
|
return &SQL::Common::_generic_int_filter('d.status', $opts{status}); |
12 |
|
|
} |
13 |
|
|
|
14 |
|
|
sub _class_filter { |
15 |
|
|
my ($self, %opts)=@_; |
16 |
|
|
return undef unless ( exists($opts{class}) ); |
17 |
|
|
return &SQL::Common::_generic_text_filter('d.class', $opts{class}); |
18 |
|
|
} |
19 |
|
|
|
20 |
|
|
sub _in_id_filter { |
21 |
|
|
my ($self, %opts)=@_; |
22 |
|
|
return undef unless ( exists($opts{in_id}) ); |
23 |
|
|
return &SQL::Common::_generic_int_filter('d.id', $opts{in_id}); |
24 |
|
|
} |
25 |
|
|
|
26 |
|
|
sub _id_filter { |
27 |
|
|
my ($self, %opts)=@_; |
28 |
|
|
return undef unless ( exists($opts{id}) ); |
29 |
|
|
return &SQL::Common::_generic_int_filter('d.id', $opts{id}); |
30 |
|
|
} |
31 |
|
|
|
32 |
|
|
sub _sfilter_filter { |
33 |
|
|
my ($self, %opts)=@_; |
34 |
|
|
return undef unless ( exists($opts{sfilter}) ); |
35 |
|
|
return &SQL::Common::_generic_intarray_filter('d.sections', $opts{sfilter}); |
36 |
|
|
} |
37 |
|
|
|
38 |
|
|
sub _name_filter { |
39 |
|
|
my ($self, %opts)=@_; |
40 |
|
|
return undef unless ( exists($opts{name}) ); |
41 |
|
|
return &SQL::Common::_generic_name_filter('d.name', $opts{name}, 0, \%opts); |
42 |
|
|
} |
43 |
|
|
|
44 |
|
|
|
45 |
|
|
sub _datetime_filter { |
46 |
|
|
my ($self, %opts)=@_; |
47 |
|
|
return undef unless ( exists($opts{datetime}) ); |
48 |
|
|
if ($opts{datetime} eq 'future') { |
49 |
|
|
return " ($opts{usedtime} >= CURRENT_TIMESTAMP) "; |
50 |
|
|
} elsif ($opts{datetime} eq 'past') { |
51 |
|
|
return " ($opts{usedtime} <= CURRENT_TIMESTAMP) "; |
52 |
|
|
} elsif ($opts{datetime} eq 'today') { |
53 |
|
|
return " ($opts{usedtime}>=CURRENT_DATE AND $opts{usedtime}<CURRENT_DATE+'1 day'::INTERVAL) "; |
54 |
|
|
} elsif (ref $opts{'datetime'} && ref $opts{'datetime'} eq 'HASH') { |
55 |
|
|
my ($type, $time) = %{$opts{'datetime'}}; |
56 |
|
|
if ($time =~ /^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}(?:\.\d+)?$/ && $type eq 'after') { |
57 |
|
|
return " ($opts{usedtime} >= '$time') "; |
58 |
|
|
} elsif ($time =~ /^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}(?:\.\d+)?$/ && $type eq 'before') { |
59 |
|
|
return " ($opts{usedtime} <= '$time') "; |
60 |
|
|
} else { |
61 |
|
|
warn "Contenido Warning: ������� ����� ������ datetime='$opts{datetime}' ���������� ��������: 'future','past','today', {['after' || 'before'] => [timestamp]}\n"; |
62 |
|
|
return ' FALSE '; |
63 |
|
|
} |
64 |
|
|
return " ($opts{usedtime}>=CURRENT_DATE AND $opts{usedtime}<CURRENT_DATE+'1 day'::INTERVAL) "; |
65 |
|
|
|
66 |
|
|
} else { |
67 |
|
|
warn "Contenido Warning: ������� ����� ������ datetime='$opts{datetime}' ���������� ��������: 'future','past','today', {['after' || 'before'] => [timestamp]}\n"; |
68 |
|
|
return ' FALSE '; |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
sub _date_equal_filter { |
73 |
|
|
my ($self, %opts)=@_; |
74 |
|
|
return undef unless ( exists($opts{date_equal}) ); |
75 |
|
|
|
76 |
|
|
# - ������ �� ���������� ���� / YYYY-MM-DD |
77 |
|
|
if ( $opts{date_equal} =~ /^\d{4}-\d{2}-\d{2}$/) { |
78 |
|
|
return " ($opts{usedtime}>=?::TIMESTAMP AND $opts{usedtime}<?::TIMESTAMP+'1 day'::INTERVAL) ", [$opts{date_equal},$opts{date_equal}]; |
79 |
|
|
} else { |
80 |
|
|
warn "Contenido Warning: ������� ����� ������ ���� '$opts{date_equal}'. ���������� ������ - YYYY-MM-DD."; |
81 |
|
|
return ' FALSE '; |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
sub _date_filter { |
86 |
|
|
my ($self, %opts)=@_; |
87 |
|
|
return undef unless ( exists($opts{date}) ); |
88 |
|
|
# - ������ �� ���������� ���������� �� ��������� ���... |
89 |
|
|
if ( ref($opts{date}) eq 'ARRAY' and scalar(@{$opts{date}})==2 ) { |
90 |
|
|
#pure dates |
91 |
|
|
if ( ($opts{date}->[0] =~ /^\d{4}-\d{2}-\d{2}$/) and ($opts{date}->[1] =~ /^\d{4}-\d{2}-\d{2}$/) ) { |
92 |
|
|
return " ($opts{usedtime}>=?::TIMESTAMP AND $opts{usedtime}<?::TIMESTAMP+'1 day'::INTERVAL) ", [$opts{date}->[0],$opts{date}->[1]]; |
93 |
|
|
#datetimes |
94 |
|
|
} elsif ( ($opts{date}->[0] =~ /^\d{4}-\d{2}-\d{2}/) && ($opts{date}->[1] =~ /^\d{4}-\d{2}-\d{2}/) ) { |
95 |
|
|
return " ($opts{usedtime}>=? AND $opts{usedtime}<=?) ", [$opts{date}->[0],$opts{date}->[1]]; |
96 |
|
|
} else { |
97 |
|
|
warn "Contenido Warning: ������� ����� ������ ���� ��� ��������� date. ��� ������ ���� ������ � ����� ���������� ���� YYYY-MM-DD ��� YYYY-MM-DD HH:MM:SS. ['$opts{date}->[0]', '$opts{date}->[1]']\n"; |
98 |
|
|
return ' FALSE '; |
99 |
|
|
} |
100 |
|
|
} else { |
101 |
|
|
warn "Contenido Warning: ������� ����� ������ ���� ��� ��������� date. ��� ������ ���� ������ � ����� ���������� ���� YYYY-MM-DD ��� YYYY-MM-DD HH:MM:SS."; |
102 |
|
|
return ' FALSE '; |
103 |
|
|
} |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
sub _class_excludes_filter { |
107 |
|
|
my ($self, %opts)=@_; |
108 |
|
|
return undef unless ( exists($opts{class_excludes}) ); |
109 |
|
|
return &SQL::Common::_generic_text_filter('d.class', $opts{class_excludes}, 'NEGATION'); |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
sub _s_filter { |
113 |
|
|
my ($self, %opts) = @_; |
114 |
|
|
return undef unless ( exists($opts{s}) ); |
115 |
|
|
|
116 |
|
|
if ($opts{dive}) { |
117 |
|
|
my @all_childs = @{$opts{all_childs}}; |
118 |
|
|
# - ���� ����� �������� include_parent, �� ������� � ������� ������... |
119 |
|
|
# �� ��������� ��������... |
120 |
|
|
push (@all_childs, $opts{s}) if ($opts{include_parent}); |
121 |
|
|
|
122 |
|
|
return &SQL::Common::_generic_intarray_filter('d.sections', \@all_childs, \%opts); |
123 |
|
|
} else { |
124 |
|
|
return &SQL::Common::_generic_intarray_filter('d.sections', $opts{s}, \%opts); |
125 |
|
|
} |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
|
129 |
|
|
sub _previous_days_filter { |
130 |
|
|
my ($self, %opts)=@_; |
131 |
|
|
return undef unless ( exists($opts{previous_days}) ); |
132 |
|
|
# - ������ �� ��� ������ �� �������� ��������� ����... |
133 |
|
|
if ($opts{previous_days} =~ /^\d+$/) { |
134 |
|
|
return " $opts{usedtime} >= (CURRENT_DATE - ?::interval)::TIMESTAMP ", "$opts{previous_days} DAYS"; |
135 |
|
|
} else { |
136 |
|
|
warn "Contenido Warning: ������� ����� ������ ���� ��� ��������� previous_days. ��� ������ ���� ����� ����\n"; |
137 |
|
|
return ' FALSE '; |
138 |
|
|
} |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
sub _previous_time_filter { |
142 |
|
|
my ($self, %opts)=@_; |
143 |
|
|
return undef unless exists $opts{previous_time}; |
144 |
|
|
if ($opts{previous_time} =~ /\D/) { |
145 |
|
|
warn "Contenido Warning: ������� ������ ���-�� ��� ��������� previous_time.\n"; |
146 |
|
|
return ' FALSE '; |
147 |
|
|
} else { |
148 |
|
|
return "$opts{usedtime} >= (NOW() - ?::interval)::TIMESTAMP ", ($opts{previous_time} . ' ' . ($opts{previous_time_units} || 'HOURS')); |
149 |
|
|
} |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
sub _prev_to_filter { |
153 |
|
|
my ($self, %opts)=@_; |
154 |
|
|
return undef unless ( exists $opts{prevto} ); |
155 |
|
|
my ($wheres, $values) = ([],[]); |
156 |
|
|
my $field = exists $opts{use_id} ? 'id' : exists $opts{use_ctime} ? 'ctime' : exists $opts{use_mtime} ? 'mtime' : 'dtime'; |
157 |
|
|
push @$wheres, " d.$field < ? "; |
158 |
|
|
if ( ref $opts{prevto} ) { |
159 |
|
|
my $ctime = $opts{prevto}; |
160 |
|
|
push @$values, $ctime->ymd('-').' '.$ctime->hms.'.'.$ctime->nanosecond; |
161 |
|
|
} else { |
162 |
|
|
push @$values, $opts{prevto}; |
163 |
|
|
} |
164 |
|
|
return ($wheres, $values); |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
sub _next_to_filter { |
168 |
|
|
my ($self, %opts)=@_; |
169 |
|
|
return undef unless ( exists $opts{nextto} ); |
170 |
|
|
my ($wheres, $values) = ([],[]); |
171 |
|
|
my $field = exists $opts{use_id} ? 'id' : exists $opts{use_ctime} ? 'ctime' : exists $opts{use_mtime} ? 'mtime' : 'dtime'; |
172 |
|
|
push @$wheres, " d.$field > ? "; |
173 |
|
|
if ( ref $opts{nextto} ) { |
174 |
|
|
my $ctime = $opts{nextto}; |
175 |
|
|
push @$values, $ctime->ymd('-').' '.$ctime->hms.'.'.$ctime->nanosecond; |
176 |
|
|
} else { |
177 |
|
|
push @$values, $opts{nextto}; |
178 |
|
|
} |
179 |
|
|
return ($wheres, $values); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
sub _excludes_filter { |
183 |
|
|
my ($self,%opts)=@_; |
184 |
|
|
return undef unless ( exists($opts{excludes}) ); |
185 |
|
|
return &SQL::Common::_generic_int_filter('d.id', $opts{excludes}, 'NEGATION'); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
sub _auto_filter { |
189 |
|
|
my ( $self, %opts ) = @_; |
190 |
|
|
my @exclude = qw( order_by limit offset no_limit count ids light hash_by return_mode ); |
191 |
|
|
my $sql; |
192 |
|
|
|
193 |
|
|
my @wheres; |
194 |
|
|
my @binds; |
195 |
|
|
my @joins; |
196 |
|
|
|
197 |
|
|
my ( $struct, $query_table ); |
198 |
|
|
|
199 |
|
|
if ( $opts{join} ) { |
200 |
|
|
|
201 |
|
|
if ( !$opts{join}->can('class_table') || !$opts{join}->class_table()->can('db_table') ) { |
202 |
|
|
warn "Contenido Warning (_auto_filter): �� ���� �������� ��� ������� ��� \"�������\"!\n"; |
203 |
|
|
return (undef); |
204 |
|
|
} |
205 |
|
|
$query_table = $opts{join}->class_table()->db_table(); |
206 |
|
|
$struct = $opts{join}->class_table()->required_hash(); |
207 |
|
|
|
208 |
|
|
if ( $opts{field} && !$struct->{ $opts{field} } ) { |
209 |
|
|
warn "Contenido Warning (_auto_filter): � ������� $query_table ��� ���� ".$opts{field}."!\n"; |
210 |
|
|
return (undef); |
211 |
|
|
} |
212 |
|
|
|
213 |
|
|
push @joins, ' join '.$query_table.' on '.$query_table.'.'.( $opts{field} ? $opts{field} : 'id' ).' = '.$opts{__join_table}.'.'.$opts{__join_field}.' '; |
214 |
|
|
|
215 |
|
|
} else { |
216 |
|
|
$struct = $self->required_hash(); |
217 |
|
|
$query_table = 'd'; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
foreach my $param ( keys %opts ) { |
221 |
|
|
next if ( grep { $param eq $_ } @exclude ) || !$struct->{$param} || !exists($opts{$param}) || $struct->{$param}->{_no_autofilter}; |
222 |
|
|
next if $opts{$param} eq SQL::Common::NIL(); |
223 |
|
|
if ( uc($opts{$param}) eq 'NULL' || uc($opts{$param}) eq 'NOT NULL' || !defined($opts{$param}) ) { |
224 |
|
|
$opts{$param} = 'NULL' unless defined $opts{$param}; |
225 |
|
|
my ($where, $values) = &SQL::Common::_generic_null_filter($query_table.'.'.$param, $opts{$param}); |
226 |
|
|
push (@wheres, $where); |
227 |
|
|
push (@binds, $values) if (defined $values); |
228 |
|
|
next; |
229 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'integer' or $struct->{$param}->{type} eq 'checkbox') { |
230 |
|
|
my ($where, $values); |
231 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
232 |
|
|
if ( $opts{$param}->{join} ) { |
233 |
|
|
my ( $sub_wheres, $sub_binds, $joins ) = $self->_auto_filter( %{ $opts{$param} }, __join_table => $query_table, __join_field => $param ); |
234 |
|
|
push (@wheres, ref($sub_wheres) eq 'ARRAY' ? @{ $sub_wheres } : $sub_wheres ) if defined $sub_wheres; |
235 |
|
|
push (@binds, ref($sub_binds) eq 'ARRAY' ? @{ $sub_binds } : $sub_binds ) if defined $sub_binds; |
236 |
|
|
push (@joins, ref($joins) eq 'ARRAY' ? @{ $joins } : $joins ) if defined $joins; |
237 |
|
|
|
238 |
|
|
} else { |
239 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
240 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
241 |
|
|
push (@wheres, $where); |
242 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
} else { |
246 |
|
|
if ( !ref($opts{$param}) && $opts{$param} !~ /^\-?\d+$/ ) { |
247 |
|
|
warn "Contenido Warning (_auto_filter): ������� ������ �������� ��� ���� integer! ($opts{$param})\n"; |
248 |
|
|
next; |
249 |
|
|
} |
250 |
|
|
($where, $values) = &SQL::Common::_generic_int_filter($query_table.'.'.$param, $opts{$param}); |
251 |
|
|
push (@wheres, $where); |
252 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
253 |
|
|
|
254 |
|
|
} |
255 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'integer[]' ) { |
256 |
|
|
my ($where, $values) = &SQL::Common::_generic_intarray_filter($query_table.'.'.$param, $opts{$param}); |
257 |
|
|
push (@wheres, ref $where ? @$where : $where); |
258 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
259 |
|
|
} elsif ( $struct->{$param}->{db_type} =~ /char/ || $struct->{$param}->{db_type} eq 'text' ) { |
260 |
|
|
my ($where, $values); |
261 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
262 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
263 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}, 'text'); |
264 |
|
|
push (@wheres, $where); |
265 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
266 |
|
|
} |
267 |
|
|
} elsif ($param eq 'name') { |
268 |
|
|
# ����������: ��� ��������� name ���������� ����������� ������ |
269 |
|
|
($where, $values) = &SQL::Common::_generic_name_filter($query_table.'.'.$param, $opts{$param}, undef, \%opts); |
270 |
|
|
push (@wheres, $where); |
271 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
272 |
|
|
} else { |
273 |
|
|
($where, $values) = &SQL::Common::_generic_text_filter($query_table.'.'.$param, $opts{$param}, $opts{"${param}_negative"}); |
274 |
|
|
push (@wheres, $where); |
275 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
276 |
|
|
} |
277 |
|
|
} elsif ( $struct->{$param}->{type} eq 'datetime' or $struct->{$param}->{type} eq 'date' ) { |
278 |
|
|
my ($where, $values); |
279 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
280 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
281 |
|
|
($where, $values) = &SQL::Common::_composite_date_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
282 |
|
|
push (@wheres, $where); |
283 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
284 |
|
|
} |
285 |
|
|
} elsif ( $opts{$param} && !ref( $opts{$param} ) ) { |
286 |
|
|
($where, $values) = &SQL::Common::_generic_date_filter($query_table.'.'.$param, $opts{$param}); |
287 |
|
|
push (@wheres, $where); |
288 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
289 |
|
|
} else { |
290 |
|
|
warn "Contenido Warning (_auto_filter): ������� ������ �������� ��� ���� datetime, ��������� ������ � ������� 'YYYY-MM-DD[ HH24:MI]', ���� � ������� unixtime ��� ������ �� ���!\n"; |
291 |
|
|
next; |
292 |
|
|
} |
293 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'real' ) { |
294 |
|
|
my ($where, $values); |
295 |
|
|
if ( !ref($opts{$param}) && $opts{$param} !~ /^\-?[\d\.]+$/ ) { |
296 |
|
|
warn "Contenido Warning (_auto_filter): ������� ������ �������� ��� ������������� ����!\n"; |
297 |
|
|
next; |
298 |
|
|
} |
299 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
300 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
301 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
302 |
|
|
push (@wheres, $where); |
303 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
304 |
|
|
} |
305 |
|
|
} else { |
306 |
|
|
($where, $values) = &SQL::Common::_generic_text_filter($query_table.'.'.$param, $opts{$param}); |
307 |
|
|
push (@wheres, $where); |
308 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
} |
312 |
|
|
} |
313 |
|
|
return (\@wheres, \@binds, \@joins); |
314 |
|
|
|
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
sub _link_filter { |
318 |
|
|
my ($self,%opts)=@_; |
319 |
|
|
|
320 |
|
|
my @wheres=(); |
321 |
|
|
my @binds=(); |
322 |
|
|
|
323 |
|
|
# ����� ������������� ������ |
324 |
|
|
if (exists($opts{lclass})) { |
325 |
|
|
my ($where, $values) = SQL::Common::_generic_text_filter('l.class', $opts{lclass}); |
326 |
|
|
push (@wheres, $where); |
327 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
my $lclass = $opts{lclass} || 'Contenido::Link'; |
331 |
|
|
# my $link_table = $lclass->class_table->db_table(); |
332 |
|
|
my $link_table = $lclass->_get_table->db_table(); |
333 |
|
|
|
334 |
|
|
# ����������� �� ������� ����� |
335 |
|
|
if ( exists $opts{lstatus} ) { |
336 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.status', $opts{lstatus}); |
337 |
|
|
push (@wheres, $where); |
338 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
# ����� � ������������ ��������(��/����) �� ���� ����� |
342 |
|
|
if ( exists $opts{ldest} ) { |
343 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.dest_id', $opts{ldest}); |
344 |
|
|
push (@wheres, $where); |
345 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
346 |
|
|
if ($self->_single_class) { |
347 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id"); |
348 |
|
|
} else { |
349 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id and l.source_class=d.class"); |
350 |
|
|
} |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
# ����� � ������������ ��������(��/����) �� ��������� ����� |
354 |
|
|
if ( exists $opts{lsource} ) { |
355 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.source_id', $opts{lsource}); |
356 |
|
|
push (@wheres, $where); |
357 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
358 |
|
|
if ($self->_single_class) { |
359 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id"); |
360 |
|
|
} else { |
361 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id and l.dest_class=d.class"); |
362 |
|
|
} |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
return (undef); |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
1; |
369 |
|
|
|