Skip to content

Commit a0cbf63

Browse files
authored
update sort parameter (#41)
* remove obsolete files * update deps * update sort parameter
1 parent 97b1600 commit a0cbf63

File tree

5 files changed

+391
-50
lines changed

5 files changed

+391
-50
lines changed

pom.xml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45

56
<parent>
67
<groupId>org.springframework.boot</groupId>
78
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.5.6</version>
9+
<version>3.5.7</version>
910
<relativePath/> <!-- lookup parent from repository -->
1011
</parent>
1112

@@ -78,7 +79,7 @@
7879
<dependency>
7980
<groupId>org.springdoc</groupId>
8081
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
81-
<version>2.8.13</version>
82+
<version>2.8.14</version>
8283
</dependency>
8384

8485
<!-- Testing -->
@@ -115,7 +116,7 @@
115116
<dependency>
116117
<groupId>org.testcontainers</groupId>
117118
<artifactId>testcontainers</artifactId>
118-
<version>1.21.3</version>
119+
<version>2.0.2</version>
119120
<scope>test</scope>
120121
<exclusions>
121122
<exclusion>
@@ -136,14 +137,14 @@
136137
</dependency>
137138
<dependency>
138139
<groupId>org.testcontainers</groupId>
139-
<artifactId>junit-jupiter</artifactId>
140-
<version>1.21.3</version>
140+
<artifactId>testcontainers-junit-jupiter</artifactId>
141+
<version>2.0.2</version>
141142
<scope>test</scope>
142143
</dependency>
143144
<dependency>
144145
<groupId>org.testcontainers</groupId>
145-
<artifactId>postgresql</artifactId>
146-
<version>1.21.3</version>
146+
<artifactId>testcontainers-postgresql</artifactId>
147+
<version>2.0.2</version>
147148
<scope>test</scope>
148149
</dependency>
149150
</dependencies>

src/main/java/it/aboutbits/springboot/toolbox/parameter/SortParameter.java

Lines changed: 206 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,62 @@
11
package it.aboutbits.springboot.toolbox.parameter;
22

3+
import lombok.EqualsAndHashCode;
4+
import lombok.Getter;
35
import lombok.NonNull;
6+
import lombok.experimental.Accessors;
47
import org.springframework.data.domain.Sort;
58

6-
import java.util.Collections;
9+
import java.util.ArrayList;
710
import java.util.List;
811
import java.util.Map;
912
import java.util.stream.Collectors;
1013
import java.util.stream.Stream;
1114

12-
public record SortParameter<T extends Enum<?> & SortParameter.Definition>(List<SortField> sortFields) {
15+
/**
16+
* Represents sorting parameters for data retrieval and manipulation.
17+
* This class provides methods for creating, customizing, and applying sorting criteria
18+
* based on enum constants and associated sort properties. Sorting criteria can be defined
19+
* with various configurations, including direction and null-handling behavior.
20+
*/
21+
@EqualsAndHashCode
22+
public final class SortParameter<T extends Enum<?> & SortParameter.Definition> {
1323
private static final String DEFAULT_SORT_PROPERTY = "id";
14-
private static final Sort DEFAULT_SORT = Sort.by(
15-
Sort.Direction.ASC,
16-
DEFAULT_SORT_PROPERTY
17-
);
24+
private static final Sort.Direction DEFAULT_SORT_DIRETION = Sort.Direction.ASC;
1825

26+
@Accessors(fluent = true)
27+
@Getter
28+
private final List<SortField> sortFields = new ArrayList<>();
29+
30+
public SortParameter(List<SortField> sortFields) {
31+
if (sortFields == null) {
32+
return;
33+
}
34+
this.sortFields.addAll(sortFields);
35+
}
36+
37+
private SortParameter() {
38+
}
39+
40+
/**
41+
* Creates a {@link SortParameter} that represents an unsorted state.
42+
*
43+
* @param <T> a type that extends both {@link Enum} and {@link Definition}.
44+
* @return an instance of {@link SortParameter} configured with no sorting fields.
45+
*/
1946
public static <T extends Enum<?> & Definition> SortParameter<T> unsorted() {
20-
return new SortParameter<>(Collections.emptyList());
47+
return new SortParameter<>();
2148
}
2249

50+
/**
51+
* Creates a {@link SortParameter} initialized with the provided sort definitions.
52+
* Each provided enum constant is converted into a {@link SortField} with ascending
53+
* order direction and default null-handling behavior. This method allows the
54+
* specification of multiple sorting criteria.
55+
*
56+
* @param <T> a type parameter representing an enum that implements the {@link Definition} interface.
57+
* @param sortDefinitions an array of enum constants defining the sort properties. Must not be null.
58+
* @return a {@link SortParameter} instance configured with the given sort definitions.
59+
*/
2360
@SafeVarargs
2461
public static <T extends Enum<?> & Definition> SortParameter<T> by(
2562
@NonNull T... sortDefinitions
@@ -36,6 +73,42 @@ public static <T extends Enum<?> & Definition> SortParameter<T> by(
3673
);
3774
}
3875

76+
/**
77+
* Creates a {@link SortParameter} initialized with a single sort definition.
78+
* This method allows specifying the property to sort by, the direction of sorting,
79+
* and uses the default null-handling behavior ({@link Sort.NullHandling#NATIVE}).
80+
*
81+
* @param <T> a type that extends both {@link Enum} and {@link Definition}.
82+
* @param sortDefinition an enum constant defining the property to sort by. Must not be null.
83+
* @param direction the direction of sorting, either {@link Sort.Direction#ASC} or {@link Sort.Direction#DESC}.
84+
* Must not be null.
85+
* @return an instance of {@link SortParameter} configured with the given sort definition and direction.
86+
*/
87+
public static <T extends Enum<?> & Definition> SortParameter<T> by(
88+
@NonNull T sortDefinition,
89+
@NonNull Sort.Direction direction
90+
) {
91+
return new SortParameter<>(
92+
List.of(new SortField(
93+
sortDefinition.name(),
94+
direction,
95+
Sort.NullHandling.NATIVE
96+
)
97+
)
98+
);
99+
}
100+
101+
/**
102+
* Creates a {@link SortParameter} instance configured with a single sort definition.
103+
* This method allows specifying the property to sort by, the direction of sorting,
104+
* and null-handling behavior.
105+
*
106+
* @param <T> the type parameter extending both {@link Enum} and {@link Definition}.
107+
* @param sortDefinition an enum constant defining the property to sort by. Must not be null.
108+
* @param direction the direction of sorting, either {@link Sort.Direction#ASC} or {@link Sort.Direction#DESC}. Must not be null.
109+
* @param nullHandling the strategy for handling null values during sorting, specified by {@link Sort.NullHandling}. Must not be null.
110+
* @return an instance of {@link SortParameter} configured with the given sort definition, direction, and null-handling behavior.
111+
*/
39112
public static <T extends Enum<?> & Definition> SortParameter<T> by(
40113
@NonNull T sortDefinition,
41114
@NonNull Sort.Direction direction,
@@ -51,10 +124,105 @@ public static <T extends Enum<?> & Definition> SortParameter<T> by(
51124
);
52125
}
53126

127+
/**
128+
* Adds additional sorting criteria to the existing {@link SortParameter}.
129+
* Each provided enum constant is converted into a {@link SortField} with ascending
130+
* order direction and default null-handling behavior.
131+
*
132+
* @param sortDefinitions an array of enum constants defining the additional sort properties. Must not be null.
133+
* @return the updated {@link SortParameter} instance containing the new sort definitions.
134+
*/
135+
@SafeVarargs
136+
public final SortParameter<T> and(
137+
@NonNull T... sortDefinitions
138+
) {
139+
sortFields.addAll(
140+
Stream.of(sortDefinitions)
141+
.map(sortDefinition -> new SortField(
142+
sortDefinition.name(),
143+
Sort.Direction.ASC,
144+
Sort.NullHandling.NATIVE
145+
)
146+
)
147+
.toList()
148+
);
149+
150+
return this;
151+
}
152+
153+
/**
154+
* Adds a sorting criterion to the current {@link SortParameter} instance.
155+
* The provided sort definition and direction are converted into a {@link SortField}
156+
* with default null-handling behavior and appended to the existing sort fields.
157+
*
158+
* @param sortDefinition the enum constant defining the property to sort by. Must not be null.
159+
* @param direction the direction of sorting, either {@link Sort.Direction#ASC} or {@link Sort.Direction#DESC}. Must not be null.
160+
* @return the updated {@link SortParameter} instance containing the new sorting criterion.
161+
*/
162+
public SortParameter<T> and(
163+
@NonNull T sortDefinition,
164+
@NonNull Sort.Direction direction
165+
) {
166+
sortFields.add(
167+
new SortField(
168+
sortDefinition.name(),
169+
direction,
170+
Sort.NullHandling.NATIVE
171+
)
172+
);
173+
174+
return this;
175+
}
176+
177+
/**
178+
* Adds a sorting criterion to the current {@link SortParameter} instance. The provided sort definition,
179+
* direction, and null-handling behavior are converted into a {@link SortField} and appended to the
180+
* existing sort fields.
181+
*
182+
* @param sortDefinition the enum constant defining the property to sort by. Must not be null.
183+
* @param direction the direction of sorting, either {@link Sort.Direction#ASC} or {@link Sort.Direction#DESC}. Must not be null.
184+
* @param nullHandling the strategy for handling null values during sorting, specified by {@link Sort.NullHandling}. Must not be null.
185+
* @return the updated {@link SortParameter} instance containing the new sorting criterion.
186+
*/
187+
public SortParameter<T> and(
188+
@NonNull T sortDefinition,
189+
@NonNull Sort.Direction direction,
190+
@NonNull Sort.NullHandling nullHandling
191+
) {
192+
sortFields.add(
193+
new SortField(
194+
sortDefinition.name(),
195+
direction,
196+
nullHandling
197+
)
198+
);
199+
200+
return this;
201+
}
202+
203+
/**
204+
* Returns the current {@link SortParameter} instance if it has defined sorting fields.
205+
* Otherwise, returns the provided fallback {@link SortParameter}.
206+
*
207+
* @param fallback the {@link SortParameter} to use as a fallback in case the current instance
208+
* has no defined sorting fields. Must not be null.
209+
* @return the current {@link SortParameter} if it has defined sorting fields,
210+
* or the provided fallback if it does not.
211+
*/
54212
public SortParameter<T> or(@NonNull SortParameter<T> fallback) {
55-
return sortFields == null || sortFields.isEmpty() ? fallback : this;
213+
return sortFields.isEmpty() ? fallback : this;
56214
}
57215

216+
/**
217+
* Builds a {@link Sort} object without applying any default sorting parameters. Converts the enum keys
218+
* of the provided map to their string names and generates the sort object.
219+
*
220+
* @param mapping a non-null map where the keys are enumeration values representing sort properties
221+
* and the values are their associated sort directions. The enumeration keys must
222+
* have a `name()` method for string conversion. Must not be null.
223+
* @return an instance of {@link Sort} created using the transformed key-value mapping,
224+
* excluding default sorting behavior.
225+
*/
58226
public Sort buildSortWithoutDefault(@NonNull Map<T, String> mapping) {
59227
var stringMapping = mapping.entrySet().stream()
60228
.collect(Collectors.toMap(
@@ -65,6 +233,16 @@ public Sort buildSortWithoutDefault(@NonNull Map<T, String> mapping) {
65233
return buildSort(stringMapping, false);
66234
}
67235

236+
/**
237+
* Builds a {@link Sort} object based on the provided mapping of enumeration values to string properties.
238+
* Converts enum keys to their respective string names and generates the sort object.
239+
* <p>
240+
* If a sort mapping for "id" is provided, it will be used as the default sort property. Unless specified, this sort will be applied last.
241+
*
242+
* @param mapping a non-null map where the keys represent enumeration values and the values represent sort property names.
243+
* The enumeration keys must implement the `name()` method to retrieve their string representation.
244+
* @return an instance of {@link Sort} created using the transformed key-value mapping with default sorting behavior.
245+
*/
68246
public Sort buildSort(@NonNull Map<T, String> mapping) {
69247
var stringMapping = mapping.entrySet().stream()
70248
.collect(Collectors.toMap(
@@ -75,41 +253,47 @@ public Sort buildSort(@NonNull Map<T, String> mapping) {
75253
return buildSort(stringMapping, true);
76254
}
77255

78-
// SonarLint: Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.
79-
@SuppressWarnings("java:S6204")
80256
private Sort buildSort(@NonNull Map<String, String> mapping, boolean withDefault) {
81-
if (sortFields == null || sortFields.isEmpty()) {
82-
return withDefault ? DEFAULT_SORT : Sort.unsorted();
257+
if (sortFields.isEmpty()) {
258+
return withDefault ? getMappedDefaultSort(mapping) : Sort.unsorted();
83259
}
84260

85261
var additionalSort = Sort.by(
86-
sortFields.stream()
87-
.filter(sortField -> mapping.containsKey(sortField.property()))
88-
.map(sortField -> new Sort.Order(
89-
sortField.direction(),
90-
mapping.get(sortField.property()),
91-
sortField.nullHandling()
92-
))
93-
// We do not use .toList() here as we potentially want to modify the sort list later in the StoreImpl
94-
.collect(Collectors.toList())
262+
new ArrayList<>(
263+
sortFields.stream()
264+
.filter(sortField -> mapping.containsKey(sortField.property()))
265+
.map(sortField -> new Sort.Order(
266+
sortField.direction(),
267+
mapping.get(sortField.property()),
268+
sortField.nullHandling()
269+
))
270+
.toList()
271+
)
95272
);
96273

97274
if (withDefault) {
98275
var includesDefault = additionalSort.getOrderFor(DEFAULT_SORT_PROPERTY) != null;
99276
if (!includesDefault) {
100-
return additionalSort.and(DEFAULT_SORT);
277+
return additionalSort.and(getMappedDefaultSort(mapping));
101278
}
102279
}
103280
return additionalSort;
104281
}
105282

283+
private static Sort getMappedDefaultSort(Map<String, String> mapping) {
284+
return Sort.by(DEFAULT_SORT_DIRETION, mapping.getOrDefault(DEFAULT_SORT_PROPERTY, DEFAULT_SORT_PROPERTY));
285+
}
286+
106287
public record SortField(
107288
@NonNull String property,
108289
@NonNull Sort.Direction direction,
109290
@NonNull Sort.NullHandling nullHandling
110291
) {
111292
}
112293

294+
/**
295+
* Interface to give enums the purpose of listing sortable keys.
296+
*/
113297
public interface Definition {
114298
}
115299
}

0 commit comments

Comments
 (0)