Skip to content

Commit d809e3b

Browse files
feat: order content from database (#139)
* feat: order content from database * fix: use lowest interface possible * FIX: @order on SuperUser aspect * FIX: EntityListener instead of AOP for SuperUser --------- Co-authored-by: brian-mulier <[email protected]>
1 parent 9e759e9 commit d809e3b

File tree

7 files changed

+116
-24
lines changed

7 files changed

+116
-24
lines changed

tzatziki-spring-jpa/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ Then content is the User entities
163163

164164
The `content` variable created will be a List created from `org.springframework.data.repository.CrudRepository#findAll`
165165

166+
For both you can order the List fetched from the database (direction is not mandatory and defaults to ascending)
167+
```gherkin
168+
Then content is the users table content ordered by date_of_birth desc and date_of_death
169+
170+
# or alternatively
171+
Then content is the User entities ordered by date_of_birth desc and date_of_death
172+
```
173+
174+
The `content` variable created will be a List created from `org.springframework.data.jpa.repository.JpaRepository#findAll(Sort)`
175+
166176
## Resetting the database between tests
167177

168178
The library will automatically reset the database between each test.

tzatziki-spring-jpa/src/main/java/com/decathlon/tzatziki/steps/SpringJPASteps.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
import org.jetbrains.annotations.NotNull;
1010
import org.jetbrains.annotations.Nullable;
1111
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.data.domain.Sort;
1213
import org.springframework.data.repository.CrudRepository;
14+
import org.springframework.data.repository.PagingAndSortingRepository;
1315
import org.springframework.jdbc.core.JdbcTemplate;
1416
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
1517

1618
import javax.persistence.Table;
1719
import javax.sql.DataSource;
1820
import java.lang.reflect.Type;
1921
import java.lang.reflect.TypeVariable;
22+
import java.util.Arrays;
2023
import java.util.List;
2124
import java.util.Map;
2225
import java.util.Optional;
@@ -32,6 +35,9 @@
3235

3336
public class SpringJPASteps {
3437

38+
public static final String ORDER_PATTERN = "[a-zA-Z]+(?: asc| desc)?";
39+
public static final String ORDER_SEPARATOR = " and ";
40+
3541
static {
3642
DynamicTransformers.register(Type.class, TypeParser::parse);
3743
DynamicTransformers.register(InsertionMode.class, InsertionMode::parse);
@@ -69,7 +75,7 @@ public void before() {
6975
.stream()
7076
.map(crudRepository -> Map.entry(crudRepository, TypeUtils.getTypeArguments(crudRepository.getClass(), CrudRepository.class).get(CrudRepository.class.getTypeParameters()[0])))
7177
.sorted((e1, e2) -> {
72-
if(e1.getValue() instanceof Class) return -1;
78+
if (e1.getValue() instanceof Class) return -1;
7379
return e2.getValue() instanceof Class ? 1 : 0;
7480
})
7581
.<Map.Entry<Class<?>, CrudRepository<?, ?>>>mapMulti((crudRepositoryWithType, consumer) -> {
@@ -175,6 +181,27 @@ public void add_entities_to_variable(Guard guard, String name, Type type) {
175181
add_repository_content_to_variable(guard, name, getRepositoryForEntity(type));
176182
}
177183

184+
185+
@Then(THAT + GUARD + VARIABLE + " is the ([^ ]+) table content ordered by (" + ORDER_PATTERN + "(?:" + ORDER_SEPARATOR + ORDER_PATTERN + ")*)$")
186+
public void add_ordered_table_content_to_variable(Guard guard, String name, String table, String orders) {
187+
add_ordered_repository_content_to_variable(guard, name, getRepositoryForTable(table), parseSort(orders));
188+
}
189+
190+
@Then(THAT + GUARD + VARIABLE + " is the " + TYPE + " entities ordered by (" + ORDER_PATTERN + "(?:" + ORDER_SEPARATOR + ORDER_PATTERN + ")*)$")
191+
public void add_ordered_entities_to_variable(Guard guard, String name, Type type, String orders) {
192+
add_ordered_repository_content_to_variable(guard, name, getRepositoryForEntity(type), parseSort(orders));
193+
}
194+
195+
@NotNull
196+
private Sort parseSort(String orders) {
197+
return Sort.by(Arrays.stream(orders.split(ORDER_SEPARATOR)).map(this::parseOrder).toList());
198+
}
199+
200+
private Sort.Order parseOrder(String propertyAndDirection) {
201+
String[] elmts = propertyAndDirection.split(" ");
202+
return elmts.length > 1 ? new Sort.Order(Sort.Direction.fromString(elmts[1]), elmts[0]) : Sort.Order.by(elmts[0]);
203+
}
204+
178205
private void the_repository_contains_nothing(Guard guard, CrudRepository<Object, ?> repositoryOfEntity) {
179206
guard.in(objects, () -> assertThat(repositoryOfEntity.count()).isZero());
180207
}
@@ -220,6 +247,15 @@ public <E> void add_repository_content_to_variable(Guard guard, String name, Cru
220247
guard.in(objects, () -> objects.add(name, StreamSupport.stream(repository.findAll().spliterator(), false).toList()));
221248
}
222249

250+
@SuppressWarnings("unchecked")
251+
public <E> void add_ordered_repository_content_to_variable(Guard guard, String name, CrudRepository<E, ?> repository, Sort sort) {
252+
if (repository instanceof PagingAndSortingRepository sortingRepository) {
253+
guard.in(objects, () -> objects.add(name, StreamSupport.stream(sortingRepository.findAll(sort).spliterator(), false).toList()));
254+
} else {
255+
throw new AssertionError(repository.getClass() + " is not a PagingAndSortingRepository!");
256+
}
257+
}
258+
223259
public <E> CrudRepository<E, ?> getRepositoryForTable(String table) {
224260
return getRepositoryForEntity(Optional.ofNullable(this.entityClassByTableName.get(table)).orElseGet(() -> TypeParser.parse(table)));
225261
}

tzatziki-spring-jpa/src/test/java/com/decathlon/tzatziki/app/aspects/SuperUserCrudSavePrefixerAspect.java

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.decathlon.tzatziki.app.dao;
22

33
import com.decathlon.tzatziki.app.model.User;
4-
import org.springframework.data.repository.CrudRepository;
4+
import org.springframework.data.jpa.repository.JpaRepository;
55

6-
public interface UserDataSpringRepository<T extends User> extends CrudRepository<T, Integer> {}
6+
public interface UserDataSpringRepository<T extends User> extends JpaRepository<T, Integer> {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.decathlon.tzatziki.app.entity_listeners;
2+
3+
import com.decathlon.tzatziki.app.model.SuperUser;
4+
5+
import javax.persistence.PrePersist;
6+
7+
public class SuperUserEntityListener {
8+
@PrePersist
9+
public void addPrefixToRoles(SuperUser superUser) {
10+
superUser.setRole("superUser_" + superUser.getRole());
11+
}
12+
}

tzatziki-spring-jpa/src/test/java/com/decathlon/tzatziki/app/model/SuperUser.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package com.decathlon.tzatziki.app.model;
22

3+
import com.decathlon.tzatziki.app.entity_listeners.SuperUserEntityListener;
34
import lombok.Getter;
45
import lombok.NoArgsConstructor;
56
import lombok.Setter;
67

78
import javax.persistence.Column;
89
import javax.persistence.Entity;
10+
import javax.persistence.EntityListeners;
911
import javax.persistence.Table;
1012

1113
@Getter
1214
@Entity
1315
@NoArgsConstructor
1416
@Table(name = "super_users")
17+
@EntityListeners(SuperUserEntityListener.class)
1518
public class SuperUser extends User {
1619
@Setter
1720
@Column(name = "role")

tzatziki-spring-jpa/src/test/resources/com/decathlon/tzatziki/steps/spring-jpa.feature

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,58 @@ Feature: to interact with a spring boot service having a persistence layer
190190
| 1 | Darth | Vader |
191191
| 2 | Han | Solo |
192192

193+
Scenario: we can get a table content ordered
194+
Given that the users table will contain only:
195+
| id | firstName | lastName | birthDate | updatedAt |
196+
| 1 | Darth | Vader | {{{[@41 years before The 19th of october 1977]}}} | {{{[@now]}}} |
197+
| 2 | Han | Solo | {{{[@32 years before The 19th of october 1977]}}} | {{{[@now]}}} |
198+
Then usersTableContent is the users table content ordered by lastName
199+
And usersTableContent contains only and in order:
200+
| id | firstName | lastName |
201+
| 2 | Han | Solo |
202+
| 1 | Darth | Vader |
203+
Then usersTableContent is the users table content ordered by birthDate
204+
And usersTableContent contains only and in order:
205+
| id | firstName | lastName |
206+
| 1 | Darth | Vader |
207+
| 2 | Han | Solo |
208+
Then usersTableContent is the users table content ordered by birthDate desc
209+
And usersTableContent contains only and in order:
210+
| id | firstName | lastName |
211+
| 2 | Han | Solo |
212+
| 1 | Darth | Vader |
213+
Then usersTableContent is the users table content ordered by updatedAt and birthDate desc
214+
And usersTableContent contains only and in order:
215+
| id | firstName | lastName |
216+
| 2 | Han | Solo |
217+
| 1 | Darth | Vader |
218+
219+
Scenario: we can get entities ordered
220+
Given that the User entities will contain only:
221+
| id | firstName | lastName | birthDate | updatedAt |
222+
| 1 | Darth | Vader | {{{[@41 years before The 19th of october 1977]}}} | {{{[@now]}}} |
223+
| 2 | Han | Solo | {{{[@32 years before The 19th of october 1977]}}} | {{{[@now]}}} |
224+
Then userEntities is the User entities ordered by lastName
225+
And userEntities contains only and in order:
226+
| id | firstName | lastName |
227+
| 2 | Han | Solo |
228+
| 1 | Darth | Vader |
229+
Then userEntities is the User entities ordered by birthDate
230+
And userEntities contains only and in order:
231+
| id | firstName | lastName |
232+
| 1 | Darth | Vader |
233+
| 2 | Han | Solo |
234+
Then userEntities is the User entities ordered by birthDate desc
235+
And userEntities contains only and in order:
236+
| id | firstName | lastName |
237+
| 2 | Han | Solo |
238+
| 1 | Darth | Vader |
239+
Then userEntities is the User entities ordered by updatedAt and birthDate desc
240+
And userEntities contains only and in order:
241+
| id | firstName | lastName |
242+
| 2 | Han | Solo |
243+
| 1 | Darth | Vader |
244+
193245
Scenario: there shouldn't be any "within" implicit guard in JPA assertions
194246
Given that after 100ms the User entities will contain only:
195247
| id | firstName | lastName |

0 commit comments

Comments
 (0)