1 |
8 |
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 |
670 |
ahitrov |
return undef unless ( exists $opts{prevto} || exists $opts{prev_to} ); |
155 |
|
|
my $prevto = exists $opts{prevto} ? 'prevto' : 'prev_to'; |
156 |
8 |
ahitrov@rambler.ru |
my ($wheres, $values) = ([],[]); |
157 |
|
|
my $field = exists $opts{use_id} ? 'id' : exists $opts{use_ctime} ? 'ctime' : exists $opts{use_mtime} ? 'mtime' : 'dtime'; |
158 |
|
|
push @$wheres, " d.$field < ? "; |
159 |
670 |
ahitrov |
if ( ref $opts{$prevto} ) { |
160 |
|
|
my $ctime = $opts{$prevto}; |
161 |
8 |
ahitrov@rambler.ru |
push @$values, $ctime->ymd('-').' '.$ctime->hms.'.'.$ctime->nanosecond; |
162 |
|
|
} else { |
163 |
670 |
ahitrov |
push @$values, $opts{$prevto}; |
164 |
8 |
ahitrov@rambler.ru |
} |
165 |
|
|
return ($wheres, $values); |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
sub _next_to_filter { |
169 |
|
|
my ($self, %opts)=@_; |
170 |
670 |
ahitrov |
return undef unless ( exists $opts{nextto} || exists $opts{next_to} ); |
171 |
|
|
my $nextto = exists $opts{nextto} ? 'nextto' : 'next_to'; |
172 |
8 |
ahitrov@rambler.ru |
my ($wheres, $values) = ([],[]); |
173 |
|
|
my $field = exists $opts{use_id} ? 'id' : exists $opts{use_ctime} ? 'ctime' : exists $opts{use_mtime} ? 'mtime' : 'dtime'; |
174 |
|
|
push @$wheres, " d.$field > ? "; |
175 |
670 |
ahitrov |
if ( ref $opts{$nextto} ) { |
176 |
|
|
my $ctime = $opts{$nextto}; |
177 |
8 |
ahitrov@rambler.ru |
push @$values, $ctime->ymd('-').' '.$ctime->hms.'.'.$ctime->nanosecond; |
178 |
|
|
} else { |
179 |
670 |
ahitrov |
push @$values, $opts{$nextto}; |
180 |
8 |
ahitrov@rambler.ru |
} |
181 |
|
|
return ($wheres, $values); |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
sub _excludes_filter { |
185 |
|
|
my ($self,%opts)=@_; |
186 |
|
|
return undef unless ( exists($opts{excludes}) ); |
187 |
|
|
return &SQL::Common::_generic_int_filter('d.id', $opts{excludes}, 'NEGATION'); |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
sub _auto_filter { |
191 |
|
|
my ( $self, %opts ) = @_; |
192 |
|
|
my @exclude = qw( order_by limit offset no_limit count ids light hash_by return_mode ); |
193 |
|
|
my $sql; |
194 |
|
|
|
195 |
|
|
my @wheres; |
196 |
|
|
my @binds; |
197 |
|
|
my @joins; |
198 |
|
|
|
199 |
|
|
my ( $struct, $query_table ); |
200 |
|
|
|
201 |
|
|
if ( $opts{join} ) { |
202 |
|
|
|
203 |
|
|
if ( !$opts{join}->can('class_table') || !$opts{join}->class_table()->can('db_table') ) { |
204 |
|
|
warn "Contenido Warning (_auto_filter): Не могу получить имя таблицы для \"склейки\"!\n"; |
205 |
|
|
return (undef); |
206 |
|
|
} |
207 |
|
|
$query_table = $opts{join}->class_table()->db_table(); |
208 |
|
|
$struct = $opts{join}->class_table()->required_hash(); |
209 |
|
|
|
210 |
|
|
if ( $opts{field} && !$struct->{ $opts{field} } ) { |
211 |
|
|
warn "Contenido Warning (_auto_filter): В таблице $query_table нет поля ".$opts{field}."!\n"; |
212 |
|
|
return (undef); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
push @joins, ' join '.$query_table.' on '.$query_table.'.'.( $opts{field} ? $opts{field} : 'id' ).' = '.$opts{__join_table}.'.'.$opts{__join_field}.' '; |
216 |
|
|
|
217 |
|
|
} else { |
218 |
|
|
$struct = $self->required_hash(); |
219 |
|
|
$query_table = 'd'; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
foreach my $param ( keys %opts ) { |
223 |
|
|
next if ( grep { $param eq $_ } @exclude ) || !$struct->{$param} || !exists($opts{$param}) || $struct->{$param}->{_no_autofilter}; |
224 |
|
|
next if $opts{$param} eq SQL::Common::NIL(); |
225 |
|
|
if ( uc($opts{$param}) eq 'NULL' || uc($opts{$param}) eq 'NOT NULL' || !defined($opts{$param}) ) { |
226 |
|
|
$opts{$param} = 'NULL' unless defined $opts{$param}; |
227 |
|
|
my ($where, $values) = &SQL::Common::_generic_null_filter($query_table.'.'.$param, $opts{$param}); |
228 |
|
|
push (@wheres, $where); |
229 |
|
|
push (@binds, $values) if (defined $values); |
230 |
|
|
next; |
231 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'integer' or $struct->{$param}->{type} eq 'checkbox') { |
232 |
|
|
my ($where, $values); |
233 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
234 |
|
|
if ( $opts{$param}->{join} ) { |
235 |
|
|
my ( $sub_wheres, $sub_binds, $joins ) = $self->_auto_filter( %{ $opts{$param} }, __join_table => $query_table, __join_field => $param ); |
236 |
|
|
push (@wheres, ref($sub_wheres) eq 'ARRAY' ? @{ $sub_wheres } : $sub_wheres ) if defined $sub_wheres; |
237 |
|
|
push (@binds, ref($sub_binds) eq 'ARRAY' ? @{ $sub_binds } : $sub_binds ) if defined $sub_binds; |
238 |
|
|
push (@joins, ref($joins) eq 'ARRAY' ? @{ $joins } : $joins ) if defined $joins; |
239 |
|
|
|
240 |
|
|
} else { |
241 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
242 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
243 |
|
|
push (@wheres, $where); |
244 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
245 |
|
|
} |
246 |
|
|
} |
247 |
|
|
} else { |
248 |
|
|
if ( !ref($opts{$param}) && $opts{$param} !~ /^\-?\d+$/ ) { |
249 |
|
|
warn "Contenido Warning (_auto_filter): Неверно задано значение для типа integer! ($opts{$param})\n"; |
250 |
|
|
next; |
251 |
|
|
} |
252 |
|
|
($where, $values) = &SQL::Common::_generic_int_filter($query_table.'.'.$param, $opts{$param}); |
253 |
|
|
push (@wheres, $where); |
254 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
255 |
|
|
|
256 |
|
|
} |
257 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'integer[]' ) { |
258 |
|
|
my ($where, $values) = &SQL::Common::_generic_intarray_filter($query_table.'.'.$param, $opts{$param}); |
259 |
|
|
push (@wheres, ref $where ? @$where : $where); |
260 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
261 |
|
|
} elsif ( $struct->{$param}->{db_type} =~ /char/ || $struct->{$param}->{db_type} eq 'text' ) { |
262 |
|
|
my ($where, $values); |
263 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
264 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
265 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}, 'text'); |
266 |
|
|
push (@wheres, $where); |
267 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
268 |
|
|
} |
269 |
|
|
} elsif ($param eq 'name') { |
270 |
|
|
# Исключение: для параметра name используем специальный фильтр |
271 |
|
|
($where, $values) = &SQL::Common::_generic_name_filter($query_table.'.'.$param, $opts{$param}, undef, \%opts); |
272 |
|
|
push (@wheres, $where); |
273 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
274 |
|
|
} else { |
275 |
|
|
($where, $values) = &SQL::Common::_generic_text_filter($query_table.'.'.$param, $opts{$param}, $opts{"${param}_negative"}); |
276 |
|
|
push (@wheres, $where); |
277 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
278 |
|
|
} |
279 |
|
|
} elsif ( $struct->{$param}->{type} eq 'datetime' or $struct->{$param}->{type} eq 'date' ) { |
280 |
|
|
my ($where, $values); |
281 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
282 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
283 |
|
|
($where, $values) = &SQL::Common::_composite_date_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
284 |
|
|
push (@wheres, $where); |
285 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
286 |
|
|
} |
287 |
|
|
} elsif ( $opts{$param} && !ref( $opts{$param} ) ) { |
288 |
|
|
($where, $values) = &SQL::Common::_generic_date_filter($query_table.'.'.$param, $opts{$param}); |
289 |
|
|
push (@wheres, $where); |
290 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
291 |
|
|
} else { |
292 |
|
|
warn "Contenido Warning (_auto_filter): Неверно задано значение для поля datetime, ожидается строка в формате 'YYYY-MM-DD[ HH24:MI]', дата в формате unixtime или ссылка на хэш!\n"; |
293 |
|
|
next; |
294 |
|
|
} |
295 |
|
|
} elsif ( $struct->{$param}->{db_type} eq 'real' ) { |
296 |
|
|
my ($where, $values); |
297 |
|
|
if ( !ref($opts{$param}) && $opts{$param} !~ /^\-?[\d\.]+$/ ) { |
298 |
|
|
warn "Contenido Warning (_auto_filter): Неверно задано значение для вещественного поля!\n"; |
299 |
|
|
next; |
300 |
|
|
} |
301 |
|
|
if ( ref( $opts{$param} ) eq 'HASH') { |
302 |
|
|
foreach my $condition ( keys %{ $opts{$param} } ) { |
303 |
|
|
($where, $values) = &SQL::Common::_generic_composite_filter($query_table.'.'.$param, $condition, $opts{$param}->{$condition}); |
304 |
|
|
push (@wheres, $where); |
305 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
306 |
|
|
} |
307 |
|
|
} else { |
308 |
|
|
($where, $values) = &SQL::Common::_generic_text_filter($query_table.'.'.$param, $opts{$param}); |
309 |
|
|
push (@wheres, $where); |
310 |
|
|
push (@binds, ref($values) ? @$values : $values) if (defined $values); |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
} |
314 |
|
|
} |
315 |
|
|
return (\@wheres, \@binds, \@joins); |
316 |
|
|
|
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
sub _link_filter { |
320 |
|
|
my ($self,%opts)=@_; |
321 |
|
|
|
322 |
|
|
my @wheres=(); |
323 |
|
|
my @binds=(); |
324 |
|
|
|
325 |
|
|
# Связь определенного класса |
326 |
|
|
if (exists($opts{lclass})) { |
327 |
|
|
my ($where, $values) = SQL::Common::_generic_text_filter('l.class', $opts{lclass}); |
328 |
|
|
push (@wheres, $where); |
329 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
my $lclass = $opts{lclass} || 'Contenido::Link'; |
333 |
|
|
# my $link_table = $lclass->class_table->db_table(); |
334 |
|
|
my $link_table = $lclass->_get_table->db_table(); |
335 |
|
|
|
336 |
|
|
# Ограничение по статусу связи |
337 |
|
|
if ( exists $opts{lstatus} ) { |
338 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.status', $opts{lstatus}); |
339 |
|
|
push (@wheres, $where); |
340 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
# Связь с определенным документ(ом/тами) по цели линка |
344 |
|
|
if ( exists $opts{ldest} ) { |
345 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.dest_id', $opts{ldest}); |
346 |
|
|
push (@wheres, $where); |
347 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
348 |
|
|
if ($self->_single_class) { |
349 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id"); |
350 |
|
|
} else { |
351 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id and l.source_class=d.class"); |
352 |
|
|
} |
353 |
|
|
} |
354 |
|
|
|
355 |
|
|
# Связь с определенным документ(ом/тами) по источнику линка |
356 |
|
|
if ( exists $opts{lsource} ) { |
357 |
|
|
my ($where, $values) = SQL::Common::_generic_int_filter('l.source_id', $opts{lsource}); |
358 |
|
|
push (@wheres, $where); |
359 |
|
|
push (@binds, ref($values) ? @$values:$values) if (defined $values); |
360 |
|
|
if ($self->_single_class) { |
361 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id"); |
362 |
|
|
} else { |
363 |
|
|
return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id and l.dest_class=d.class"); |
364 |
|
|
} |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
return (undef); |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
1; |
371 |
|
|
|