diff --git a/project/gradle.properties b/project/gradle.properties index 961a469844..e444308297 100644 --- a/project/gradle.properties +++ b/project/gradle.properties @@ -1,2 +1,2 @@ group=org.babyfish.jimmer -version=0.9.0 +version=0.9.1 diff --git a/project/jimmer-core/src/main/java/org/babyfish/jimmer/impl/util/GenericValidator.java b/project/jimmer-core/src/main/java/org/babyfish/jimmer/impl/util/GenericValidator.java index 722caad213..250f8eda0b 100644 --- a/project/jimmer-core/src/main/java/org/babyfish/jimmer/impl/util/GenericValidator.java +++ b/project/jimmer-core/src/main/java/org/babyfish/jimmer/impl/util/GenericValidator.java @@ -5,8 +5,7 @@ import org.babyfish.jimmer.meta.ModelException; import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; +import java.lang.reflect.*; import java.util.Map; import java.util.TreeMap; @@ -73,7 +72,7 @@ public void validate() { ); } if (expected.allowSubType) { - if (!TypeUtils.isAssignable(actualType, expected.type)) { + if (!match(actualType, expected.type)) { ex( "that type specifies the type arguments[" + expected.typeParameterIndex + @@ -115,6 +114,55 @@ private void ex(String message) { ); } + private static boolean match(Type a, Type b) { + if (a == null || b == null) { + return a == b; + } + a = noWildcardType(a); + b = noWildcardType(b); + if (a instanceof ParameterizedType) { + if (!(b instanceof ParameterizedType)) { + return false; + } + ParameterizedType pa = (ParameterizedType) a; + ParameterizedType pb = (ParameterizedType) b; + if (!match(pa.getOwnerType(), pb.getOwnerType())) { + return false; + } + if (!match(pa.getRawType(), pb.getRawType())) { + return false; + } + Type[] arr1 = pa.getActualTypeArguments(); + Type[] arr2 = pb.getActualTypeArguments(); + if (arr1.length != arr2.length) { + return false; + } + for (int i = arr1.length - 1; i >= 0; --i) { + if (!match(arr1[i], arr2[i])) { + return false; + } + } + return true; + } + if (a instanceof GenericArrayType) { + if (!(b instanceof GenericArrayType)) { + return false; + } + GenericArrayType ga = (GenericArrayType) a; + GenericArrayType gb = (GenericArrayType) b; + return match(ga.getGenericComponentType(), gb.getGenericComponentType()); + } + return a == b; + } + + private static Type noWildcardType(Type type) { + if (type instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) type; + return wildcardType.getUpperBounds()[0]; + } + return type; + } + private static class Expected { final int typeParameterIndex; diff --git a/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/model/classic/store/BookStore.kt b/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/model/classic/store/BookStore.kt index 4ea4e07f35..369d49dbba 100644 --- a/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/model/classic/store/BookStore.kt +++ b/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/model/classic/store/BookStore.kt @@ -5,6 +5,7 @@ import org.babyfish.jimmer.sql.kt.model.calc.BookStoreAvgPriceResolver import org.babyfish.jimmer.sql.kt.model.calc.BookStoreNewestBooksResolver import org.babyfish.jimmer.sql.kt.model.classic.book.Book import java.math.BigDecimal +import java.util.UUID import javax.validation.constraints.NotBlank /** @@ -54,4 +55,8 @@ interface BookStore { */ @Transient(BookStoreNewestBooksResolver::class) val newestBooks: List + + // For issue 714 + @Transient(BookStoreNewestBooksResolver::class) + val newestBookIds: List } \ No newline at end of file diff --git a/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/query/FetcherTest.kt b/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/query/FetcherTest.kt index 65a698cdea..203dedab74 100644 --- a/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/query/FetcherTest.kt +++ b/project/jimmer-sql-kotlin/src/test/kotlin/org/babyfish/jimmer/sql/kt/query/FetcherTest.kt @@ -750,6 +750,49 @@ class FetcherTest : AbstractQueryTest() { } } + @Test + fun testIssue714() { + executeAndExpect( + sqlClient.createQuery(BookStore::class) { + select(table.fetchBy { + allScalarFields() + newestBookIds() + }) + } + ) { + sql( + """select tb_1_.ID, tb_1_.NAME, tb_1_.VERSION, tb_1_.WEBSITE + |from BOOK_STORE tb_1_""".trimMargin() + ) + statement(1).sql( + """select tb_1_.ID, tb_2_.ID + |from BOOK_STORE tb_1_ + |inner join BOOK tb_2_ on tb_1_.ID = tb_2_.STORE_ID + |where (tb_2_.NAME, tb_2_.EDITION) in ( + |--->select tb_3_.NAME, max(tb_3_.EDITION) + |--->from BOOK tb_3_ + |--->where tb_3_.STORE_ID in (?, ?) + |--->group by tb_3_.NAME + |)""".trimMargin() + ) + rows( + """[{ + |--->"id":1, + |--->"name":"O'REILLY", + |--->"version":0, + |--->"website":null, + |--->"newestBookIds":[3,6,9] + |},{ + |--->"id":2, + |--->"name":"MANNING", + |--->"version":0, + |--->"website":null, + |--->"newestBookIds":[12] + |}]""".trimMargin() + ) + } + } + @Test fun testFlatIdForIssue671() { executeAndExpect( diff --git a/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/fetcher/impl/FetcherTask.java b/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/fetcher/impl/FetcherTask.java index cca48e094d..bd3cd4730b 100644 --- a/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/fetcher/impl/FetcherTask.java +++ b/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/fetcher/impl/FetcherTask.java @@ -160,6 +160,9 @@ private void afterLoad(TaskData taskData, Object value, boolean updateCache) { for (DraftSpi draft : taskData.getDrafts()) { setDraftProp(draft, value, field); } + if (!field.getProp().isAssociation(TargetLevel.ENTITY)) { + return; + } RecursionStrategy recursionStrategy = (RecursionStrategy) field.getRecursionStrategy(); if (value instanceof List) { diff --git a/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/runtime/ConnectionManager.java b/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/runtime/ConnectionManager.java index 04d60c43fa..4489e59239 100644 --- a/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/runtime/ConnectionManager.java +++ b/project/jimmer-sql/src/main/java/org/babyfish/jimmer/sql/runtime/ConnectionManager.java @@ -1,6 +1,5 @@ package org.babyfish.jimmer.sql.runtime; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.sql.DataSource; diff --git a/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/fetcher/TransientResolverTest.java b/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/fetcher/TransientResolverTest.java index ffce777896..af4f0f479a 100644 --- a/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/fetcher/TransientResolverTest.java +++ b/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/fetcher/TransientResolverTest.java @@ -296,6 +296,59 @@ public void testNewestBooks() { ); } + @Test + public void testIssue714() { + executeAndExpect( + getLambdaClient().createQuery(BookStoreTable.class, (q, store) -> { + return q.select( + store.fetch( + BookStoreFetcher.$ + .allScalarFields() + .newestBookIds() + ) + ); + }), + ctx -> { + ctx.sql( + "select tb_1_.ID, tb_1_.NAME, tb_1_.WEBSITE, tb_1_.VERSION " + + "from BOOK_STORE tb_1_" + ); + ctx.statement(1).sql( + "select tb_1_.ID, tb_2_.ID " + + "from BOOK_STORE tb_1_ " + + "inner join BOOK tb_2_ on tb_1_.ID = tb_2_.STORE_ID " + + "where (tb_2_.NAME, tb_2_.EDITION) in (" + + "--->select tb_3_.NAME, max(tb_3_.EDITION) " + + "--->from BOOK tb_3_ " + + "--->where tb_3_.STORE_ID in (?, ?) " + + "--->group by tb_3_.NAME" + + ")" + ); + ctx.rows( + "[{" + + "--->\"id\":\"d38c10da-6be8-4924-b9b9-5e81899612a0\"," + + "--->\"name\":\"O'REILLY\"," + + "--->\"website\":null," + + "--->\"version\":0," + + "--->\"newestBookIds\":[" + + "--->--->\"64873631-5d82-4bae-8eb8-72dd955bfc56\"," + + "--->--->\"9eded40f-6d2e-41de-b4e7-33a28b11c8b6\"," + + "--->--->\"782b9a9d-eac8-41c4-9f2d-74a5d047f45a\"" + + "--->]" + + "},{" + + "--->\"id\":\"2fa3955e-3e83-49b9-902e-0465c109c779\"," + + "--->\"name\":\"MANNING\"," + + "--->\"website\":null," + + "--->\"version\":0," + + "--->\"newestBookIds\":[" + + "--->--->\"780bdf07-05af-48bf-9be9-f8c65236fecc\"" + + "--->]" + + "}]" + ); + } + ); + } + @Test public void testNewestBooksWithPropFilter() { executeAndExpect( diff --git a/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/model/BookStore.java b/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/model/BookStore.java index 076292dfa6..d19ad549b3 100644 --- a/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/model/BookStore.java +++ b/project/jimmer-sql/src/test/java/org/babyfish/jimmer/sql/model/BookStore.java @@ -47,6 +47,10 @@ public interface BookStore { @Transient(BookStoreNewestBooksResolver.class) List newestBooks(); + // For issue714 + @Transient(BookStoreNewestBooksResolver.class) + List newestBookIds(); + @Formula(dependencies = "books.price") default BigDecimal maxPrice() { BigDecimal maxPrice = BigDecimal.ZERO;