]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Isearch.pm
imap+nntp: share COMPRESS implementation
[public-inbox.git] / lib / PublicInbox / Isearch.pm
index 0ab3b19a64966a7ebad8f4d3df5fbb102d94f766..df940e76156d0f162d179f99352e4f7091ba6cc4 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2020 all contributors <meta@public-inbox.org>
+# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # Provides everything the PublicInbox::Search object does;
@@ -15,12 +15,6 @@ sub new {
        bless { es => $es, eidx_key => $ibx->eidx_key }, __PACKAGE__;
 }
 
-sub mset {
-       my ($self, $str, $opt) = @_;
-       $self->{es}->mset($str, { $opt ? %$opt : (),
-                               eidx_key => $self->{eidx_key} });
-}
-
 sub _ibx_id ($) {
        my ($self) = @_;
        my $sth = $self->{es}->over->dbh->prepare_cached(<<'', undef, 1);
@@ -31,11 +25,58 @@ SELECT ibx_id FROM inboxes WHERE eidx_key = ? LIMIT 1
                die "E: `$self->{eidx_key}' not in $self->{es}->{topdir}\n";
 }
 
+sub query_approxidate { $_[0]->{es}->query_approxidate($_[1], $_[2]) }
+
+sub mset {
+       my ($self, $str, $opt) = @_;
+       my %opt = $opt ? %$opt : ();
+       $opt{eidx_key} = $self->{eidx_key};
+       if (my $uid_range = $opt{uid_range}) {
+               my ($beg, $end) = @$uid_range;
+               my $ibx_id = $self->{-ibx_id} //= _ibx_id($self);
+               my $dbh = $self->{es}->over->dbh;
+               my $sth = $dbh->prepare_cached(<<'', undef, 1);
+SELECT MIN(docid) FROM xref3 WHERE ibx_id = ? AND xnum >= ? AND xnum <= ?
+
+               $sth->execute($ibx_id, $beg, $end);
+               my @r = ($sth->fetchrow_array);
+
+               $sth = $dbh->prepare_cached(<<'', undef, 1);
+SELECT MAX(docid) FROM xref3 WHERE ibx_id = ? AND xnum >= ? AND xnum <= ?
+
+               $sth->execute($ibx_id, $beg, $end);
+               $r[1] = $sth->fetchrow_array;
+               if (defined($r[1]) && defined($r[0])) {
+                       $opt{limit} = $r[1] - $r[0] + 1;
+               } else {
+                       $r[1] //= 0xffffffff;
+                       $r[0] //= 0;
+               }
+               $opt{uid_range} = \@r;
+       }
+       $self->{es}->mset($str, \%opt);
+}
+
 sub mset_to_artnums {
-       my ($self, $mset) = @_;
+       my ($self, $mset, $opt) = @_;
        my $docids = PublicInbox::Search::mset_to_artnums($self->{es}, $mset);
        my $ibx_id = $self->{-ibx_id} //= _ibx_id($self);
        my $qmarks = join(',', map { '?' } @$docids);
+       if ($opt && ($opt->{relevance} // 0) == -1) { # -1 => ENQ_ASCENDING
+               my $range = '';
+               my @r;
+               if (my $r = $opt->{uid_range}) {
+                       $range = 'AND xnum >= ? AND xnum <= ?';
+                       @r = @$r;
+               }
+               my $rows = $self->{es}->over->dbh->
+                       selectall_arrayref(<<"", undef, $ibx_id, @$docids, @r);
+SELECT xnum FROM xref3 WHERE ibx_id = ? AND docid IN ($qmarks) $range
+ORDER BY xnum ASC
+
+               return [ map { $_->[0] } @$rows ];
+       }
+
        my $rows = $self->{es}->over->dbh->
                        selectall_arrayref(<<"", undef, $ibx_id, @$docids);
 SELECT docid,xnum FROM xref3 WHERE ibx_id = ? AND docid IN ($qmarks)
@@ -49,7 +90,7 @@ SELECT docid,xnum FROM xref3 WHERE ibx_id = ? AND docid IN ($qmarks)
        }
        if (scalar keys %order) {
                warn "W: $self->{es}->{topdir} #",
-                       join(', #', sort keys %order),
+                       join(', ', sort { $a <=> $b } keys %order),
                        " not mapped to `$self->{eidx_key}'\n";
                warn "W: $self->{es}->{topdir} may need to be reindexed\n";
                @xnums = grep { defined } @xnums;
@@ -73,7 +114,7 @@ sub mset_to_smsg {
        }
        if (scalar keys %order) {
                warn "W: $ibx->{inboxdir} #",
-                       join(', #', sort keys %order),
+                       join(', ', sort { $a <=> $b } keys %order),
                        " no longer valid\n";
                warn "W: $self->{es}->{topdir} may need to be reindexed\n";
        }