Skip to content

Commit 43158c7

Browse files
authored
Merge pull request #1460 from metacpan/oalders/metacpan-api/max-result-window
bump MAX_RESULT_WINDOW for favorites
2 parents 320d6b6 + c4e9841 commit 43158c7

4 files changed

Lines changed: 49 additions & 16 deletions

File tree

lib/MetaCPAN/Query/Favorite.pm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use MetaCPAN::Moose;
44

55
use Log::Contextual qw( :log );
66
use MetaCPAN::ESConfig qw( es_doc_path );
7-
use MetaCPAN::Util qw( hit_total paginate );
7+
use MetaCPAN::Util
8+
qw( hit_total paginate MAX_FAVORITE_RESULT_WINDOW MAX_FAVORITE_PAGE_SIZE );
89

910
with 'MetaCPAN::Query::Role::Common';
1011

@@ -65,7 +66,9 @@ sub agg_by_distributions {
6566
sub by_user {
6667
my ( $self, $user, $page, $size ) = @_;
6768
my $from;
68-
( $page, $size, $from ) = paginate( $page, $size );
69+
( $page, $size, $from )
70+
= paginate( $page, $size, MAX_FAVORITE_RESULT_WINDOW,
71+
MAX_FAVORITE_PAGE_SIZE );
6972

7073
return +{ favorites => [], took => 0, total => 0 }
7174
unless defined $page;

lib/MetaCPAN/Util.pm

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,35 @@ use Sub::Exporter -setup => {
4242
is_bool
4343
to_bool
4444
MAX_RESULT_WINDOW
45+
MAX_FAVORITE_RESULT_WINDOW
4546
MAX_PAGE_SIZE
47+
MAX_FAVORITE_PAGE_SIZE
4648
paginate
4749
) ]
4850
};
4951

50-
# Limit the maximum result window to 1000, really should be enough!
52+
# Must not exceed the ES index.max_result_window setting (default 10,000).
5153
use constant MAX_RESULT_WINDOW => 1000;
52-
use constant MAX_PAGE_SIZE => 250;
54+
55+
# The UI's list_as_json needs a complete set of user favorites, so the default
56+
# of 250 will not be enough for heavy users of the ++ button.
57+
use constant MAX_FAVORITE_RESULT_WINDOW => 5000;
58+
use constant MAX_PAGE_SIZE => 250;
59+
use constant MAX_FAVORITE_PAGE_SIZE => 2000;
5360

5461
# Returns ($page, $size, $from) or empty list if the request exceeds
55-
# the ES result window. Use strict ">" so that page*size == MAX_RESULT_WINDOW
56-
# (e.g. page 4 × 250 = 1000) is still valid — ES allows from+size ≤ window.
62+
# the configured result window. Use strict ">" so that page*size equal to
63+
# the window (e.g. page 4 × 250 = 1000) is still valid — ES allows from+size ≤ window.
5764
sub paginate {
58-
my ( $page, $size ) = @_;
65+
my ( $page, $size, $max_result_window, $max_page_size ) = @_;
66+
$max_result_window //= MAX_RESULT_WINDOW;
67+
$max_page_size //= MAX_PAGE_SIZE;
5968
$page = Int->check($page) ? max( 1, $page ) : 1;
6069
$size
6170
= Int->check($size) && $size >= 1
62-
? min( MAX_PAGE_SIZE, $size )
63-
: MAX_PAGE_SIZE;
64-
return if $page * $size > MAX_RESULT_WINDOW;
71+
? min( $max_page_size, $size )
72+
: $max_page_size;
73+
return if $page * $size > $max_result_window;
6574
return ( $page, $size, ( $page - 1 ) * $size );
6675
}
6776

t/server/controller/favorite.t

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ test_psgi app, sub {
3737
);
3838
};
3939

40-
subtest 'page beyond MAX_RESULT_WINDOW returns empty' => sub {
40+
subtest 'page beyond MAX_FAVORITE_RESULT_WINDOW returns empty' => sub {
4141
ok(
4242
my $res = $cb->(
43-
GET '/favorite/by_user/DOESNOTEXIST?page=100&page_size=250'
43+
GET '/favorite/by_user/DOESNOTEXIST?page=21&page_size=250'
4444
),
45-
'GET with page*size > MAX_RESULT_WINDOW'
45+
'GET with page*size > MAX_FAVORITE_RESULT_WINDOW'
4646
);
4747
is( $res->code, 200, 'code 200' );
4848
my $json = decode_json_ok($res);
@@ -53,12 +53,12 @@ test_psgi app, sub {
5353
);
5454
};
5555

56-
subtest 'page at MAX_RESULT_WINDOW boundary is allowed' => sub {
56+
subtest 'page at MAX_FAVORITE_RESULT_WINDOW boundary is allowed' => sub {
5757
ok(
5858
my $res = $cb->(
59-
GET '/favorite/by_user/DOESNOTEXIST?page=4&page_size=250'
59+
GET '/favorite/by_user/DOESNOTEXIST?page=20&page_size=250'
6060
),
61-
'GET with page*size == MAX_RESULT_WINDOW'
61+
'GET with page*size == MAX_FAVORITE_RESULT_WINDOW'
6262
);
6363
is( $res->code, 200, 'code 200' );
6464
my $json = decode_json_ok($res);

t/util.t

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,27 @@ subtest 'paginate' => sub {
159159
'max page accepted'
160160
);
161161
is_deeply( [ paginate( 1001, 1 ) ], [], 'page beyond window' );
162+
163+
# Custom max_result_window parameter.
164+
is_deeply(
165+
[ paginate( 20, 250, 5000 ) ],
166+
[ 20, 250, 4750 ],
167+
'custom window: page*size == 5000 is allowed'
168+
);
169+
is_deeply( [ paginate( 21, 250, 5000 ) ],
170+
[], 'custom window: page*size > 5000 returns empty' );
171+
172+
# Custom max_page_size parameter.
173+
is_deeply(
174+
[ paginate( 1, 2000, 5000, 2000 ) ],
175+
[ 1, 2000, 0 ],
176+
'custom page size: 2000 accepted'
177+
);
178+
is_deeply(
179+
[ paginate( 1, 3000, 5000, 2000 ) ],
180+
[ 1, 2000, 0 ],
181+
'custom page size: 3000 capped to 2000'
182+
);
162183
is_deeply( [ paginate( 1, 500 ) ], [ 1, 250, 0 ], 'size > 250 capped' );
163184
is_deeply( [ paginate( 1, 1000 ) ], [ 1, 250, 0 ], 'size = 1000 capped' );
164185

0 commit comments

Comments
 (0)