Skip to content

Commit 2ebc35b

Browse files
committed
ImplicitSoftDeleteTests
1 parent ec9e1e1 commit 2ebc35b

File tree

1 file changed

+225
-0
lines changed

1 file changed

+225
-0
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive;
7+
8+
import java.util.Collection;
9+
import java.util.List;
10+
import java.util.Objects;
11+
import java.util.concurrent.CompletionStage;
12+
13+
import org.hibernate.ObjectNotFoundException;
14+
import org.hibernate.annotations.NaturalId;
15+
import org.hibernate.annotations.SoftDelete;
16+
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.Test;
19+
20+
import io.vertx.junit5.Timeout;
21+
import io.vertx.junit5.VertxTestContext;
22+
import jakarta.persistence.Entity;
23+
import jakarta.persistence.Id;
24+
import jakarta.persistence.Table;
25+
import jakarta.persistence.Tuple;
26+
27+
import static java.util.concurrent.TimeUnit.MINUTES;
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.hibernate.reactive.common.Identifier.id;
30+
import static org.hibernate.reactive.testing.ReactiveAssertions.assertThrown;
31+
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
32+
33+
@Timeout(value = 10, timeUnit = MINUTES)
34+
public class ImplicitSoftDeleteTests extends BaseReactiveTest {
35+
36+
@Override
37+
protected Collection<Class<?>> annotatedEntities() {
38+
return List.of( ImplicitEntity.class );
39+
}
40+
41+
@Override
42+
protected CompletionStage<Void> cleanDb() {
43+
return voidFuture();
44+
}
45+
46+
@BeforeEach
47+
void createTestData(VertxTestContext context) {
48+
test(
49+
context, getMutinySessionFactory()
50+
.withTransaction( s -> s.createNativeQuery( "delete from implicit_entities" ).executeUpdate() )
51+
.call( () -> getMutinySessionFactory().withTransaction( s -> s
52+
.persistAll( new ImplicitEntity( 1, "first" ), new ImplicitEntity( 2, "second" ), new ImplicitEntity( 3, "third" ) )
53+
) )
54+
.chain( () -> getMutinySessionFactory().withTransaction( s -> {
55+
final ImplicitEntity first = s.getReference( ImplicitEntity.class, 1 );
56+
return s.remove( first ).call( s::flush );
57+
} ) )
58+
.call( () -> getMutinySessionFactory()
59+
.withTransaction( s -> s.createNativeQuery( "select * from implicit_entities e order by id", Tuple.class ).getResultList() )
60+
.invoke( tuples -> assertThat( tuples ).hasSize( 3 ) )
61+
)
62+
);
63+
}
64+
65+
@Test
66+
void testSelectionQuery(VertxTestContext context) {
67+
test(
68+
context, getMutinySessionFactory()
69+
.withTransaction( s -> s.createQuery( "from ImplicitEntity", ImplicitEntity.class ).getResultList() )
70+
.invoke( list -> assertThat( list ).hasSize( 2 ) )
71+
);
72+
}
73+
74+
@Test
75+
void testLoading(VertxTestContext context) {
76+
test(
77+
context, getMutinySessionFactory()
78+
// Load
79+
.withTransaction( s -> s
80+
.find( ImplicitEntity.class, 1 ).invoke( entity -> assertThat( entity ).isNull() )
81+
.call( () -> s.find( ImplicitEntity.class, 2 ).invoke( entity -> assertThat( entity ).isNotNull() ) )
82+
.call( () -> s.find( ImplicitEntity.class, 3 ).invoke( entity -> assertThat( entity ).isNotNull() ) )
83+
)
84+
// Proxy
85+
// We deleted the entity, so we expect an ObjectNotFoundException
86+
.chain( () -> assertThrown( ObjectNotFoundException.class, getMutinySessionFactory().withTransaction( s -> {
87+
final ImplicitEntity reference = s.getReference( ImplicitEntity.class, 1 );
88+
return s.fetch( reference ).map( ImplicitEntity::getName );
89+
} ) ) )
90+
.chain( () -> getMutinySessionFactory().withTransaction( s -> {
91+
final ImplicitEntity reference = s.getReference( ImplicitEntity.class, 2 );
92+
return s.fetch( reference ).map( ImplicitEntity::getName );
93+
} ) )
94+
.invoke( name -> assertThat( name ).isEqualTo( "second" ) )
95+
.chain( () -> getMutinySessionFactory().withTransaction( s -> {
96+
final ImplicitEntity reference = s.getReference( ImplicitEntity.class, 3 );
97+
return s.fetch( reference ).map( ImplicitEntity::getName );
98+
} ) )
99+
.invoke( name -> assertThat( name ).isEqualTo( "third" ) )
100+
);
101+
}
102+
103+
@Test
104+
void testMultiLoading(VertxTestContext context) {
105+
test(
106+
context, getMutinySessionFactory()
107+
.withTransaction( s -> s.find( ImplicitEntity.class, 1, 2, 3 ) )
108+
.invoke( list -> assertThat( list )
109+
.containsExactly( null, new ImplicitEntity( null, "second" ), new ImplicitEntity( null, "third" ) ) )
110+
);
111+
}
112+
113+
@Test
114+
void testNaturalIdLoading(VertxTestContext context) {
115+
test(
116+
context, getMutinySessionFactory()
117+
.withTransaction( s -> s.find( ImplicitEntity.class, id( "name", "first" ) ) )
118+
.invoke( entity -> assertThat( entity ).isNull() )
119+
.chain( () -> getMutinySessionFactory().withTransaction( s -> s.find( ImplicitEntity.class, id( "name", "second" ) ) ) )
120+
.invoke( entity -> assertThat( entity ).extracting( ImplicitEntity::getId ).isEqualTo( 2 ) )
121+
.chain( () -> getMutinySessionFactory().withTransaction( s -> s.find( ImplicitEntity.class, id( "name", "third" ) ) ) )
122+
.invoke( entity -> assertThat( entity ).extracting( ImplicitEntity::getId ).isEqualTo( 3 ) )
123+
);
124+
}
125+
126+
@Test
127+
void testDeletion(VertxTestContext context) {
128+
test(
129+
context, getMutinySessionFactory().withTransaction( s -> {
130+
final ImplicitEntity reference = s.getReference( ImplicitEntity.class, 2 );
131+
return s.remove( reference ).call( s::flush )
132+
.call( () -> s.createSelectionQuery( "from ImplicitEntity", ImplicitEntity.class ).getResultList()
133+
// #1 was "deleted" up front and we just "deleted" #2... only #3 should be active
134+
.invoke( list -> {
135+
assertThat( list ).extracting( ImplicitEntity::getId ).containsExactly( 3 );
136+
assertThat( list ).extracting( ImplicitEntity::getName ).containsExactly( "third" );
137+
} )
138+
);
139+
} )
140+
);
141+
}
142+
143+
@Test
144+
void testFullUpdateMutationQuery(VertxTestContext context) {
145+
test(
146+
context, getMutinySessionFactory()
147+
.withTransaction( s -> s.createMutationQuery( "update ImplicitEntity set name = null" ).executeUpdate() )
148+
.invoke( affected -> assertThat( affected ).isEqualTo( 2 ) )
149+
);
150+
}
151+
152+
@Test
153+
void testRestrictedUpdateMutationQuery(VertxTestContext context) {
154+
test(
155+
context, getMutinySessionFactory()
156+
.withTransaction( s -> s.createMutationQuery( "update ImplicitEntity set name = null where name = 'second'" ).executeUpdate() )
157+
.invoke( affected -> assertThat( affected ).isEqualTo( 1 ) )
158+
);
159+
}
160+
161+
@Test
162+
void testFullDeleteMutationQuery(VertxTestContext context) {
163+
test(
164+
context, getMutinySessionFactory()
165+
.withTransaction( s -> s.createMutationQuery( "delete ImplicitEntity" ).executeUpdate() )
166+
// only #2 and #3
167+
.invoke( affected -> assertThat( affected ).isEqualTo( 2 ) )
168+
);
169+
}
170+
171+
@Test
172+
void testRestrictedDeleteMutationQuery(VertxTestContext context) {
173+
test(
174+
context, getMutinySessionFactory()
175+
.withTransaction( s -> s.createMutationQuery( "delete ImplicitEntity where name = 'second'" ).executeUpdate() )
176+
// only #2
177+
.invoke( affected -> assertThat( affected ).isEqualTo( 1 ) )
178+
);
179+
}
180+
181+
182+
@Entity(name = "ImplicitEntity")
183+
@Table(name = "implicit_entities")
184+
@SoftDelete
185+
public static class ImplicitEntity {
186+
@Id
187+
private Integer id;
188+
@NaturalId
189+
private String name;
190+
191+
public ImplicitEntity() {
192+
}
193+
194+
public ImplicitEntity(Integer id, String name) {
195+
this.id = id;
196+
this.name = name;
197+
}
198+
199+
public Integer getId() {
200+
return id;
201+
}
202+
203+
public String getName() {
204+
return name;
205+
}
206+
207+
public void setName(String name) {
208+
this.name = name;
209+
}
210+
211+
@Override
212+
public boolean equals(Object object) {
213+
if ( object == null || getClass() != object.getClass() ) {
214+
return false;
215+
}
216+
ImplicitEntity that = (ImplicitEntity) object;
217+
return Objects.equals( name, that.name );
218+
}
219+
220+
@Override
221+
public int hashCode() {
222+
return Objects.hashCode( name );
223+
}
224+
}
225+
}

0 commit comments

Comments
 (0)