summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2022-08-03 14:24:14 +0200
committerYorhel <git@yorhel.nl>2022-08-03 14:24:14 +0200
commita74aef240cd270047730cd7931f5d7f35f3701a8 (patch)
treecfb64e304d24d8ee74ed94e588ea9432b06befe5
parentf13f03ac6700e0364344b8543842d68d697f2032 (diff)
AdvSearch: Add option to not match child tags
-rw-r--r--elm/AdvSearch/Fields.elm11
-rw-r--r--elm/AdvSearch/Tags.elm19
-rw-r--r--lib/VNWeb/AdvSearch.pm34
3 files changed, 40 insertions, 24 deletions
diff --git a/elm/AdvSearch/Fields.elm b/elm/AdvSearch/Fields.elm
index fa08f585..b933f229 100644
--- a/elm/AdvSearch/Fields.elm
+++ b/elm/AdvSearch/Fields.elm
@@ -426,10 +426,13 @@ fields =
, f V "Language" 1 FMLang (AS.langInit AS.LangVN) (AS.langFromQuery AS.LangVN)
, f V "Original language" 2 FMLang (AS.langInit AS.LangVNO) (AS.langFromQuery AS.LangVNO)
, f V "Platform" 3 FMVPlatform AS.init AS.platformFromQuery
- , f V "Tags" 4 FMTag AG.init (AG.fromQuery -1)
- , f V "" -4 FMTag AG.init (AG.fromQuery 0)
- , f V "" -4 FMTag AG.init (AG.fromQuery 1)
- , f V "" -4 FMTag AG.init (AG.fromQuery 2)
+ , f V "Tags" 4 FMTag AG.init (AG.fromQuery -1 True)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 0 True)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 1 True)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 2 True)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 0 False)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 1 False)
+ , f V "" -4 FMTag AG.init (AG.fromQuery 2 False)
, f V "My Labels" 0 FMLabel AS.init AS.labelFromQuery
, l V "My List" 0 [(QInt 65 Eq 1, "On my list"), (QInt 65 Ne 1, "Not on my list")]
, f V "Length" 0 FMLength AS.init AS.lengthFromQuery
diff --git a/elm/AdvSearch/Tags.elm b/elm/AdvSearch/Tags.elm
index 715b8c25..9dfa4e9b 100644
--- a/elm/AdvSearch/Tags.elm
+++ b/elm/AdvSearch/Tags.elm
@@ -18,12 +18,14 @@ type alias Model =
, conf : A.Config Msg GApi.ApiTagResult
, search : A.Model GApi.ApiTagResult
, spoiler : Int
+ , inherit : Bool
}
type Msg
= Sel (S.Msg (Int,Int))
| Level (Int,Int) Int
| Spoiler
+ | Inherit Bool
| Search (A.Msg GApi.ApiTagResult)
@@ -35,6 +37,7 @@ init dat =
, conf = { wrap = Search, id = "advsearch_tag" ++ String.fromInt ndat.objid, source = A.tagSource }
, search = A.init ""
, spoiler = dat.defaultSpoil
+ , inherit = True
}
)
@@ -45,6 +48,7 @@ update dat msg model =
Sel m -> (dat, { model | sel = S.update m model.sel }, Cmd.none)
Level (t,ol) nl -> (dat, { model | sel = S.update (S.Sel (t,ol) False) model.sel |> S.update (S.Sel (t,nl) True) }, Cmd.none)
Spoiler -> (dat, { model | spoiler = if model.spoiler < 2 then model.spoiler + 1 else 0 }, Cmd.none)
+ Inherit b -> (dat, { model | inherit = b }, Cmd.none)
Search m ->
let (nm, c, res) = A.update model.conf m model.search
in case res of
@@ -55,12 +59,15 @@ update dat msg model =
, c )
-toQuery m = S.toQuery (\o (t,l) -> if m.spoiler == 0 && l == 0 then QInt 8 o t else QTuple 8 o t (l*3+m.spoiler)) m.sel
+toQuery m = S.toQuery (\o (t,l) ->
+ let id = if m.inherit then 8 else 14
+ in if m.spoiler == 0 && l == 0 then QInt id o t else QTuple id o t (l*3+m.spoiler)) m.sel
-fromQuery spoil dat q =
- let f qr = case qr of
- QInt 8 op t -> if spoil == 0 then Just (op, (t,0)) else Nothing
- QTuple 8 op t v -> if modBy 3 v == spoil then Just (op, (t,v//3)) else Nothing
+fromQuery spoil inherit dat q =
+ let id = if inherit then 8 else 14
+ f qr = case qr of
+ QInt x op t -> if id == x && spoil == 0 then Just (op, (t,0)) else Nothing
+ QTuple x op t v -> if id == x && modBy 3 v == spoil then Just (op, (t,v//3)) else Nothing
_ -> Nothing
in
S.fromQuery f dat q |> Maybe.map (\(ndat,sel) ->
@@ -69,6 +76,7 @@ fromQuery spoil dat q =
, conf = { wrap = Search, id = "advsearch_tag" ++ String.fromInt ndat.objid, source = A.tagSource }
, search = A.init ""
, spoiler = spoil
+ , inherit = inherit
}
))
@@ -92,6 +100,7 @@ view dat model =
[ text <| if model.spoiler == 0 then "no spoilers" else if model.spoiler == 1 then "minor spoilers" else "major spoilers" ]
, linkRadio model.sel.neg (Sel << S.Neg) [ text "invert" ]
]
+ , div [ class "opts" ] [ span [] [], linkRadio model.inherit Inherit [ text "child tags" ] ]
]
, ul [] <| List.map (\(t,l) ->
li [ style "overflow" "hidden", style "text-overflow" "ellipsis" ]
diff --git a/lib/VNWeb/AdvSearch.pm b/lib/VNWeb/AdvSearch.pm
index 39f8a014..27e3f88a 100644
--- a/lib/VNWeb/AdvSearch.pm
+++ b/lib/VNWeb/AdvSearch.pm
@@ -303,6 +303,7 @@ sub f {
$f{vndbid} = ref $v eq 'HASH' && $v->{vndbid} && !ref $v->{vndbid} && $v->{vndbid};
$f{int} = ref $f{value} && ($v->{fuzzyrdate} || $f{value}->analyze->{type} eq 'int' || $f{value}->analyze->{type} eq 'bool');
$FIELDS{$t}{$n} = \%f;
+ die "Duplicate number $num for $t\n" if $NUMFIELDS{$t}{$num};
$NUMFIELDS{$t}{$num} = $n;
}
@@ -325,9 +326,8 @@ f v => 64 => 'has-review', { uint => 1, range => [1,1] }, '=' => sub { 'EXI
f v => 65 => 'on-list', { uint => 1, range => [1,1] }, '=' => sub { auth ? sql 'v.id IN(SELECT vid FROM ulist_vns WHERE uid =', \auth->uid, ')' : '1=0' };
f v => 66 => 'devstatus', { uint => 1, enum => \%DEVSTATUS }, '=' => sub { 'v.devstatus =', \$_ };
-f v => 8 => 'tag', { type => 'any', func => \&_validate_tag },
- compact => sub { my $id = ($_->[0] =~ s/^g//r)*1; $_->[1] == 0 && $_->[2] == 0 ? $id : [ $id, int($_->[2]*5)*3 + $_->[1] ] },
- sql_list => \&_sql_where_tag;
+f v => 8 => 'tag', { type => 'any', func => \&_validate_tag }, compact => \&_compact_tag, sql_list => _sql_where_tag('tags_vn_inherit');
+f v => 14 => 'dtag', { type => 'any', func => \&_validate_tag }, compact => \&_compact_tag, sql_list => _sql_where_tag('tags_vn_direct');
f v => 12 => 'label', { type => 'any', func => \&_validate_label },
compact => sub { [ ($_->[0] =~ s/^u//r)*1, $_->[1]*1 ] },
@@ -487,6 +487,7 @@ sub _validate_tag {
1
}
+sub _compact_tag { my $id = ($_->[0] =~ s/^g//r)*1; $_->[1] == 0 && $_->[2] == 0 ? $id : [ $id, int($_->[2]*5)*3 + $_->[1] ] }
# Accepts either $trait or [$trait, $maxspoil]. Normalizes to the latter.
sub _validate_trait {
@@ -595,21 +596,24 @@ sub _canon {
}
-# sql_list function for tags
+# returns an sql_list function for tags
sub _sql_where_tag {
- my($neg, $all, $val) = @_;
- my %f; # spoiler -> rating -> list
- my @l;
- push $f{$_->[1]}{$_->[2]}->@*, $_->[0] for @$val;
- for my $s (keys %f) {
- for my $r (keys $f{$s}->%*) {
- push @l, sql_and
- $s < 2 ? sql('spoiler <=', \$s) : (),
- $r > 0 ? sql('rating >=', \$r) : (),
- sql('tag IN', $f{$s}{$r});
+ my($table) = @_;
+ sub {
+ my($neg, $all, $val) = @_;
+ my %f; # spoiler -> rating -> list
+ my @l;
+ push $f{$_->[1]}{$_->[2]}->@*, $_->[0] for @$val;
+ for my $s (keys %f) {
+ for my $r (keys $f{$s}->%*) {
+ push @l, sql_and
+ $s < 2 ? sql('spoiler <=', \$s) : (),
+ $r > 0 ? sql('rating >=', \$r) : (),
+ sql('tag IN', $f{$s}{$r});
+ }
}
+ sql 'v.id', $neg ? 'NOT' : (), 'IN(SELECT vid FROM', $table, 'WHERE', sql_or(@l), $all && @$val > 1 ? ('GROUP BY vid HAVING COUNT(tag) =', \scalar @$val) : (), ')'
}
- sql 'v.id', $neg ? 'NOT' : (), 'IN(SELECT vid FROM tags_vn_inherit WHERE', sql_or(@l), $all && @$val > 1 ? ('GROUP BY vid HAVING COUNT(tag) =', \scalar @$val) : (), ')'
}
sub _sql_where_trait {