Skip to content

Commit e54c03f

Browse files
committed
[#1744] Add test for @RowId
1 parent d8a2d61 commit e54c03f

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
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+
11+
import org.hibernate.annotations.RowId;
12+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
13+
import org.hibernate.cfg.Configuration;
14+
import org.hibernate.reactive.testing.DBSelectionExtension;
15+
import org.hibernate.reactive.testing.SqlStatementTracker;
16+
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.extension.RegisterExtension;
20+
21+
import io.vertx.junit5.VertxTestContext;
22+
import jakarta.persistence.CascadeType;
23+
import jakarta.persistence.Column;
24+
import jakarta.persistence.Entity;
25+
import jakarta.persistence.Id;
26+
import jakarta.persistence.MapsId;
27+
import jakarta.persistence.OneToOne;
28+
import jakarta.persistence.Table;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2;
32+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.ORACLE;
33+
import static org.hibernate.reactive.testing.DBSelectionExtension.skipTestsFor;
34+
35+
/**
36+
* Adapted from the test with the same name in Hibernate ORM: {@literal org.hibernate.orm.test.rowid.RowIdUpdateTest}
37+
*/
38+
public class RowIdUpdateTest extends BaseReactiveTest {
39+
40+
// Db2: Exception: IllegalStateException: Needed to have 6 in buffer but only had 0
41+
// Oracle: Vert.x driver doesn't support RowId type parameters
42+
@RegisterExtension
43+
public final DBSelectionExtension skip = skipTestsFor( DB2, ORACLE );
44+
45+
private static SqlStatementTracker sqlTracker;
46+
47+
@Override
48+
protected Collection<Class<?>> annotatedEntities() {
49+
return List.of( ParentEntity.class, SimpleEntity.class );
50+
}
51+
52+
@Override
53+
protected Configuration constructConfiguration() {
54+
Configuration configuration = super.constructConfiguration();
55+
sqlTracker = new SqlStatementTracker( RowIdUpdateTest::isUsingRowId, configuration.getProperties() );
56+
return configuration;
57+
}
58+
59+
@Override
60+
protected void addServices(StandardServiceRegistryBuilder builder) {
61+
sqlTracker.registerService( builder );
62+
}
63+
64+
private static boolean isUsingRowId(String s) {
65+
return s.toLowerCase().startsWith( "update" );
66+
}
67+
68+
@BeforeEach
69+
public void prepareDb(VertxTestContext context) {
70+
test( context, getMutinySessionFactory().withTransaction( session -> session.persistAll(
71+
new SimpleEntity( 1L, "initial_status" ),
72+
new ParentEntity( 2L, new SimpleEntity( 2L, "initial_status" ) )
73+
) ) );
74+
}
75+
76+
@Test
77+
public void testSimpleUpdateSameTransaction(VertxTestContext context) {
78+
sqlTracker.clear();
79+
test( context, getMutinySessionFactory()
80+
.withTransaction( session -> {
81+
final SimpleEntity simpleEntity = new SimpleEntity( 3L, "initial_status" );
82+
return session.persist( simpleEntity )
83+
.call( session::flush )
84+
.invoke( () -> simpleEntity.setStatus( "new_status" ) );
85+
} )
86+
.chain( () -> getMutinySessionFactory()
87+
.withSession( session -> session.find( SimpleEntity.class, 3L ) ) )
88+
// the update should have used the primary key, as the row-id value is not available
89+
.invoke( RowIdUpdateTest::shouldUsePrimaryKey )
90+
.invoke( entity -> assertThat( entity ).hasFieldOrPropertyWithValue( "status", "new_status" ) )
91+
);
92+
}
93+
94+
@Test
95+
public void testRelatedUpdateSameTransaction(VertxTestContext context) {
96+
sqlTracker.clear();
97+
test( context, getMutinySessionFactory()
98+
.withTransaction( session -> {
99+
final SimpleEntity simple = new SimpleEntity( 4L, "initial_status" );
100+
final ParentEntity parent = new ParentEntity( 4L, simple );
101+
return session.persist( parent )
102+
.call( session::flush )
103+
.invoke( () -> parent.getChild().setStatus( "new_status" ) );
104+
} )
105+
.chain( () -> getMutinySessionFactory()
106+
.withSession( session -> session.find( SimpleEntity.class, 4L ) ) )
107+
// the update should have used the primary key, as the row-id value is not available
108+
.invoke( RowIdUpdateTest::shouldUsePrimaryKey )
109+
.invoke( entity -> assertThat( entity ).hasFieldOrPropertyWithValue( "status", "new_status" ) )
110+
);
111+
}
112+
113+
@Test
114+
public void testSimpleUpdateDifferentTransaction(VertxTestContext context) {
115+
sqlTracker.clear();
116+
test( context, getMutinySessionFactory()
117+
.withTransaction( session -> session
118+
.find( SimpleEntity.class, 1L )
119+
.invoke( entity -> entity.setStatus( "new_status" ) )
120+
)
121+
.chain( () -> getMutinySessionFactory()
122+
.withSession( session -> session.find( SimpleEntity.class, 1L ) ) )
123+
.invoke( RowIdUpdateTest::shouldUseRowId )
124+
.invoke( entity -> assertThat( entity ).hasFieldOrPropertyWithValue( "status", "new_status" ) )
125+
);
126+
}
127+
128+
@Test
129+
public void testRelatedUpdateRelatedDifferentTransaction(VertxTestContext context) {
130+
sqlTracker.clear();
131+
test( context, getMutinySessionFactory()
132+
.withTransaction( session -> session
133+
.find( ParentEntity.class, 2L )
134+
.invoke( entity -> entity.getChild().setStatus( "new_status" ) )
135+
)
136+
.invoke( RowIdUpdateTest::shouldUseRowId )
137+
.chain( () -> getMutinySessionFactory()
138+
.withSession( session -> session.find( SimpleEntity.class, 2L ) ) )
139+
.invoke( entity -> assertThat( entity )
140+
.hasFieldOrPropertyWithValue( "status", "new_status" )
141+
)
142+
);
143+
}
144+
145+
private static void shouldUsePrimaryKey() {
146+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
147+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
148+
.matches( "update SimpleEntity set status=.+ where primary_key=.+" );
149+
}
150+
151+
private static void shouldUseRowId() {
152+
// Not all databases have a rowId column
153+
String rowId = getDialect().rowId( "" );
154+
String column = rowId == null ? "primary_key" : rowId;
155+
assertThat( sqlTracker.getLoggedQueries() ).hasSize( 1 );
156+
assertThat( sqlTracker.getLoggedQueries().get( 0 ) )
157+
.matches( "update SimpleEntity set status=.+ where " + column + "=.+" );
158+
}
159+
160+
@Entity(name = "SimpleEntity")
161+
@Table(name = "SimpleEntity")
162+
@RowId
163+
public static class SimpleEntity {
164+
@Id
165+
@Column(name = "primary_key")
166+
public Long primaryKey;
167+
168+
public String status;
169+
170+
public SimpleEntity() {
171+
}
172+
173+
public SimpleEntity(Long primaryKey, String status) {
174+
this.primaryKey = primaryKey;
175+
this.status = status;
176+
}
177+
178+
public String getStatus() {
179+
return status;
180+
}
181+
182+
public void setStatus(String status) {
183+
this.status = status;
184+
}
185+
}
186+
187+
@Entity(name = "ParentEntity")
188+
@Table(name = "ParentEntity")
189+
public static class ParentEntity {
190+
@Id
191+
public Long id;
192+
193+
@OneToOne(cascade = CascadeType.ALL)
194+
@MapsId
195+
public SimpleEntity child;
196+
197+
public ParentEntity() {
198+
}
199+
200+
public ParentEntity(Long id, SimpleEntity child) {
201+
this.id = id;
202+
this.child = child;
203+
}
204+
205+
public SimpleEntity getChild() {
206+
return child;
207+
}
208+
}
209+
}

0 commit comments

Comments
 (0)