Line # Revision Author
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