Skip to content

Commit 90ddaed

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

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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.POSTGRESQL;
37+
38+
@Timeout(value = 10, timeUnit = MINUTES)
39+
@EnabledFor(POSTGRESQL)
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+
public void criteriaQueryWithJsonbAndFunction(VertxTestContext context) {
71+
CriteriaBuilder cb = getMutinySessionFactory().getCriteriaBuilder();
72+
CriteriaQuery<Book> bookQuery = cb.createQuery( Book.class );
73+
Root<Book> bookRoot = bookQuery.from( Book.class );
74+
bookQuery.where( cb.equal(
75+
cb.function( "jsonb_extract_path_text", String.class, bookRoot.get( "author" ), cb.literal( "name" ) ),
76+
cb.literal( fakeHistory.author.name )
77+
) );
78+
79+
test( context, getMutinySessionFactory()
80+
.withTransaction( s -> s.createQuery( bookQuery ).getSingleResult() )
81+
.invoke( result -> assertThat( result ).isEqualTo( fakeHistory ) )
82+
);
83+
}
84+
85+
@Test
86+
public void criteriaQueryWithJson(VertxTestContext context) {
87+
CriteriaBuilder cb = getMutinySessionFactory().getCriteriaBuilder();
88+
CriteriaQuery<Book> bookQuery = cb.createQuery( Book.class );
89+
bookQuery.from( Book.class );
90+
bookQuery.where( cb.between(
91+
cb.function( "sql", BigDecimal.class, cb.literal( "(price ->> ?)::decimal" ), cb.literal( "amount" ) ),
92+
BigDecimal.valueOf( 4.0 ),
93+
BigDecimal.valueOf( 100.0 )
94+
) );
95+
96+
test( context, getMutinySessionFactory()
97+
.withTransaction( s -> s.createQuery( bookQuery ).getSingleResult() )
98+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
99+
);
100+
}
101+
102+
@Test
103+
public void hqlQueryWithJson(VertxTestContext context) {
104+
test( context, getMutinySessionFactory()
105+
.withTransaction( s -> s
106+
.createSelectionQuery(
107+
"from Book where sql('(price ->> ?)::decimal', 'amount') between ?1 and ?2",
108+
Book.class
109+
)
110+
.setParameter( 1, BigDecimal.valueOf( 4.0 ) )
111+
.setParameter( 2, BigDecimal.valueOf( 100.0 ) )
112+
.getSingleResult()
113+
)
114+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
115+
);
116+
}
117+
118+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
119+
@Test
120+
public void nativeSelectAll(VertxTestContext context) {
121+
test( context, getMutinySessionFactory()
122+
.withTransaction( s -> s.createNativeQuery( "select * from BookWithJson", Book.class ).getResultList() )
123+
.invoke( results -> assertThat( results ).containsExactlyInAnyOrder( fakeHistory, theBookOfM ) )
124+
);
125+
}
126+
127+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
128+
@Test
129+
public void nativeSelectWithoutResultType(VertxTestContext context) {
130+
test( context, getMutinySessionFactory()
131+
.withTransaction( s -> s.createNativeQuery( "select * from BookWithJson" ).getResultList() )
132+
.invoke( results -> assertThat( results ).containsExactlyInAnyOrder( fakeHistory, theBookOfM ) )
133+
);
134+
}
135+
136+
@Disabled("https://github.com/hibernate/hibernate-reactive/issues/1999")
137+
@Test
138+
public void nativeQueryWithJson(VertxTestContext context) {
139+
test( context, getMutinySessionFactory()
140+
.withTransaction( s -> s
141+
.createNativeQuery(
142+
"select * from BookWithJson b where (b.price ->> 'amount')::decimal between ?1 and ?2",
143+
Book.class
144+
)
145+
.setParameter( 1, BigDecimal.valueOf( 4.0 ) )
146+
.setParameter( 2, BigDecimal.valueOf( 100.0 ) )
147+
.getSingleResult()
148+
)
149+
.invoke( result -> assertThat( result ).isEqualTo( theBookOfM ) )
150+
);
151+
}
152+
153+
@Entity(name = "Book")
154+
@Table(name = "BookWithJson")
155+
public static class Book {
156+
157+
@Id
158+
Integer id;
159+
160+
String title;
161+
162+
@Column(name = "price")
163+
JsonObject price;
164+
165+
@JdbcTypeCode(SqlTypes.JSON)
166+
Author author;
167+
168+
public Book() {
169+
}
170+
171+
public Book(Integer id, String title, JsonObject price, Author author) {
172+
this.id = id;
173+
this.title = title;
174+
this.price = price;
175+
this.author = author;
176+
}
177+
178+
@Override
179+
public boolean equals(Object o) {
180+
if ( this == o ) {
181+
return true;
182+
}
183+
if ( o == null || getClass() != o.getClass() ) {
184+
return false;
185+
}
186+
Book book = (Book) o;
187+
return Objects.equals( id, book.id ) && Objects.equals(
188+
title,
189+
book.title
190+
) && Objects.equals( price, book.price ) && Objects.equals( author, book.author );
191+
}
192+
193+
@Override
194+
public int hashCode() {
195+
return Objects.hash( id, title, price, author );
196+
}
197+
198+
@Override
199+
public String toString() {
200+
return id + ":" + title + ":" + price + ":" + author;
201+
}
202+
203+
204+
@Embeddable
205+
public static class Author {
206+
private String name;
207+
private String surname;
208+
209+
public Author() {
210+
}
211+
212+
public Author(String name, String surname) {
213+
this.name = name;
214+
this.surname = surname;
215+
}
216+
217+
public String getName() {
218+
return name;
219+
}
220+
221+
public void setName(String name) {
222+
this.name = name;
223+
}
224+
225+
public String getSurname() {
226+
return surname;
227+
}
228+
229+
public void setSurname(String surname) {
230+
this.surname = surname;
231+
}
232+
233+
@Override
234+
public boolean equals(Object o) {
235+
if ( this == o ) {
236+
return true;
237+
}
238+
if ( o == null || getClass() != o.getClass() ) {
239+
return false;
240+
}
241+
Author author = (Author) o;
242+
return Objects.equals( name, author.name ) && Objects.equals( surname, author.surname );
243+
}
244+
245+
@Override
246+
public int hashCode() {
247+
return Objects.hash( name, surname );
248+
}
249+
250+
@Override
251+
public String toString() {
252+
return name + ' ' + surname;
253+
}
254+
}
255+
}
256+
}

0 commit comments

Comments
 (0)