blob: 918eb2c488349d85274c274e15d69397e54ed377 [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2020 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5from __future__ import print_function
6from __future__ import division
7from __future__ import absolute_import
8
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01009import six
10
Copybara854996b2021-09-07 19:36:02 +000011from framework import exceptions
12from framework import paginate
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010013from mrproto import secrets_pb2
Copybara854996b2021-09-07 19:36:02 +000014
15
16def CoercePageSize(page_size, max_size, default_size=None):
17 # type: (int, int, Optional[int]) -> int
18 """Validates page_size and coerces it to max_size if needed.
19
20 Args:
21 page_size: The page_size requested by the user.
22 max_size: the maximum page size allowed. Must be > 0.
23 Also used as default if default_size not provided
24 default_size: default size to use if page_size not provided. Must be > 0.
25
26 Returns:
27 The appropriate page size to use for the request, based on the parameters.
28 Specifically this means
29 - page_size if not greater than max_size
30 - max_size if page_size > max_size
31 - max_size if page_size is not provided and default_size is not provided
32 - default_size if page_size is not provided
33
34 Raises:
35 InputException: if page_size is negative.
36 """
37 # These are programming errors. They are not user input.
38 assert max_size > 0
39 assert default_size is None or default_size > 0
40
41 # Check for invalid user provided page_size.
42 if page_size and page_size < 0:
43 raise exceptions.InputException('`page_size` cannot be negative.')
44
45 if not page_size:
46 return default_size or max_size
47 if page_size > max_size:
48 return max_size
49 return page_size
50
51
52class Paginator(object):
53 """Class to manage API pagination.
54
55 Paginator handles the pagination tasks and info of a single List or
56 Search API method implementation, given the contents of the request.
57 """
58
59 def __init__(self, parent=None, page_size=None, order_by=None,
60 filter_str=None, query=None, projects=None):
61 # type: (Optional[str], Optional[int], Optional[str], Optional[str],
62 # Optional[str], Optional[Collection[str]]]) -> None
63 self.request_contents = secrets_pb2.ListRequestContents(
64 parent=parent, page_size=page_size, order_by=order_by,
65 filter=filter_str, query=query, projects=projects)
66
67 def GetStart(self, page_token):
68 # type: (Optional[str]) -> int
69 """Validates a request.page_token and returns the start index for it."""
70 if page_token:
71 # TODO(crbug.com/monorail/6758): Proto string fields are unicode types in
72 # python 2. In python 3 these unicode strings will be represented with
73 # string types. paginate.ValidateAndParsePageToken requires a string token
74 # during validation (compare_digest()). Once we move to python 3, we can
75 # remove this string casting.
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010076 token = six.ensure_binary(page_token)
Copybara854996b2021-09-07 19:36:02 +000077 return paginate.ValidateAndParsePageToken(token, self.request_contents)
78 return 0
79
80 def GenerateNextPageToken(self, next_start):
81 # type: (Optional[int]) -> str
82 """Generates the `next_page_token` for the API response.
83
84 Args:
85 next_start: The start index of the next page, or None if no more results.
86
87 Returns:
88 A string clients can use to request the next page. Returns None if
89 next_start was None
90 """
91 if next_start is None:
92 return None
93 return paginate.GeneratePageToken(self.request_contents, next_start)