Skip to content

Commit 182859c

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

File tree

1 file changed

+258
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)