Skip to content

Commit 17ec43d

Browse files
authored
feat: Initial support for multi-sort (#335)
1 parent cafd7d1 commit 17ec43d

94 files changed

Lines changed: 5169 additions & 227 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,74 @@ public class ListProjectBranchesExample {
7777
}
7878
```
7979

80+
### Sorting results
81+
82+
You can sort the results of `list*` methods by one or multiple fields using the `OrderByField` class.
83+
If sort direction is not specified, results will be sorted in ascending (`ASC`) order by default.
84+
85+
#### Example: Sort string comments by `id` descending
86+
87+
```java
88+
import com.crowdin.client.Client;
89+
import com.crowdin.client.core.model.Credentials;
90+
import com.crowdin.client.stringcomments.model.OrderByField;
91+
import com.crowdin.client.stringcomments.model.SortOrder;
92+
import com.crowdin.client.stringcomments.model.StringComment;
93+
94+
import java.util.Collections;
95+
import java.util.List;
96+
97+
public class ListCommentsSortedExample {
98+
99+
public static void main(String[] args) {
100+
Credentials credentials = new Credentials("your-token", "your-organization");
101+
Client client = new Client(credentials);
102+
103+
OrderByField orderByIdDesc = new OrderByField();
104+
orderByIdDesc.setFieldName("id");
105+
orderByIdDesc.setOrderBy(SortOrder.DESC); // Optional: default is ASC
106+
107+
List<StringComment> comments = client
108+
.getStringCommentsApi()
109+
.listStringComments(
110+
123L, // projectId
111+
null, null, null, null, null, null,
112+
Collections.singletonList(orderByIdDesc)
113+
)
114+
.getData()
115+
.stream()
116+
.map(response -> response.getData())
117+
.toList();
118+
119+
comments.forEach(comment -> System.out.println(comment.getId()));
120+
}
121+
122+
}
123+
```
124+
#### Example: Sort by multiple fields
125+
126+
You can also sort by multiple fields, for example: first by `createdAt`, then by `id`.
127+
128+
```java
129+
import java.util.Arrays;
130+
import com.crowdin.client.stringcomments.model.OrderByField;
131+
import com.crowdin.client.stringcomments.model.SortOrder;
132+
133+
public class ListCommentsSortedExample {
134+
135+
public static void main(String[] args) {
136+
OrderByField orderByCreatedAtAsc = new OrderByField();
137+
orderByCreatedAtAsc.setFieldName("createdAt"); // ASC by default
138+
139+
OrderByField orderByIdDesc = new OrderByField();
140+
orderByIdDesc.setFieldName("id");
141+
orderByIdDesc.setOrderBy(SortOrder.DESC);
142+
143+
List<OrderByField> orderBy = Arrays.asList(orderByCreatedAtAsc, orderByIdDesc);
144+
}
145+
}
146+
```
147+
80148
### Customization
81149

82150
This client uses [Apache http client](https://hc.apache.org/) and [Jackson json library](https://github.com/FasterXML/jackson).
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.crowdin.client.core.http.impl.util;
2+
3+
import java.io.UnsupportedEncodingException;
4+
import java.net.URLEncoder;
5+
6+
public class RequestEncoder {
7+
public static String encodeSpaces(String url) {
8+
try {
9+
return URLEncoder.encode(url, "UTF-8").replaceAll("\\+", "%20");
10+
} catch (UnsupportedEncodingException e) {
11+
return null;
12+
}
13+
}
14+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.crowdin.client.core.model;
2+
3+
import com.crowdin.client.core.http.impl.util.RequestEncoder;
4+
import lombok.Data;
5+
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
9+
@Data
10+
public class OrderByField {
11+
private String fieldName;
12+
private SortOrder orderBy;
13+
14+
public static String generateSortParam(List<OrderByField> fields) {
15+
if (fields == null || fields.isEmpty()) {
16+
return null;
17+
}
18+
19+
String sortParam = fields.stream()
20+
.map(field -> {
21+
if (field.getOrderBy() == null) {
22+
field.setOrderBy(SortOrder.ASC);
23+
}
24+
25+
return field.getFieldName() + " " + field.getOrderBy().to(field.getOrderBy());
26+
})
27+
.collect(Collectors.joining(","));
28+
29+
return RequestEncoder.encodeSpaces(sortParam);
30+
}
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.crowdin.client.core.model;
2+
3+
public enum SortOrder implements EnumConverter<SortOrder> {
4+
ASC, DESC;
5+
6+
public static SortOrder from(String value) {
7+
if (value == null) return ASC;
8+
9+
return SortOrder.valueOf(value.toUpperCase());
10+
}
11+
12+
@Override
13+
public String to(SortOrder v) {
14+
return (v != null ? v : ASC).name().toLowerCase();
15+
}
16+
}

src/main/java/com/crowdin/client/glossaries/GlossariesApi.java

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@
44
import com.crowdin.client.core.http.HttpRequestConfig;
55
import com.crowdin.client.core.http.exceptions.HttpBadRequestException;
66
import com.crowdin.client.core.http.exceptions.HttpException;
7-
import com.crowdin.client.core.model.ClientConfig;
8-
import com.crowdin.client.core.model.Credentials;
9-
import com.crowdin.client.core.model.DownloadLink;
10-
import com.crowdin.client.core.model.DownloadLinkResponseObject;
11-
import com.crowdin.client.core.model.PatchRequest;
12-
import com.crowdin.client.core.model.ResponseList;
13-
import com.crowdin.client.core.model.ResponseObject;
7+
import com.crowdin.client.core.model.*;
148
import com.crowdin.client.glossaries.model.*;
159

1610
import java.util.List;
@@ -59,11 +53,36 @@ public ResponseList<Concept> listConcepts(Long glossaryId, Integer limit, Intege
5953
return listConcepts(glossaryId, params);
6054
}
6155

56+
/**
57+
* @param glossaryId glossary identifier
58+
* @param limit maximum number of items to retrieve (default 25)
59+
* @param offset starting offset in the collection (default 0)
60+
* @param orderBy list of OrderByFields
61+
* @return list of concepts
62+
* @see <ul>
63+
* <li><a href="https://developer.crowdin.com/api/v2/#operation/api.glossaries.concepts.getMany" target="_blank"><b>API Documentation</b></a></li>
64+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.concepts.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
65+
* </ul>
66+
*/
67+
public ResponseList<Concept> listConcepts(Long glossaryId, Integer limit, Integer offset, List<OrderByField> orderBy) throws HttpException, HttpBadRequestException {
68+
ListConceptsParams params = new ListConceptsParams();
69+
params.setLimit(limit);
70+
params.setOffset(offset);
71+
params.setOrderByList(orderBy);
72+
return listConcepts(glossaryId, params);
73+
}
74+
6275
public ResponseList<Concept> listConcepts(Long glossaryId, ListConceptsParams params) throws HttpException, HttpBadRequestException {
76+
ListConceptsParams query = Optional.ofNullable(params).orElse(new ListConceptsParams());
77+
78+
String orderBy = query.getOrderByList() != null
79+
? OrderByField.generateSortParam(query.getOrderByList())
80+
: query.getOrderBy();
81+
6382
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
64-
"orderBy", Optional.ofNullable(params.getOrderBy()),
65-
"limit", Optional.ofNullable(params.getLimit()),
66-
"offset", Optional.ofNullable(params.getOffset())
83+
"orderBy", Optional.ofNullable(orderBy),
84+
"limit", Optional.ofNullable(query.getLimit()),
85+
"offset", Optional.ofNullable(query.getOffset())
6786
);
6887
ConceptResponseList conceptResponseList = this.httpClient.get(this.url + "/glossaries/" + glossaryId + "/concepts", new HttpRequestConfig(queryParams), ConceptResponseList.class);
6988
return ConceptResponseList.to(conceptResponseList);
@@ -128,12 +147,39 @@ public ResponseList<Glossary> listGlossaries(Long groupId, Integer limit, Intege
128147
return listGlossaries(params);
129148
}
130149

150+
/**
151+
* @param groupId group identifier
152+
* @param limit maximum number of items to retrieve (default 25)
153+
* @param offset starting offset in the collection (default 0)
154+
* @param orderBy list of OrderByField
155+
* @return list of glossaries
156+
* @see <ul>
157+
* <li><a href="https://developer.crowdin.com/api/v2/#operation/api.glossaries.getMany" target="_blank"><b>API Documentation</b></a></li>
158+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
159+
* </ul>
160+
*/
161+
public ResponseList<Glossary> listGlossaries(Long groupId, Integer limit, Integer offset, List<OrderByField> orderBy) throws HttpException, HttpBadRequestException {
162+
ListGlossariesParams params = new ListGlossariesParams();
163+
params.setGroupId(groupId);
164+
params.setLimit(limit);
165+
params.setOffset(offset);
166+
params.setOrderByList(orderBy);
167+
return listGlossaries(params);
168+
}
169+
131170
public ResponseList<Glossary> listGlossaries(ListGlossariesParams params) throws HttpException, HttpBadRequestException {
171+
ListGlossariesParams query = Optional.ofNullable(params).orElse(new ListGlossariesParams());
172+
173+
String orderBy = query.getOrderByList() != null
174+
? OrderByField.generateSortParam(query.getOrderByList())
175+
: query.getOrderBy();
176+
132177
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
133-
"groupId", Optional.ofNullable(params.getGroupId()),
134-
"userId", Optional.ofNullable(params.getUserId()),
135-
"limit", Optional.ofNullable(params.getLimit()),
136-
"offset", Optional.ofNullable(params.getOffset())
178+
"groupId", Optional.ofNullable(query.getGroupId()),
179+
"userId", Optional.ofNullable(query.getUserId()),
180+
"limit", Optional.ofNullable(query.getLimit()),
181+
"offset", Optional.ofNullable(query.getOffset()),
182+
"orderBy", Optional.ofNullable(orderBy)
137183
);
138184
GlossaryResponseList glossaryResponseList = this.httpClient.get(this.url + "/glossaries", new HttpRequestConfig(queryParams), GlossaryResponseList.class);
139185
return GlossaryResponseList.to(glossaryResponseList);
@@ -285,16 +331,49 @@ public ResponseList<Term> listTerms(Long glossaryId, Long userId, String languag
285331
return listTerms(glossaryId, params);
286332
}
287333

334+
/**
335+
* @param glossaryId glossary identifier
336+
* @param userId user identifier
337+
* @param languageId language identifier
338+
* @param conceptId concept identifier
339+
* @param translationOfTermId term identifier
340+
* @param limit maximum number of items to retrieve (default 25)
341+
* @param offset starting offset in the collection (default 0)
342+
* @param orderBy list of OrderByField
343+
* @return list of terms
344+
* @see <ul>
345+
* <li><a href="https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.getMany" target="_blank"><b>API Documentation</b></a></li>
346+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
347+
* </ul>
348+
*/
349+
public ResponseList<Term> listTerms(Long glossaryId, Long userId, String languageId, Long conceptId, @Deprecated Long translationOfTermId, Integer limit, Integer offset, List<OrderByField> orderBy) throws HttpException, HttpBadRequestException {
350+
ListTermsParams params = new ListTermsParams();
351+
params.setUserId(userId);
352+
params.setLanguageId(languageId);
353+
params.setConceptId(conceptId);
354+
params.setTranslationOfTermId(translationOfTermId);
355+
params.setLimit(limit);
356+
params.setOffset(offset);
357+
params.setOrderByList(orderBy);
358+
return listTerms(glossaryId, params);
359+
}
360+
288361
public ResponseList<Term> listTerms(Long glossaryId, ListTermsParams params) throws HttpException, HttpBadRequestException {
362+
ListTermsParams query = Optional.ofNullable(params).orElse(new ListTermsParams());
363+
364+
String orderBy = query.getOrderByList() != null
365+
? OrderByField.generateSortParam(query.getOrderByList())
366+
: query.getOrderBy();
367+
289368
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
290-
"orderBy", Optional.ofNullable(params.getOrderBy()),
291-
"userId", Optional.ofNullable(params.getUserId()),
292-
"languageId", Optional.ofNullable(params.getLanguageId()),
293-
"conceptId", Optional.ofNullable(params.getConceptId()),
294-
"translationOfTermId", Optional.ofNullable(params.getTranslationOfTermId()),
295-
"croql", Optional.ofNullable(params.getCroql()),
296-
"limit", Optional.ofNullable(params.getLimit()),
297-
"offset", Optional.ofNullable(params.getOffset())
369+
"orderBy", Optional.ofNullable(orderBy),
370+
"userId", Optional.ofNullable(query.getUserId()),
371+
"languageId", Optional.ofNullable(query.getLanguageId()),
372+
"conceptId", Optional.ofNullable(query.getConceptId()),
373+
"translationOfTermId", Optional.ofNullable(query.getTranslationOfTermId()),
374+
"croql", Optional.ofNullable(query.getCroql()),
375+
"limit", Optional.ofNullable(query.getLimit()),
376+
"offset", Optional.ofNullable(query.getOffset())
298377
);
299378
TermResponseList termResponseList = this.httpClient.get(this.url + "/glossaries/" + glossaryId + "/terms", new HttpRequestConfig(queryParams), TermResponseList.class);
300379
return TermResponseList.to(termResponseList);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.crowdin.client.glossaries.model;
22

3+
import com.crowdin.client.core.model.OrderByField;
34
import com.crowdin.client.core.model.Pagination;
45
import lombok.Data;
56

7+
import java.util.List;
8+
69
@Data
710
public class ListConceptsParams extends Pagination {
811

912
private String orderBy;
13+
private List<OrderByField> orderByList;
1014
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.crowdin.client.glossaries.model;
22

3+
import com.crowdin.client.core.model.OrderByField;
34
import com.crowdin.client.core.model.Pagination;
45
import lombok.Data;
56

7+
import java.util.List;
8+
69
@Data
710
public class ListGlossariesParams extends Pagination {
811

912
private String orderBy;
1013
private Long userId;
1114
private Long groupId;
15+
private List<OrderByField> orderByList;
1216
}

src/main/java/com/crowdin/client/glossaries/model/ListTermsParams.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.crowdin.client.glossaries.model;
22

3+
import com.crowdin.client.core.model.OrderByField;
34
import com.crowdin.client.core.model.Pagination;
45
import lombok.Data;
56

7+
import java.util.List;
8+
69
@Data
710
public class ListTermsParams extends Pagination {
811

@@ -15,4 +18,5 @@ public class ListTermsParams extends Pagination {
1518
*/
1619
private Long translationOfTermId;
1720
private String croql;
21+
private List<OrderByField> orderByList;
1822
}

src/main/java/com/crowdin/client/labels/LabelsApi.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@
44
import com.crowdin.client.core.http.HttpRequestConfig;
55
import com.crowdin.client.core.http.exceptions.HttpBadRequestException;
66
import com.crowdin.client.core.http.exceptions.HttpException;
7-
import com.crowdin.client.core.model.BooleanInt;
8-
import com.crowdin.client.core.model.ClientConfig;
9-
import com.crowdin.client.core.model.Credentials;
10-
import com.crowdin.client.core.model.PatchRequest;
11-
import com.crowdin.client.core.model.ResponseList;
12-
import com.crowdin.client.core.model.ResponseObject;
7+
import com.crowdin.client.core.model.*;
138
import com.crowdin.client.labels.model.AddLabelRequest;
149
import com.crowdin.client.labels.model.Label;
1510
import com.crowdin.client.labels.model.LabelResponseList;
@@ -58,6 +53,30 @@ public ResponseList<Label> listLabels(Long projectId, Integer limit, Integer off
5853
return LabelResponseList.to(labelResponseList);
5954
}
6055

56+
/**
57+
* @param projectId Project Identifier
58+
* @param limit A maximum number of items to retrieve. Default: 25
59+
* @param offset A starting offset in the collection. Default: 0
60+
* @param isSystem Filter collection by isSystem value
61+
* @param orderBy list of OrderByField
62+
* @return list of labels
63+
* @see <ul>
64+
* <li><a href="https://developer.crowdin.com/api/v2/#operation/api.projects.labels.getMany" target="_blank"><b>API Documentation</b></a></li>
65+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.labels.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
66+
* </ul>
67+
*/
68+
public ResponseList<Label> listLabels(Long projectId, Integer limit, Integer offset, BooleanInt isSystem, List<OrderByField> orderBy) throws HttpException, HttpBadRequestException {
69+
String builtUrl = String.format("%s/projects/%d/labels", this.url, projectId);
70+
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
71+
"limit", Optional.ofNullable(limit),
72+
"offset", Optional.ofNullable(offset),
73+
"isSystem", Optional.ofNullable(isSystem),
74+
"orderBy", Optional.ofNullable(OrderByField.generateSortParam(orderBy))
75+
);
76+
LabelResponseList labelResponseList = this.httpClient.get(builtUrl, new HttpRequestConfig(queryParams), LabelResponseList.class);
77+
return LabelResponseList.to(labelResponseList);
78+
}
79+
6180
/**
6281
* @param projectId Project Identifier
6382
* @param request Request object

0 commit comments

Comments
 (0)