Skip to content

Commit 21dba51

Browse files
authored
Merge pull request #837 from commercetools/query_all_improvement
[DEVX-322] QueryAll allows different field than id to be used
2 parents 88f5536 + f7c3ae9 commit 21dba51

File tree

2 files changed

+192
-8
lines changed

2 files changed

+192
-8
lines changed

commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/QueryAll.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,48 @@ final class QueryAll<TMethod extends SimplePagedQueryResourceRequest<TMethod, TR
2525

2626
private Consumer<List<TElement>> pageConsumer;
2727

28-
private QueryAll(@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> baseQuery,
29-
final int pageSize) {
28+
private final String sortField;
3029

31-
this.baseQuery = withDefaults(baseQuery, pageSize);
30+
private final QueryUtils.SortOrder sortOrder;
31+
32+
private final Function<TElement, String> elementIdentifier;
33+
34+
private QueryAll(@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> baseQuery, final int pageSize,
35+
final String sortField, final QueryUtils.SortOrder sortOrder,
36+
final Function<TElement, String> elementIdentifier) {
37+
38+
this.sortField = sortField;
39+
this.sortOrder = sortOrder;
40+
this.baseQuery = withDefaults(baseQuery, pageSize, sortField, sortOrder);
3241
this.pageSize = pageSize;
3342
this.mappedResultsTillNow = new ArrayList<>();
43+
this.elementIdentifier = elementIdentifier;
3444
}
3545

3646
@Nonnull
3747
private static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>> SimplePagedQueryResourceRequest<TMethod, TResult, ?> withDefaults(
38-
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> request, final int pageSize) {
48+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> request, final int pageSize,
49+
final String sortField, final QueryUtils.SortOrder sortOrder) {
3950

4051
final SimplePagedQueryResourceRequest<TMethod, TResult, ?> withLimit = request.withLimit(pageSize)
4152
.withWithTotal(false);
42-
return !withLimit.getQueryParam("sort").isEmpty() ? withLimit : withLimit.withSort("id asc");
53+
return !withLimit.getQueryParam("sort").isEmpty() ? withLimit
54+
: withLimit.withSort(sortField + " " + sortOrder.getValue());
4355
}
4456

4557
@Nonnull
4658
static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>, S> QueryAll<TMethod, TResult, TElement, S> of(
4759
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> baseQuery, final int pageSize) {
60+
return of(baseQuery, pageSize, "id", QueryUtils.SortOrder.ASCENDING, DomainResource::getId);
61+
}
62+
63+
@Nonnull
64+
static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>, S> QueryAll<TMethod, TResult, TElement, S> of(
65+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> baseQuery, final int pageSize,
66+
final String sortField, final QueryUtils.SortOrder sortOrder,
67+
final Function<TElement, String> elementIdentifier) {
4868

49-
return new QueryAll<>(baseQuery, pageSize);
69+
return new QueryAll<>(baseQuery, pageSize, sortField, sortOrder, elementIdentifier);
5070
}
5171

5272
/**
@@ -157,8 +177,14 @@ private void mapOrConsume(@Nonnull final List<TElement> pageElements) {
157177
@Nonnull
158178
private CompletionStage<ApiHttpResponse<TResult>> getNextPageStage(@Nonnull final List<TElement> pageElements) {
159179
if (pageElements.size() == pageSize) {
160-
final String lastElementId = pageElements.get(pageElements.size() - 1).getId();
161-
return baseQuery.addWhere("id > :lastId", "lastId", lastElementId).execute();
180+
final String lastElementId = elementIdentifier.apply(pageElements.get(pageElements.size() - 1));
181+
if (sortOrder == QueryUtils.SortOrder.ASCENDING) {
182+
return baseQuery.addWhere(sortField + " > :lastValue", "lastValue", lastElementId).execute();
183+
}
184+
else {
185+
return baseQuery.addWhere(sortField + " < :lastValue", "lastValue", lastElementId).execute();
186+
187+
}
162188
}
163189
return completedFuture(null);
164190
}

commercetools/commercetools-sdk-java-api/src/main/java/com/commercetools/api/client/QueryUtils.java

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@
1212
import com.commercetools.api.models.ResourcePagedQueryResponse;
1313

1414
public class QueryUtils {
15+
16+
public enum SortOrder {
17+
ASCENDING("asc"), DESCENDING("desc");
18+
19+
private final String value;
20+
21+
SortOrder(final String value) {
22+
this.value = value;
23+
}
24+
25+
public String getValue() {
26+
return value;
27+
}
28+
}
29+
1530
static int DEFAULT_PAGE_SIZE = 500;
1631
/**
1732
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
@@ -26,6 +41,8 @@ public class QueryUtils {
2641
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
2742
* parallel.
2843
*
44+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
45+
*
2946
* @param query query containing predicates and expansion paths
3047
* @param pageMapper callback function that is called on every page queried
3148
* @param <TElement> type of one query result element
@@ -41,6 +58,40 @@ public class QueryUtils {
4158
return queryAll(query, pageMapper, DEFAULT_PAGE_SIZE);
4259
}
4360

61+
/**
62+
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
63+
* id sorting and a page size 500. More on the algorithm can be found here:
64+
* <a href="https://docs.commercetools.com/api/general-concepts#iterating-over-all-elements">Iterating all elements</a>.</p>
65+
*
66+
* <p>The method takes a callback {@link java.util.function.Function} that returns a result of type {@code <S>} that
67+
* is returned on every page of elements queried. Eventually, the method returns a {@link
68+
* java.util.concurrent.CompletionStage} that contains a list of all the results of the callbacks returned from every
69+
* page.
70+
*
71+
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
72+
* parallel.
73+
*
74+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
75+
*
76+
* @param query query containing predicates and expansion paths
77+
* @param pageMapper callback function that is called on every page queried
78+
* @param sortField field the results should sort on
79+
* @param sortOrder order of the results
80+
* @param elementIdentifierFn function to retrieve the sort order field from an element
81+
* @param <TElement> type of one query result element
82+
* @param <TMethod> type of the query
83+
* @param <TResult> type of the result
84+
* @param <S> type of the returned result of the callback function on every page.
85+
* @return a completion stage containing a list of mapped pages as a result.
86+
*/
87+
@Nonnull
88+
public static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>, S> CompletionStage<List<S>> queryAll(
89+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> query,
90+
@Nonnull final Function<List<TElement>, S> pageMapper, final String sortField, final SortOrder sortOrder,
91+
final Function<TElement, String> elementIdentifierFn) {
92+
return queryAll(query, pageMapper, DEFAULT_PAGE_SIZE, sortField, sortOrder, elementIdentifierFn);
93+
}
94+
4495
/**
4596
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
4697
* id sorting and a page size 500. More on the algorithm can be found here:
@@ -52,6 +103,8 @@ public class QueryUtils {
52103
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
53104
* parallel.
54105
*
106+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
107+
*
55108
* @param query query containing predicates and expansion paths
56109
* @param pageConsumer consumer applied on every page queried
57110
* @param <TElement> type of one query result element
@@ -67,6 +120,38 @@ public class QueryUtils {
67120
return queryAll(query, pageConsumer, DEFAULT_PAGE_SIZE);
68121
}
69122

123+
/**
124+
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
125+
* id sorting and a page size 500. More on the algorithm can be found here:
126+
* <a href="https://docs.commercetools.com/api/general-concepts#iterating-over-all-elements">Iterating all elements</a>.</p>
127+
*
128+
* <p>The method takes a consumer {@link Consumer} that is applied on every page of elements
129+
* queried.
130+
*
131+
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
132+
* parallel.
133+
*
134+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
135+
*
136+
* @param query query containing predicates and expansion paths
137+
* @param pageConsumer consumer applied on every page queried
138+
* @param sortField field the results should sort on
139+
* @param sortOrder order of the results
140+
* @param elementIdentifierFn function to retrieve the sort order field from an element
141+
* @param <TElement> type of one query result element
142+
* @param <TMethod> type of the query
143+
* @param <TResult> type of the result
144+
* @return a completion stage containing void as a result after the consumer was applied on all
145+
* pages.
146+
*/
147+
@Nonnull
148+
public static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>> CompletionStage<Void> queryAll(
149+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> query,
150+
@Nonnull final Consumer<List<TElement>> pageConsumer, final String sortField, final SortOrder sortOrder,
151+
final Function<TElement, String> elementIdentifierFn) {
152+
return queryAll(query, pageConsumer, DEFAULT_PAGE_SIZE, sortField, sortOrder, elementIdentifierFn);
153+
}
154+
70155
/**
71156
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
72157
* id sorting and the supplied {@code pageSize}. More on the algorithm can be found here:
@@ -80,6 +165,8 @@ public class QueryUtils {
80165
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
81166
* parallel.
82167
*
168+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
169+
*
83170
* @param query query containing predicates and expansion paths
84171
* @param pageMapper callback function that is called on every page queried
85172
* @param <TElement> type of one query result element
@@ -97,6 +184,43 @@ public class QueryUtils {
97184
return queryAll.run(pageMapper);
98185
}
99186

187+
/**
188+
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
189+
* id sorting and the supplied {@code pageSize}. More on the algorithm can be found here:
190+
* <a href="https://docs.commercetools.com/api/general-concepts#iterating-over-all-elements">Iterating all elements</a>.</p>
191+
*
192+
* <p>The method takes a callback {@link Function} that returns a result of type {@code <S>} that
193+
* is returned on every page of elements queried. Eventually, the method returns a {@link
194+
* CompletionStage} that contains a list of all the results of the callbacks returned from every
195+
* page.
196+
*
197+
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
198+
* parallel.
199+
*
200+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
201+
*
202+
* @param query query containing predicates and expansion paths
203+
* @param pageMapper callback function that is called on every page queried
204+
* @param sortField field the results should sort on
205+
* @param sortOrder order of the results
206+
* @param elementIdentifierFn function to retrieve the sort order field from an element
207+
* @param <TElement> type of one query result element
208+
* @param <TMethod> type of the query
209+
* @param <TResult> type of the result
210+
* @param <S> type of the returned result of the callback function on every page.
211+
* @param pageSize the page size.
212+
* @return a completion stage containing a list of mapped pages as a result.
213+
*/
214+
@Nonnull
215+
public static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>, S> CompletionStage<List<S>> queryAll(
216+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> query,
217+
@Nonnull final Function<List<TElement>, S> pageMapper, final int pageSize, final String sortField,
218+
final SortOrder sortOrder, final Function<TElement, String> elementIdentifierFn) {
219+
final QueryAll<TMethod, TResult, TElement, S> queryAll = QueryAll.of(query, pageSize, sortField, sortOrder,
220+
elementIdentifierFn);
221+
return queryAll.run(pageMapper);
222+
}
223+
100224
/**
101225
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
102226
* id sorting and the supplied {@code pageSize}. More on the algorithm can be found here:
@@ -123,4 +247,38 @@ public class QueryUtils {
123247
final QueryAll<TMethod, TResult, TElement, Void> queryAll = QueryAll.of(query, pageSize);
124248
return queryAll.run(pageConsumer);
125249
}
250+
251+
/**
252+
* <p>Queries all elements matching a query by using a limit based pagination with a combination of
253+
* id sorting and the supplied {@code pageSize}. More on the algorithm can be found here:
254+
* <a href="https://docs.commercetools.com/api/general-concepts#iterating-over-all-elements">Iterating all elements</a>.</p>
255+
*
256+
* <p>The method takes a {@link java.util.function.Consumer} that is applied on every page of the queried elements.
257+
*
258+
* <p>NOTE: This method fetches all paged results sequentially as opposed to fetching the pages in
259+
* parallel.
260+
*
261+
* <p>NOTE: Please be aware that using a non-unique field for sorting may return incomplete results</p>
262+
*
263+
* @param query query containing predicates and expansion paths
264+
* @param pageConsumer consumer applied on every page queried
265+
* @param sortField field the results should sort on
266+
* @param sortOrder order of the results
267+
* @param elementIdentifierFn function to retrieve the sort order field from an element
268+
* @param <TElement> type of one query result element
269+
* @param <TMethod> type of the query
270+
* @param <TResult> type of the result
271+
* @param pageSize the page size
272+
* @return a completion stage containing void as a result after the consumer was applied on all
273+
* pages.
274+
*/
275+
@Nonnull
276+
public static <TMethod extends SimplePagedQueryResourceRequest<TMethod, TResult, ?>, TResult extends ResourcePagedQueryResponse<TElement>, TElement extends DomainResource<TElement>> CompletionStage<Void> queryAll(
277+
@Nonnull final SimplePagedQueryResourceRequest<TMethod, TResult, ?> query,
278+
@Nonnull final Consumer<List<TElement>> pageConsumer, final int pageSize, final String sortField,
279+
final SortOrder sortOrder, final Function<TElement, String> elementIdentifierFn) {
280+
final QueryAll<TMethod, TResult, TElement, Void> queryAll = QueryAll.of(query, pageSize, sortField, sortOrder,
281+
elementIdentifierFn);
282+
return queryAll.run(pageConsumer);
283+
}
126284
}

0 commit comments

Comments
 (0)