From 230d18e48ffd96157865743faa34a391461b7726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bucht=C3=ADk?= Date: Fri, 27 Jan 2023 11:39:37 +0100 Subject: [PATCH 1/5] failing test for rawSql select .asDto query --- .../tests/rawsql/TestRawSqlQuerySelect.java | 42 +++++++++++++++++++ .../rawsql/transport/QuerySumResponse.java | 30 +++++++++++++ .../tests/rawsql/transport/SampleReport.java | 12 ++++++ 3 files changed, 84 insertions(+) create mode 100644 ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java create mode 100644 ebean-test/src/test/java/org/tests/rawsql/transport/QuerySumResponse.java create mode 100644 ebean-test/src/test/java/org/tests/rawsql/transport/SampleReport.java diff --git a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java new file mode 100644 index 000000000..029b1ec53 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java @@ -0,0 +1,42 @@ +package org.tests.rawsql; + +import io.ebean.DB; +import io.ebean.FetchGroup; +import io.ebean.RawSql; +import io.ebean.RawSqlBuilder; +import io.ebean.xtest.BaseTestCase; +import org.junit.jupiter.api.Test; +import org.tests.model.basic.ResetBasicData; +import org.tests.rawsql.transport.QuerySumResponse; +import org.tests.rawsql.transport.SampleReport; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class TestRawSqlQuerySelect extends BaseTestCase { + + @Test + public void testRawSQL() { + + ResetBasicData.reset(); + + RawSql rawSql = RawSqlBuilder.parse("select id, name, anniversary, city from (select c.id, c.name, c.anniversary, a.city from o_customer c left join o_address a ON a.id = c.billing_address_id order by c.id) w").create(); + + var query = DB.find(SampleReport.class); + query.setMaxRows(10); + + List list = query.findList(); + assertNotNull(list); + + String sumSql = "COUNT(1)::Long AS count, SUM(id) AS sum"; + + query.setRawSql(rawSql); + //query.select(sumSql); + query.select(FetchGroup.of(SampleReport.class, sumSql)); + + query.asDto(QuerySumResponse.class); + var countSum = query.findOneOrEmpty().orElseThrow(); + //assertThat((countSum instanceof QuerySumResponse)); + } +} diff --git a/ebean-test/src/test/java/org/tests/rawsql/transport/QuerySumResponse.java b/ebean-test/src/test/java/org/tests/rawsql/transport/QuerySumResponse.java new file mode 100644 index 000000000..d6a61b6f5 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/rawsql/transport/QuerySumResponse.java @@ -0,0 +1,30 @@ +package org.tests.rawsql.transport; + +public class QuerySumResponse { + private long count; + private Double sum; + + public QuerySumResponse() { + } + + public QuerySumResponse(long count, Double sum) { + this.count = count; + this.sum = sum; + } + + public long getCount() { + return count; + } + + public void setCount(long count) { + this.count = count; + } + + public Double getSum() { + return sum; + } + + public void setSum(Double sum) { + this.sum = sum; + } +} diff --git a/ebean-test/src/test/java/org/tests/rawsql/transport/SampleReport.java b/ebean-test/src/test/java/org/tests/rawsql/transport/SampleReport.java new file mode 100644 index 000000000..a119896e8 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/rawsql/transport/SampleReport.java @@ -0,0 +1,12 @@ +package org.tests.rawsql.transport; + +import javax.persistence.Entity; +import java.sql.Date; + +@Entity +public class SampleReport { + Long id; + String name; + Date anniversary; + String city; +} From 6055a33dc8e2205938e2f02dffee8a952c568a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bucht=C3=ADk?= Date: Fri, 27 Jan 2023 12:11:01 +0100 Subject: [PATCH 2/5] fix changes --- .../src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java index 029b1ec53..1ac19ff93 100644 --- a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java +++ b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java @@ -24,6 +24,7 @@ public class TestRawSqlQuerySelect extends BaseTestCase { RawSql rawSql = RawSqlBuilder.parse("select id, name, anniversary, city from (select c.id, c.name, c.anniversary, a.city from o_customer c left join o_address a ON a.id = c.billing_address_id order by c.id) w").create(); var query = DB.find(SampleReport.class); + query.setRawSql(rawSql); query.setMaxRows(10); List list = query.findList(); @@ -31,11 +32,10 @@ public class TestRawSqlQuerySelect extends BaseTestCase { String sumSql = "COUNT(1)::Long AS count, SUM(id) AS sum"; - query.setRawSql(rawSql); //query.select(sumSql); query.select(FetchGroup.of(SampleReport.class, sumSql)); - query.asDto(QuerySumResponse.class); + var countSum = query.findOneOrEmpty().orElseThrow(); //assertThat((countSum instanceof QuerySumResponse)); } From 01a0cee3c213a0d3043730ad4e482809a6e46cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bucht=C3=ADk?= Date: Fri, 10 Feb 2023 12:17:40 +0100 Subject: [PATCH 3/5] patch RawSql query builder, fix tests --- .../server/query/CQueryBuilderRawSql.java | 15 +++++++++++- .../tests/rawsql/TestRawSqlQuerySelect.java | 24 +++++++++---------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java index 290b706c2..812a13202 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java @@ -8,6 +8,7 @@ import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.querydefn.OrmQueryLimitRequest; +import io.ebeaninternal.server.querydefn.OrmQueryProperties; import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.util.BindParamsParser; @@ -56,7 +57,19 @@ final class CQueryBuilderRawSql { private String buildMainQuery(String orderBy, OrmQueryRequest request, CQueryPredicates predicates, SpiRawSql.Sql sql) { StringBuilder sb = new StringBuilder(); - sb.append(sql.getPreFrom()); + OrmQueryProperties ormQueryProperties = request.query().getDetail().getChunk(null, false); + if (ormQueryProperties.hasSelectClause()) { + boolean first = true; + for (String selectProperty : ormQueryProperties.getIncluded()) { + if (!first) { + sb.append(", "); + } + sb.append(selectProperty.replace("::Long", "::BIGINT")); + first = false; + } + } else { + sb.append(sql.getPreFrom()); + } sb.append(" "); String s = sql.getPreWhere(); diff --git a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java index 1ac19ff93..7732fa5e6 100644 --- a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java +++ b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlQuerySelect.java @@ -5,6 +5,7 @@ import io.ebean.FetchGroup; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; import io.ebean.xtest.BaseTestCase; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.tests.model.basic.ResetBasicData; import org.tests.rawsql.transport.QuerySumResponse; @@ -12,8 +13,6 @@ import org.tests.rawsql.transport.SampleReport; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertNotNull; - public class TestRawSqlQuerySelect extends BaseTestCase { @Test @@ -22,21 +21,22 @@ public class TestRawSqlQuerySelect extends BaseTestCase { ResetBasicData.reset(); RawSql rawSql = RawSqlBuilder.parse("select id, name, anniversary, city from (select c.id, c.name, c.anniversary, a.city from o_customer c left join o_address a ON a.id = c.billing_address_id order by c.id) w").create(); + String sumSql = "COUNT(1)::BIGINT AS count, SUM(id)::DOUBLE PRECISION AS sum"; var query = DB.find(SampleReport.class); query.setRawSql(rawSql); query.setMaxRows(10); - List list = query.findList(); - assertNotNull(list); + Assertions.assertNotNull(list); + Assertions.assertTrue(!list.isEmpty() && list.size() < 11); - String sumSql = "COUNT(1)::Long AS count, SUM(id) AS sum"; - - //query.select(sumSql); - query.select(FetchGroup.of(SampleReport.class, sumSql)); - query.asDto(QuerySumResponse.class); - - var countSum = query.findOneOrEmpty().orElseThrow(); - //assertThat((countSum instanceof QuerySumResponse)); + var countSum = DB.find(SampleReport.class) + .setRawSql(rawSql) + //.select(sumSql) + .select(FetchGroup.of(SampleReport.class, sumSql)) + .setMaxRows(10) + .asDto(QuerySumResponse.class) + .findOne(); + Assertions.assertInstanceOf(QuerySumResponse.class, countSum); } } From 1af3d0bcf3e755825ca02360b94309fb9b68308d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bucht=C3=ADk?= Date: Fri, 10 Feb 2023 12:27:10 +0100 Subject: [PATCH 4/5] remove unnecessary replace --- .../java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java index 812a13202..2963d979d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilderRawSql.java @@ -64,7 +64,7 @@ final class CQueryBuilderRawSql { if (!first) { sb.append(", "); } - sb.append(selectProperty.replace("::Long", "::BIGINT")); + sb.append(selectProperty); first = false; } } else { From 523fe6ae5493efea5f240b926b7f1edca33161c3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 10 Mar 2023 20:31:54 +1300 Subject: [PATCH 5/5] #2946 - Support specify select clause for RawSql --- .../server/querydefn/DefaultOrmQuery.java | 15 ++++++-- .../ebeaninternal/server/rawsql/DRawSql.java | 4 ++ .../server/rawsql/SpiRawSql.java | 15 ++++---- .../org/tests/rawsql/TestRawSqlOrmQuery.java | 38 ++++++++++++++++--- 4 files changed, 54 insertions(+), 18 deletions(-) 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 075dbaa76..e9822ec26 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 @@ -591,10 +591,17 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { */ @Override public final void setSelectId() { - // clear select and fetch joins - detail.clear(); - select(beanDescriptor.idSelect()); - singleAttribute = true; + if (rawSql != null) { + String column = rawSql.mapToColumn(beanDescriptor.idSelect()); + if (column != null) { + select(column); + } + } else { + // clear select and fetch joins + detail.clear(); + select(beanDescriptor.idSelect()); + singleAttribute = true; + } } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSql.java index c58b8bc11..6d17f7270 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSql.java @@ -60,4 +60,8 @@ public final class DRawSql implements SpiRawSql { return columnMapping; } + @Override + public String mapToColumn(String property) { + return columnMapping.mapToColumn(property); + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/SpiRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/SpiRawSql.java index d38f600ee..d54a296e5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/SpiRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/SpiRawSql.java @@ -5,13 +5,7 @@ import io.ebean.util.CamelCaseHelper; import java.io.Serializable; import java.sql.ResultSet; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; /** * Internal service API for Raw Sql. @@ -31,6 +25,7 @@ public interface SpiRawSql extends RawSql { SpiRawSql.ColumnMapping getColumnMapping(); + String mapToColumn(String property); /** * Represents the sql part of the query. For parsed RawSql the sql is broken @@ -363,7 +358,6 @@ public interface SpiRawSql extends RawSql { *

*/ public void tableAliasMapping(String tableAlias, String path) { - String startMatch = tableAlias + "."; for (Map.Entry entry : dbColumnMap.entrySet()) { if (entry.getKey().startsWith(startMatch)) { @@ -372,6 +366,11 @@ public interface SpiRawSql extends RawSql { } } + public String mapToColumn(String property) { + final var column = propertyColumnMap.get(property); + return column == null ? null : column.getDbColumn(); + } + /** * A Column of the RawSql that is mapped to a bean property (or ignored). */ diff --git a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java index 441100133..280969cdf 100644 --- a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java +++ b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java @@ -1,10 +1,10 @@ package org.tests.rawsql; import io.ebean.*; -import io.ebean.xtest.BaseTestCase; -import io.ebean.xtest.IgnorePlatform; import io.ebean.annotation.Platform; import io.ebean.test.LoggedSql; +import io.ebean.xtest.BaseTestCase; +import io.ebean.xtest.IgnorePlatform; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.Order; @@ -21,7 +21,6 @@ public class TestRawSqlOrmQuery extends BaseTestCase { @Test public void test() { - ResetBasicData.reset(); RawSql rawSql = RawSqlBuilder.parse("select r.id, r.name from o_customer r ") @@ -42,10 +41,37 @@ public class TestRawSqlOrmQuery extends BaseTestCase { LoggedSql.start(); assertThat(query.findCount()).isEqualTo(list.size()); Listsql = LoggedSql.stop(); - assertThat(sql.get(0)).startsWith("select count(*) from ( select r.id, r.name from o_customer r"); + assertThat(sql.get(0)).startsWith("select count(*) from ( select r.id from o_customer r"); assertThat(sql.get(0)).doesNotContain("order by"); } + @Test + public void testFindCount_when_idPropertyNotMapped() { + ResetBasicData.reset(); + + // mapping does not include the id column & property + RawSql rawSql = RawSqlBuilder.parse("select r.name, r.status from o_customer r ") + .columnMapping("r.name", "name") + .columnMapping("r.status", "status") + .create(); + + Query query = DB.find(Customer.class); + query.setRawSql(rawSql); + query.where().ilike("name", "r%").orderBy("name"); + + LoggedSql.start(); + List list = query.findList(); + assertNotNull(list); + + // check also select count(*) + assertThat(query.findCount()).isEqualTo(list.size()); + Listsql = LoggedSql.stop(); + assertThat(sql.get(0)).startsWith("select r.name, r.status from o_customer r where lower(r.name) like ?"); + assertThat(sql.get(0)).contains(" order by r.name"); + assertThat(sql.get(1)).startsWith("select count(*) from ( select r.name, r.status from o_customer r where lower(r.name) like ?"); + assertThat(sql.get(1)).doesNotContain("order by"); + } + @Test @IgnorePlatform({Platform.MYSQL, Platform.MARIADB, Platform.SQLSERVER}) public void test_upperCaseSql() { @@ -158,7 +184,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { LoggedSql.start(); query.findCount(); Listsql = LoggedSql.stop(); - assertThat(sql.get(0)).startsWith("select count(*) from ( select o.id, o.order_date, o.ship_date from o_order o"); + assertThat(sql.get(0)).startsWith("select count(*) from ( select o.id from o_order o"); assertThat(sql.get(0)).doesNotContain("order by"); } @@ -193,7 +219,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { LoggedSql.start(); query.findCount(); Listsql = LoggedSql.stop(); - assertThat(sql.get(0)).startsWith("select count(*) from ( select o.id, o.order_date, o.ship_date from o_order o"); + assertThat(sql.get(0)).startsWith("select count(*) from ( select o.id from o_order o"); assertThat(sql.get(0)).doesNotContain("order by"); }