Skip to content

Commit 769b420

Browse files
blafondDavideD
authored andcommitted
[#1768] verify correct upsert sql queries for each DB
1 parent 4c72c94 commit 769b420

File tree

1 file changed

+84
-28
lines changed
  • hibernate-reactive-core/src/test/java/org/hibernate/reactive

1 file changed

+84
-28
lines changed

hibernate-reactive-core/src/test/java/org/hibernate/reactive/UpsertTest.java

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,62 @@
99
import java.util.List;
1010
import java.util.Objects;
1111

12-
import org.hibernate.reactive.testing.DBSelectionExtension;
12+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
13+
import org.hibernate.cfg.Configuration;
14+
import org.hibernate.reactive.testing.SqlStatementTracker;
1315

1416
import org.junit.jupiter.api.Test;
15-
import org.junit.jupiter.api.extension.RegisterExtension;
1617

1718
import io.vertx.junit5.Timeout;
1819
import io.vertx.junit5.VertxTestContext;
1920
import jakarta.persistence.Entity;
2021
import jakarta.persistence.Id;
2122
import jakarta.persistence.Table;
23+
import org.assertj.core.api.Condition;
2224

2325
import static java.util.concurrent.TimeUnit.MINUTES;
2426
import static org.assertj.core.api.Assertions.assertThat;
25-
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.COCKROACHDB;
26-
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2;
27-
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.MARIA;
28-
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.MYSQL;
29-
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.ORACLE;
30-
import static org.hibernate.reactive.testing.DBSelectionExtension.skipTestsFor;
27+
import static org.hibernate.reactive.containers.DatabaseConfiguration.dbType;
3128

3229
/**
3330
* Same as Hibernate ORM org.hibernate.orm.test.stateless.UpsertTest
3431
* <p>
35-
* These tests are in a separate class because we need to skip the execution on some databases,
36-
* but once this has been resolved, they could be in {@link ReactiveStatelessSessionTest}.
32+
* These tests are in a separate class because we need to skip the execution on some databases,
33+
* but once this has been resolved, they could be in {@link ReactiveStatelessSessionTest}.
3734
* </p>
3835
*/
3936
@Timeout(value = 10, timeUnit = MINUTES)
4037
public class UpsertTest extends BaseReactiveTest {
4138

42-
/**
43-
* Something is missing in HR to make it work for these databases.
44-
*/
45-
@RegisterExtension
46-
public DBSelectionExtension dbSelection = skipTestsFor( COCKROACHDB, DB2, MARIA, MYSQL, ORACLE );
39+
private static SqlStatementTracker sqlTracker;
40+
41+
// A condition to check that entities are persisted using a merge operator when the database actually supports it.
42+
private final static Condition<String> IS_USING_MERGE = new Condition<>(
43+
s -> s.toLowerCase().startsWith( "merge into" ),
44+
"insertions or updates without using the merge operator"
45+
);
46+
47+
@Override
48+
protected Configuration constructConfiguration() {
49+
Configuration configuration = super.constructConfiguration();
50+
sqlTracker = new SqlStatementTracker( UpsertTest::filter, configuration.getProperties() );
51+
return configuration;
52+
}
53+
54+
@Override
55+
protected void addServices(StandardServiceRegistryBuilder builder) {
56+
sqlTracker.registerService( builder );
57+
}
58+
59+
private static boolean filter(String s) {
60+
String[] accepted = {"insert ", "update ", "merge "};
61+
for ( String valid : accepted ) {
62+
if ( s.toLowerCase().startsWith( valid ) ) {
63+
return true;
64+
}
65+
}
66+
return false;
67+
}
4768

4869
@Override
4970
protected Collection<Class<?>> annotatedEntities() {
@@ -55,19 +76,26 @@ public void testMutinyUpsert(VertxTestContext context) {
5576
test( context, getMutinySessionFactory().withStatelessTransaction( ss -> ss
5677
.upsert( new Record( 123L, "hello earth" ) )
5778
.call( () -> ss.upsert( new Record( 456L, "hello mars" ) ) )
79+
.invoke( this::assertQueries )
5880
)
5981
.call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
60-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
61-
.invoke( results -> assertThat( results ).containsExactly(
62-
new Record( 123L, "hello earth" ),
63-
new Record( 456L, "hello mars" )
64-
) )
82+
.createQuery( "from Record order by id", Record.class )
83+
.getResultList() )
84+
.invoke( results -> {
85+
assertThat( results ).containsExactly(
86+
new Record( 123L, "hello earth" ),
87+
new Record( 456L, "hello mars" )
88+
);
89+
} )
6590
)
6691
.call( () -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
6792
.upsert( new Record( 123L, "goodbye earth" ) )
6893
) )
69-
.call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
70-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
94+
.invoke( this::assertQueries )
95+
.call( v -> getMutinySessionFactory()
96+
.withStatelessTransaction( ss -> ss
97+
.createQuery( "from Record order by id", Record.class )
98+
.getResultList() )
7199
.invoke( results -> assertThat( results ).containsExactly(
72100
new Record( 123L, "goodbye earth" ),
73101
new Record( 456L, "hello mars" )
@@ -81,9 +109,10 @@ public void testMutinyUpsertWithEntityName(VertxTestContext context) {
81109
test( context, getMutinySessionFactory().withStatelessTransaction( ss -> ss
82110
.upsert( Record.class.getName(), new Record( 123L, "hello earth" ) )
83111
.call( () -> ss.upsert( Record.class.getName(), new Record( 456L, "hello mars" ) ) )
112+
.invoke( this::assertQueries )
84113
)
85114
.call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
86-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
115+
.createQuery( "from Record order by id", Record.class ).getResultList() )
87116
.invoke( results -> assertThat( results ).containsExactly(
88117
new Record( 123L, "hello earth" ),
89118
new Record( 456L, "hello mars" )
@@ -92,8 +121,9 @@ public void testMutinyUpsertWithEntityName(VertxTestContext context) {
92121
.call( () -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
93122
.upsert( Record.class.getName(), new Record( 123L, "goodbye earth" ) )
94123
) )
124+
.invoke( this::assertQueries )
95125
.call( v -> getMutinySessionFactory().withStatelessTransaction( ss -> ss
96-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
126+
.createQuery( "from Record order by id", Record.class ).getResultList() )
97127
.invoke( results -> assertThat( results ).containsExactly(
98128
new Record( 123L, "goodbye earth" ),
99129
new Record( 456L, "hello mars" )
@@ -108,8 +138,9 @@ public void testStageUpsert(VertxTestContext context) {
108138
.upsert( new Record( 123L, "hello earth" ) )
109139
.thenCompose( v -> ss.upsert( new Record( 456L, "hello mars" ) ) )
110140
)
141+
.thenAccept( v -> this.assertQueries() )
111142
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
112-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
143+
.createQuery( "from Record order by id", Record.class ).getResultList() )
113144
.thenAccept( results -> assertThat( results ).containsExactly(
114145
new Record( 123L, "hello earth" ),
115146
new Record( 456L, "hello mars" )
@@ -118,8 +149,9 @@ public void testStageUpsert(VertxTestContext context) {
118149
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
119150
.upsert( new Record( 123L, "goodbye earth" ) )
120151
) )
152+
.thenAccept( v -> this.assertQueries() )
121153
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
122-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
154+
.createQuery( "from Record order by id", Record.class ).getResultList() )
123155
.thenAccept( results -> assertThat( results ).containsExactly(
124156
new Record( 123L, "goodbye earth" ),
125157
new Record( 456L, "hello mars" )
@@ -134,8 +166,9 @@ public void testStageUpsertWithEntityName(VertxTestContext context) {
134166
.upsert( Record.class.getName(), new Record( 123L, "hello earth" ) )
135167
.thenCompose( v -> ss.upsert( Record.class.getName(), new Record( 456L, "hello mars" ) ) )
136168
)
169+
.thenAccept( v -> this.assertQueries() )
137170
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
138-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
171+
.createQuery( "from Record order by id", Record.class ).getResultList() )
139172
.thenAccept( results -> assertThat( results ).containsExactly(
140173
new Record( 123L, "hello earth" ),
141174
new Record( 456L, "hello mars" )
@@ -144,8 +177,9 @@ public void testStageUpsertWithEntityName(VertxTestContext context) {
144177
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
145178
.upsert( Record.class.getName(), new Record( 123L, "goodbye earth" ) )
146179
) )
180+
.thenAccept( v -> this.assertQueries() )
147181
.thenCompose( v -> getSessionFactory().withStatelessTransaction( ss -> ss
148-
.createSelectionQuery( "from Record order by id", Record.class ).getResultList() )
182+
.createQuery( "from Record order by id", Record.class ).getResultList() )
149183
.thenAccept( results -> assertThat( results ).containsExactly(
150184
new Record( 123L, "goodbye earth" ),
151185
new Record( 456L, "hello mars" )
@@ -154,6 +188,28 @@ public void testStageUpsertWithEntityName(VertxTestContext context) {
154188
);
155189
}
156190

191+
private void assertQueries() {
192+
if ( hasMergeOperator() ) {
193+
assertThat( sqlTracker.getLoggedQueries() ).have( IS_USING_MERGE );
194+
}
195+
else {
196+
// This might be overkill, but it's still helpful in case more databases are going to support
197+
// the merge operator, and we need to update the documentation or warn people about it.
198+
assertThat( sqlTracker.getLoggedQueries() ).doNotHave( IS_USING_MERGE );
199+
}
200+
}
201+
202+
private boolean hasMergeOperator() {
203+
switch ( dbType() ) {
204+
case SQLSERVER:
205+
case ORACLE:
206+
case POSTGRESQL:
207+
return true;
208+
default:
209+
return false;
210+
}
211+
}
212+
157213
@Entity(name = "Record")
158214
@Table(name = "Record")
159215
public static class Record {

0 commit comments

Comments
 (0)