summaryrefslogtreecommitdiff
path: root/lib/VNWeb/Filters.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNWeb/Filters.pm')
-rw-r--r--lib/VNWeb/Filters.pm78
1 files changed, 78 insertions, 0 deletions
diff --git a/lib/VNWeb/Filters.pm b/lib/VNWeb/Filters.pm
index 6f5cef7a..79aa93dd 100644
--- a/lib/VNWeb/Filters.pm
+++ b/lib/VNWeb/Filters.pm
@@ -6,6 +6,11 @@ package VNWeb::Filters;
# we'll need to support these filters for the forseeable future.
use VNWeb::Prelude;
+use POSIX 'strftime';
+use Exporter 'import';
+
+our @EXPORT = qw/filter_parse filter_vn_query filter_release_query/;
+
my $VN = form_compile any => {
date_before => { required => 0, uint => 1, range => [0, 99999999] }, # don't use 'rdate' validation here, the search form allows invalid dates
@@ -115,4 +120,77 @@ sub filter_vn_compat {
$mod;
}
+
+# Throws error on failure.
+sub filter_parse {
+ my($type, $str) = @_;
+ my $s = {v => $VN, r => $RELEASE, c => $CHAR, s => $STAFF}->{$type};
+ my $data = ref $str ? $str : $str =~ /^{/ ? JSON::XS->new->decode($str) : VNDB::Func::fil_parse $str, keys $s->{known_keys}->%*;
+ die "Invalid filter data: $str\n" if !$data;
+ my $f = $s->validate($data)->data;
+ filter_vn_compat $f if $type eq 'vn';
+ $f
+}
+
+
+# Returns an SQL expression for use in a WHERE clause. Assumption: 'v' is an alias to the vn table being queried.
+sub filter_vn_query {
+ my($fil) = @_;
+ sql_and
+ defined $fil->{date_before} ? sql 'v.c_released <=', \$fil->{date_before} : (),
+ defined $fil->{date_after} ? sql 'v.c_released >=', \$fil->{date_after} : (),
+ defined $fil->{released} ? sql 'v.c_released', $fil->{released} ? '<=' : '>', \strftime('%Y%m%d', gmtime) : (),
+ defined $fil->{length} ? sql 'v.length IN', $fil->{length} : (),
+ defined $fil->{hasani} ? sql($fil->{hasani} ?'':'NOT', 'EXISTS(SELECT 1 FROM vn_anime iva WHERE iva.id = v.id)') : (),
+ defined $fil->{hasshot} ? sql($fil->{hasshot}?'':'NOT', 'EXISTS(SELECT 1 FROM vn_screenshots ivs WHERE ivs.id = v.id)') : (),
+ defined $fil->{tag_inc} ? sql
+ 'v.id IN(SELECT vid FROM tags_vn_inherit WHERE tag IN', $fil->{tag_inc}, 'AND spoiler <=', \$fil->{tagspoil}, 'GROUP BY vid HAVING COUNT(tag) =', scalar $fil->{tag_inc}->@*, ')' : (),
+ defined $fil->{tag_exc} ? sql 'v.id NOT IN(SELECT vid FROM tags_vn_inherit WHERE tag IN', $fil->{tag_exc}, ')' : (),
+ defined $fil->{lang} ? sql 'v.c_languages && ARRAY', $fil->{lang}, '::language[]' : (),
+ defined $fil->{olang} ? sql 'v.c_olang && ARRAY', $fil->{olang}, '::language[]' : (),
+ defined $fil->{plat} ? sql 'v.c_platforms && ARRAY', $fil->{plat}, '::platform[]' : (),
+ defined $fil->{staff_inc} ? sql 'v.id IN(SELECT ivs.id FROM vn_staff ivs JOIN staff_alias isa ON isa.aid = ivs.aid WHERE isa.id IN', $fil->{staff_inc}, ')' : (),
+ defined $fil->{staff_exc} ? sql 'v.id NOT IN(SELECT ivs.id FROM vn_staff ivs JOIN staff_alias isa ON isa.aid = ivs.aid WHERE isa.id IN', $fil->{staff_exc}, ')' : (),
+ auth ? (
+ # TODO: onwish, voted and onlist should respect the label filters in users.ulist_*
+ defined $fil->{ul_notblack} ? sql 'v.id NOT IN(SELECT vid FROM ulist_vns_labels WHERE uid =', \auth->uid, 'AND lbl =', \6, ')' : (),
+ defined $fil->{ul_onwish} ? sql 'v.id', $fil->{ul_onwish}?'':'NOT', 'IN(SELECT vid FROM ulist_vns_labels WHERE uid =', \auth->uid, 'AND lbl =', \5, ')' : (),
+ defined $fil->{ul_voted} ? sql 'v.id', $fil->{ul_voted} ?'':'NOT', 'IN(SELECT vid FROM ulist_vns_labels WHERE uid =', \auth->uid, 'AND lbl =', \7, ')' : (),
+ defined $fil->{ul_onlist} ? sql 'v.id', $fil->{ul_onlist}?'':'NOT', 'IN(SELECT vid FROM ulist_vns WHERE uid =', \auth->uid, ')' : (),
+ ) : (),
+}
+
+
+# Assumption: 'r' is an alias to the release table being queried.
+sub filter_release_query {
+ my($fil) = @_;
+ sql_and
+ defined $fil->{type} ? sql 'r.type =', \$fil->{type} : (),
+ defined $fil->{patch} ? sql($fil->{patch} ?'':'NOT', 'r.patch' ) : (),
+ defined $fil->{freeware} ? sql($fil->{freeware} ?'':'NOT', 'r.freeware' ) : (),
+ defined $fil->{doujin} ? sql($fil->{doujin} ?'':'NOT', 'r.doujin AND NOT r.patch') : (),
+ defined $fil->{uncensored} ? sql($fil->{uncensored}?'':'NOT', 'r.uncensored') : (),
+ defined $fil->{date_before} ? sql 'r.released <=', \$fil->{date_before} : (),
+ defined $fil->{date_after} ? sql 'r.released >=', \$fil->{date_after} : (),
+ defined $fil->{released} ? sql 'r.released', $fil->{released} ? '<=' : '>', \strftime('%Y%m%d', gmtime) : (),
+ defined $fil->{minage} ? sql 'r.minage IN', $fil->{minage} : (),
+ defined $fil->{lang} ? sql 'r.id IN(SELECT irl.id FROM releases_lang irl WHERE irl.lang IN', $fil->{lang}, ')' : (),
+ defined $fil->{olang} ? sql 'r.id IN(SELECT irv.id FROM releases_vn irv JOIN vn iv ON irv.vid = iv.id WHERE iv.c_olang && ARRAY', $fil->{olang}, '::language[])' : (),
+ defined $fil->{resolution} ? sql 'NOT r.patch AND ARRAY[r.reso_x,r.reso_y] IN', [ map $_ eq 'unknown' ? '{0,0}' : $_ eq 'nonstandard' ? '{0,1}' : '{'.(s/x/,/r).'}', $fil->{resolution}->@* ] : (),
+ defined $fil->{plat} ? sql_or(
+ grep( /^unk$/, $fil->{plat}->@*) ? sql 'NOT EXISTS(SELECT 1 FROM releases_platforms irp WHERE irp.id = r.id)' : (),
+ grep(!/^unk$/, $fil->{plat}->@*) ? sql 'r.id IN(SELECT irp.id FROM releases_platforms irp WHERE irp.platform IN', [grep !/^unk$/, $fil->{plat}->@*], ')' : (),
+ ) : (),
+ defined $fil->{prod_inc} ? sql 'r.id IN(SELECT irp.id FROM releases_producers irp WHERE irp.pid IN', $fil->{prod_inc}, ')' : (),
+ defined $fil->{prod_exc} ? sql 'r.id NOT IN(SELECT irp.id FROM releases_producers irp WHERE irp.pid IN', $fil->{prod_exc}, ')' : (),
+ defined $fil->{med} ? sql_or(
+ grep( /^unk$/, $fil->{med}->@*) ? sql 'NOT EXISTS(SELECT 1 FROM releases_media irm WHERE irm.id = r.id)' : (),
+ grep(!/^unk$/, $fil->{med}->@*) ? sql 'r.id IN(SELECT irm.id FROM releases_media irm WHERE irm.medium IN', [grep !/^unk$/, $fil->{med}->@*], ')' : (),
+ ) : (),
+ defined $fil->{voiced} ? sql 'NOT r.patch AND r.voiced IN', $fil->{voiced} : (),
+ defined $fil->{ani_story} ? sql 'NOT r.patch AND r.ani_story IN', $fil->{ani_story} : (),
+ defined $fil->{ani_ero} ? sql 'NOT r.patch AND r.ani_ero IN', $fil->{ani_ero} : (),
+ defined $fil->{engine} ? sql 'r.engine =', \$fil->{engine} : (),
+}
+
1;