diff --git a/README.md b/README.md index c8bb35756..5cb3026b1 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,74 @@ public class ListProjectBranchesExample { } ``` +### Sorting results + +You can sort the results of `list*` methods by one or multiple fields using the `OrderByField` class. +If sort direction is not specified, results will be sorted in ascending (`ASC`) order by default. + +#### Example: Sort string comments by `id` descending + +```java +import com.crowdin.client.Client; +import com.crowdin.client.core.model.Credentials; +import com.crowdin.client.stringcomments.model.OrderByField; +import com.crowdin.client.stringcomments.model.SortOrder; +import com.crowdin.client.stringcomments.model.StringComment; + +import java.util.Collections; +import java.util.List; + +public class ListCommentsSortedExample { + + public static void main(String[] args) { + Credentials credentials = new Credentials("your-token", "your-organization"); + Client client = new Client(credentials); + + OrderByField orderByIdDesc = new OrderByField(); + orderByIdDesc.setFieldName("id"); + orderByIdDesc.setOrderBy(SortOrder.DESC); // Optional: default is ASC + + List comments = client + .getStringCommentsApi() + .listStringComments( + 123L, // projectId + null, null, null, null, null, null, + Collections.singletonList(orderByIdDesc) + ) + .getData() + .stream() + .map(response -> response.getData()) + .toList(); + + comments.forEach(comment -> System.out.println(comment.getId())); + } + +} +``` +#### Example: Sort by multiple fields + +You can also sort by multiple fields, for example: first by `createdAt`, then by `id`. + +```java +import java.util.Arrays; +import com.crowdin.client.stringcomments.model.OrderByField; +import com.crowdin.client.stringcomments.model.SortOrder; + +public class ListCommentsSortedExample { + + public static void main(String[] args) { + OrderByField orderByCreatedAtAsc = new OrderByField(); + orderByCreatedAtAsc.setFieldName("createdAt"); // ASC by default + + OrderByField orderByIdDesc = new OrderByField(); + orderByIdDesc.setFieldName("id"); + orderByIdDesc.setOrderBy(SortOrder.DESC); + + List orderBy = Arrays.asList(orderByCreatedAtAsc, orderByIdDesc); + } +} +``` + ### Customization This client uses [Apache http client](https://hc.apache.org/) and [Jackson json library](https://github.com/FasterXML/jackson). diff --git a/src/main/java/com/crowdin/client/core/http/impl/util/RequestEncoder.java b/src/main/java/com/crowdin/client/core/http/impl/util/RequestEncoder.java new file mode 100644 index 000000000..d7d41223a --- /dev/null +++ b/src/main/java/com/crowdin/client/core/http/impl/util/RequestEncoder.java @@ -0,0 +1,14 @@ +package com.crowdin.client.core.http.impl.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +public class RequestEncoder { + public static String encodeSpaces(String url) { + try { + return URLEncoder.encode(url, "UTF-8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return null; + } + } +} diff --git a/src/main/java/com/crowdin/client/core/model/OrderByField.java b/src/main/java/com/crowdin/client/core/model/OrderByField.java new file mode 100644 index 000000000..f3a56cbb2 --- /dev/null +++ b/src/main/java/com/crowdin/client/core/model/OrderByField.java @@ -0,0 +1,31 @@ +package com.crowdin.client.core.model; + +import com.crowdin.client.core.http.impl.util.RequestEncoder; +import lombok.Data; + +import java.util.List; +import java.util.stream.Collectors; + +@Data +public class OrderByField { + private String fieldName; + private SortOrder orderBy; + + public static String generateSortParam(List fields) { + if (fields == null || fields.isEmpty()) { + return null; + } + + String sortParam = fields.stream() + .map(field -> { + if (field.getOrderBy() == null) { + field.setOrderBy(SortOrder.ASC); + } + + return field.getFieldName() + " " + field.getOrderBy().to(field.getOrderBy()); + }) + .collect(Collectors.joining(",")); + + return RequestEncoder.encodeSpaces(sortParam); + } +} diff --git a/src/main/java/com/crowdin/client/core/model/SortOrder.java b/src/main/java/com/crowdin/client/core/model/SortOrder.java new file mode 100644 index 000000000..edc73d6a5 --- /dev/null +++ b/src/main/java/com/crowdin/client/core/model/SortOrder.java @@ -0,0 +1,16 @@ +package com.crowdin.client.core.model; + +public enum SortOrder implements EnumConverter { + ASC, DESC; + + public static SortOrder from(String value) { + if (value == null) return ASC; + + return SortOrder.valueOf(value.toUpperCase()); + } + + @Override + public String to(SortOrder v) { + return (v != null ? v : ASC).name().toLowerCase(); + } +} diff --git a/src/main/java/com/crowdin/client/glossaries/GlossariesApi.java b/src/main/java/com/crowdin/client/glossaries/GlossariesApi.java index 100cf5730..0f1e2bdb5 100644 --- a/src/main/java/com/crowdin/client/glossaries/GlossariesApi.java +++ b/src/main/java/com/crowdin/client/glossaries/GlossariesApi.java @@ -4,13 +4,7 @@ import com.crowdin.client.core.http.HttpRequestConfig; import com.crowdin.client.core.http.exceptions.HttpBadRequestException; import com.crowdin.client.core.http.exceptions.HttpException; -import com.crowdin.client.core.model.ClientConfig; -import com.crowdin.client.core.model.Credentials; -import com.crowdin.client.core.model.DownloadLink; -import com.crowdin.client.core.model.DownloadLinkResponseObject; -import com.crowdin.client.core.model.PatchRequest; -import com.crowdin.client.core.model.ResponseList; -import com.crowdin.client.core.model.ResponseObject; +import com.crowdin.client.core.model.*; import com.crowdin.client.glossaries.model.*; import java.util.List; @@ -59,11 +53,36 @@ public ResponseList listConcepts(Long glossaryId, Integer limit, Intege return listConcepts(glossaryId, params); } + /** + * @param glossaryId glossary identifier + * @param limit maximum number of items to retrieve (default 25) + * @param offset starting offset in the collection (default 0) + * @param orderBy list of OrderByFields + * @return list of concepts + * @see + */ + public ResponseList listConcepts(Long glossaryId, Integer limit, Integer offset, List orderBy) throws HttpException, HttpBadRequestException { + ListConceptsParams params = new ListConceptsParams(); + params.setLimit(limit); + params.setOffset(offset); + params.setOrderByList(orderBy); + return listConcepts(glossaryId, params); + } + public ResponseList listConcepts(Long glossaryId, ListConceptsParams params) throws HttpException, HttpBadRequestException { + ListConceptsParams query = Optional.ofNullable(params).orElse(new ListConceptsParams()); + + String orderBy = query.getOrderByList() != null + ? OrderByField.generateSortParam(query.getOrderByList()) + : query.getOrderBy(); + Map> queryParams = HttpRequestConfig.buildUrlParams( - "orderBy", Optional.ofNullable(params.getOrderBy()), - "limit", Optional.ofNullable(params.getLimit()), - "offset", Optional.ofNullable(params.getOffset()) + "orderBy", Optional.ofNullable(orderBy), + "limit", Optional.ofNullable(query.getLimit()), + "offset", Optional.ofNullable(query.getOffset()) ); ConceptResponseList conceptResponseList = this.httpClient.get(this.url + "/glossaries/" + glossaryId + "/concepts", new HttpRequestConfig(queryParams), ConceptResponseList.class); return ConceptResponseList.to(conceptResponseList); @@ -128,12 +147,39 @@ public ResponseList listGlossaries(Long groupId, Integer limit, Intege return listGlossaries(params); } + /** + * @param groupId group identifier + * @param limit maximum number of items to retrieve (default 25) + * @param offset starting offset in the collection (default 0) + * @param orderBy list of OrderByField + * @return list of glossaries + * @see + */ + public ResponseList listGlossaries(Long groupId, Integer limit, Integer offset, List orderBy) throws HttpException, HttpBadRequestException { + ListGlossariesParams params = new ListGlossariesParams(); + params.setGroupId(groupId); + params.setLimit(limit); + params.setOffset(offset); + params.setOrderByList(orderBy); + return listGlossaries(params); + } + public ResponseList listGlossaries(ListGlossariesParams params) throws HttpException, HttpBadRequestException { + ListGlossariesParams query = Optional.ofNullable(params).orElse(new ListGlossariesParams()); + + String orderBy = query.getOrderByList() != null + ? OrderByField.generateSortParam(query.getOrderByList()) + : query.getOrderBy(); + Map> queryParams = HttpRequestConfig.buildUrlParams( - "groupId", Optional.ofNullable(params.getGroupId()), - "userId", Optional.ofNullable(params.getUserId()), - "limit", Optional.ofNullable(params.getLimit()), - "offset", Optional.ofNullable(params.getOffset()) + "groupId", Optional.ofNullable(query.getGroupId()), + "userId", Optional.ofNullable(query.getUserId()), + "limit", Optional.ofNullable(query.getLimit()), + "offset", Optional.ofNullable(query.getOffset()), + "orderBy", Optional.ofNullable(orderBy) ); GlossaryResponseList glossaryResponseList = this.httpClient.get(this.url + "/glossaries", new HttpRequestConfig(queryParams), GlossaryResponseList.class); return GlossaryResponseList.to(glossaryResponseList); @@ -285,16 +331,49 @@ public ResponseList listTerms(Long glossaryId, Long userId, String languag return listTerms(glossaryId, params); } + /** + * @param glossaryId glossary identifier + * @param userId user identifier + * @param languageId language identifier + * @param conceptId concept identifier + * @param translationOfTermId term identifier + * @param limit maximum number of items to retrieve (default 25) + * @param offset starting offset in the collection (default 0) + * @param orderBy list of OrderByField + * @return list of terms + * @see + */ + public ResponseList listTerms(Long glossaryId, Long userId, String languageId, Long conceptId, @Deprecated Long translationOfTermId, Integer limit, Integer offset, List orderBy) throws HttpException, HttpBadRequestException { + ListTermsParams params = new ListTermsParams(); + params.setUserId(userId); + params.setLanguageId(languageId); + params.setConceptId(conceptId); + params.setTranslationOfTermId(translationOfTermId); + params.setLimit(limit); + params.setOffset(offset); + params.setOrderByList(orderBy); + return listTerms(glossaryId, params); + } + public ResponseList listTerms(Long glossaryId, ListTermsParams params) throws HttpException, HttpBadRequestException { + ListTermsParams query = Optional.ofNullable(params).orElse(new ListTermsParams()); + + String orderBy = query.getOrderByList() != null + ? OrderByField.generateSortParam(query.getOrderByList()) + : query.getOrderBy(); + Map> queryParams = HttpRequestConfig.buildUrlParams( - "orderBy", Optional.ofNullable(params.getOrderBy()), - "userId", Optional.ofNullable(params.getUserId()), - "languageId", Optional.ofNullable(params.getLanguageId()), - "conceptId", Optional.ofNullable(params.getConceptId()), - "translationOfTermId", Optional.ofNullable(params.getTranslationOfTermId()), - "croql", Optional.ofNullable(params.getCroql()), - "limit", Optional.ofNullable(params.getLimit()), - "offset", Optional.ofNullable(params.getOffset()) + "orderBy", Optional.ofNullable(orderBy), + "userId", Optional.ofNullable(query.getUserId()), + "languageId", Optional.ofNullable(query.getLanguageId()), + "conceptId", Optional.ofNullable(query.getConceptId()), + "translationOfTermId", Optional.ofNullable(query.getTranslationOfTermId()), + "croql", Optional.ofNullable(query.getCroql()), + "limit", Optional.ofNullable(query.getLimit()), + "offset", Optional.ofNullable(query.getOffset()) ); TermResponseList termResponseList = this.httpClient.get(this.url + "/glossaries/" + glossaryId + "/terms", new HttpRequestConfig(queryParams), TermResponseList.class); return TermResponseList.to(termResponseList); diff --git a/src/main/java/com/crowdin/client/glossaries/model/ListConceptsParams.java b/src/main/java/com/crowdin/client/glossaries/model/ListConceptsParams.java index c48cbe2c7..e6f8ed0fc 100644 --- a/src/main/java/com/crowdin/client/glossaries/model/ListConceptsParams.java +++ b/src/main/java/com/crowdin/client/glossaries/model/ListConceptsParams.java @@ -1,10 +1,14 @@ package com.crowdin.client.glossaries.model; +import com.crowdin.client.core.model.OrderByField; import com.crowdin.client.core.model.Pagination; import lombok.Data; +import java.util.List; + @Data public class ListConceptsParams extends Pagination { private String orderBy; + private List orderByList; } diff --git a/src/main/java/com/crowdin/client/glossaries/model/ListGlossariesParams.java b/src/main/java/com/crowdin/client/glossaries/model/ListGlossariesParams.java index 4615f2cde..ca7f7aa8f 100644 --- a/src/main/java/com/crowdin/client/glossaries/model/ListGlossariesParams.java +++ b/src/main/java/com/crowdin/client/glossaries/model/ListGlossariesParams.java @@ -1,12 +1,16 @@ package com.crowdin.client.glossaries.model; +import com.crowdin.client.core.model.OrderByField; import com.crowdin.client.core.model.Pagination; import lombok.Data; +import java.util.List; + @Data public class ListGlossariesParams extends Pagination { private String orderBy; private Long userId; private Long groupId; + private List orderByList; } diff --git a/src/main/java/com/crowdin/client/glossaries/model/ListTermsParams.java b/src/main/java/com/crowdin/client/glossaries/model/ListTermsParams.java index 5d1ee861e..946947613 100644 --- a/src/main/java/com/crowdin/client/glossaries/model/ListTermsParams.java +++ b/src/main/java/com/crowdin/client/glossaries/model/ListTermsParams.java @@ -1,8 +1,11 @@ package com.crowdin.client.glossaries.model; +import com.crowdin.client.core.model.OrderByField; import com.crowdin.client.core.model.Pagination; import lombok.Data; +import java.util.List; + @Data public class ListTermsParams extends Pagination { @@ -15,4 +18,5 @@ public class ListTermsParams extends Pagination { */ private Long translationOfTermId; private String croql; + private List orderByList; } diff --git a/src/main/java/com/crowdin/client/labels/LabelsApi.java b/src/main/java/com/crowdin/client/labels/LabelsApi.java index a9573a981..29543e486 100644 --- a/src/main/java/com/crowdin/client/labels/LabelsApi.java +++ b/src/main/java/com/crowdin/client/labels/LabelsApi.java @@ -4,12 +4,7 @@ import com.crowdin.client.core.http.HttpRequestConfig; import com.crowdin.client.core.http.exceptions.HttpBadRequestException; import com.crowdin.client.core.http.exceptions.HttpException; -import com.crowdin.client.core.model.BooleanInt; -import com.crowdin.client.core.model.ClientConfig; -import com.crowdin.client.core.model.Credentials; -import com.crowdin.client.core.model.PatchRequest; -import com.crowdin.client.core.model.ResponseList; -import com.crowdin.client.core.model.ResponseObject; +import com.crowdin.client.core.model.*; import com.crowdin.client.labels.model.AddLabelRequest; import com.crowdin.client.labels.model.Label; import com.crowdin.client.labels.model.LabelResponseList; @@ -58,6 +53,30 @@ public ResponseList