6
6
*/
7
7
package org .hibernate .orm .test .jpa .criteria ;
8
8
9
- import org .hibernate .testing .TestForIssue ;
9
+ import java .math .BigDecimal ;
10
+ import java .util .List ;
11
+
12
+ import org .hibernate .testing .orm .junit .JiraKey ;
10
13
import org .hibernate .testing .orm .junit .EntityManagerFactoryScope ;
14
+ import org .hibernate .testing .orm .junit .Jira ;
11
15
import org .hibernate .testing .orm .junit .Jpa ;
12
16
17
+ import org .junit .jupiter .api .AfterAll ;
18
+ import org .junit .jupiter .api .BeforeAll ;
13
19
import org .junit .jupiter .api .Test ;
14
20
15
21
import jakarta .persistence .Column ;
22
+ import jakarta .persistence .Embeddable ;
23
+ import jakarta .persistence .Embedded ;
16
24
import jakarta .persistence .Entity ;
17
25
import jakarta .persistence .Id ;
26
+ import jakarta .persistence .Tuple ;
18
27
import jakarta .persistence .TypedQuery ;
19
28
import jakarta .persistence .criteria .CriteriaBuilder ;
20
29
import jakarta .persistence .criteria .CriteriaQuery ;
21
30
import jakarta .persistence .criteria .Expression ;
22
31
import jakarta .persistence .criteria .ParameterExpression ;
23
32
import jakarta .persistence .criteria .Root ;
24
33
34
+ import static org .assertj .core .api .Assertions .assertThat ;
35
+
25
36
/**
26
37
* @author Will Dazy
27
38
*/
28
- @ Jpa (annotatedClasses = CoalesceTest .HHH15291Entity .class )
29
- @ TestForIssue ( jiraKey = "HHH-15291" )
39
+ @ Jpa ( annotatedClasses = {
40
+ CoalesceTest .HHH15291Entity .class ,
41
+ CoalesceTest .ComponentEntity .class ,
42
+ CoalesceTest .ComponentA .class ,
43
+ } )
44
+ @ JiraKey ( value = "HHH-15291" )
30
45
public class CoalesceTest {
31
-
32
46
@ Test
33
47
public void hhh15291JPQL1Test (EntityManagerFactoryScope scope ) {
34
48
scope .inEntityManager (
@@ -97,9 +111,74 @@ public void hhh15291Criteria2Test(EntityManagerFactoryScope scope) {
97
111
);
98
112
}
99
113
114
+ @ Test
115
+ @ Jira ( "https://hibernate.atlassian.net/browse/HHH-18321" )
116
+ public void testCoalesceInBinaryArithmetic (EntityManagerFactoryScope scope ) {
117
+ scope .inTransaction ( entityManager -> {
118
+ final CriteriaBuilder cb = entityManager .getCriteriaBuilder ();
119
+ final CriteriaQuery <Tuple > cquery = cb .createTupleQuery ();
120
+ final Root <ComponentEntity > root = cquery .from ( ComponentEntity .class );
121
+
122
+ cquery .select ( cb .tuple (
123
+ root .get ( "id" ),
124
+ cb .diff (
125
+ cb .coalesce ( root .get ( "componentA" ).get ( "income" ), BigDecimal .ZERO ),
126
+ cb .coalesce ( root .get ( "componentA" ).get ( "expense" ), BigDecimal .ZERO )
127
+ )
128
+ ) );
129
+
130
+ final List <Tuple > resultList = entityManager .createQuery ( cquery ).getResultList ();
131
+ assertThat ( resultList ).hasSize ( 2 );
132
+ for ( Tuple result : resultList ) {
133
+ final Long id = result .get ( 0 , Long .class );
134
+ assertThat ( result .get ( 1 , BigDecimal .class ).intValue () ).isEqualTo ( id == 1L ? 0 : 1 );
135
+ }
136
+ } );
137
+ }
138
+
139
+ @ Test
140
+ @ Jira ( "https://hibernate.atlassian.net/browse/HHH-18321" )
141
+ public void testCoalesceInBinaryArithmeticParam (EntityManagerFactoryScope scope ) {
142
+ scope .inTransaction ( entityManager -> {
143
+ final CriteriaBuilder cb = entityManager .getCriteriaBuilder ();
144
+ final CriteriaQuery <Tuple > cquery = cb .createTupleQuery ();
145
+ final Root <ComponentEntity > root = cquery .from ( ComponentEntity .class );
146
+
147
+ final ParameterExpression <BigDecimal > defaultValue = cb .parameter ( BigDecimal .class , "default-value" );
148
+
149
+ cquery .select ( cb .tuple (
150
+ root .get ( "id" ),
151
+ cb .diff (
152
+ defaultValue ,
153
+ cb .coalesce ( root .get ( "componentA" ).get ( "expense" ), defaultValue )
154
+ )
155
+ ) );
156
+
157
+ final List <Tuple > resultList = entityManager .createQuery ( cquery )
158
+ .setParameter ( "default-value" , BigDecimal .ZERO ).getResultList ();
159
+ assertThat ( resultList ).hasSize ( 2 );
160
+ for ( Tuple result : resultList ) {
161
+ final Long id = result .get ( 0 , Long .class );
162
+ assertThat ( result .get ( 1 , BigDecimal .class ).intValue () ).isEqualTo ( id == 1L ? -1 : 0 );
163
+ }
164
+ } );
165
+ }
166
+
167
+ @ BeforeAll
168
+ public void setUp (EntityManagerFactoryScope scope ) {
169
+ scope .inTransaction ( entityManager -> {
170
+ entityManager .persist ( new ComponentEntity ( 1L , new ComponentA ( BigDecimal .ONE , BigDecimal .ONE ) ) );
171
+ entityManager .persist ( new ComponentEntity ( 2L , new ComponentA ( BigDecimal .ONE , null ) ) );
172
+ } );
173
+ }
174
+
175
+ @ AfterAll
176
+ public void tearDown (EntityManagerFactoryScope scope ) {
177
+ scope .inTransaction ( entityManager -> entityManager .createQuery ( "delete from ComponentEntity" ).executeUpdate () );
178
+ }
179
+
100
180
@ Entity (name = "HHH15291Entity" )
101
181
public static class HHH15291Entity {
102
-
103
182
@ Id
104
183
@ Column (name = "KEY_CHAR" )
105
184
private String KeyString ;
@@ -118,53 +197,36 @@ public static class HHH15291Entity {
118
197
119
198
@ Column (name = "ITEM_INTEGER1" )
120
199
private Integer itemInteger1 ;
200
+ }
121
201
122
- public String getKeyString () {
123
- return KeyString ;
124
- }
125
-
126
- public void setKeyString (String keyString ) {
127
- KeyString = keyString ;
128
- }
129
-
130
- public String getItemString1 () {
131
- return itemString1 ;
132
- }
133
-
134
- public void setItemString1 (String itemString1 ) {
135
- this .itemString1 = itemString1 ;
136
- }
137
-
138
- public String getItemString2 () {
139
- return itemString2 ;
140
- }
141
-
142
- public void setItemString2 (String itemString2 ) {
143
- this .itemString2 = itemString2 ;
144
- }
202
+ @ Entity ( name = "ComponentEntity" )
203
+ static class ComponentEntity {
204
+ @ Id
205
+ private Long id ;
145
206
146
- public String getItemString3 () {
147
- return itemString3 ;
148
- }
207
+ @ Embedded
208
+ private ComponentA componentA ;
149
209
150
- public void setItemString3 (String itemString3 ) {
151
- this .itemString3 = itemString3 ;
210
+ public ComponentEntity () {
152
211
}
153
212
154
- public String getItemString4 () {
155
- return itemString4 ;
213
+ public ComponentEntity (Long id , ComponentA componentA ) {
214
+ this .id = id ;
215
+ this .componentA = componentA ;
156
216
}
217
+ }
157
218
158
- public void setItemString4 (String itemString4 ) {
159
- this .itemString4 = itemString4 ;
160
- }
219
+ @ Embeddable
220
+ static class ComponentA {
221
+ private BigDecimal income ;
222
+ private BigDecimal expense ;
161
223
162
- public Integer getItemInteger1 () {
163
- return itemInteger1 ;
224
+ public ComponentA () {
164
225
}
165
226
166
- public void setItemInteger1 (Integer itemInteger1 ) {
167
- this .itemInteger1 = itemInteger1 ;
227
+ public ComponentA (BigDecimal income , BigDecimal expense ) {
228
+ this .income = income ;
229
+ this .expense = expense ;
168
230
}
169
231
}
170
232
}
0 commit comments