Skip to content

Commit 68e98e6

Browse files
committed
Added support for api_kaminari_count_with_limit (#305).
1 parent 5dba51a commit 68e98e6

File tree

1 file changed

+64
-20
lines changed

1 file changed

+64
-20
lines changed

src/main/java/org/gitlab4j/api/Pager.java

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class Pager<T> implements Iterator<List<T>>, Constants {
4545
private int totalPages;
4646
private int totalItems;
4747
private int currentPage;
48+
private int kaminariNextPage;
4849

4950
private List<String> pageParam = new ArrayList<>(1);
5051
private List<T> currentItems;
@@ -92,41 +93,74 @@ public class Pager<T> implements Iterator<List<T>>, Constants {
9293
throw new GitLabApiException(e);
9394
}
9495

96+
if (currentItems == null) {
97+
throw new GitLabApiException("Invalid response from from GitLab server");
98+
}
99+
95100
this.api = api;
96101
this.queryParams = queryParams;
97102
this.pathArgs = pathArgs;
103+
this.itemsPerPage = getIntHeaderValue(response, PER_PAGE);
104+
105+
// Some API endpoints do not return the "X-Per-Page" header when there is only 1 page, check for that condition and act accordingly
106+
if (this.itemsPerPage == -1) {
107+
this.itemsPerPage = itemsPerPage;
108+
totalPages = 1;
109+
totalItems = currentItems.size();
110+
return;
111+
}
98112

99-
try {
100-
this.itemsPerPage = getHeaderValue(response, PER_PAGE);
101-
totalPages = getHeaderValue(response, TOTAL_PAGES_HEADER);
102-
totalItems = getHeaderValue(response, TOTAL_HEADER);
103-
} catch (GitLabApiException glae) {
104-
105-
// Some API endpoints do not return the proper headers, check for that condition and act accordingly
106-
if (currentItems != null && currentItems.size() < itemsPerPage) {
107-
this.itemsPerPage = itemsPerPage;
113+
totalPages = getIntHeaderValue(response, TOTAL_PAGES_HEADER);
114+
totalItems = getIntHeaderValue(response, TOTAL_HEADER);
115+
116+
// Since GitLab 11.8 and behind the api_kaminari_count_with_limit feature flag,
117+
// if the number of resources is more than 10,000, the X-Total and X-Total-Page
118+
// headers as well as the rel="last" Link are not present in the response headers.
119+
if (totalPages == -1 || totalItems == -1) {
120+
121+
int nextPage = getIntHeaderValue(response, NEXT_PAGE_HEADER);
122+
if (nextPage < 2) {
108123
totalPages = 1;
109124
totalItems = currentItems.size();
110125
} else {
111-
throw (glae);
126+
kaminariNextPage = 2;
112127
}
113128
}
114-
}
129+
}
115130

116131
/**
117-
* Get the specified integer header value from the Response instance.
132+
* Get the specified header value from the Response instance.
118133
*
119134
* @param response the Response instance to get the value from
120135
* @param key the HTTP header key to get the value for
121-
* @return the specified integer header value from the Response instance
136+
* @return the specified header value from the Response instance, or null if the header is not present
122137
* @throws GitLabApiException if any error occurs
123138
*/
124-
private int getHeaderValue(Response response, String key) throws GitLabApiException {
139+
private String getHeaderValue(Response response, String key) throws GitLabApiException {
125140

126141
String value = response.getHeaderString(key);
127142
value = (value != null ? value.trim() : null);
128-
if (value == null || value.length() == 0)
129-
throw new GitLabApiException("Missing '" + key + "' header from server");
143+
if (value == null || value.length() == 0) {
144+
return (null);
145+
}
146+
147+
return (value);
148+
}
149+
150+
/**
151+
* Get the specified integer header value from the Response instance.
152+
*
153+
* @param response the Response instance to get the value from
154+
* @param key the HTTP header key to get the value for
155+
* @return the specified integer header value from the Response instance, or -1 if the header is not present
156+
* @throws GitLabApiException if any error occurs
157+
*/
158+
private int getIntHeaderValue(Response response, String key) throws GitLabApiException {
159+
160+
String value = getHeaderValue(response, key);
161+
if (value == null) {
162+
return -1;
163+
}
130164

131165
try {
132166
return (Integer.parseInt(value));
@@ -157,7 +191,7 @@ public int getItemsPerPage() {
157191
/**
158192
* Get the total number of pages returned by the GitLab API.
159193
*
160-
* @return the total number of pages returned by the GitLab API
194+
* @return the total number of pages returned by the GitLab API, or -1 if the Kaminari limit of 10,000 has been exceeded
161195
*/
162196
public int getTotalPages() {
163197
return (totalPages);
@@ -166,7 +200,7 @@ public int getTotalPages() {
166200
/**
167201
* Get the total number of items (T instances) returned by the GitLab API.
168202
*
169-
* @return the total number of items (T instances) returned by the GitLab API
203+
* @return the total number of items (T instances) returned by the GitLab API, or -1 if the Kaminari limit of 10,000 has been exceeded
170204
*/
171205
public int getTotalItems() {
172206
return (totalItems);
@@ -188,7 +222,7 @@ public int getCurrentPage() {
188222
*/
189223
@Override
190224
public boolean hasNext() {
191-
return (currentPage < totalPages);
225+
return (currentPage < totalPages || currentPage < kaminariNextPage);
192226
}
193227

194228
/**
@@ -230,6 +264,11 @@ public List<T> first() throws GitLabApiException {
230264
* @throws GitLabApiException if any error occurs
231265
*/
232266
public List<T> last() throws GitLabApiException {
267+
268+
if (kaminariNextPage != 0) {
269+
throw new GitLabApiException("Kaminari count limit exceeded, unable to fetch last page");
270+
}
271+
233272
return (page(totalPages));
234273
}
235274

@@ -263,7 +302,7 @@ public List<T> current() throws GitLabApiException {
263302
*/
264303
public List<T> page(int pageNumber) {
265304

266-
if (pageNumber > totalPages) {
305+
if (pageNumber > totalPages && pageNumber > kaminariNextPage) {
267306
throw new NoSuchElementException();
268307
} else if (pageNumber < 1) {
269308
throw new NoSuchElementException();
@@ -284,6 +323,11 @@ public List<T> page(int pageNumber) {
284323
Response response = api.get(Response.Status.OK, queryParams, pathArgs);
285324
currentItems = mapper.readValue((InputStream) response.getEntity(), javaType);
286325
currentPage = pageNumber;
326+
327+
if (kaminariNextPage > 0) {
328+
kaminariNextPage = getIntHeaderValue(response, NEXT_PAGE_HEADER);
329+
}
330+
287331
return (currentItems);
288332

289333
} catch (GitLabApiException | IOException e) {

0 commit comments

Comments
 (0)