Skip to content

Commit 4c1cd8a

Browse files
committed
[hibernate#1984] Test queries on JSON column mapped with an embedded field
1 parent f918fcc commit 4c1cd8a

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
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.types;
7+
8+
import java.math.BigDecimal;
9+
import java.util.Collection;
10+
import java.util.List;
11+
import java.util.Objects;
12+
13+
import org.hibernate.annotations.JdbcTypeCode;
14+
import org.hibernate.reactive.BaseReactiveTest;
15+
import org.hibernate.reactive.annotations.EnabledFor;
16+
import org.hibernate.type.SqlTypes;
17+
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Disabled;
20+
import org.junit.jupiter.api.Test;
21+
22+
import io.vertx.core.json.JsonObject;
23+
import io.vertx.junit5.Timeout;
24+
import io.vertx.junit5.VertxTestContext;
25+
import jakarta.persistence.Column;
26+
import jakarta.persistence.Embeddable;
27+
import jakarta.persistence.Entity;
28+
import jakarta.persistence.Id;
29+
import jakarta.persistence.Table;
30+
import jakarta.persistence.criteria.CriteriaBuilder;
31+
import jakarta.persistence.criteria.CriteriaQuery;
32+
import jakarta.persistence.criteria.Root;
33+
34+
import static java.util.concurrent.TimeUnit.MINUTES;
35+
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.COCKROACHDB;
37+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.POSTGRESQL;
38+
39+
@Timeout(value = 10, timeUnit = MINUTES)
40+
public class JsonQueryTest extends BaseReactiveTest {
41+
42+
private final static BigDecimal PIE = BigDecimal.valueOf( 3.1416 );
43+
private final static BigDecimal TAO = BigDecimal.valueOf( 6.2832 );
44+
45+
final Book fakeHistory = new Book( 3, "Fake History", new JsonObject().put( "amount", PIE ), new Book.Author( "Jo", "Hedwig Teeuwisse" ) );
46+
final Book theBookOfM = new Book( 5, "The Book of M", new JsonObject().put( "amount", TAO ), new Book.Author( "Peng", "Shepherd" ) );
47+
48+
@Override
49+
protected Collection<Class<?>> annotatedEntities() {
50+
return List.of( Book.class );
51+
}
52+
53+
@BeforeEach
54+
public void populateDb(VertxTestContext context) {
55+
test( context, getMutinySessionFactory().withTransaction( s -> s.persistAll( theBookOfM, fakeHistory ) ) );
56+
}
57+
58+
@Test
59+
public void criteriaSelectAll(VertxTestContext context) {
60+
CriteriaBuilder cb = getMutinySessionFactory().getCriteriaBuilder();
61+
CriteriaQuery<Book> bookQuery = cb.createQuery( Book.class );
62+
bookQuery.from( Book.class );
63+
test( context, getMutinySessionFactory()
64+
.withTransaction( s -> s.createQuery( bookQuery ).getResultList() )
65+
.invoke( results -> assertThat( results ).containsExactlyInAnyOrder( fakeHistory, theBookOfM ) )
66+
);
67+
}
68+
69+
@Test
70+
@EnabledFor(POSTGRESQL)
71+
@EnabledFor(COCKROACHDB)
72+
public void criteriaQueryWithJsonbAndFunction(VertxTestContext context) {
73+
CriteriaBuilder cb = getMutinySessionFactory().getCriteriaBuilder();
74+
CriteriaQuery<Book> bookQuery = cb.createQuery( Book.class );
75+
Root<Book> bookRoot = bookQuery.from( Book.class );
76+
bookQuery.where( cb.equal(
77+
cb.function( "jsonb_extract_path_text", String.class, bookRoot.get( "author" ), cb.literal( "name" ) ),
78+
cb.literal( fakeHistory.author.name )
79+
) );
80+
81+
test( context, getMutinySessionFactory()
82+
.withTransaction( s -> s.createQuery( bookQuery ).getSingleResult() )
83+
.invoke( result -> assertThat( result ).isEqualTo( fakeHistory ) )
84+
);
85+
}
86+
87+
@Test
88+
@EnabledFor(POSTGRESQL)
89+
@EnabledFor(COCKROACHDB)
90+
public void criteriaQueryWithJson(VertxTestContext context) {
91+
CriteriaBuilder cb = getMutinySessionFactory().getCriteriaBuilder();
92+
CriteriaQuery<Book> bookQuery = cb.createQuery( Book.class );
93+
bookQuery.from( Book.class );
94+
bookQuery.where( cb.between(
95+
cb.function( "sql", BigDecimal.class, cb.literal( "(price ->> ?)::decimal" ), cb.literal( "amount" ) ),
96+
BigDecimal.valueOf( 4.0 ),
97+
BigDecimal.valueOf( 100.0 )
98+
) );
99+
100+
test( context, getMutinySessionFactory()
101+
.withTransaction( s -> s.createQuery( bookQuery ).getSingleResult() )
102+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
103+
);
104+
}
105+
106+
@Test
107+
@EnabledFor(POSTGRESQL)
108+
@EnabledFor(COCKROACHDB)
109+
public void hqlQueryWithJson(VertxTestContext context) {
110+
test( context, getMutinySessionFactory()
111+
.withTransaction( s -> s
112+
.createSelectionQuery(
113+
"from Book where sql('(price ->> ?)::decimal', 'amount') between ?1 and ?2",
114+
Book.class
115+
)
116+
.setParameter( 1, BigDecimal.valueOf( 4.0 ) )
117+
.setParameter( 2, BigDecimal.valueOf( 100.0 ) )
118+
.getSingleResult()
119+
)
120+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
121+
);
122+
}
123+
124+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
125+
@Test
126+
public void nativeSelectAll(VertxTestContext context) {
127+
test( context, getMutinySessionFactory()
128+
.withTransaction( s -> s.createNativeQuery( "select * from BookWithJson", Book.class ).getResultList() )
129+
.invoke( results -> assertThat( results ).containsExactlyInAnyOrder( fakeHistory, theBookOfM ) )
130+
);
131+
}
132+
133+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
134+
@Test
135+
public void nativeSelectWithoutResultType(VertxTestContext context) {
136+
test( context, getMutinySessionFactory()
137+
.withTransaction( s -> s.createNativeQuery( "select * from BookWithJson" ).getResultList() )
138+
.invoke( results -> assertThat( results ).containsExactlyInAnyOrder( fakeHistory, theBookOfM ) )
139+
);
140+
}
141+
142+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
143+
@Test
144+
public void nativeQueryWithJson(VertxTestContext context) {
145+
test( context, getMutinySessionFactory()
146+
.withTransaction( s -> s
147+
.createNativeQuery(
148+
"select * from BookWithJson b where (b.price ->> 'amount')::decimal between ?1 and ?2",
149+
Book.class
150+
)
151+
.setParameter( 1, BigDecimal.valueOf( 4.0 ) )
152+
.setParameter( 2, BigDecimal.valueOf( 100.0 ) )
153+
.getSingleResult()
154+
)
155+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
156+
);
157+
}
158+
159+
@Entity(name = "Book")
160+
@Table(name = "BookWithJson")
161+
public static class Book {
162+
163+
@Id
164+
Integer id;
165+
166+
String title;
167+
168+
@Column(name = "price")
169+
JsonObject price;
170+
171+
@JdbcTypeCode(SqlTypes.JSON)
172+
Author author;
173+
174+
@Embeddable
175+
public static class Author {
176+
private String name;
177+
private String surname;
178+
179+
public Author() {
180+
}
181+
182+
public Author(String name, String surname) {
183+
this.name = name;
184+
this.surname = surname;
185+
}
186+
187+
public String getName() {
188+
return name;
189+
}
190+
191+
public void setName(String name) {
192+
this.name = name;
193+
}
194+
195+
public String getSurname() {
196+
return surname;
197+
}
198+
199+
public void setSurname(String surname) {
200+
this.surname = surname;
201+
}
202+
203+
@Override
204+
public boolean equals(Object o) {
205+
if ( this == o ) {
206+
return true;
207+
}
208+
if ( o == null || getClass() != o.getClass() ) {
209+
return false;
210+
}
211+
Author author = (Author) o;
212+
return Objects.equals( name, author.name ) && Objects.equals( surname, author.surname );
213+
}
214+
215+
@Override
216+
public int hashCode() {
217+
return Objects.hash( name, surname );
218+
}
219+
220+
@Override
221+
public String toString() {
222+
return name + ' ' + surname;
223+
}
224+
}
225+
226+
public Book() {
227+
}
228+
229+
public Book(Integer id, String title, JsonObject price, Author author) {
230+
this.id = id;
231+
this.title = title;
232+
this.price = price;
233+
this.author = author;
234+
}
235+
236+
@Override
237+
public boolean equals(Object o) {
238+
if ( this == o ) {
239+
return true;
240+
}
241+
if ( o == null || getClass() != o.getClass() ) {
242+
return false;
243+
}
244+
Book book = (Book) o;
245+
return Objects.equals( id, book.id ) && Objects.equals(
246+
title,
247+
book.title
248+
) && Objects.equals( price, book.price ) && Objects.equals( author, book.author );
249+
}
250+
251+
@Override
252+
public int hashCode() {
253+
return Objects.hash( id, title, price, author );
254+
}
255+
256+
@Override
257+
public String toString() {
258+
return id + ":" + title + ":" + price + ":" + author;
259+
}
260+
}
261+
}

0 commit comments

Comments
 (0)