From eafdc4e68d0aab65153f5aefbc99c069f2222fb4 Mon Sep 17 00:00:00 2001 From: Radovan Radic Date: Thu, 5 Sep 2024 16:28:56 +0200 Subject: [PATCH] Regression issue with criteria inList failing to compile (#3108) * Regression issue with criteria inList failing to compile * Fix IN predicate --------- Co-authored-by: Denis Stepanov --- ...ractSourcePersistentEntityJoinSupport.java | 2 +- .../impl/SourcePersistentAssociationPath.java | 28 +++++++++++++++++++ .../data/processor/sql/BuildQuerySpec.groovy | 23 +++++++++++++++ .../tck/tests/AbstractRepositorySpec.groovy | 13 ++++++++- .../data/tck/repositories/BookRepository.java | 2 ++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/AbstractSourcePersistentEntityJoinSupport.java b/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/AbstractSourcePersistentEntityJoinSupport.java index 245eef96353..587f5896d13 100644 --- a/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/AbstractSourcePersistentEntityJoinSupport.java +++ b/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/AbstractSourcePersistentEntityJoinSupport.java @@ -39,7 +39,7 @@ @Internal abstract class AbstractSourcePersistentEntityJoinSupport extends AbstractPersistentEntityJoinSupport { - private final CriteriaBuilder criteriaBuilder; + protected final CriteriaBuilder criteriaBuilder; AbstractSourcePersistentEntityJoinSupport(CriteriaBuilder criteriaBuilder) { this.criteriaBuilder = criteriaBuilder; diff --git a/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/SourcePersistentAssociationPath.java b/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/SourcePersistentAssociationPath.java index 069f97c0ca3..44ed05af5f3 100644 --- a/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/SourcePersistentAssociationPath.java +++ b/data-processor/src/main/java/io/micronaut/data/processor/model/criteria/impl/SourcePersistentAssociationPath.java @@ -21,13 +21,20 @@ import io.micronaut.data.model.Association; import io.micronaut.data.model.jpa.criteria.PersistentAssociationPath; import io.micronaut.data.model.jpa.criteria.PersistentEntityFrom; +import io.micronaut.data.model.jpa.criteria.impl.predicate.PersistentPropertyInPredicate; import io.micronaut.data.processor.model.SourceAssociation; import io.micronaut.data.processor.model.SourcePersistentEntity; import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; /** * The internal source implementation of {@link PersistentAssociationPath}. @@ -62,6 +69,27 @@ final class SourcePersistentAssociationPath extends AbstractSourcePers this.alias = alias; } + @Override + public Predicate in(Object... values) { + return in(Arrays.asList(Objects.requireNonNull(values))); + } + + @Override + public Predicate in(Collection values) { + List> expressions = Objects.requireNonNull(values).stream().map(criteriaBuilder::literal).collect(Collectors.toList()); + return new PersistentPropertyInPredicate<>(this, expressions, criteriaBuilder); + } + + @Override + public Predicate in(Expression... values) { + return new PersistentPropertyInPredicate<>(this, Arrays.asList(values), criteriaBuilder); + } + + @Override + public Predicate in(Expression> values) { + return new PersistentPropertyInPredicate<>(this, List.of(Objects.requireNonNull(values)), criteriaBuilder); + } + @Override public PersistentEntityFrom getParent() { return parent; diff --git a/data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildQuerySpec.groovy b/data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildQuerySpec.groovy index c16ec5b59a9..fac6eee9d65 100644 --- a/data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildQuerySpec.groovy +++ b/data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildQuerySpec.groovy @@ -1969,4 +1969,27 @@ interface TestRepository extends GenericRepository { findByTitleIlikeQuery.endsWith('FROM "book" book_ WHERE (LOWER(book_."title") LIKE LOWER(?))') findByTitleNotLikeQuery.endsWith('FROM "book" book_ WHERE (NOT(book_."title" LIKE ?))') } + + void "test IN"() { + given: + def repository = buildRepository('test.TestRepository', """ + +import io.micronaut.data.jdbc.annotation.JdbcRepository; +import io.micronaut.data.repository.GenericRepository; +import io.micronaut.data.tck.entities.Book; +import io.micronaut.data.tck.entities.Author; +import io.micronaut.data.model.query.builder.sql.Dialect; + +import java.util.List; + +@JdbcRepository(dialect = Dialect.MYSQL) +interface TestRepository extends GenericRepository { + List findByAuthorInList(List authors); +} + +""") + def findByAuthorInListMethod = repository.findPossibleMethods("findByAuthorInList").findFirst().get() + expect: + getQuery(findByAuthorInListMethod) == "SELECT book_.`id`,book_.`author_id`,book_.`genre_id`,book_.`title`,book_.`total_pages`,book_.`publisher_id`,book_.`last_updated` FROM `book` book_ WHERE (book_.`author_id` IN (?))" + } } diff --git a/data-tck/src/main/groovy/io/micronaut/data/tck/tests/AbstractRepositorySpec.groovy b/data-tck/src/main/groovy/io/micronaut/data/tck/tests/AbstractRepositorySpec.groovy index f2bf0b9d03f..cec02e195a0 100644 --- a/data-tck/src/main/groovy/io/micronaut/data/tck/tests/AbstractRepositorySpec.groovy +++ b/data-tck/src/main/groovy/io/micronaut/data/tck/tests/AbstractRepositorySpec.groovy @@ -3078,7 +3078,18 @@ abstract class AbstractRepositorySpec extends Specification { basicTypeRepository.deleteById(entity.myId) TimeZone.setDefault(defaultTimeZone) } - + + void "find by joined entity in list"() { + given: + saveSampleBooks() + + when: + def author = authorRepository.findByName("Stephen King") + def books = bookRepository.findByAuthorInList(List.of(author)) + then: + books.size() > 0 + } + private GregorianCalendar getYearMonthDay(Date dateCreated) { def cal = dateCreated.toCalendar() def localDate = LocalDate.of(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)) diff --git a/data-tck/src/main/java/io/micronaut/data/tck/repositories/BookRepository.java b/data-tck/src/main/java/io/micronaut/data/tck/repositories/BookRepository.java index 0fe3b40e368..bdb66567337 100644 --- a/data-tck/src/main/java/io/micronaut/data/tck/repositories/BookRepository.java +++ b/data-tck/src/main/java/io/micronaut/data/tck/repositories/BookRepository.java @@ -178,4 +178,6 @@ protected Book newBook(Author author, String title, int pages) { @Query("SELECT b FROM Book b WHERE b.author.id in :authorIds") public abstract List findByAuthorIds(List authorIds); + + public abstract List findByAuthorInList(List authors); }