Skip to content

[3.0] Test HQL new operator with many-to-one #2282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package org.hibernate.reactive;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
Expand All @@ -17,32 +18,41 @@
import io.vertx.junit5.Timeout;
import io.vertx.junit5.VertxTestContext;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;

import static jakarta.persistence.CascadeType.PERSIST;
import static jakarta.persistence.FetchType.LAZY;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@Timeout(value = 10, timeUnit = MINUTES)

public class HQLQueryTest extends BaseReactiveTest {

Flour spelt = new Flour( 1, "Spelt", "An ancient grain, is a hexaploid species of wheat.", "Wheat flour" );
Flour rye = new Flour( 2, "Rye", "Used to bake the traditional sourdough breads of Germany.", "Wheat flour" );
Flour almond = new Flour( 3, "Almond", "made from ground almonds.", "Gluten free" );

Author miller = new Author( "Madeline Miller");
Author camilleri = new Author( "Andrea Camilleri");
Book circe = new Book( "9780316556347", "Circe", miller );
Book shapeOfWater = new Book( "0-330-49286-1 ", "The Shape of Water", camilleri );
Book spider = new Book( "978-0-14-311203-7", "The Patience of the Spider", camilleri );

@Override
protected Collection<Class<?>> annotatedEntities() {
return List.of( Flour.class );
return List.of( Flour.class, Book.class, Author.class );
}

@BeforeEach
public void populateDb(VertxTestContext context) {
test( context, getMutinySessionFactory()
.withTransaction( (session, transaction) -> session.persistAll( spelt, rye, almond ) ) );
test( context, getMutinySessionFactory().withTransaction( session -> session
.persistAll( spelt, rye, almond, miller, camilleri, circe, shapeOfWater, spider ) )
);
}

@Test
Expand All @@ -69,7 +79,7 @@ public void testAutoFlushOnResultList(VertxTestContext context) {
public void testSelectScalarString(VertxTestContext context) {
test( context, getSessionFactory().withSession( s -> {
Stage.SelectionQuery<String> qr = s.createSelectionQuery( "SELECT 'Prova' FROM Flour WHERE id = " + rye.getId(), String.class );
assertNotNull( qr );
assertThat( qr ).isNotNull();
return qr.getSingleResult();
} ).thenAccept( found -> assertEquals( "Prova", found ) ) );
}
Expand All @@ -78,30 +88,33 @@ public void testSelectScalarString(VertxTestContext context) {
public void testSelectScalarCount(VertxTestContext context) {
test( context, getSessionFactory().withSession( s -> {
Stage.SelectionQuery<Long> qr = s.createSelectionQuery( "SELECT count(*) FROM Flour", Long.class );
assertNotNull( qr );
assertThat( qr ).isNotNull();
return qr.getSingleResult();
} ).thenAccept( found -> assertEquals( 3L, found ) ) );
}

@Test
public void testSelectWithMultipleScalarValues(VertxTestContext context) {
test( context, getSessionFactory().withSession( s -> {
Stage.SelectionQuery<?> qr = s.createSelectionQuery( "SELECT 'Prova', f.id FROM Flour f WHERE f.id = " + rye.getId(), Object[].class );
assertNotNull( qr );
return qr.getSingleResult();
} ).thenAccept( found -> {
assertTrue( found instanceof Object[] );
assertEquals( "Prova", ( (Object[]) found )[0] );
assertEquals( rye.getId(), ( (Object[]) found )[1] );
} )
Stage.SelectionQuery<?> qr = s.createSelectionQuery(
"SELECT 'Prova', f.id FROM Flour f WHERE f.id = " + rye.getId(),
Object[].class
);
assertThat( qr ).isNotNull();
return qr.getSingleResult();
} ).thenAccept( found -> {
assertThat( found ).isInstanceOf( Object[].class );
assertEquals( "Prova", ( (Object[]) found )[0] );
assertEquals( rye.getId(), ( (Object[]) found )[1] );
} )
);
}

@Test
public void testSingleResultQueryOnId(VertxTestContext context) {
test( context, getSessionFactory().withSession( s -> {
Stage.SelectionQuery<?> qr = s.createSelectionQuery( "FROM Flour WHERE id = 1", Flour.class );
assertNotNull( qr );
assertThat( qr ).isNotNull();
return qr.getSingleResult();
} ).thenAccept( flour -> assertEquals( spelt, flour ) )
);
Expand All @@ -111,7 +124,7 @@ public void testSingleResultQueryOnId(VertxTestContext context) {
public void testSingleResultQueryOnName(VertxTestContext context) {
test( context, getSessionFactory().withSession( s -> {
Stage.SelectionQuery<?> qr = s.createSelectionQuery( "FROM Flour WHERE name = 'Almond'", Flour.class );
assertNotNull( qr );
assertThat( qr ).isNotNull();
return qr.getSingleResult();
} ).thenAccept( flour -> assertEquals( almond, flour ) )
);
Expand All @@ -122,13 +135,28 @@ public void testFromQuery(VertxTestContext context) {
test( context, getSessionFactory()
.withSession( s -> {
Stage.SelectionQuery<Flour> qr = s.createSelectionQuery( "FROM Flour ORDER BY name", Flour.class );
assertNotNull( qr );
assertThat( qr ).isNotNull();
return qr.getResultList();
} )
.thenAccept( results -> assertThat( results ).containsExactly( almond, rye, spelt ) )
);
}

@Test
public void testSelectNewConstructor(VertxTestContext context) {
test( context, getMutinySessionFactory()
.withTransaction( session -> session
.createQuery( "SELECT NEW Book(b.title, b.author) FROM Book b ORDER BY b.title DESC", Book.class )
.getResultList()
)
.invoke( books -> assertThat( books ).containsExactly(
new Book( shapeOfWater.title, camilleri ),
new Book( spider.title, camilleri ),
new Book( circe.title, miller )
) )
);
}

@Entity(name = "Flour")
@Table(name = "Flour")
public static class Flour {
Expand Down Expand Up @@ -204,4 +232,122 @@ public int hashCode() {
return Objects.hash( name, description, type );
}
}

@Entity(name = "Book")
@Table(name = "Book_HQL")
public static class Book {
@Id
@GeneratedValue
private Integer id;

private String isbn;

private String title;

@ManyToOne(fetch = LAZY)
private Author author;

public Book() {
}

public Book(String title, Author author) {
this.title = title;
this.author = author;
}

public Book(String isbn, String title, Author author) {
this.isbn = isbn;
this.title = title;
this.author = author;
author.books.add( this );
}

public Integer getId() {
return id;
}

public String getIsbn() {
return isbn;
}

public String getTitle() {
return title;
}

public Author getAuthor() {
return author;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Book book = (Book) o;
return Objects.equals( isbn, book.isbn ) && Objects.equals(
title,
book.title
) && Objects.equals( author, book.author );
}

@Override
public int hashCode() {
return Objects.hash( isbn, title, author );
}

@Override
public String toString() {
return id + ":" + isbn + ":" + title + ":" + author;
}
}

@Entity(name = "Author")
@Table(name = "Author_HQL")
public static class Author {
@Id @GeneratedValue
private Integer id;

private String name;

@OneToMany(mappedBy = "author", cascade = PERSIST)
private List<Book> books = new ArrayList<>();

public Author() {
}

public Author(String name) {
this.name = name;
}

public Integer getId() {
return id;
}

public String getName() {
return name;
}

public List<Book> getBooks() {
return books;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Author author = (Author) o;
return Objects.equals( name, author.name );
}

@Override
public int hashCode() {
return Objects.hashCode( name );
}

@Override
public String toString() {
return id + ":" + name;
}
}
}
Loading