From ef1143bb702822654d40b4e05312e4ada477c7a0 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Tue, 2 Mar 2021 15:26:29 +0100 Subject: [PATCH] FIX: orderBy does not work when used on formula property or in conjunction with "exists" query --- .../server/query/CQueryBuilder.java | 12 +++++-- .../server/querydefn/DefaultOrmQuery.java | 9 +++++ .../java/org/tests/basic/TestFetchId.java | 36 +++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index ab008a5cf..1162e914d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -616,11 +616,19 @@ class CQueryBuilder { if (request.isInlineCountDistinct()) { sb.append(")"); } - if (distinct && dbOrderBy != null && !query.isSingleAttribute()) { + if (distinct && dbOrderBy != null) { // add the orderBy columns to the select clause (due to distinct) final OrderBy orderBy = query.getOrderBy(); if (orderBy != null && orderBy.supportsSelect()) { - sb.append(", ").append(DbOrderByTrim.trim(dbOrderBy)); + String trimmed = DbOrderByTrim.trim(dbOrderBy); + if (query.isSingleAttribute() && trimmed.equals(select.getSelectSql())) { + // NOP, already in SQL + // TODO: what to do if we select("id").orderBy("prop,id")? + // Can we live with a query like "select t0.id, t0.prop, t0.id from" + // or should we elliminate the second "t0.id" from select + } else { + sb.append(", ").append(trimmed); + } } } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 6f72febb9..e6eafc0b8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -53,6 +53,7 @@ import io.ebeaninternal.server.deploy.BeanNaturalKey; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; +import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.expression.DefaultExpressionList; import io.ebeaninternal.server.expression.IdInExpression; import io.ebeaninternal.server.expression.SimpleExpression; @@ -537,6 +538,14 @@ public class DefaultOrmQuery implements SpiQuery { if (havingExpressions != null) { havingExpressions.containsMany(beanDescriptor, manyWhereJoins); } + if (orderBy != null) { + for (Property orderProperty : orderBy.getProperties()) { + ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(orderProperty.getProperty()); + if (elProp != null && elProp.containsFormulaWithJoin()) { + manyWhereJoins.addFormulaWithJoin(orderProperty.getProperty()); + } + } + } } /** diff --git a/ebean-core/src/test/java/org/tests/basic/TestFetchId.java b/ebean-core/src/test/java/org/tests/basic/TestFetchId.java index cf207995c..c830208d5 100644 --- a/ebean-core/src/test/java/org/tests/basic/TestFetchId.java +++ b/ebean-core/src/test/java/org/tests/basic/TestFetchId.java @@ -1,10 +1,14 @@ package org.tests.basic; import io.ebean.BaseTestCase; +import io.ebean.DB; import io.ebean.Ebean; import io.ebean.FutureIds; import io.ebean.Query; +import io.ebeantest.LoggedSql; + import org.tests.model.basic.Order; +import org.tests.model.basic.OrderDetail; import org.tests.model.basic.ResetBasicData; import org.junit.Test; @@ -36,4 +40,36 @@ public class TestFetchId extends BaseTestCase { List idList = futureIds.get(); assertThat(idList).isNotEmpty(); } + + @Test + public void testFetchIdWithExists() throws InterruptedException, ExecutionException { + + ResetBasicData.reset(); + + Query subQuery = Ebean.find(OrderDetail.class) + .alias("sq") + .where().raw("details.id = sq.id").query(); + Query query = Ebean.find(Order.class) + .where().exists(subQuery) + .orderBy("orderDate").query(); + + List ids = query.findIds(); + // TODO: assert(query.getGeneratedSql()) + assertThat(ids).isNotEmpty(); + FutureIds futureIds = query.findFutureIds(); + + // wait for all the id's to be fetched + List idList = futureIds.get(); + assertThat(idList).isNotEmpty(); + } + + @Test + public void testFetchIdWithOrderFormula() throws InterruptedException, ExecutionException { + + ResetBasicData.reset(); + + Query query = DB.find(Order.class).orderBy("totalItems"); + query.findIds(); + // TODO: assert(query.getGeneratedSql()) + } }